X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=include%2Fmmc.h;h=032873c2ff9b43266a138087dfa2a440bb873cb3;hb=513e00b64e63c277ad6dd667b823282ef4d177c1;hp=8346b0e19e2cd6309e3dbc374d4b100f88a8be0e;hpb=ddb3ac3c716f56cead695444e65a7ba7b0946555;p=oweals%2Fu-boot.git diff --git a/include/mmc.h b/include/mmc.h index 8346b0e19e..032873c2ff 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -1,10 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Copyright 2008,2010 Freescale Semiconductor, Inc * Andy Fleming * * Based (loosely) on the Linux code - * - * SPDX-License-Identifier: GPL-2.0+ */ #ifndef _MMC_H_ @@ -15,6 +14,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) @@ -47,17 +53,28 @@ #define MMC_VERSION_4_1 MAKE_MMC_VERSION(4, 1, 0) #define MMC_VERSION_4_2 MAKE_MMC_VERSION(4, 2, 0) #define MMC_VERSION_4_3 MAKE_MMC_VERSION(4, 3, 0) +#define MMC_VERSION_4_4 MAKE_MMC_VERSION(4, 4, 0) #define MMC_VERSION_4_41 MAKE_MMC_VERSION(4, 4, 1) #define MMC_VERSION_4_5 MAKE_MMC_VERSION(4, 5, 0) #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_HS200 MMC_CAP(MMC_HS_200) +#define MMC_MODE_HS400 MMC_CAP(MMC_HS_400) + +#define MMC_CAP_NONREMOVABLE BIT(14) +#define MMC_CAP_NEEDS_POLL BIT(15) +#define MMC_CAP_CD_ACTIVE_HIGH BIT(16) + +#define MMC_MODE_8BIT BIT(30) +#define MMC_MODE_4BIT BIT(29) +#define MMC_MODE_1BIT BIT(28) +#define MMC_MODE_SPI BIT(27) + #define SD_DATA_4BIT 0x00040000 @@ -82,6 +99,8 @@ #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 #define MMC_CMD_WRITE_MULTIPLE_BLOCK 25 @@ -109,12 +128,34 @@ #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) || + (cmdidx == MMC_CMD_SEND_TUNING_BLOCK)) + return true; + return false; +} + /* SCR definitions in different words */ #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 @@ -185,10 +226,12 @@ #define EXT_CSD_HS_TIMING 185 /* R/W */ #define EXT_CSD_REV 192 /* RO */ #define EXT_CSD_CARD_TYPE 196 /* RO */ +#define EXT_CSD_PART_SWITCH_TIME 199 /* RO */ #define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */ #define EXT_CSD_HC_WP_GRP_SIZE 221 /* RO */ #define EXT_CSD_HC_ERASE_GRP_SIZE 224 /* RO */ #define EXT_CSD_BOOT_MULT 226 /* RO */ +#define EXT_CSD_GENERIC_CMD6_TIME 248 /* RO */ #define EXT_CSD_BKOPS_SUPPORT 502 /* RO */ /* @@ -206,11 +249,28 @@ #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_CARD_TYPE_HS400_1_8V BIT(6) +#define EXT_CSD_CARD_TYPE_HS400_1_2V BIT(7) +#define EXT_CSD_CARD_TYPE_HS400 (EXT_CSD_CARD_TYPE_HS400_1_8V | \ + EXT_CSD_CARD_TYPE_HS400_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 */ #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_TIMING_HS200 2 /* HS200 */ +#define EXT_CSD_TIMING_HS400 3 /* HS400 */ #define EXT_CSD_BOOT_ACK_ENABLE (1 << 6) #define EXT_CSD_BOOT_PARTITION_ENABLE (1 << 3) @@ -221,6 +281,10 @@ #define EXT_CSD_BOOT_PART_NUM(x) (x << 3) #define EXT_CSD_PARTITION_ACCESS(x) (x << 0) +#define EXT_CSD_EXTRACT_BOOT_ACK(x) (((x) >> 6) & 0x1) +#define EXT_CSD_EXTRACT_BOOT_PART(x) (((x) >> 3) & 0x7) +#define EXT_CSD_EXTRACT_PARTITION_ACCESS(x) ((x) & 0x7) + #define EXT_CSD_BOOT_BUS_WIDTH_MODE(x) (x << 3) #define EXT_CSD_BOOT_BUS_WIDTH_RESET(x) (x << 2) #define EXT_CSD_BOOT_BUS_WIDTH_WIDTH(x) (x) @@ -261,6 +325,20 @@ #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 = 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 @@ -321,7 +399,7 @@ struct mmc_data { /* forward decl. */ struct mmc; -#ifdef CONFIG_DM_MMC_OPS +#if CONFIG_IS_ENABLED(DM_MMC) struct dm_mmc_ops { /** * send_cmd() - Send a command to the MMC device @@ -357,6 +435,28 @@ struct dm_mmc_ops { * @return 0 if write-enabled, 1 if write-protected, -ve on error */ int (*get_wp)(struct udevice *dev); + +#ifdef MMC_SUPPORTS_TUNING + /** + * 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); +#endif + + /** + * 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) @@ -366,11 +466,15 @@ int dm_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, int dm_mmc_set_ios(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); 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 { @@ -385,7 +489,7 @@ struct mmc_ops { struct mmc_config { const char *name; -#ifndef CONFIG_DM_MMC_OPS +#if !CONFIG_IS_ENABLED(DM_MMC) const struct mmc_ops *ops; #endif uint host_caps; @@ -402,6 +506,55 @@ struct sd_ssr { unsigned int erase_offset; /* In milliseconds */ }; +enum bus_mode { + MMC_LEGACY, + SD_LEGACY, + MMC_HS, + SD_HS, + MMC_HS_52, + MMC_DDR_52, + UHS_SDR12, + UHS_SDR25, + UHS_SDR50, + UHS_DDR50, + UHS_SDR104, + MMC_HS_200, + MMC_HS_400, + MMC_MODES_END +}; + +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) + return true; +#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) + else if (mode == UHS_DDR50) + return true; +#endif +#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) + else if (mode == MMC_HS_400) + return true; +#endif + else + 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) +{ +#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) + return (caps & UHS_CAPS) ? true : false; +#else + return false; +#endif +} + /* * With CONFIG_DM_MMC enabled, struct mmc can be accessed from the MMC device * with mmc_get_mmc_dev(). @@ -409,7 +562,7 @@ struct sd_ssr { * TODO struct mmc should be in mmc_private but it's hard to fix right now */ struct mmc { -#ifndef CONFIG_BLK +#if !CONFIG_IS_ENABLED(BLK) struct list_head link; #endif const struct mmc_config *cfg; /* provided configuration */ @@ -417,9 +570,12 @@ 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; uint card_caps; + uint host_caps; uint ocr; uint dsr; uint dsr_imp; @@ -430,30 +586,55 @@ struct mmc { u8 part_support; u8 part_attr; u8 wr_rel_set; - char part_config; + u8 part_config; + u8 gen_cmd6_time; + u8 part_switch_time; 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 +#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 u64 capacity; u64 capacity_user; u64 capacity_boot; u64 capacity_rpmb; u64 capacity_gp[4]; +#ifndef CONFIG_SPL_BUILD u64 enh_user_start; u64 enh_user_size; -#ifndef CONFIG_BLK +#endif +#if !CONFIG_IS_ENABLED(BLK) struct blk_desc block_dev; #endif char op_cond_pending; /* 1 if we are waiting on an op_cond command */ char init_in_progress; /* 1 if we have done mmc_start_init() */ char preinit; /* start init as early as possible */ int ddr_mode; -#ifdef CONFIG_DM_MMC +#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 + 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 + * operating mode due to limitations when + * accessing the boot partitions + */ + u32 quirks; }; struct mmc_hwpart_conf { @@ -503,8 +684,45 @@ 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); + +#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || \ + CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \ + CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) +int mmc_deinit(struct mmc *mmc); +#endif + +/** + * 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); -void mmc_set_clock(struct mmc *mmc, uint clock); + +/** + * 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 + * @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); + +#define MMC_CLK_ENABLE false +#define MMC_CLK_DISABLE true + struct mmc *find_mmc_device(int dev_num); int mmc_set_dev(int dev_num); void print_mmc_devices(char separator); @@ -519,7 +737,7 @@ int mmc_switch_part(struct mmc *mmc, unsigned int part_num); int mmc_hwpart_config(struct mmc *mmc, const struct mmc_hwpart_conf *conf, enum mmc_hwpart_conf_mode mode); -#ifndef CONFIG_DM_MMC_OPS +#if !CONFIG_IS_ENABLED(DM_MMC) int mmc_getcd(struct mmc *mmc); int board_mmc_getcd(struct mmc *mmc); int mmc_getwp(struct mmc *mmc); @@ -543,10 +761,39 @@ int mmc_rpmb_read(struct mmc *mmc, void *addr, unsigned short blk, unsigned short cnt, unsigned char *key); int mmc_rpmb_write(struct mmc *mmc, void *addr, unsigned short blk, unsigned short cnt, unsigned char *key); + +/** + * mmc_rpmb_route_frames() - route RPMB data frames + * @mmc Pointer to a MMC device struct + * @req Request data frames + * @reqlen Length of data frames in bytes + * @rsp Supplied buffer for response data frames + * @rsplen Length of supplied buffer for response data frames + * + * The RPMB data frames are routed to/from some external entity, for + * example a Trusted Exectuion Environment in an arm TrustZone protected + * secure world. It's expected that it's the external entity who is in + * control of the RPMB key. + * + * Returns 0 on success, < 0 on error. + */ +int mmc_rpmb_route_frames(struct mmc *mmc, void *req, unsigned long reqlen, + void *rsp, unsigned long rsplen); + #ifdef CONFIG_CMD_BKOPS_ENABLE int mmc_set_bkops_enable(struct mmc *mmc); #endif +/** + * Start device initialization and return immediately; it does not block on + * polling OCR (operation condition register) status. Useful for checking + * the presence of SD/eMMC when no card detect logic is available. + * + * @param mmc Pointer to a MMC device struct + * @return 0 on success, <0 on error. + */ +int mmc_get_op_cond(struct mmc *mmc); + /** * Start device initialization and return immediately; it does not block on * polling OCR (operation condition register) status. Then you should call @@ -554,7 +801,7 @@ int mmc_set_bkops_enable(struct mmc *mmc); * initializatin. * * @param mmc Pointer to a MMC device struct - * @return 0 on success, IN_PROGRESS on waiting for OCR status, <0 on error. + * @return 0 on success, <0 on error. */ int mmc_start_init(struct mmc *mmc); @@ -583,8 +830,14 @@ void board_mmc_power_init(void); int board_mmc_init(bd_t *bis); int cpu_mmc_init(bd_t *bis); int mmc_get_env_addr(struct mmc *mmc, int copy, u32 *env_addr); +# ifdef CONFIG_SYS_MMC_ENV_PART +extern uint mmc_get_env_part(struct mmc *mmc); +# endif int mmc_get_env_dev(void); +/* Minimum partition switch timeout in units of 10-milliseconds */ +#define MMC_MIN_PART_SWITCH_TIME 30 /* 300 ms */ + /* Set block count limit because of 16 bit register limit on some hardware*/ #ifndef CONFIG_SYS_MMC_MAX_BLK_COUNT #define CONFIG_SYS_MMC_MAX_BLK_COUNT 65535