diff options
29 files changed, 531 insertions, 84 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 37ff21a037..2c43573ff5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -180,6 +180,7 @@ F: board/cortina/common/ F: drivers/gpio/cortina_gpio.c F: drivers/watchdog/cortina_wdt.c F: drivers/serial/serial_cortina.c +F: drivers/mmc/ca_dw_mmc.c ARM/CZ.NIC TURRIS MOX SUPPORT M: Marek Behun <marek.behun@nic.cz> @@ -672,6 +673,7 @@ F: board/cortina/common/ F: drivers/gpio/cortina_gpio.c F: drivers/watchdog/cortina_wdt.c F: drivers/serial/serial_cortina.c +F: drivers/mmc/ca_dw_mmc.c MIPS MSCC M: Gregory CLEMENT <gregory.clement@bootlin.com> diff --git a/arch/arm/dts/k3-am65-main.dtsi b/arch/arm/dts/k3-am65-main.dtsi index ab40dafceb..028f57379b 100644 --- a/arch/arm/dts/k3-am65-main.dtsi +++ b/arch/arm/dts/k3-am65-main.dtsi @@ -98,7 +98,17 @@ interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>; mmc-ddr-1_8v; mmc-hs200-1_8v; - ti,otap-del-sel = <0x2>; + ti,otap-del-sel-legacy = <0x0>; + ti,otap-del-sel-mmc-hs = <0x0>; + ti,otap-del-sel-sd-hs = <0x0>; + ti,otap-del-sel-sdr12 = <0x0>; + ti,otap-del-sel-sdr25 = <0x0>; + ti,otap-del-sel-sdr50 = <0x8>; + ti,otap-del-sel-sdr104 = <0x5>; + ti,otap-del-sel-ddr50 = <0x5>; + ti,otap-del-sel-ddr52 = <0x5>; + ti,otap-del-sel-hs200 = <0x5>; + ti,otap-del-sel-hs400 = <0x0>; ti,trm-icp = <0x8>; dma-coherent; }; diff --git a/arch/arm/dts/k3-am654-base-board-u-boot.dtsi b/arch/arm/dts/k3-am654-base-board-u-boot.dtsi index a349edcfa5..54ecb3d444 100644 --- a/arch/arm/dts/k3-am654-base-board-u-boot.dtsi +++ b/arch/arm/dts/k3-am654-base-board-u-boot.dtsi @@ -29,7 +29,16 @@ clock-names = "clk_ahb", "clk_xin"; power-domains = <&k3_pds 48 TI_SCI_PD_EXCLUSIVE>; max-frequency = <25000000>; - ti,otap-del-sel = <0x2>; + ti,otap-del-sel-legacy = <0x0>; + ti,otap-del-sel-mmc-hs = <0x0>; + ti,otap-del-sel-sd-hs = <0x0>; + ti,otap-del-sel-sdr12 = <0x0>; + ti,otap-del-sel-sdr25 = <0x0>; + ti,otap-del-sel-sdr50 = <0x8>; + ti,otap-del-sel-sdr104 = <0x7>; + ti,otap-del-sel-ddr50 = <0x4>; + ti,otap-del-sel-ddr52 = <0x4>; + ti,otap-del-sel-hs200 = <0x7>; ti,trm-icp = <0x8>; }; diff --git a/arch/arm/dts/k3-j721e-main.dtsi b/arch/arm/dts/k3-j721e-main.dtsi index 45ac98c47e..1433932e7f 100644 --- a/arch/arm/dts/k3-j721e-main.dtsi +++ b/arch/arm/dts/k3-j721e-main.dtsi @@ -232,9 +232,14 @@ assigned-clocks = <&k3_clks 91 1>; assigned-clock-parents = <&k3_clks 91 2>; bus-width = <8>; - ti,otap-del-sel = <0x2>; ti,trm-icp = <0x8>; dma-coherent; + mmc-ddr-1_8v; + ti,otap-del-sel-legacy = <0x0>; + ti,otap-del-sel-mmc-hs = <0x0>; + ti,otap-del-sel-ddr52 = <0x5>; + ti,otap-del-sel-hs200 = <0x6>; + ti,otap-del-sel-hs400 = <0x0>; }; main_sdhci1: sdhci@4fb0000 { @@ -246,7 +251,13 @@ clocks = <&k3_clks 92 0>, <&k3_clks 92 5>; assigned-clocks = <&k3_clks 92 0>; assigned-clock-parents = <&k3_clks 92 1>; - ti,otap-del-sel = <0x2>; + ti,otap-del-sel-legacy = <0x0>; + ti,otap-del-sel-sd-hs = <0xf>; + ti,otap-del-sel-sdr12 = <0xf>; + ti,otap-del-sel-sdr25 = <0xf>; + ti,otap-del-sel-sdr50 = <0xc>; + ti,otap-del-sel-sdr104 = <0x5>; + ti,otap-del-sel-ddr50 = <0xc>; ti,trm-icp = <0x8>; dma-coherent; }; diff --git a/arch/arm/dts/k3-j721e-r5-common-proc-board.dts b/arch/arm/dts/k3-j721e-r5-common-proc-board.dts index eb577cdbc6..5973e211c3 100644 --- a/arch/arm/dts/k3-j721e-r5-common-proc-board.dts +++ b/arch/arm/dts/k3-j721e-r5-common-proc-board.dts @@ -34,14 +34,14 @@ u-boot,dm-spl; }; - clk_200mhz: dummy_clock { + clk_200mhz: dummy_clock_200mhz { compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <200000000>; u-boot,dm-spl; }; - clk_19_2mhz: dummy_clock { + clk_19_2mhz: dummy_clock_19_2mhz { compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <19200000>; diff --git a/arch/arm/mach-imx/imx8/image.c b/arch/arm/mach-imx/imx8/image.c index c956a8092d..e6b299691d 100644 --- a/arch/arm/mach-imx/imx8/image.c +++ b/arch/arm/mach-imx/imx8/image.c @@ -197,7 +197,8 @@ unsigned long spl_spi_get_uboot_offs(struct spi_flash *flash) #endif #ifdef CONFIG_SPL_MMC_SUPPORT -unsigned long spl_mmc_get_uboot_raw_sector(struct mmc *mmc) +unsigned long spl_mmc_get_uboot_raw_sector(struct mmc *mmc, + unsigned long raw_sect) { int end; diff --git a/arch/arm/mach-k3/am6_init.c b/arch/arm/mach-k3/am6_init.c index 63cd7e0458..d0b10e58ad 100644 --- a/arch/arm/mach-k3/am6_init.c +++ b/arch/arm/mach-k3/am6_init.c @@ -17,6 +17,7 @@ #include <dm/uclass-internal.h> #include <dm/pinctrl.h> #include <linux/soc/ti/ti_sci_protocol.h> +#include <mmc.h> #ifdef CONFIG_SPL_BUILD #ifdef CONFIG_K3_LOAD_SYSFW @@ -86,6 +87,33 @@ static void store_boot_index_from_rom(void) bootindex = *(u32 *)(CONFIG_SYS_K3_BOOT_PARAM_TABLE_INDEX); } +#if defined(CONFIG_K3_LOAD_SYSFW) +void k3_mmc_stop_clock(void) +{ + if (spl_boot_device() == BOOT_DEVICE_MMC1) { + struct mmc *mmc = find_mmc_device(0); + + if (!mmc) + return; + + mmc->saved_clock = mmc->clock; + mmc_set_clock(mmc, 0, true); + } +} + +void k3_mmc_restart_clock(void) +{ + if (spl_boot_device() == BOOT_DEVICE_MMC1) { + struct mmc *mmc = find_mmc_device(0); + + if (!mmc) + return; + + mmc_set_clock(mmc, mmc->saved_clock, false); + } +} +#endif + void board_init_f(ulong dummy) { #if defined(CONFIG_K3_LOAD_SYSFW) || defined(CONFIG_K3_AM654_DDRSS) @@ -138,7 +166,10 @@ void board_init_f(ulong dummy) * callback hook, effectively switching on (or over) the console * output. */ - k3_sysfw_loader(preloader_console_init); + k3_sysfw_loader(k3_mmc_stop_clock, k3_mmc_restart_clock); + + /* Prepare console output */ + preloader_console_init(); /* Disable ROM configured firewalls right after loading sysfw */ #ifdef CONFIG_TI_SECURE_DEVICE diff --git a/arch/arm/mach-k3/include/mach/sysfw-loader.h b/arch/arm/mach-k3/include/mach/sysfw-loader.h index 36eb265348..6f5612b4fd 100644 --- a/arch/arm/mach-k3/include/mach/sysfw-loader.h +++ b/arch/arm/mach-k3/include/mach/sysfw-loader.h @@ -7,6 +7,6 @@ #ifndef _SYSFW_LOADER_H_ #define _SYSFW_LOADER_H_ -void k3_sysfw_loader(void (*config_pm_done_callback)(void)); +void k3_sysfw_loader(void (*config_pm_pre_callback)(void), void (*config_pm_done_callback)(void)); #endif diff --git a/arch/arm/mach-k3/j721e_init.c b/arch/arm/mach-k3/j721e_init.c index f7f7398081..0994522f6c 100644 --- a/arch/arm/mach-k3/j721e_init.c +++ b/arch/arm/mach-k3/j721e_init.c @@ -18,6 +18,7 @@ #include <dm.h> #include <dm/uclass-internal.h> #include <dm/pinctrl.h> +#include <mmc.h> #ifdef CONFIG_SPL_BUILD #ifdef CONFIG_K3_LOAD_SYSFW @@ -100,6 +101,33 @@ static void ctrl_mmr_unlock(void) mmr_unlock(CTRL_MMR0_BASE, 7); } +#if defined(CONFIG_K3_LOAD_SYSFW) +void k3_mmc_stop_clock(void) +{ + if (spl_boot_device() == BOOT_DEVICE_MMC1) { + struct mmc *mmc = find_mmc_device(0); + + if (!mmc) + return; + + mmc->saved_clock = mmc->clock; + mmc_set_clock(mmc, 0, true); + } +} + +void k3_mmc_restart_clock(void) +{ + if (spl_boot_device() == BOOT_DEVICE_MMC1) { + struct mmc *mmc = find_mmc_device(0); + + if (!mmc) + return; + + mmc_set_clock(mmc, mmc->saved_clock, false); + } +} +#endif + /* * This uninitialized global variable would normal end up in the .bss section, * but the .bss is cleared between writing and reading this variable, so move @@ -154,7 +182,10 @@ void board_init_f(ulong dummy) * callback hook, effectively switching on (or over) the console * output. */ - k3_sysfw_loader(preloader_console_init); + k3_sysfw_loader(k3_mmc_stop_clock, k3_mmc_restart_clock); + + /* Prepare console output */ + preloader_console_init(); /* Disable ROM configured firewalls right after loading sysfw */ #ifdef CONFIG_TI_SECURE_DEVICE diff --git a/arch/arm/mach-k3/sysfw-loader.c b/arch/arm/mach-k3/sysfw-loader.c index 94dbeb9437..db02607b17 100644 --- a/arch/arm/mach-k3/sysfw-loader.c +++ b/arch/arm/mach-k3/sysfw-loader.c @@ -197,7 +197,8 @@ exit: } #endif -void k3_sysfw_loader(void (*config_pm_done_callback)(void)) +void k3_sysfw_loader(void (*config_pm_pre_callback) (void), + void (*config_pm_done_callback)(void)) { struct spl_image_info spl_image = { 0 }; struct spl_boot_device bootdev = { 0 }; @@ -291,6 +292,9 @@ void k3_sysfw_loader(void (*config_pm_done_callback)(void)) /* Get handle for accessing SYSFW services */ ti_sci = get_ti_sci_handle(); + if (config_pm_pre_callback) + config_pm_pre_callback(); + /* Parse and apply the different SYSFW configuration fragments */ k3_sysfw_configure_using_fit(sysfw_load_address, ti_sci); diff --git a/common/spl/spl_mmc.c b/common/spl/spl_mmc.c index 3e6a17c110..a2ea363e96 100644 --- a/common/spl/spl_mmc.c +++ b/common/spl/spl_mmc.c @@ -317,13 +317,10 @@ int spl_boot_partition(const u32 boot_device) } #endif -unsigned long __weak spl_mmc_get_uboot_raw_sector(struct mmc *mmc) +unsigned long __weak spl_mmc_get_uboot_raw_sector(struct mmc *mmc, + unsigned long raw_sect) { -#ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR - return CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR; -#else - return 0; -#endif + return raw_sect; } int spl_mmc_load(struct spl_image_info *spl_image, @@ -392,7 +389,7 @@ int spl_mmc_load(struct spl_image_info *spl_image, return err; } - raw_sect = spl_mmc_get_uboot_raw_sector(mmc); + raw_sect = spl_mmc_get_uboot_raw_sector(mmc, raw_sect); #ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION err = mmc_load_image_raw_partition(spl_image, mmc, raw_part, diff --git a/configs/am65x_evm_a53_defconfig b/configs/am65x_evm_a53_defconfig index 121d8de231..df7723b71e 100644 --- a/configs/am65x_evm_a53_defconfig +++ b/configs/am65x_evm_a53_defconfig @@ -74,6 +74,7 @@ CONFIG_DM_KEYBOARD=y CONFIG_DM_MAILBOX=y CONFIG_K3_SEC_PROXY=y CONFIG_DM_MMC=y +CONFIG_SUPPORT_EMMC_BOOT=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_ADMA=y CONFIG_SPL_MMC_SDHCI_ADMA=y diff --git a/configs/am65x_evm_r5_defconfig b/configs/am65x_evm_r5_defconfig index 69055d5536..b475aceefe 100644 --- a/configs/am65x_evm_r5_defconfig +++ b/configs/am65x_evm_r5_defconfig @@ -73,6 +73,7 @@ CONFIG_K3_SEC_PROXY=y CONFIG_MISC=y CONFIG_K3_AVS0=y CONFIG_DM_MMC=y +CONFIG_SUPPORT_EMMC_BOOT=y CONFIG_MMC_SDHCI=y CONFIG_SPL_MMC_SDHCI_ADMA=y CONFIG_MMC_SDHCI_AM654=y diff --git a/configs/cortina_presidio-asic-emmc_defconfig b/configs/cortina_presidio-asic-emmc_defconfig new file mode 100644 index 0000000000..e10008a2b7 --- /dev/null +++ b/configs/cortina_presidio-asic-emmc_defconfig @@ -0,0 +1,33 @@ +CONFIG_ARM=y +# CONFIG_SYS_ARCH_TIMER is not set +CONFIG_TARGET_PRESIDIO_ASIC=y +CONFIG_SYS_TEXT_BASE=0x04000000 +CONFIG_ENV_SIZE=0x20000 +CONFIG_DM_GPIO=y +CONFIG_NR_DRAM_BANKS=1 +CONFIG_IDENT_STRING="Presidio-SoC" +CONFIG_SHOW_BOOT_PROGRESS=y +CONFIG_BOOTDELAY=3 +CONFIG_BOARD_EARLY_INIT_R=y +CONFIG_SYS_PROMPT="G3#" +CONFIG_CMD_MMC=y +CONFIG_CMD_PART=y +CONFIG_CMD_WDT=y +CONFIG_CMD_CACHE=y +CONFIG_CMD_TIMER=y +CONFIG_CMD_SMC=y +CONFIG_CMD_EXT2=y +CONFIG_CMD_EXT4=y +CONFIG_OF_CONTROL=y +CONFIG_OF_LIVE=y +CONFIG_DEFAULT_DEVICE_TREE="ca-presidio-engboard" +# CONFIG_NET is not set +CONFIG_DM=y +CONFIG_CORTINA_GPIO=y +CONFIG_DM_MMC=y +CONFIG_MMC_DW=y +CONFIG_MMC_DW_CORTINA=y +CONFIG_DM_SERIAL=y +CONFIG_CORTINA_UART=y +CONFIG_WDT=y +CONFIG_WDT_CORTINA=y diff --git a/configs/j721e_evm_a72_defconfig b/configs/j721e_evm_a72_defconfig index ef44ed0367..b27f9ba27b 100644 --- a/configs/j721e_evm_a72_defconfig +++ b/configs/j721e_evm_a72_defconfig @@ -29,6 +29,8 @@ CONFIG_SPL_BOARD_INIT=y CONFIG_SPL_SYS_MALLOC_SIMPLE=y CONFIG_SPL_STACK_R=y CONFIG_SPL_SEPARATE_BSS=y +CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR=y +CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR=0x1400 CONFIG_SPL_ENV_SUPPORT=y CONFIG_SPL_I2C_SUPPORT=y CONFIG_SPL_DM_MAILBOX=y @@ -99,6 +101,7 @@ CONFIG_SYS_I2C_OMAP24XX=y CONFIG_DM_MAILBOX=y CONFIG_K3_SEC_PROXY=y CONFIG_DM_MMC=y +CONFIG_SUPPORT_EMMC_BOOT=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_ADMA=y CONFIG_SPL_MMC_SDHCI_ADMA=y diff --git a/configs/j721e_evm_r5_defconfig b/configs/j721e_evm_r5_defconfig index 607e748ef7..ea70c34c5a 100644 --- a/configs/j721e_evm_r5_defconfig +++ b/configs/j721e_evm_r5_defconfig @@ -27,6 +27,8 @@ CONFIG_USE_BOOTCOMMAND=y CONFIG_SPL_STACK_R=y CONFIG_SPL_SEPARATE_BSS=y CONFIG_SPL_EARLY_BSS=y +CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR=y +CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR=0x400 CONFIG_SPL_ENV_SUPPORT=y CONFIG_SPL_I2C_SUPPORT=y CONFIG_SPL_DM_MAILBOX=y @@ -77,6 +79,7 @@ CONFIG_MISC=y CONFIG_FS_LOADER=y CONFIG_K3_AVS0=y CONFIG_DM_MMC=y +CONFIG_SUPPORT_EMMC_BOOT=y CONFIG_MMC_SDHCI=y CONFIG_SPL_MMC_SDHCI_ADMA=y CONFIG_MMC_SDHCI_AM654=y diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 2f0eedc22f..bb38787eca 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -205,6 +205,17 @@ config MMC_DW block, this provides host support for SD and MMC interfaces, in both PIO, internal DMA mode and external DMA mode. +config MMC_DW_CORTINA + bool "Cortina specific extensions for Synopsys DW Memory Card Interface" + depends on DM_MMC + depends on MMC_DW + depends on BLK + default n + help + This selects support for Cortina SoC specific extensions to the + Synopsys DesignWare Memory Card Interface driver. Select this option + for platforms based on Cortina CAxxxx Soc's. + config MMC_DW_EXYNOS bool "Exynos specific extensions for Synopsys DW Memory Card Interface" depends on ARCH_EXYNOS diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 9c1f8e56e2..615b724bf0 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -20,6 +20,7 @@ endif obj-$(CONFIG_ARM_PL180_MMCI) += arm_pl180_mmci.o obj-$(CONFIG_MMC_DAVINCI) += davinci_mmc.o obj-$(CONFIG_MMC_DW) += dw_mmc.o +obj-$(CONFIG_MMC_DW_CORTINA) += ca_dw_mmc.o obj-$(CONFIG_MMC_DW_EXYNOS) += exynos_dw_mmc.o obj-$(CONFIG_MMC_DW_K3) += hi6220_dw_mmc.o obj-$(CONFIG_MMC_DW_ROCKCHIP) += rockchip_dw_mmc.o diff --git a/drivers/mmc/am654_sdhci.c b/drivers/mmc/am654_sdhci.c index aad9d8b85b..ca76e1f559 100644 --- a/drivers/mmc/am654_sdhci.c +++ b/drivers/mmc/am654_sdhci.c @@ -74,7 +74,7 @@ struct am654_sdhci_plat { struct mmc mmc; struct regmap *base; bool non_removable; - u32 otap_del_sel; + u32 otap_del_sel[11]; u32 trm_icp; u32 drv_strength; u32 strb_sel; @@ -86,6 +86,25 @@ struct am654_sdhci_plat { bool dll_on; }; +struct timing_data { + const char *binding; + u32 capability; +}; + +static const struct timing_data td[] = { + [MMC_LEGACY] = {"ti,otap-del-sel-legacy", 0}, + [MMC_HS] = {"ti,otap-del-sel-mmc-hs", MMC_CAP(MMC_HS)}, + [SD_HS] = {"ti,otap-del-sel-sd-hs", MMC_CAP(SD_HS)}, + [UHS_SDR12] = {"ti,otap-del-sel-sdr12", MMC_CAP(UHS_SDR12)}, + [UHS_SDR25] = {"ti,otap-del-sel-sdr25", MMC_CAP(UHS_SDR25)}, + [UHS_SDR50] = {"ti,otap-del-sel-sdr50", MMC_CAP(UHS_SDR50)}, + [UHS_SDR104] = {"ti,otap-del-sel-sdr104", MMC_CAP(UHS_SDR104)}, + [UHS_DDR50] = {"ti,otap-del-sel-ddr50", MMC_CAP(UHS_DDR50)}, + [MMC_DDR_52] = {"ti,otap-del-sel-ddr52", MMC_CAP(MMC_DDR_52)}, + [MMC_HS_200] = {"ti,otap-del-sel-hs200", MMC_CAP(MMC_HS_200)}, + [MMC_HS_400] = {"ti,otap-del-sel-hs400", MMC_CAP(MMC_HS_400)}, +}; + struct am654_driver_data { const struct sdhci_ops *ops; u32 flags; @@ -112,6 +131,7 @@ static int am654_sdhci_set_ios_post(struct sdhci_host *host) struct am654_sdhci_plat *plat = dev_get_platdata(dev); unsigned int speed = host->mmc->clock; int sel50, sel100, freqsel; + u32 otap_del_sel; u32 mask, val; int ret; @@ -132,9 +152,10 @@ static int am654_sdhci_set_ios_post(struct sdhci_host *host) /* switch phy back on */ if (speed > AM654_SDHCI_MIN_FREQ) { + otap_del_sel = plat->otap_del_sel[host->mmc->selected_mode]; mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK; val = (1 << OTAPDLYENA_SHIFT) | - (plat->otap_del_sel << OTAPDLYSEL_SHIFT); + (otap_del_sel << OTAPDLYSEL_SHIFT); /* Write to STRBSEL for HS400 speed mode */ if (host->mmc->selected_mode == MMC_HS_400) { @@ -197,44 +218,6 @@ static int am654_sdhci_set_ios_post(struct sdhci_host *host) return 0; } -const struct sdhci_ops am654_sdhci_ops = { - .set_ios_post = &am654_sdhci_set_ios_post, - .set_control_reg = &am654_sdhci_set_control_reg, -}; - -const struct am654_driver_data am654_drv_data = { - .ops = &am654_sdhci_ops, - .flags = IOMUX_PRESENT | FREQSEL_2_BIT | DLL_PRESENT | STRBSEL_4_BIT, -}; - -const struct am654_driver_data j721e_8bit_drv_data = { - .ops = &am654_sdhci_ops, - .flags = DLL_PRESENT, -}; - -static int j721e_4bit_sdhci_set_ios_post(struct sdhci_host *host) -{ - struct udevice *dev = host->mmc->dev; - struct am654_sdhci_plat *plat = dev_get_platdata(dev); - u32 mask, val; - - mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK; - val = (1 << OTAPDLYENA_SHIFT) | - (plat->otap_del_sel << OTAPDLYSEL_SHIFT); - regmap_update_bits(plat->base, PHY_CTRL4, mask, val); - - return 0; -} - -const struct sdhci_ops j721e_4bit_sdhci_ops = { - .set_ios_post = &j721e_4bit_sdhci_set_ios_post, -}; - -const struct am654_driver_data j721e_4bit_drv_data = { - .ops = &j721e_4bit_sdhci_ops, - .flags = IOMUX_PRESENT, -}; - int am654_sdhci_init(struct am654_sdhci_plat *plat) { u32 ctl_cfg_2 = 0; @@ -281,6 +264,104 @@ int am654_sdhci_init(struct am654_sdhci_plat *plat) return 0; } +#define MAX_SDCD_DEBOUNCE_TIME 2000 +static int am654_sdhci_deferred_probe(struct sdhci_host *host) +{ + struct udevice *dev = host->mmc->dev; + struct am654_sdhci_plat *plat = dev_get_platdata(dev); + unsigned long start; + int val; + + /* + * The controller takes about 1 second to debounce the card detect line + * and doesn't let us power on until that time is up. Instead of waiting + * for 1 second at every stage, poll on the CARD_PRESENT bit upto a + * maximum of 2 seconds to be safe.. + */ + start = get_timer(0); + do { + if (get_timer(start) > MAX_SDCD_DEBOUNCE_TIME) + return -ENOMEDIUM; + + val = mmc_getcd(host->mmc); + } while (!val); + + am654_sdhci_init(plat); + + return sdhci_probe(dev); +} + +const struct sdhci_ops am654_sdhci_ops = { + .deferred_probe = am654_sdhci_deferred_probe, + .set_ios_post = &am654_sdhci_set_ios_post, + .set_control_reg = &am654_sdhci_set_control_reg, +}; + +const struct am654_driver_data am654_drv_data = { + .ops = &am654_sdhci_ops, + .flags = IOMUX_PRESENT | FREQSEL_2_BIT | DLL_PRESENT | STRBSEL_4_BIT, +}; + +const struct am654_driver_data j721e_8bit_drv_data = { + .ops = &am654_sdhci_ops, + .flags = DLL_PRESENT, +}; + +static int j721e_4bit_sdhci_set_ios_post(struct sdhci_host *host) +{ + struct udevice *dev = host->mmc->dev; + struct am654_sdhci_plat *plat = dev_get_platdata(dev); + u32 otap_del_sel, mask, val; + + otap_del_sel = plat->otap_del_sel[host->mmc->selected_mode]; + mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK; + val = (1 << OTAPDLYENA_SHIFT) | (otap_del_sel << OTAPDLYSEL_SHIFT); + regmap_update_bits(plat->base, PHY_CTRL4, mask, val); + + return 0; +} + +const struct sdhci_ops j721e_4bit_sdhci_ops = { + .deferred_probe = am654_sdhci_deferred_probe, + .set_ios_post = &j721e_4bit_sdhci_set_ios_post, +}; + +const struct am654_driver_data j721e_4bit_drv_data = { + .ops = &j721e_4bit_sdhci_ops, + .flags = IOMUX_PRESENT, +}; + +static int sdhci_am654_get_otap_delay(struct udevice *dev, + struct mmc_config *cfg) +{ + struct am654_sdhci_plat *plat = dev_get_platdata(dev); + int ret; + int i; + + /* ti,otap-del-sel-legacy is mandatory */ + ret = dev_read_u32(dev, "ti,otap-del-sel-legacy", + &plat->otap_del_sel[0]); + if (ret) + return ret; + /* + * Remove the corresponding capability if an otap-del-sel + * value is not found + */ + for (i = MMC_HS; i <= MMC_HS_400; i++) { + ret = dev_read_u32(dev, td[i].binding, &plat->otap_del_sel[i]); + if (ret) { + dev_dbg(dev, "Couldn't find %s\n", td[i].binding); + /* + * Remove the corresponding capability + * if an otap-del-sel value is not found + */ + cfg->host_caps &= ~td[i].capability; + } + } + + return 0; +} + static int am654_sdhci_probe(struct udevice *dev) { struct am654_driver_data *drv_data = @@ -313,15 +394,17 @@ static int am654_sdhci_probe(struct udevice *dev) if (ret) return ret; + ret = sdhci_am654_get_otap_delay(dev, cfg); + if (ret) + return ret; + host->ops = drv_data->ops; host->mmc->priv = host; upriv->mmc = host->mmc; regmap_init_mem_index(dev_ofnode(dev), &plat->base, 1); - am654_sdhci_init(plat); - - return sdhci_probe(dev); + return 0; } static int am654_sdhci_ofdata_to_platdata(struct udevice *dev) @@ -336,10 +419,6 @@ static int am654_sdhci_ofdata_to_platdata(struct udevice *dev) host->ioaddr = (void *)dev_read_addr(dev); plat->non_removable = dev_read_bool(dev, "non-removable"); - ret = dev_read_u32(dev, "ti,otap-del-sel", &plat->otap_del_sel); - if (ret) - return ret; - if (plat->flags & DLL_PRESENT) { ret = dev_read_u32(dev, "ti,trm-icp", &plat->trm_icp); if (ret) diff --git a/drivers/mmc/ca_dw_mmc.c b/drivers/mmc/ca_dw_mmc.c new file mode 100644 index 0000000000..acbc850fcb --- /dev/null +++ b/drivers/mmc/ca_dw_mmc.c @@ -0,0 +1,181 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2019 Cortina Access + * Arthur Li <arthur.li@cortina-access.com> + */ + +#include <common.h> +#include <dwmmc.h> +#include <fdtdec.h> +#include <linux/libfdt.h> +#include <malloc.h> +#include <errno.h> +#include <dm.h> +#include <mapmem.h> + +#define SD_CLK_SEL_MASK (0x3) +#define SD_DLL_DEFAULT (0x143000) +#define SD_SCLK_MAX (200000000) + +#define SD_CLK_SEL_200MHZ (0x2) +#define SD_CLK_SEL_100MHZ (0x1) + +#define IO_DRV_SD_DS_OFFSET (16) +#define IO_DRV_SD_DS_MASK (0xff << IO_DRV_SD_DS_OFFSET) + +#define MIN_FREQ (400000) + +DECLARE_GLOBAL_DATA_PTR; + +struct ca_mmc_plat { + struct mmc_config cfg; + struct mmc mmc; +}; + +struct ca_dwmmc_priv_data { + struct dwmci_host host; + void __iomem *sd_dll_reg; + void __iomem *io_drv_reg; + u8 ds; +}; + +static void ca_dwmci_clksel(struct dwmci_host *host) +{ + struct ca_dwmmc_priv_data *priv = host->priv; + u32 val = readl(priv->sd_dll_reg); + + if (host->bus_hz >= 200000000) { + val &= ~SD_CLK_SEL_MASK; + val |= SD_CLK_SEL_200MHZ; + } else if (host->bus_hz >= 100000000) { + val &= ~SD_CLK_SEL_MASK; + val |= SD_CLK_SEL_100MHZ; + } else { + val &= ~SD_CLK_SEL_MASK; + } + + writel(val, priv->sd_dll_reg); +} + +static void ca_dwmci_board_init(struct dwmci_host *host) +{ + struct ca_dwmmc_priv_data *priv = host->priv; + u32 val = readl(priv->io_drv_reg); + + writel(SD_DLL_DEFAULT, priv->sd_dll_reg); + + val &= ~IO_DRV_SD_DS_MASK; + if (priv && priv->ds) + val |= priv->ds << IO_DRV_SD_DS_OFFSET; + writel(val, priv->io_drv_reg); +} + +unsigned int ca_dwmci_get_mmc_clock(struct dwmci_host *host, uint freq) +{ + struct ca_dwmmc_priv_data *priv = host->priv; + u8 sd_clk_sel = readl(priv->sd_dll_reg) & SD_CLK_SEL_MASK; + u8 clk_div; + + switch (sd_clk_sel) { + case 2: + clk_div = 1; + break; + case 1: + clk_div = 2; + break; + default: + clk_div = 4; + } + + return SD_SCLK_MAX / clk_div / (host->div + 1); +} + +static int ca_dwmmc_ofdata_to_platdata(struct udevice *dev) +{ + struct ca_dwmmc_priv_data *priv = dev_get_priv(dev); + struct dwmci_host *host = &priv->host; + u32 tmp; + + host->name = dev->name; + host->dev_index = 0; + + host->buswidth = dev_read_u32_default(dev, "bus-width", 1); + if (host->buswidth != 1 && host->buswidth != 4) + return -EINVAL; + + host->bus_hz = dev_read_u32_default(dev, "max-frequency", 50000000); + priv->ds = dev_read_u32_default(dev, "io_ds", 0x33); + host->fifo_mode = dev_read_bool(dev, "fifo-mode"); + + dev_read_u32(dev, "sd_dll_ctrl", &tmp); + priv->sd_dll_reg = map_sysmem((uintptr_t)tmp, sizeof(uintptr_t)); + if (!priv->sd_dll_reg) + return -EINVAL; + + dev_read_u32(dev, "io_drv_ctrl", &tmp); + priv->io_drv_reg = map_sysmem((uintptr_t)tmp, sizeof(uintptr_t)); + if (!priv->io_drv_reg) + return -EINVAL; + + host->ioaddr = dev_read_addr_ptr(dev); + if (host->ioaddr == (void *)FDT_ADDR_T_NONE) { + printf("DWMMC: base address is invalid\n"); + return -EINVAL; + } + + host->priv = priv; + + return 0; +} + +struct dm_mmc_ops ca_dwmci_dm_ops; + +static int ca_dwmmc_probe(struct udevice *dev) +{ + struct ca_mmc_plat *plat = dev_get_platdata(dev); + struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); + struct ca_dwmmc_priv_data *priv = dev_get_priv(dev); + struct dwmci_host *host = &priv->host; + + memcpy(&ca_dwmci_dm_ops, &dm_dwmci_ops, sizeof(struct dm_mmc_ops)); + + dwmci_setup_cfg(&plat->cfg, host, host->bus_hz, MIN_FREQ); + if (host->buswidth == 1) { + (&plat->cfg)->host_caps &= ~MMC_MODE_8BIT; + (&plat->cfg)->host_caps &= ~MMC_MODE_4BIT; + } + + host->mmc = &plat->mmc; + host->mmc->priv = &priv->host; + upriv->mmc = host->mmc; + host->mmc->dev = dev; + host->clksel = ca_dwmci_clksel; + host->board_init = ca_dwmci_board_init; + host->get_mmc_clk = ca_dwmci_get_mmc_clock; + + return dwmci_probe(dev); +} + +static int ca_dwmmc_bind(struct udevice *dev) +{ + struct ca_mmc_plat *plat = dev_get_platdata(dev); + + return dwmci_bind(dev, &plat->mmc, &plat->cfg); +} + +static const struct udevice_id ca_dwmmc_ids[] = { + { .compatible = "snps,dw-cortina" }, + { } +}; + +U_BOOT_DRIVER(ca_dwmmc_drv) = { + .name = "cortina_dwmmc", + .id = UCLASS_MMC, + .of_match = ca_dwmmc_ids, + .ofdata_to_platdata = ca_dwmmc_ofdata_to_platdata, + .bind = ca_dwmmc_bind, + .ops = &ca_dwmci_dm_ops, + .probe = ca_dwmmc_probe, + .priv_auto_alloc_size = sizeof(struct ca_dwmmc_priv_data), + .platdata_auto_alloc_size = sizeof(struct ca_mmc_plat), +}; diff --git a/drivers/mmc/fsl_esdhc_imx.c b/drivers/mmc/fsl_esdhc_imx.c index 4900498e9b..6bca2a9c82 100644 --- a/drivers/mmc/fsl_esdhc_imx.c +++ b/drivers/mmc/fsl_esdhc_imx.c @@ -743,7 +743,6 @@ static int esdhc_set_timing(struct mmc *mmc) switch (mmc->selected_mode) { case MMC_LEGACY: - case SD_LEGACY: esdhc_reset_tuning(mmc); writel(mixctrl, ®s->mixctrl); break; diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c index 0b90a97650..c75892a72c 100644 --- a/drivers/mmc/mmc-uclass.c +++ b/drivers/mmc/mmc-uclass.c @@ -138,6 +138,21 @@ int mmc_host_power_cycle(struct mmc *mmc) return dm_mmc_host_power_cycle(mmc->dev); } +int dm_mmc_deferred_probe(struct udevice *dev) +{ + struct dm_mmc_ops *ops = mmc_get_ops(dev); + + if (ops->deferred_probe) + return ops->deferred_probe(dev); + + return 0; +} + +int mmc_deferred_probe(struct mmc *mmc) +{ + return dm_mmc_deferred_probe(mmc->dev); +} + int mmc_of_parse(struct udevice *dev, struct mmc_config *cfg) { int val; diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index b50fcbf6cf..3e36566693 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -132,7 +132,6 @@ const char *mmc_mode_name(enum bus_mode mode) { static const char *const names[] = { [MMC_LEGACY] = "MMC legacy", - [SD_LEGACY] = "SD Legacy", [MMC_HS] = "MMC High Speed (26MHz)", [SD_HS] = "SD High Speed (50MHz)", [UHS_SDR12] = "UHS SDR12 (25MHz)", @@ -158,7 +157,6 @@ static uint mmc_mode2freq(struct mmc *mmc, enum bus_mode mode) { static const int freqs[] = { [MMC_LEGACY] = 25000000, - [SD_LEGACY] = 25000000, [MMC_HS] = 26000000, [SD_HS] = 50000000, [MMC_HS_52] = 52000000, @@ -1239,7 +1237,7 @@ static int sd_get_capabilities(struct mmc *mmc) u32 sd3_bus_mode; #endif - mmc->card_caps = MMC_MODE_1BIT | MMC_CAP(SD_LEGACY); + mmc->card_caps = MMC_MODE_1BIT | MMC_CAP(MMC_LEGACY); if (mmc_host_is_spi(mmc)) return 0; @@ -1352,7 +1350,7 @@ static int sd_set_card_speed(struct mmc *mmc, enum bus_mode mode) return 0; switch (mode) { - case SD_LEGACY: + case MMC_LEGACY: speed = UHS_SDR12_BUS_SPEED; break; case SD_HS: @@ -1695,7 +1693,7 @@ static const struct mode_width_tuning sd_modes_by_pref[] = { }, #endif { - .mode = SD_LEGACY, + .mode = MMC_LEGACY, .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, } }; @@ -1725,7 +1723,7 @@ static int sd_select_mode_and_width(struct mmc *mmc, uint card_caps) if (mmc_host_is_spi(mmc)) { mmc_set_bus_width(mmc, 1); - mmc_select_mode(mmc, SD_LEGACY); + mmc_select_mode(mmc, MMC_LEGACY); mmc_set_clock(mmc, mmc->tran_speed, MMC_CLK_ENABLE); return 0; } @@ -1784,7 +1782,7 @@ static int sd_select_mode_and_width(struct mmc *mmc, uint card_caps) error: /* revert to a safer bus speed */ - mmc_select_mode(mmc, SD_LEGACY); + mmc_select_mode(mmc, MMC_LEGACY); mmc_set_clock(mmc, mmc->tran_speed, MMC_CLK_ENABLE); } @@ -2561,7 +2559,7 @@ static int mmc_startup(struct mmc *mmc) #if CONFIG_IS_ENABLED(MMC_TINY) mmc_set_clock(mmc, mmc->legacy_speed, false); - mmc_select_mode(mmc, IS_SD(mmc) ? SD_LEGACY : MMC_LEGACY); + mmc_select_mode(mmc, MMC_LEGACY); mmc_set_bus_width(mmc, 1); #else if (IS_SD(mmc)) { @@ -2843,9 +2841,11 @@ int mmc_start_init(struct mmc *mmc) * all hosts are capable of 1 bit bus-width and able to use the legacy * timings. */ - mmc->host_caps = mmc->cfg->host_caps | MMC_CAP(SD_LEGACY) | + mmc->host_caps = mmc->cfg->host_caps | MMC_CAP(MMC_LEGACY) | MMC_CAP(MMC_LEGACY) | MMC_MODE_1BIT; - +#if CONFIG_IS_ENABLED(DM_MMC) + mmc_deferred_probe(mmc); +#endif #if !defined(CONFIG_MMC_BROKEN_CD) no_card = mmc_getcd(mmc) == 0; #else diff --git a/drivers/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c index 5334723a9f..4d0dc33936 100644 --- a/drivers/mmc/omap_hsmmc.c +++ b/drivers/mmc/omap_hsmmc.c @@ -392,7 +392,6 @@ static void omap_hsmmc_set_timing(struct mmc *mmc) break; case MMC_LEGACY: case MMC_HS: - case SD_LEGACY: case UHS_SDR12: val |= AC12_UHSMC_SDR12; break; diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 9b7c5f8f68..520c9f9feb 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -658,6 +658,20 @@ int sdhci_probe(struct udevice *dev) return sdhci_init(mmc); } +static int sdhci_deferred_probe(struct udevice *dev) +{ + int err; + struct mmc *mmc = mmc_get_mmc_dev(dev); + struct sdhci_host *host = mmc->priv; + + if (host->ops && host->ops->deferred_probe) { + err = host->ops->deferred_probe(host); + if (err) + return err; + } + return 0; +} + static int sdhci_get_cd(struct udevice *dev) { struct mmc *mmc = mmc_get_mmc_dev(dev); @@ -692,6 +706,7 @@ const struct dm_mmc_ops sdhci_ops = { .send_cmd = sdhci_send_command, .set_ios = sdhci_set_ios, .get_cd = sdhci_get_cd, + .deferred_probe = sdhci_deferred_probe, #ifdef MMC_SUPPORTS_TUNING .execute_tuning = sdhci_execute_tuning, #endif diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c index 24fabeee95..da3ff53da1 100644 --- a/drivers/mmc/zynq_sdhci.c +++ b/drivers/mmc/zynq_sdhci.c @@ -37,7 +37,6 @@ struct arasan_sdhci_priv { static const u8 mode2timing[] = { [MMC_LEGACY] = UHS_SDR12_BUS_SPEED, - [SD_LEGACY] = UHS_SDR12_BUS_SPEED, [MMC_HS] = HIGH_SPEED_BUS_SPEED, [SD_HS] = HIGH_SPEED_BUS_SPEED, [MMC_HS_52] = HIGH_SPEED_BUS_SPEED, diff --git a/include/configs/am65x_evm.h b/include/configs/am65x_evm.h index 7d7f86a059..23ee2254ed 100644 --- a/include/configs/am65x_evm.h +++ b/include/configs/am65x_evm.h @@ -127,8 +127,6 @@ #define CONFIG_SYS_MMC_ENV_PART 1 #endif -#define CONFIG_SUPPORT_EMMC_BOOT - /* Now for the remaining common defines */ #include <configs/ti_armv7_common.h> diff --git a/include/mmc.h b/include/mmc.h index 71e2e1735a..e83c22423b 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -15,6 +15,8 @@ #include <linux/dma-direction.h> #include <part.h> +struct bd_info; + #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) #define MMC_SUPPORTS_TUNING #endif @@ -408,6 +410,14 @@ struct mmc; #if CONFIG_IS_ENABLED(DM_MMC) struct dm_mmc_ops { /** + * deferred_probe() - Some configurations that need to be deferred + * to just before enumerating the device + * + * @dev: Device to init + * @return 0 if Ok, -ve if error + */ + int (*deferred_probe)(struct udevice *dev); + /** * send_cmd() - Send a command to the MMC device * * @dev: Device to receive the command @@ -490,6 +500,7 @@ 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_us); int dm_mmc_host_power_cycle(struct udevice *dev); +int dm_mmc_deferred_probe(struct udevice *dev); /* Transition functions for compatibility */ int mmc_set_ios(struct mmc *mmc); @@ -499,6 +510,7 @@ int mmc_execute_tuning(struct mmc *mmc, uint opcode); int mmc_wait_dat0(struct mmc *mmc, int state, int timeout_us); int mmc_set_enhanced_strobe(struct mmc *mmc); int mmc_host_power_cycle(struct mmc *mmc); +int mmc_deferred_probe(struct mmc *mmc); #else struct mmc_ops { @@ -533,7 +545,6 @@ struct sd_ssr { enum bus_mode { MMC_LEGACY, - SD_LEGACY, MMC_HS, SD_HS, MMC_HS_52, @@ -603,6 +614,7 @@ struct mmc { bool clk_disable; /* true if the clock can be turned off */ uint bus_width; uint clock; + uint saved_clock; enum mmc_voltage signal_voltage; uint card_caps; uint host_caps; @@ -712,7 +724,7 @@ void mmc_destroy(struct mmc *mmc); * @return 0 if OK, -ve on error */ int mmc_unbind(struct udevice *dev); -int mmc_initialize(bd_t *bis); +int mmc_initialize(struct bd_info *bis); int mmc_init_device(int num); int mmc_init(struct mmc *mmc); int mmc_send_tuning(struct mmc *mmc, u32 opcode, int *cmd_error); @@ -857,8 +869,8 @@ void mmc_set_preinit(struct mmc *mmc, int preinit); #endif void board_mmc_power_init(void); -int board_mmc_init(bd_t *bis); -int cpu_mmc_init(bd_t *bis); +int board_mmc_init(struct bd_info *bis); +int cpu_mmc_init(struct bd_info *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); diff --git a/include/sdhci.h b/include/sdhci.h index 7f8feefa45..aa4378fd57 100644 --- a/include/sdhci.h +++ b/include/sdhci.h @@ -268,6 +268,7 @@ struct sdhci_ops { void (*set_clock)(struct sdhci_host *host, u32 div); int (*platform_execute_tuning)(struct mmc *host, u8 opcode); void (*set_delay)(struct sdhci_host *host); + int (*deferred_probe)(struct sdhci_host *host); }; #if CONFIG_IS_ENABLED(MMC_SDHCI_ADMA) |