From 06ec045feeea08993834e2f1d2d1e4ec52cdeff1 Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Thu, 21 Sep 2017 16:29:48 +0200 Subject: mmc: dm: get the IO-line and main voltage regulators from the dts Get a reference to the regulator devices from the dts and store them in the struct mmc for later use. Signed-off-by: Jean-Jacques Hiblot --- include/mmc.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'include') diff --git a/include/mmc.h b/include/mmc.h index 010ebe048c4..188dc749dd7 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -457,6 +457,10 @@ struct mmc { int ddr_mode; #if CONFIG_IS_ENABLED(DM_MMC) struct udevice *dev; /* Device for this MMC controller */ +#if CONFIG_IS_ENABLED(DM_REGULATOR) + struct udevice *vmmc_supply; /* Main voltage regulator (Vcc)*/ + struct udevice *vqmmc_supply; /* IO voltage regulator (Vccq)*/ +#endif #endif }; -- cgit v1.2.3 From dfda9d88e5062620952956f7ed8e2a31ceffa6e6 Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Thu, 21 Sep 2017 16:29:51 +0200 Subject: mmc: make ext_csd part of struct mmc The ext csd is used for comparison many times. Keep a reference content of the ext csd in the struct mmc to avoid reading multiple times Signed-off-by: Jean-Jacques Hiblot Reviewed-by: Simon Glass --- include/mmc.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/mmc.h b/include/mmc.h index 188dc749dd7..7d2b363acbb 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -462,6 +462,7 @@ struct mmc { struct udevice *vqmmc_supply; /* IO voltage regulator (Vccq)*/ #endif #endif + u8 *ext_csd; }; struct mmc_hwpart_conf { -- cgit v1.2.3 From 35f9e196f9573af4091076c19aaa6d5afeb91338 Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Thu, 21 Sep 2017 16:29:53 +0200 Subject: mmc: introduce mmc modes no functionnal changes. In order to add the support for the high speed SD and MMC modes, it is useful to track this information. Signed-off-by: Jean-Jacques Hiblot Reviewed-by: Simon Glass --- include/mmc.h | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/mmc.h b/include/mmc.h index 7d2b363acbb..76bd57ae429 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -52,12 +52,15 @@ #define MMC_VERSION_5_0 MAKE_MMC_VERSION(5, 0, 0) #define MMC_VERSION_5_1 MAKE_MMC_VERSION(5, 1, 0) -#define MMC_MODE_HS (1 << 0) -#define MMC_MODE_HS_52MHz (1 << 1) -#define MMC_MODE_4BIT (1 << 2) -#define MMC_MODE_8BIT (1 << 3) -#define MMC_MODE_SPI (1 << 4) -#define MMC_MODE_DDR_52MHz (1 << 5) +#define MMC_CAP(mode) (1 << mode) +#define MMC_MODE_HS (MMC_CAP(MMC_HS) | MMC_CAP(SD_HS)) +#define MMC_MODE_HS_52MHz MMC_CAP(MMC_HS_52) +#define MMC_MODE_DDR_52MHz MMC_CAP(MMC_DDR_52) + +#define MMC_MODE_8BIT BIT(30) +#define MMC_MODE_4BIT BIT(29) +#define MMC_MODE_SPI BIT(27) + #define SD_DATA_4BIT 0x00040000 @@ -406,6 +409,24 @@ struct sd_ssr { unsigned int erase_offset; /* In milliseconds */ }; +enum bus_mode { + MMC_LEGACY, + SD_LEGACY, + MMC_HS, + SD_HS, + UHS_SDR12, + UHS_SDR25, + UHS_SDR50, + UHS_SDR104, + UHS_DDR50, + MMC_HS_52, + MMC_DDR_52, + MMC_HS_200, + MMC_MODES_END +}; + +const char *mmc_mode_name(enum bus_mode mode); + /* * With CONFIG_DM_MMC enabled, struct mmc can be accessed from the MMC device * with mmc_get_mmc_dev(). @@ -436,6 +457,7 @@ struct mmc { u8 wr_rel_set; u8 part_config; uint tran_speed; + uint legacy_speed; /* speed for the legacy mode provided by the card */ uint read_bl_len; uint write_bl_len; uint erase_grp_size; /* in 512-byte sectors */ @@ -463,6 +485,7 @@ struct mmc { #endif #endif u8 *ext_csd; + enum bus_mode selected_mode; }; struct mmc_hwpart_conf { -- cgit v1.2.3 From 4c9d2aaa7ea720ff8c304dd8621afa3ed085486e Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Thu, 21 Sep 2017 16:29:54 +0200 Subject: mmc: Add a function to dump the mmc capabilities This adds a simple helper function to display information (bus width and mode) based on a capability mask. Useful for debug. Signed-off-by: Jean-Jacques Hiblot --- include/mmc.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/mmc.h b/include/mmc.h index 76bd57ae429..dd83f14b6cd 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -426,6 +426,7 @@ enum bus_mode { }; const char *mmc_mode_name(enum bus_mode mode); +void mmc_dump_capabilities(const char *text, uint caps); /* * With CONFIG_DM_MMC enabled, struct mmc can be accessed from the MMC device -- cgit v1.2.3 From d0c221fe7336fc7d9ada57d96f4a8911a3aac041 Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Thu, 21 Sep 2017 16:29:57 +0200 Subject: mmc: refactor SD startup to make it easier to support new modes The SDcard startup process currently handles only 2 modes. To make it easier to add support for more modes, let's make the process more generic and use a list of the modes to try. The major functional change is that when a mode fails we try the next one. Not all modes are tried, only those supported by the card and the host. Signed-off-by: Jean-Jacques Hiblot Reviewed-by: Simon Glass --- include/mmc.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/mmc.h b/include/mmc.h index dd83f14b6cd..9fe6a87e882 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -59,6 +59,7 @@ #define MMC_MODE_8BIT BIT(30) #define MMC_MODE_4BIT BIT(29) +#define MMC_MODE_1BIT BIT(28) #define MMC_MODE_SPI BIT(27) -- cgit v1.2.3 From 3862b854740d296356a5cfd3146b270ad3501d97 Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Thu, 21 Sep 2017 16:29:58 +0200 Subject: mmc: refactor MMC startup to make it easier to support new modes The MMC startup process currently handles 4 modes. To make it easier to add support for more modes, let's make the process more generic and use a list of the modes to try. The major functional change is that when a mode fails we try the next one. Not all modes are tried, only those supported by the card and the host. Signed-off-by: Jean-Jacques Hiblot Reviewed-by: Simon Glass --- include/mmc.h | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'include') diff --git a/include/mmc.h b/include/mmc.h index 9fe6a87e882..988bf177d7b 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -215,7 +215,10 @@ #define EXT_CSD_BUS_WIDTH_8 2 /* Card is in 8 bit mode */ #define EXT_CSD_DDR_BUS_WIDTH_4 5 /* Card is in 4 bit DDR mode */ #define EXT_CSD_DDR_BUS_WIDTH_8 6 /* Card is in 8 bit DDR mode */ +#define EXT_CSD_DDR_FLAG BIT(2) /* Flag for DDR mode */ +#define EXT_CSD_TIMING_LEGACY 0 /* no high speed */ +#define EXT_CSD_TIMING_HS 1 /* HS */ #define EXT_CSD_BOOT_ACK_ENABLE (1 << 6) #define EXT_CSD_BOOT_PARTITION_ENABLE (1 << 3) #define EXT_CSD_PARTITION_ACCESS_ENABLE (1 << 0) @@ -429,6 +432,14 @@ enum bus_mode { const char *mmc_mode_name(enum bus_mode mode); void mmc_dump_capabilities(const char *text, uint caps); +static inline bool mmc_is_mode_ddr(enum bus_mode mode) +{ + if ((mode == MMC_DDR_52) || (mode == UHS_DDR50)) + return true; + else + return false; +} + /* * With CONFIG_DM_MMC enabled, struct mmc can be accessed from the MMC device * with mmc_get_mmc_dev(). -- cgit v1.2.3 From 2a4d212f7110712f51ae8af73abbdb0ae2af0814 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 21 Sep 2017 16:29:59 +0200 Subject: mmc: make mmc_set_ios() return status set_ios callback has a return value of 'int' but the mmc_set_ios() function ignore this. Modify mmc_set_ios() and the callers of mmc_set_ios() to to return the error status. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Jean-Jacques Hiblot Reviewed-by: Simon Glass --- include/mmc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/mmc.h b/include/mmc.h index 988bf177d7b..3e57887af01 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -549,7 +549,7 @@ int mmc_unbind(struct udevice *dev); int mmc_initialize(bd_t *bis); int mmc_init(struct mmc *mmc); int mmc_read(struct mmc *mmc, u64 src, uchar *dst, int size); -void mmc_set_clock(struct mmc *mmc, uint clock); +int mmc_set_clock(struct mmc *mmc, uint clock); struct mmc *find_mmc_device(int dev_num); int mmc_set_dev(int dev_num); void print_mmc_devices(char separator); -- cgit v1.2.3 From aff5d3c83fb8c294b3c4b97c5b6386306b47f1a0 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 21 Sep 2017 16:30:00 +0200 Subject: mmc: Enable signal voltage to be selected from mmc core Add a new function *mmc_set_signal_voltage* in mmc core which can be used during mmc initialization to select the signal voltage. Platform driver should use the set_ios callback function to select the signal voltage. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Jean-Jacques Hiblot --- include/mmc.h | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'include') diff --git a/include/mmc.h b/include/mmc.h index 3e57887af01..e5249637c85 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -272,6 +272,13 @@ #define ENHNCD_SUPPORT (0x2) #define PART_ENH_ATTRIB (0x1f) +enum mmc_voltage { + MMC_SIGNAL_VOLTAGE_000 = 0, + MMC_SIGNAL_VOLTAGE_120, + MMC_SIGNAL_VOLTAGE_180, + MMC_SIGNAL_VOLTAGE_330 +}; + /* Maximum block size for MMC */ #define MMC_MAX_BLOCK_LEN 512 @@ -457,6 +464,7 @@ struct mmc { int high_capacity; uint bus_width; uint clock; + enum mmc_voltage signal_voltage; uint card_caps; uint ocr; uint dsr; -- cgit v1.2.3 From 318a7a576bc49aa8b4207e694d3fbd48c663d6ac Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Thu, 21 Sep 2017 16:30:01 +0200 Subject: mmc: Add a new callback function to perform the 74 clocks cycle sequence Add a new callback function *send_init_stream* which start a sequence of at least 74 clock cycles. The mmc core uses *mmc_send_init_stream* in order to invoke the callback function. This will be used during power cycle where the specification requires such a sequence after power up. Signed-off-by: Jean-Jacques Hiblot --- include/mmc.h | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'include') diff --git a/include/mmc.h b/include/mmc.h index e5249637c85..bd096aeb218 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -360,6 +360,14 @@ struct dm_mmc_ops { */ int (*set_ios)(struct udevice *dev); + /** + * send_init_stream() - send the initialization stream: 74 clock cycles + * This is used after power up before sending the first command + * + * @dev: Device to update + */ + void (*send_init_stream)(struct udevice *dev); + /** * get_cd() - See whether a card is present * @@ -382,11 +390,13 @@ struct dm_mmc_ops { int dm_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, struct mmc_data *data); int dm_mmc_set_ios(struct udevice *dev); +void dm_mmc_send_init_stream(struct udevice *dev); int dm_mmc_get_cd(struct udevice *dev); int dm_mmc_get_wp(struct udevice *dev); /* Transition functions for compatibility */ int mmc_set_ios(struct mmc *mmc); +void mmc_send_init_stream(struct mmc *mmc); int mmc_getcd(struct mmc *mmc); int mmc_getwp(struct mmc *mmc); -- cgit v1.2.3 From 35f6782055c99410fbeae33ab28ea68de154360c Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 21 Sep 2017 16:30:03 +0200 Subject: mmc: add a new mmc parameter to disable mmc clock mmc clock has to be disabled in certain cases like during the voltage switch sequence. Modify mmc_set_clock function to take disable as an argument that signifies if the clock has to be enabled or disabled. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Jean-Jacques Hiblot --- include/mmc.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/mmc.h b/include/mmc.h index bd096aeb218..8d6e0f8fb04 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -472,6 +472,7 @@ struct mmc { void *priv; uint has_init; int high_capacity; + bool clk_disable; /* true if the clock can be turned off */ uint bus_width; uint clock; enum mmc_voltage signal_voltage; @@ -567,7 +568,16 @@ int mmc_unbind(struct udevice *dev); int mmc_initialize(bd_t *bis); int mmc_init(struct mmc *mmc); int mmc_read(struct mmc *mmc, u64 src, uchar *dst, int size); -int mmc_set_clock(struct mmc *mmc, uint clock); + +/** + * mmc_set_clock() - change the bus clock + * @mmc: MMC struct + * @clock: bus frequency in Hz + * @disable: flag indicating if the clock must on or off + * @return 0 if OK, -ve on error + */ +int mmc_set_clock(struct mmc *mmc, uint clock, bool disable); + struct mmc *find_mmc_device(int dev_num); int mmc_set_dev(int dev_num); void print_mmc_devices(char separator); -- cgit v1.2.3 From ec841209a7d250c1616d56744e1e79acab6c2921 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 21 Sep 2017 16:30:05 +0200 Subject: mmc: Add a execute_tuning() callback to the mmc operations. Tuning is a mandatory step in the initialization of SDR104 and HS200 modes. This callback execute the tuning process. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Jean-Jacques Hiblot --- include/mmc.h | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'include') diff --git a/include/mmc.h b/include/mmc.h index 8d6e0f8fb04..56fa869ea8f 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -383,6 +383,15 @@ struct dm_mmc_ops { * @return 0 if write-enabled, 1 if write-protected, -ve on error */ int (*get_wp)(struct udevice *dev); + + /** + * execute_tuning() - Start the tuning process + * + * @dev: Device to start the tuning + * @opcode: Command opcode to send + * @return 0 if OK, -ve on error + */ + int (*execute_tuning)(struct udevice *dev, uint opcode); }; #define mmc_get_ops(dev) ((struct dm_mmc_ops *)(dev)->driver->ops) @@ -393,12 +402,14 @@ int dm_mmc_set_ios(struct udevice *dev); void dm_mmc_send_init_stream(struct udevice *dev); int dm_mmc_get_cd(struct udevice *dev); int dm_mmc_get_wp(struct udevice *dev); +int dm_mmc_execute_tuning(struct udevice *dev, uint opcode); /* Transition functions for compatibility */ int mmc_set_ios(struct mmc *mmc); void mmc_send_init_stream(struct mmc *mmc); int mmc_getcd(struct mmc *mmc); int mmc_getwp(struct mmc *mmc); +int mmc_execute_tuning(struct mmc *mmc, uint opcode); #else struct mmc_ops { -- cgit v1.2.3 From 634d48494011fafc615ce613ab9aeeee77a9434d Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 21 Sep 2017 16:30:06 +0200 Subject: mmc: add HS200 support in MMC core Add HS200 to the list of supported modes and introduce tuning in the MMC startup process. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Jean-Jacques Hiblot Reviewed-by: Simon Glass --- include/mmc.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'include') diff --git a/include/mmc.h b/include/mmc.h index 56fa869ea8f..407fddf94c3 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -56,6 +56,7 @@ #define MMC_MODE_HS (MMC_CAP(MMC_HS) | MMC_CAP(SD_HS)) #define MMC_MODE_HS_52MHz MMC_CAP(MMC_HS_52) #define MMC_MODE_DDR_52MHz MMC_CAP(MMC_DDR_52) +#define MMC_MODE_HS200 MMC_CAP(MMC_HS_200) #define MMC_MODE_8BIT BIT(30) #define MMC_MODE_4BIT BIT(29) @@ -86,6 +87,7 @@ #define MMC_CMD_SET_BLOCKLEN 16 #define MMC_CMD_READ_SINGLE_BLOCK 17 #define MMC_CMD_READ_MULTIPLE_BLOCK 18 +#define MMC_CMD_SEND_TUNING_BLOCK_HS200 21 #define MMC_CMD_SET_BLOCK_COUNT 23 #define MMC_CMD_WRITE_SINGLE_BLOCK 24 #define MMC_CMD_WRITE_MULTIPLE_BLOCK 25 @@ -113,6 +115,13 @@ #define SD_CMD_APP_SEND_OP_COND 41 #define SD_CMD_APP_SEND_SCR 51 +static inline bool mmc_is_tuning_cmd(uint cmdidx) +{ + if (cmdidx == MMC_CMD_SEND_TUNING_BLOCK_HS200) + return true; + return false; +} + /* SCR definitions in different words */ #define SD_HIGHSPEED_BUSY 0x00020000 #define SD_HIGHSPEED_SUPPORTED 0x00020000 @@ -210,6 +219,13 @@ #define EXT_CSD_CARD_TYPE_DDR_52 (EXT_CSD_CARD_TYPE_DDR_1_8V \ | EXT_CSD_CARD_TYPE_DDR_1_2V) +#define EXT_CSD_CARD_TYPE_HS200_1_8V BIT(4) /* Card can run at 200MHz */ + /* SDR mode @1.8V I/O */ +#define EXT_CSD_CARD_TYPE_HS200_1_2V BIT(5) /* Card can run at 200MHz */ + /* SDR mode @1.2V I/O */ +#define EXT_CSD_CARD_TYPE_HS200 (EXT_CSD_CARD_TYPE_HS200_1_8V | \ + EXT_CSD_CARD_TYPE_HS200_1_2V) + #define EXT_CSD_BUS_WIDTH_1 0 /* Card is in 1 bit mode */ #define EXT_CSD_BUS_WIDTH_4 1 /* Card is in 4 bit mode */ #define EXT_CSD_BUS_WIDTH_8 2 /* Card is in 8 bit mode */ @@ -219,6 +235,8 @@ #define EXT_CSD_TIMING_LEGACY 0 /* no high speed */ #define EXT_CSD_TIMING_HS 1 /* HS */ +#define EXT_CSD_TIMING_HS200 2 /* HS200 */ + #define EXT_CSD_BOOT_ACK_ENABLE (1 << 6) #define EXT_CSD_BOOT_PARTITION_ENABLE (1 << 3) #define EXT_CSD_PARTITION_ACCESS_ENABLE (1 << 0) -- cgit v1.2.3 From c10b85d6c25f9ae0cdcf3ec9809a3063e0c3c2c9 Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Thu, 21 Sep 2017 16:30:07 +0200 Subject: mmc: Add support for UHS modes Add UHS modes to the list of supported modes, get the UHS capabilites of the SDcard and implement the procedure to switch the voltage (UHS modes use 1v8 IO lines) During the voltage switch procedure, DAT0 is used by the card to signal when it's ready. The optional card_busy() callback can be used to get this information from the host driver. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Jean-Jacques Hiblot Reviewed-by: Simon Glass --- include/mmc.h | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/mmc.h b/include/mmc.h index 407fddf94c3..ba4a13e8617 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -87,6 +87,7 @@ #define MMC_CMD_SET_BLOCKLEN 16 #define MMC_CMD_READ_SINGLE_BLOCK 17 #define MMC_CMD_READ_MULTIPLE_BLOCK 18 +#define MMC_CMD_SEND_TUNING_BLOCK 19 #define MMC_CMD_SEND_TUNING_BLOCK_HS200 21 #define MMC_CMD_SET_BLOCK_COUNT 23 #define MMC_CMD_WRITE_SINGLE_BLOCK 24 @@ -117,7 +118,8 @@ static inline bool mmc_is_tuning_cmd(uint cmdidx) { - if (cmdidx == MMC_CMD_SEND_TUNING_BLOCK_HS200) + if ((cmdidx == MMC_CMD_SEND_TUNING_BLOCK_HS200) || + (cmdidx == MMC_CMD_SEND_TUNING_BLOCK)) return true; return false; } @@ -126,8 +128,22 @@ static inline bool mmc_is_tuning_cmd(uint cmdidx) #define SD_HIGHSPEED_BUSY 0x00020000 #define SD_HIGHSPEED_SUPPORTED 0x00020000 +#define UHS_SDR12_BUS_SPEED 0 +#define HIGH_SPEED_BUS_SPEED 1 +#define UHS_SDR25_BUS_SPEED 1 +#define UHS_SDR50_BUS_SPEED 2 +#define UHS_SDR104_BUS_SPEED 3 +#define UHS_DDR50_BUS_SPEED 4 + +#define SD_MODE_UHS_SDR12 BIT(UHS_SDR12_BUS_SPEED) +#define SD_MODE_UHS_SDR25 BIT(UHS_SDR25_BUS_SPEED) +#define SD_MODE_UHS_SDR50 BIT(UHS_SDR50_BUS_SPEED) +#define SD_MODE_UHS_SDR104 BIT(UHS_SDR104_BUS_SPEED) +#define SD_MODE_UHS_DDR50 BIT(UHS_DDR50_BUS_SPEED) + #define OCR_BUSY 0x80000000 #define OCR_HCS 0x40000000 +#define OCR_S18R 0x1000000 #define OCR_VOLTAGE_MASK 0x007FFF80 #define OCR_ACCESS_MODE 0x60000000 @@ -410,6 +426,17 @@ struct dm_mmc_ops { * @return 0 if OK, -ve on error */ int (*execute_tuning)(struct udevice *dev, uint opcode); + + /** + * wait_dat0() - wait until dat0 is in the target state + * (CLK must be running during the wait) + * + * @dev: Device to check + * @state: target state + * @timeout: timeout in us + * @return 0 if dat0 is in the target state, -ve on error + */ + int (*wait_dat0)(struct udevice *dev, int state, int timeout); }; #define mmc_get_ops(dev) ((struct dm_mmc_ops *)(dev)->driver->ops) @@ -421,6 +448,7 @@ void dm_mmc_send_init_stream(struct udevice *dev); int dm_mmc_get_cd(struct udevice *dev); int dm_mmc_get_wp(struct udevice *dev); int dm_mmc_execute_tuning(struct udevice *dev, uint opcode); +int dm_mmc_wait_dat0(struct udevice *dev, int state, int timeout); /* Transition functions for compatibility */ int mmc_set_ios(struct mmc *mmc); @@ -428,6 +456,7 @@ void mmc_send_init_stream(struct mmc *mmc); int mmc_getcd(struct mmc *mmc); int mmc_getwp(struct mmc *mmc); int mmc_execute_tuning(struct mmc *mmc, uint opcode); +int mmc_wait_dat0(struct mmc *mmc, int state, int timeout); #else struct mmc_ops { @@ -486,6 +515,15 @@ static inline bool mmc_is_mode_ddr(enum bus_mode mode) return false; } +#define UHS_CAPS (MMC_CAP(UHS_SDR12) | MMC_CAP(UHS_SDR25) | \ + MMC_CAP(UHS_SDR50) | MMC_CAP(UHS_SDR104) | \ + MMC_CAP(UHS_DDR50)) + +static inline bool supports_uhs(uint caps) +{ + return (caps & UHS_CAPS) ? true : false; +} + /* * With CONFIG_DM_MMC enabled, struct mmc can be accessed from the MMC device * with mmc_get_mmc_dev(). -- cgit v1.2.3 From 04a2ea248f58b3b6216d0cd0a6b8698df8b14355 Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Thu, 21 Sep 2017 16:30:08 +0200 Subject: mmc: disable UHS modes if Vcc cannot be switched on and off If a power cycle cannot be done on Vcc, it is safer not to try the UHS modes because we wouldn't be able to recover from an error occurring during the UHS initialization. Signed-off-by: Jean-Jacques Hiblot --- include/mmc.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/mmc.h b/include/mmc.h index ba4a13e8617..59ea363ea27 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -544,6 +544,7 @@ struct mmc { uint clock; enum mmc_voltage signal_voltage; uint card_caps; + uint host_caps; uint ocr; uint dsr; uint dsr_imp; -- cgit v1.2.3 From 01298da31d92ecc46cf9130d8cff68bc51698197 Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Thu, 21 Sep 2017 16:30:09 +0200 Subject: mmc: Change mode when switching to a boot partition Boot partitions do not support HS200. Changing to a lower performance mode is required to access them. mmc_select_mode_and_width() and sd_select_mode_and_width() are modified to make it easier to call them outside of the initialization context. Signed-off-by: Jean-Jacques Hiblot Reviewed-by: Simon Glass --- include/mmc.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/mmc.h b/include/mmc.h index 59ea363ea27..a8901bffc7b 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -585,7 +585,12 @@ struct mmc { #endif #endif u8 *ext_csd; - enum bus_mode selected_mode; + enum bus_mode selected_mode; /* mode currently used */ + enum bus_mode best_mode; /* best mode is the supported mode with the + * highest bandwidth. It may not always be the + * operating mode due to limitations when + * accessing the boot partitions + */ }; struct mmc_hwpart_conf { -- cgit v1.2.3 From 83dc42271f79202b746bc9614817b41a6911c88f Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 21 Sep 2017 16:30:10 +0200 Subject: mmc: Retry some MMC cmds on failure With certain SD cards like Kingston 8GB/16GB UHS card, it is seen that MMC_CMD_ALL_SEND_CID cmd fails on first attempt, but succeeds subsequently. Therefore, retry MMC_CMD_ALL_SEND_CID cmd a few time as done in Linux kernel. Similarly, it is seen that MMC_CMD_SET_BLOCKLEN may fail on first attempt, therefore retry this cmd a few times as done in kernel. To make it clear that those are optionnal workarounds, a new Kconfig option 'MMC_QUIRKS' is added (enabled by default). Signed-off-by: Vignesh R Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Jean-Jacques Hiblot --- include/mmc.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'include') diff --git a/include/mmc.h b/include/mmc.h index a8901bffc7b..a9ebc880cb4 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -306,6 +306,9 @@ static inline bool mmc_is_tuning_cmd(uint cmdidx) #define ENHNCD_SUPPORT (0x2) #define PART_ENH_ATTRIB (0x1f) +#define MMC_QUIRK_RETRY_SEND_CID BIT(0) +#define MMC_QUIRK_RETRY_SET_BLOCKLEN BIT(1) + enum mmc_voltage { MMC_SIGNAL_VOLTAGE_000 = 0, MMC_SIGNAL_VOLTAGE_120, @@ -591,6 +594,7 @@ struct mmc { * operating mode due to limitations when * accessing the boot partitions */ + u32 quirks; }; struct mmc_hwpart_conf { -- cgit v1.2.3 From bc1e3272ff3437f7cfc5e8bf1d1f2767f6d78262 Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Thu, 21 Sep 2017 16:30:11 +0200 Subject: mmc: use the right voltage level for MMC DDR and HS200 modes HS200 only supports 1.2v and 1.8v signal voltages. DDR52 supports 3.3v/1.8v or 1.2v signal voltages. Select the lowest voltage available when using those modes. Signed-off-by: Jean-Jacques Hiblot --- include/mmc.h | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/mmc.h b/include/mmc.h index a9ebc880cb4..c11f69859ed 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -311,11 +311,15 @@ static inline bool mmc_is_tuning_cmd(uint cmdidx) enum mmc_voltage { MMC_SIGNAL_VOLTAGE_000 = 0, - MMC_SIGNAL_VOLTAGE_120, - MMC_SIGNAL_VOLTAGE_180, - MMC_SIGNAL_VOLTAGE_330 + MMC_SIGNAL_VOLTAGE_120 = 1, + MMC_SIGNAL_VOLTAGE_180 = 2, + MMC_SIGNAL_VOLTAGE_330 = 4, }; +#define MMC_ALL_SIGNAL_VOLTAGE (MMC_SIGNAL_VOLTAGE_120 |\ + MMC_SIGNAL_VOLTAGE_180 |\ + MMC_SIGNAL_VOLTAGE_330) + /* Maximum block size for MMC */ #define MMC_MAX_BLOCK_LEN 512 @@ -588,6 +592,8 @@ struct mmc { #endif #endif u8 *ext_csd; + u32 cardtype; /* cardtype read from the MMC */ + enum mmc_voltage current_voltage; enum bus_mode selected_mode; /* mode currently used */ enum bus_mode best_mode; /* best mode is the supported mode with the * highest bandwidth. It may not always be the @@ -646,6 +652,14 @@ int mmc_initialize(bd_t *bis); int mmc_init(struct mmc *mmc); int mmc_read(struct mmc *mmc, u64 src, uchar *dst, int size); +/** + * mmc_voltage_to_mv() - Convert a mmc_voltage in mV + * + * @voltage: The mmc_voltage to convert + * @return the value in mV if OK, -EINVAL on error (invalid mmc_voltage value) + */ +int mmc_voltage_to_mv(enum mmc_voltage voltage); + /** * mmc_set_clock() - change the bus clock * @mmc: MMC struct -- cgit v1.2.3 From 9815e3ba807ddf395631be35629498e55af02fa0 Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Thu, 21 Sep 2017 16:30:12 +0200 Subject: mmc: add a library function to send tuning command HS200/SDR104 requires tuning command to be sent to the card. Add a simple function to send tuning command and to read and compare the received data with the tuning block pattern. This function can be used by platform driver to perform DLL tuning. This patch is similar to commit 996903de92f0 ("mmc: core: add core-level function for sending tuning commands") added in linux kernel. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Jean-Jacques Hiblot --- include/mmc.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/mmc.h b/include/mmc.h index c11f69859ed..79be6b4bc34 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -650,6 +650,7 @@ void mmc_destroy(struct mmc *mmc); int mmc_unbind(struct udevice *dev); int mmc_initialize(bd_t *bis); int mmc_init(struct mmc *mmc); +int mmc_send_tuning(struct mmc *mmc, u32 opcode, int *cmd_error); int mmc_read(struct mmc *mmc, u64 src, uchar *dst, int size); /** -- cgit v1.2.3 From 9215ef5ed508b5de8b0c021a87b76f74561d1bad Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 21 Sep 2017 16:30:13 +0200 Subject: dm: mmc: Add a library function to parse generic dt binding Add a new function to parse host controller dt node and set mmc_config. This function can be used by mmc controller drivers to set the generic mmc_config. This function can be extended to set other UHS mode caps once UHS mode support is added. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Jean-Jacques Hiblot --- include/mmc.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/mmc.h b/include/mmc.h index 79be6b4bc34..6230a32823f 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -651,6 +651,7 @@ int mmc_unbind(struct udevice *dev); int mmc_initialize(bd_t *bis); int mmc_init(struct mmc *mmc); int mmc_send_tuning(struct mmc *mmc, u32 opcode, int *cmd_error); +int mmc_of_parse(const void *fdt, int node, struct mmc_config *cfg); int mmc_read(struct mmc *mmc, u64 src, uchar *dst, int size); /** -- cgit v1.2.3 From 7abff2c3b3cbf091f486605684f306d0d631d8d6 Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Thu, 30 Nov 2017 17:43:55 +0100 Subject: dm: mmc: update mmc_of_parse() * convert to livetree API * don't fail because of an invalid bus-width, instead default to 1-bit. * recognize 1.2v DDR and 1.2v HS200 flags Signed-off-by: Jean-Jacques Hiblot --- include/mmc.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/mmc.h b/include/mmc.h index 6230a32823f..e3f777f6803 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -651,7 +651,16 @@ int mmc_unbind(struct udevice *dev); int mmc_initialize(bd_t *bis); int mmc_init(struct mmc *mmc); int mmc_send_tuning(struct mmc *mmc, u32 opcode, int *cmd_error); -int mmc_of_parse(const void *fdt, int node, struct mmc_config *cfg); + +/** + * mmc_of_parse() - Parse the device tree to get the capabilities of the host + * + * @dev: MMC device + * @cfg: MMC configuration + * @return 0 if OK, -ve on error + */ +int mmc_of_parse(struct udevice *dev, struct mmc_config *cfg); + int mmc_read(struct mmc *mmc, u64 src, uchar *dst, int size); /** -- cgit v1.2.3 From f99c2efe5672d7355a632dcae3551ffadea1163a Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Thu, 30 Nov 2017 17:44:01 +0100 Subject: mmc: make UHS and HS200 optional Supporting USH and HS200 increases the code size as it brings in IO voltage control, tuning and fatter data structures. Use Kconfig configuration to select which of those features should be built in. Signed-off-by: Jean-Jacques Hiblot --- include/mmc.h | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/mmc.h b/include/mmc.h index e3f777f6803..e89ba95e5dc 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -15,6 +15,13 @@ #include #include +#if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) +#define MMC_SUPPORTS_TUNING +#endif +#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) +#define MMC_SUPPORTS_TUNING +#endif + /* SD/MMC version bits; 8 flags, 8 major, 8 minor, 8 change */ #define SD_VERSION_SD (1U << 31) #define MMC_VERSION_MMC (1U << 30) @@ -425,6 +432,7 @@ struct dm_mmc_ops { */ int (*get_wp)(struct udevice *dev); +#ifdef MMC_SUPPORTS_TUNING /** * execute_tuning() - Start the tuning process * @@ -433,7 +441,9 @@ struct dm_mmc_ops { * @return 0 if OK, -ve on error */ int (*execute_tuning)(struct udevice *dev, uint opcode); +#endif +#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) /** * wait_dat0() - wait until dat0 is in the target state * (CLK must be running during the wait) @@ -444,6 +454,7 @@ struct dm_mmc_ops { * @return 0 if dat0 is in the target state, -ve on error */ int (*wait_dat0)(struct udevice *dev, int state, int timeout); +#endif }; #define mmc_get_ops(dev) ((struct dm_mmc_ops *)(dev)->driver->ops) @@ -500,13 +511,13 @@ enum bus_mode { SD_LEGACY, MMC_HS, SD_HS, + MMC_HS_52, + MMC_DDR_52, UHS_SDR12, UHS_SDR25, UHS_SDR50, - UHS_SDR104, UHS_DDR50, - MMC_HS_52, - MMC_DDR_52, + UHS_SDR104, MMC_HS_200, MMC_MODES_END }; @@ -516,8 +527,12 @@ void mmc_dump_capabilities(const char *text, uint caps); static inline bool mmc_is_mode_ddr(enum bus_mode mode) { - if ((mode == MMC_DDR_52) || (mode == UHS_DDR50)) + if (mode == MMC_DDR_52) + return true; +#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) + else if (mode == UHS_DDR50) return true; +#endif else return false; } @@ -528,7 +543,11 @@ static inline bool mmc_is_mode_ddr(enum bus_mode mode) static inline bool supports_uhs(uint caps) { +#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) return (caps & UHS_CAPS) ? true : false; +#else + return false; +#endif } /* -- cgit v1.2.3 From 5b2e72f32721484d2dea3d0dcf8c020bf3cbe574 Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Thu, 4 Jan 2018 15:23:33 +0100 Subject: mmc: read ssr only if MMC write support is enabled The content of ssr is useful only for erase operations. on ARM, removing sd_read_ssr() saves around 300 bytes. Signed-off-by: Jean-Jacques Hiblot --- include/mmc.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/mmc.h b/include/mmc.h index e89ba95e5dc..f50c7144284 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -588,7 +588,9 @@ struct mmc { uint write_bl_len; uint erase_grp_size; /* in 512-byte sectors */ uint hc_wp_grp_size; /* in 512-byte sectors */ +#if CONFIG_IS_ENABLED(MMC_WRITE) struct sd_ssr ssr; /* SD status register */ +#endif u64 capacity; u64 capacity_user; u64 capacity_boot; -- cgit v1.2.3 From e6fa5a546154a42c4f6662cd8890c238207ce21a Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Thu, 4 Jan 2018 15:23:34 +0100 Subject: mmc: compile out erase and write mmc commands if write operations are not enabled Also remove erase_grp_size and write_bl_len from struct mmc as they are not used anymore. On ARM, removing them saves about 100 bytes of code space in SPL. Signed-off-by: Jean-Jacques Hiblot --- include/mmc.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/mmc.h b/include/mmc.h index f50c7144284..3abeb581aef 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -585,8 +585,10 @@ struct mmc { uint tran_speed; uint legacy_speed; /* speed for the legacy mode provided by the card */ uint read_bl_len; +#if CONFIG_IS_ENABLED(MMC_WRITE) uint write_bl_len; uint erase_grp_size; /* in 512-byte sectors */ +#endif uint hc_wp_grp_size; /* in 512-byte sectors */ #if CONFIG_IS_ENABLED(MMC_WRITE) struct sd_ssr ssr; /* SD status register */ -- cgit v1.2.3 From 173c06dfcc5419e38160d7eaf596256df0b4bdd5 Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Thu, 4 Jan 2018 15:23:35 +0100 Subject: mmc: don't read the size of eMMC enhanced user data area in SPL This information is only used by the "mmc info" command. On ARM removing this information from SPL saves about 140 of code space. Signed-off-by: Jean-Jacques Hiblot --- include/mmc.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/mmc.h b/include/mmc.h index 3abeb581aef..cd068b9429b 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -598,8 +598,10 @@ struct mmc { u64 capacity_boot; u64 capacity_rpmb; u64 capacity_gp[4]; +#ifndef CONFIG_SPL_BUILD u64 enh_user_start; u64 enh_user_size; +#endif #if !CONFIG_IS_ENABLED(BLK) struct blk_desc block_dev; #endif -- cgit v1.2.3 From b7a6e2c9c396c35596f467f5187da937306ddeb8 Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Thu, 4 Jan 2018 15:23:36 +0100 Subject: mmc: remove hc_wp_grp_size from struct mmc if not needed hc_wp_grp_size is needed only if hardware partitionning is used. On ARM removing it saves about 30 bytes of code space. Signed-off-by: Jean-Jacques Hiblot --- include/mmc.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/mmc.h b/include/mmc.h index cd068b9429b..a46eaed7469 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -589,7 +589,9 @@ struct mmc { uint write_bl_len; uint erase_grp_size; /* in 512-byte sectors */ #endif +#if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING) uint hc_wp_grp_size; /* in 512-byte sectors */ +#endif #if CONFIG_IS_ENABLED(MMC_WRITE) struct sd_ssr ssr; /* SD status register */ #endif -- cgit v1.2.3