Skip to content

Commit f18b8cf

Browse files
committed
[DM/SDIO] Support DM mode
1. Support features read by DM. 2. Support regulator API in drivers. 3. Support send tuning option CMD. 4. Replace `switch_uhs_voltage` by `signal_voltage_switch`. Link: #9732 Signed-off-by: GuEe-GUI <[email protected]>
1 parent 7998166 commit f18b8cf

File tree

8 files changed

+761
-31
lines changed

8 files changed

+761
-31
lines changed

components/drivers/include/drivers/dev_mmcsd_core.h

+6
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,12 @@ void mmcsd_set_bus_width(struct rt_mmcsd_host *host, rt_uint32_t width);
242242
void mmcsd_set_timing(struct rt_mmcsd_host *host, rt_uint32_t timing);
243243
void mmcsd_set_data_timeout(struct rt_mmcsd_data *data, const struct rt_mmcsd_card *card);
244244
rt_uint32_t mmcsd_select_voltage(struct rt_mmcsd_host *host, rt_uint32_t ocr);
245+
rt_err_t mmcsd_set_signal_voltage(struct rt_mmcsd_host *host, unsigned char signal_voltage);
246+
void mmcsd_set_initial_signal_voltage(struct rt_mmcsd_host *host);
247+
rt_err_t mmcsd_host_set_uhs_voltage(struct rt_mmcsd_host *host);
248+
rt_err_t mmcsd_set_uhs_voltage(struct rt_mmcsd_host *host, rt_uint32_t ocr);
249+
rt_err_t mmcsd_send_tuning(struct rt_mmcsd_host *host, rt_uint32_t opcode, rt_err_t *cmd_error);
250+
rt_err_t mmcsd_send_abort_tuning(struct rt_mmcsd_host *host, rt_uint32_t opcode);
245251
void mmcsd_change(struct rt_mmcsd_host *host);
246252
void mmcsd_detect(void *param);
247253
void mmcsd_host_init(struct rt_mmcsd_host *host);

components/drivers/include/drivers/mmcsd_host.h

+22-1
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,23 @@ struct rt_mmcsd_host_ops
8888
rt_int32_t (*get_card_status)(struct rt_mmcsd_host *host);
8989
void (*enable_sdio_irq)(struct rt_mmcsd_host *host, rt_int32_t en);
9090
rt_int32_t (*execute_tuning)(struct rt_mmcsd_host *host, rt_int32_t opcode);
91-
rt_int32_t (*switch_uhs_voltage)(struct rt_mmcsd_host *host);
91+
rt_bool_t (*card_busy)(struct rt_mmcsd_host *host);
92+
rt_err_t (*signal_voltage_switch)(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io_cfg);
9293
};
9394

95+
#ifdef RT_USING_REGULATOR
96+
struct rt_regulator;
97+
98+
struct rt_mmcsd_supply
99+
{
100+
rt_bool_t vqmmc_enabled;
101+
rt_bool_t regulator_enabled;
102+
103+
struct rt_regulator *vmmc; /* Card power supply */
104+
struct rt_regulator *vqmmc; /* Optional Vccq supply */
105+
};
106+
#endif /* RT_USING_REGULATOR */
107+
94108
struct rt_mmcsd_host
95109
{
96110
char name[RT_NAME_MAX];
@@ -158,6 +172,13 @@ struct rt_mmcsd_host
158172
struct rt_semaphore *sdio_irq_sem;
159173
struct rt_thread *sdio_irq_thread;
160174

175+
#ifdef RT_USING_REGULATOR
176+
struct rt_mmcsd_supply supply;
177+
#endif
178+
#ifdef RT_USING_OFW
179+
void *ofw_node;
180+
#endif
181+
161182
void *private_data;
162183
};
163184
#ifdef __cplusplus

components/drivers/sdio/SConscript

+6
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ dev_mmc.c
1313
# The set of source files associated with this SConscript file.
1414
path = [cwd + '/../include']
1515

16+
if GetDepend(['RT_USING_DM']):
17+
src += ['dev_sdio_dm.c']
18+
19+
if GetDepend(['RT_USING_REGULATOR']):
20+
src += ['dev_regulator.c']
21+
1622
group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_SDIO'], CPPPATH = path)
1723

1824
Return('group')

components/drivers/sdio/dev_mmcsd_core.c

+288
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,281 @@ rt_uint32_t mmcsd_select_voltage(struct rt_mmcsd_host *host, rt_uint32_t ocr)
549549
return ocr;
550550
}
551551

552+
rt_err_t mmcsd_set_signal_voltage(struct rt_mmcsd_host *host, unsigned char signal_voltage)
553+
{
554+
rt_err_t err = RT_EOK;
555+
unsigned char old_signal_voltage = host->io_cfg.signal_voltage;
556+
557+
host->io_cfg.signal_voltage = signal_voltage;
558+
if (host->ops->signal_voltage_switch)
559+
{
560+
err = host->ops->signal_voltage_switch(host, &host->io_cfg);
561+
}
562+
563+
if (err)
564+
{
565+
host->io_cfg.signal_voltage = old_signal_voltage;
566+
}
567+
568+
return err;
569+
}
570+
571+
void mmcsd_set_initial_signal_voltage(struct rt_mmcsd_host *host)
572+
{
573+
/* 3.3V -> 1.8v -> 1.2v */
574+
if (!mmcsd_set_signal_voltage(host, MMCSD_SIGNAL_VOLTAGE_330))
575+
{
576+
LOG_D("Initial signal voltage of %sv", "3.3");
577+
}
578+
else if (!mmcsd_set_signal_voltage(host, MMCSD_SIGNAL_VOLTAGE_180))
579+
{
580+
LOG_D("Initial signal voltage of %sv", "1.8");
581+
}
582+
else if (!mmcsd_set_signal_voltage(host, MMCSD_SIGNAL_VOLTAGE_120))
583+
{
584+
LOG_D("Initial signal voltage of %sv", "1.2");
585+
}
586+
}
587+
588+
rt_err_t mmcsd_host_set_uhs_voltage(struct rt_mmcsd_host *host)
589+
{
590+
rt_uint32_t old_clock = host->io_cfg.clock;
591+
592+
host->io_cfg.clock = 0;
593+
mmcsd_set_iocfg(host);
594+
595+
if (mmcsd_set_signal_voltage(host, MMCSD_SIGNAL_VOLTAGE_180))
596+
{
597+
return -RT_ERROR;
598+
}
599+
600+
/* Keep clock gated for at least 10 ms, though spec only says 5 ms */
601+
rt_thread_mdelay(10);
602+
603+
host->io_cfg.clock = old_clock;
604+
mmcsd_set_iocfg(host);
605+
606+
return RT_EOK;
607+
}
608+
609+
static void mmcsd_power_cycle(struct rt_mmcsd_host *host, rt_uint32_t ocr);
610+
611+
rt_err_t mmcsd_set_uhs_voltage(struct rt_mmcsd_host *host, rt_uint32_t ocr)
612+
{
613+
rt_err_t err = RT_EOK;
614+
struct rt_mmcsd_cmd cmd;
615+
616+
if (!host->ops->signal_voltage_switch)
617+
{
618+
return -RT_EINVAL;
619+
}
620+
621+
if (!host->ops->card_busy)
622+
{
623+
LOG_W("%s: Cannot verify signal voltage switch", host->name);
624+
}
625+
626+
rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd));
627+
628+
cmd.cmd_code = VOLTAGE_SWITCH;
629+
cmd.arg = 0;
630+
cmd.flags = RESP_R1 | CMD_AC;
631+
632+
err = mmcsd_send_cmd(host, &cmd, 0);
633+
if (err)
634+
{
635+
goto power_cycle;
636+
}
637+
638+
if (!controller_is_spi(host) && (cmd.resp[0] & R1_ERROR))
639+
{
640+
return -RT_EIO;
641+
}
642+
643+
/*
644+
* The card should drive cmd and dat[0:3] low immediately
645+
* after the response of cmd11, but wait 1 ms to be sure
646+
*/
647+
rt_thread_mdelay(1);
648+
if (host->ops->card_busy && !host->ops->card_busy(host))
649+
{
650+
err = -RT_ERROR;
651+
goto power_cycle;
652+
}
653+
654+
if (mmcsd_host_set_uhs_voltage(host))
655+
{
656+
/*
657+
* Voltages may not have been switched, but we've already
658+
* sent CMD11, so a power cycle is required anyway
659+
*/
660+
err = -RT_ERROR;
661+
goto power_cycle;
662+
}
663+
664+
/* Wait for at least 1 ms according to spec */
665+
rt_thread_mdelay(1);
666+
667+
/*
668+
* Failure to switch is indicated by the card holding
669+
* dat[0:3] low
670+
*/
671+
if (host->ops->card_busy && host->ops->card_busy(host))
672+
{
673+
err = -RT_ERROR;
674+
}
675+
676+
power_cycle:
677+
if (err)
678+
{
679+
LOG_D("%s: Signal voltage switch failed, power cycling card", host->name);
680+
mmcsd_power_cycle(host, ocr);
681+
}
682+
683+
return err;
684+
}
685+
686+
static const rt_uint8_t tuning_blk_pattern_4bit[] =
687+
{
688+
0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
689+
0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef,
690+
0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb,
691+
0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef,
692+
0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c,
693+
0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee,
694+
0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff,
695+
0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
696+
};
697+
698+
static const rt_uint8_t tuning_blk_pattern_8bit[] =
699+
{
700+
0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
701+
0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc,
702+
0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff,
703+
0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
704+
0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd,
705+
0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb,
706+
0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff,
707+
0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff,
708+
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
709+
0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc,
710+
0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff,
711+
0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee,
712+
0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd,
713+
0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff,
714+
0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff,
715+
0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
716+
};
717+
718+
rt_err_t mmcsd_send_tuning(struct rt_mmcsd_host *host, rt_uint32_t opcode, rt_err_t *cmd_error)
719+
{
720+
rt_err_t err = RT_EOK;
721+
int size;
722+
rt_uint8_t *data_buf;
723+
const rt_uint8_t *tuning_block_pattern;
724+
struct rt_mmcsd_req req = {};
725+
struct rt_mmcsd_cmd cmd = {};
726+
struct rt_mmcsd_data data = {};
727+
struct rt_mmcsd_io_cfg *io_cfg = &host->io_cfg;
728+
729+
if (io_cfg->bus_width == MMCSD_BUS_WIDTH_8)
730+
{
731+
tuning_block_pattern = tuning_blk_pattern_8bit;
732+
size = sizeof(tuning_blk_pattern_8bit);
733+
}
734+
else if (io_cfg->bus_width == MMCSD_BUS_WIDTH_4)
735+
{
736+
tuning_block_pattern = tuning_blk_pattern_4bit;
737+
size = sizeof(tuning_blk_pattern_4bit);
738+
}
739+
else
740+
{
741+
return -RT_EINVAL;
742+
}
743+
744+
data_buf = rt_malloc(size);
745+
if (!data_buf)
746+
{
747+
return -RT_ENOMEM;
748+
}
749+
750+
rt_memset(data_buf, 0, size);
751+
rt_memset(&req, 0, sizeof(struct rt_mmcsd_req));
752+
rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd));
753+
rt_memset(&data, 0, sizeof(struct rt_mmcsd_data));
754+
755+
req.cmd = &cmd;
756+
req.data = &data;
757+
758+
cmd.cmd_code = opcode;
759+
cmd.flags = RESP_R1 | CMD_ADTC;
760+
761+
data.blksize = size;
762+
data.blks = 1;
763+
data.flags = DATA_DIR_READ;
764+
765+
/*
766+
* According to the tuning specs, Tuning process
767+
* is normally shorter 40 executions of CMD19,
768+
* and timeout value should be shorter than 150 ms
769+
*/
770+
data.timeout_ns = 150 * 1000000;
771+
772+
mmcsd_send_request(host, &req);
773+
774+
if (cmd_error)
775+
{
776+
*cmd_error = cmd.err;
777+
}
778+
779+
if (cmd.err)
780+
{
781+
err = cmd.err;
782+
goto out_free;
783+
}
784+
785+
if (data.err)
786+
{
787+
err = data.err;
788+
goto out_free;
789+
}
790+
791+
if (rt_memcmp(data_buf, tuning_block_pattern, size))
792+
{
793+
err = -RT_EIO;
794+
}
795+
796+
out_free:
797+
rt_free(data_buf);
798+
799+
return err;
800+
}
801+
802+
rt_err_t mmcsd_send_abort_tuning(struct rt_mmcsd_host *host, rt_uint32_t opcode)
803+
{
804+
struct rt_mmcsd_cmd cmd = {};
805+
806+
/*
807+
* eMMC specification specifies that CMD12 can be used to stop a tuning
808+
* command, but SD specification does not, so do nothing unless it is eMMC.
809+
*/
810+
if (opcode != SEND_TUNING_BLOCK_HS200)
811+
{
812+
return 0;
813+
}
814+
815+
cmd.cmd_code = STOP_TRANSMISSION;
816+
cmd.flags = RESP_SPI_R1 | RESP_R1 | CMD_AC;
817+
818+
/*
819+
* For drivers that override R1 to R1b, set an arbitrary timeout based
820+
* on the tuning timeout i.e. 150ms.
821+
*/
822+
cmd.busy_timeout = 150;
823+
824+
return mmcsd_send_cmd(host, &cmd, 0);
825+
}
826+
552827
static void mmcsd_power_up(struct rt_mmcsd_host *host)
553828
{
554829
int bit = __rt_fls(host->valid_ocr) - 1;
@@ -568,6 +843,8 @@ static void mmcsd_power_up(struct rt_mmcsd_host *host)
568843
host->io_cfg.bus_width = MMCSD_BUS_WIDTH_1;
569844
mmcsd_set_iocfg(host);
570845

846+
mmcsd_set_initial_signal_voltage(host);
847+
571848
/*
572849
* This delay should be sufficient to allow the power supply
573850
* to reach the minimum voltage.
@@ -599,6 +876,17 @@ static void mmcsd_power_off(struct rt_mmcsd_host *host)
599876
mmcsd_set_iocfg(host);
600877
}
601878

879+
static void mmcsd_power_cycle(struct rt_mmcsd_host *host, rt_uint32_t ocr)
880+
{
881+
mmcsd_power_off(host);
882+
883+
/* Wait at least 1 ms according to SD spec */
884+
rt_thread_mdelay(1);
885+
886+
mmcsd_power_up(host);
887+
mmcsd_select_voltage(host, ocr);
888+
}
889+
602890
int mmcsd_wait_cd_changed(rt_int32_t timeout)
603891
{
604892
struct rt_mmcsd_host *host;

0 commit comments

Comments
 (0)