diff options
Diffstat (limited to 'drivers/mmc')
69 files changed, 1486 insertions, 652 deletions
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 549634891a3..22c65681f0a 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -41,7 +41,6 @@ config MMC_BROKEN_CD config DM_MMC bool "Enable MMC controllers using Driver Model" depends on DM - select BLK help This enables the MultiMediaCard (MMC) uclass which supports MMC and Secure Digital I/O (SDIO) cards. Both removable (SD, micro-SD, etc.) @@ -62,6 +61,17 @@ config SPL_DM_MMC appear as block devices in U-Boot and can support filesystems such as EXT4 and FAT. +config TPL_DM_MMC + bool "Enable MMC controllers using Driver Model in TPL" + depends on TPL_DM && DM_MMC + select TPL_BLK + help + This enables the MultiMediaCard (MMC) uclass which supports MMC and + Secure Digital I/O (SDIO) cards. Both removable (SD, micro-SD, etc.) + and non-removable (e.g. eMMC chip) devices are supported. These + appear as block devices in U-Boot and can support filesystems such + as EXT4 and FAT. + if MMC config MMC_SDHCI_ADMA_HELPERS @@ -147,9 +157,16 @@ config SPL_MMC_IO_VOLTAGE support. For eMMC this not mandatory, but not enabling this option may prevent the driver of using the faster modes. +config MMC_SUPPORTS_TUNING + bool + +config SPL_MMC_SUPPORTS_TUNING + bool + config MMC_UHS_SUPPORT bool "enable UHS support" depends on MMC_IO_VOLTAGE + select MMC_SUPPORTS_TUNING help The Ultra High Speed (UHS) bus is available on some SDHC and SDXC cards. The IO voltage must be switchable from 3.3v to 1.8v. The bus @@ -158,6 +175,7 @@ config MMC_UHS_SUPPORT config SPL_MMC_UHS_SUPPORT bool "enable UHS support in SPL" depends on SPL_MMC_IO_VOLTAGE + select SPL_MMC_SUPPORTS_TUNING help The Ultra High Speed (UHS) bus is available on some SDHC and SDXC cards. The IO voltage must be switchable from 3.3v to 1.8v. The bus @@ -193,6 +211,7 @@ config SPL_MMC_HS400_SUPPORT config MMC_HS200_SUPPORT bool "enable HS200 support" + select MMC_SUPPORTS_TUNING help The HS200 mode is support by some eMMC. The bus frequency is up to 200MHz. This mode requires tuning the IO. @@ -200,6 +219,7 @@ config MMC_HS200_SUPPORT config SPL_MMC_HS200_SUPPORT bool "enable HS200 support in SPL" depends on SPL_MMC + select SPL_MMC_SUPPORTS_TUNING help The HS200 mode is support by some eMMC. The bus frequency is up to 200MHz. This mode requires tuning the IO. @@ -239,7 +259,6 @@ 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 help This selects support for Cortina SoC specific extensions to the Synopsys DesignWare Memory Card Interface driver. Select this option @@ -303,7 +322,7 @@ config NEXELL_DWMMC config MMC_MESON_GX bool "Meson GX EMMC controller support" - depends on DM_MMC && BLK && ARCH_MESON + depends on DM_MMC && ARCH_MESON help Support for EMMC host controller on Meson GX ARM SoCs platform (S905) @@ -347,6 +366,7 @@ config MMC_OCTEONTX bool "Marvell Octeon Multimedia Card Interface support" depends on (ARCH_OCTEON || ARCH_OCTEONTX || ARCH_OCTEONTX2) depends on DM_MMC + select MMC_SUPPORTS_TUNING if ARCH_OCTEONTX2 help This selects the Octeon Multimedia card Interface. If you have an OcteonTX/TX2 or MIPS Octeon board with a @@ -356,7 +376,7 @@ config MMC_OCTEONTX config MVEBU_MMC bool "Kirkwood MMC controller support" - depends on DM_MMC && BLK && ARCH_KIRKWOOD + depends on DM_MMC && ARCH_KIRKWOOD help Support for MMC host controller on Kirkwood SoCs. If you are on a Kirkwood architecture, say Y here. @@ -397,7 +417,7 @@ config MMC_OMAP36XX_PINS config HSMMC2_8BIT bool "Enable 8-bit interface for eMMC (interface #2)" - depends on MMC_OMAP_HS && (OMAP44XX || OMAP54XX || DRA7XX || AM33XX || \ + depends on MMC_OMAP_HS && (OMAP54XX || DRA7XX || AM33XX || \ AM43XX || ARCH_KEYSTONE) config SH_MMCIF @@ -409,7 +429,7 @@ config SH_MMCIF config MMC_UNIPHIER bool "UniPhier SD/MMC Host Controller support" depends on ARCH_UNIPHIER - depends on BLK && DM_MMC + depends on DM_MMC depends on OF_CONTROL help This selects support for the Matsushita SD/MMC Host Controller on @@ -418,7 +438,7 @@ config MMC_UNIPHIER config RENESAS_SDHI bool "Renesas R-Car SD/MMC Host Controller support" depends on ARCH_RENESAS - depends on BLK && DM_MMC + depends on DM_MMC depends on OF_CONTROL select BOUNCE_BUFFER help @@ -428,7 +448,7 @@ config RENESAS_SDHI config MMC_BCM2835 bool "BCM2835 family custom SD/MMC Host Controller support" depends on ARCH_BCM283X - depends on BLK && DM_MMC + depends on DM_MMC depends on OF_CONTROL default y help @@ -448,7 +468,7 @@ config JZ47XX_MMC config MMC_SANDBOX bool "Sandbox MMC support" depends on SANDBOX - depends on BLK && DM_MMC && OF_CONTROL + depends on DM_MMC && OF_CONTROL help This select a dummy sandbox MMC driver. At present this does nothing other than allow sandbox to be build with MMC support. This @@ -550,7 +570,7 @@ config MMC_SDHCI_ASPEED config MMC_SDHCI_ATMEL bool "Atmel SDHCI controller support" depends on ARCH_AT91 - depends on DM_MMC && BLK && ARCH_AT91 + depends on DM_MMC && ARCH_AT91 depends on MMC_SDHCI help This enables support for the Atmel SDHCI controller, which supports @@ -585,7 +605,7 @@ config MMC_SDHCI_BCMSTB config MMC_SDHCI_CADENCE bool "SDHCI support for the Cadence SD/SDIO/eMMC controller" - depends on BLK && DM_MMC + depends on DM_MMC depends on MMC_SDHCI depends on OF_CONTROL help @@ -597,7 +617,7 @@ config MMC_SDHCI_CADENCE config MMC_SDHCI_CV1800B bool "SDHCI support for the CV1800B SD/SDIO/eMMC controller" - depends on BLK && DM_MMC + depends on DM_MMC depends on MMC_SDHCI depends on OF_CONTROL help @@ -632,7 +652,7 @@ config MMC_SDHCI_IPROC config MMC_SDHCI_F_SDH30 bool "SDHCI support for Fujitsu Semiconductor/Socionext F_SDH30" - depends on BLK && DM_MMC + depends on DM_MMC depends on MMC_SDHCI help This selects the Secure Digital Host Controller Interface (SDHCI) @@ -652,7 +672,7 @@ config MMC_SDHCI_KONA config MMC_SDHCI_MSM bool "Qualcomm SDHCI controller" - depends on BLK && DM_MMC + depends on DM_MMC depends on MMC_SDHCI help Enables support for SDHCI 2.0 controller present on some Qualcomm @@ -818,7 +838,7 @@ config MMC_PITON config GENERIC_ATMEL_MCI bool "Atmel Multimedia Card Interface support" - depends on DM_MMC && BLK && ARCH_AT91 + depends on DM_MMC && ARCH_AT91 help This enables support for Atmel High Speed Multimedia Card Interface (HSMCI), which supports the MultiMedia Card (MMC) Specification V4.3, @@ -827,7 +847,7 @@ config GENERIC_ATMEL_MCI config STM32_SDMMC2 bool "STMicroelectronics STM32H7 SD/MMC Host Controller support" - depends on DM_MMC && BLK && OF_CONTROL + depends on DM_MMC && OF_CONTROL help This selects support for the SD/MMC controller on STM32H7 SoCs. If you have a board based on such a SoC and with a SD/MMC slot, @@ -847,7 +867,7 @@ config FTSDC010_SDIO config MMC_MTK bool "MediaTek SD/MMC Card Interface support" depends on ARCH_MEDIATEK || ARCH_MTMIPS - depends on BLK && DM_MMC + depends on DM_MMC depends on OF_CONTROL help This selects the MediaTek(R) Secure digital and Multimedia card Interface. diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 72c3fb66ce0..235c477c2e0 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -60,6 +60,7 @@ obj-$(CONFIG_MMC_SDHCI_ATMEL) += atmel_sdhci.o obj-$(CONFIG_MMC_SDHCI_BCM2835) += bcm2835_sdhci.o obj-$(CONFIG_MMC_SDHCI_BCMSTB) += bcmstb_sdhci.o obj-$(CONFIG_MMC_SDHCI_CADENCE) += sdhci-cadence.o +obj-$(CONFIG_MMC_SDHCI_CADENCE) += sdhci-cadence6.o obj-$(CONFIG_MMC_SDHCI_CV1800B) += cv1800b_sdhci.o obj-$(CONFIG_MMC_SDHCI_AM654) += am654_sdhci.o obj-$(CONFIG_MMC_SDHCI_IPROC) += iproc_sdhci.o diff --git a/drivers/mmc/am654_sdhci.c b/drivers/mmc/am654_sdhci.c index 2139fea04d5..b4c60a48d2e 100644 --- a/drivers/mmc/am654_sdhci.c +++ b/drivers/mmc/am654_sdhci.c @@ -6,7 +6,6 @@ */ #include <clk.h> -#include <common.h> #include <dm.h> #include <malloc.h> #include <mmc.h> @@ -85,6 +84,8 @@ #define AM654_SDHCI_MIN_FREQ 400000 #define CLOCK_TOO_SLOW_HZ 50000000 +#define ENABLE 0x1 + struct am654_sdhci_plat { struct mmc_config cfg; struct mmc mmc; @@ -92,16 +93,20 @@ struct am654_sdhci_plat { bool non_removable; u32 otap_del_sel[MMC_MODES_END]; u32 itap_del_sel[MMC_MODES_END]; + u32 itap_del_ena[MMC_MODES_END]; u32 trm_icp; u32 drv_strength; u32 strb_sel; u32 clkbuf_sel; u32 flags; + bool dll_enable; #define DLL_PRESENT BIT(0) #define IOMUX_PRESENT BIT(1) #define FREQSEL_2_BIT BIT(2) #define STRBSEL_4_BIT BIT(3) #define DLL_CALIB BIT(4) + u32 quirks; +#define SDHCI_AM654_QUIRK_FORCE_CDTEST BIT(0) }; struct timing_data { @@ -110,6 +115,12 @@ struct timing_data { u32 capability; }; +struct window { + u8 start; + u8 end; + u8 length; +}; + static const struct timing_data td[] = { [MMC_LEGACY] = {"ti,otap-del-sel-legacy", "ti,itap-del-sel-legacy", @@ -216,8 +227,10 @@ static int am654_sdhci_setup_dll(struct am654_sdhci_plat *plat, } static void am654_sdhci_write_itapdly(struct am654_sdhci_plat *plat, - u32 itapdly) + u32 itapdly, u32 enable) { + regmap_update_bits(plat->base, PHY_CTRL4, ITAPDLYENA_MASK, + enable << ITAPDLYENA_SHIFT); /* Set ITAPCHGWIN before writing to ITAPDLY */ regmap_update_bits(plat->base, PHY_CTRL4, ITAPCHGWIN_MASK, 1 << ITAPCHGWIN_SHIFT); @@ -235,7 +248,8 @@ static void am654_sdhci_setup_delay_chain(struct am654_sdhci_plat *plat, mask = SELDLYTXCLK_MASK | SELDLYRXCLK_MASK; regmap_update_bits(plat->base, PHY_CTRL5, mask, val); - am654_sdhci_write_itapdly(plat, plat->itap_del_sel[mode]); + am654_sdhci_write_itapdly(plat, plat->itap_del_sel[mode], + plat->itap_del_ena[mode]); } static int am654_sdhci_set_ios_post(struct sdhci_host *host) @@ -276,12 +290,22 @@ static int am654_sdhci_set_ios_post(struct sdhci_host *host) regmap_update_bits(plat->base, PHY_CTRL4, mask, val); - if (mode > UHS_SDR25 && speed >= CLOCK_TOO_SLOW_HZ) { + if ((mode > UHS_SDR25 || mode == MMC_DDR_52) && speed >= CLOCK_TOO_SLOW_HZ) { ret = am654_sdhci_setup_dll(plat, speed); if (ret) return ret; + + plat->dll_enable = true; + if (mode == MMC_HS_400) { + plat->itap_del_ena[mode] = ENABLE; + plat->itap_del_sel[mode] = plat->itap_del_sel[mode - 1]; + } + + am654_sdhci_write_itapdly(plat, plat->itap_del_sel[mode], + plat->itap_del_ena[mode]); } else { am654_sdhci_setup_delay_chain(plat, mode); + plat->dll_enable = false; } regmap_update_bits(plat->base, PHY_CTRL5, CLKBUFSEL_MASK, @@ -328,10 +352,8 @@ int am654_sdhci_init(struct am654_sdhci_plat *plat) } #define MAX_SDCD_DEBOUNCE_TIME 2000 -static int am654_sdhci_deferred_probe(struct sdhci_host *host) +static int am654_sdhci_cd_poll(struct mmc *mmc) { - struct udevice *dev = host->mmc->dev; - struct am654_sdhci_plat *plat = dev_get_plat(dev); unsigned long start; int val; @@ -346,12 +368,35 @@ static int am654_sdhci_deferred_probe(struct sdhci_host *host) if (get_timer(start) > MAX_SDCD_DEBOUNCE_TIME) return -ENOMEDIUM; - val = mmc_getcd(host->mmc); + val = mmc_getcd(mmc); } while (!val); + return 0; +} + +static int am654_sdhci_deferred_probe(struct sdhci_host *host) +{ + struct udevice *dev = host->mmc->dev; + struct am654_sdhci_plat *plat = dev_get_plat(dev); + int ret; + + if (!(plat->quirks & SDHCI_AM654_QUIRK_FORCE_CDTEST)) { + if (am654_sdhci_cd_poll(host->mmc)) + return -ENOMEDIUM; + } + am654_sdhci_init(plat); - return sdhci_probe(dev); + ret = sdhci_probe(dev); + + if (plat->quirks & SDHCI_AM654_QUIRK_FORCE_CDTEST) { + u8 hostctrlreg = sdhci_readb(host, SDHCI_HOST_CONTROL); + + hostctrlreg |= SDHCI_CTRL_CD_TEST_INS | SDHCI_CTRL_CD_TEST; + sdhci_writeb(host, hostctrlreg, SDHCI_HOST_CONTROL); + } + + return ret; } static void am654_sdhci_write_b(struct sdhci_host *host, u8 val, int reg) @@ -374,46 +419,110 @@ static void am654_sdhci_write_b(struct sdhci_host *host, u8 val, int reg) writeb(val, host->ioaddr + reg); } -#ifdef MMC_SUPPORTS_TUNING -#define ITAP_MAX 32 +#if CONFIG_IS_ENABLED(MMC_SUPPORTS_TUNING) +#define ITAPDLY_LENGTH 32 +#define ITAPDLY_LAST_INDEX (ITAPDLY_LENGTH - 1) + +static u32 am654_sdhci_calculate_itap(struct udevice *dev, struct window + *fail_window, u8 num_fails, bool circular_buffer) +{ + u8 itap = 0, start_fail = 0, end_fail = 0, pass_length = 0; + u8 first_fail_start = 0, last_fail_end = 0; + struct window pass_window = {0, 0, 0}; + int prev_fail_end = -1; + u8 i; + + if (!num_fails) + return ITAPDLY_LAST_INDEX >> 1; + + if (fail_window->length == ITAPDLY_LENGTH) { + dev_err(dev, "No passing ITAPDLY, return 0\n"); + return 0; + } + + first_fail_start = fail_window->start; + last_fail_end = fail_window[num_fails - 1].end; + + for (i = 0; i < num_fails; i++) { + start_fail = fail_window[i].start; + end_fail = fail_window[i].end; + pass_length = start_fail - (prev_fail_end + 1); + + if (pass_length > pass_window.length) { + pass_window.start = prev_fail_end + 1; + pass_window.length = pass_length; + } + prev_fail_end = end_fail; + } + + if (!circular_buffer) + pass_length = ITAPDLY_LAST_INDEX - last_fail_end; + else + pass_length = ITAPDLY_LAST_INDEX - last_fail_end + first_fail_start; + + if (pass_length > pass_window.length) { + pass_window.start = last_fail_end + 1; + pass_window.length = pass_length; + } + + if (!circular_buffer) + itap = pass_window.start + (pass_window.length >> 1); + else + itap = (pass_window.start + (pass_window.length >> 1)) % ITAPDLY_LENGTH; + + return (itap > ITAPDLY_LAST_INDEX) ? ITAPDLY_LAST_INDEX >> 1 : itap; +} + static int am654_sdhci_execute_tuning(struct mmc *mmc, u8 opcode) { struct udevice *dev = mmc->dev; struct am654_sdhci_plat *plat = dev_get_plat(dev); - int cur_val, prev_val = 1, fail_len = 0, pass_window = 0, pass_len; - u32 itap; + struct window fail_window[ITAPDLY_LENGTH]; + int mode = mmc->selected_mode; + u8 curr_pass, itap; + u8 fail_index = 0; + u8 prev_pass = 1; + + memset(fail_window, 0, sizeof(fail_window)); /* Enable ITAPDLY */ - regmap_update_bits(plat->base, PHY_CTRL4, ITAPDLYENA_MASK, - 1 << ITAPDLYENA_SHIFT); + plat->itap_del_ena[mode] = ENABLE; - for (itap = 0; itap < ITAP_MAX; itap++) { - am654_sdhci_write_itapdly(plat, itap); + for (itap = 0; itap < ITAPDLY_LENGTH; itap++) { + am654_sdhci_write_itapdly(plat, itap, plat->itap_del_ena[mode]); - cur_val = !mmc_send_tuning(mmc, opcode); - if (cur_val && !prev_val) - pass_window = itap; + curr_pass = !mmc_send_tuning(mmc, opcode); - if (!cur_val) - fail_len++; + if (!curr_pass && prev_pass) + fail_window[fail_index].start = itap; - prev_val = cur_val; + if (!curr_pass) { + fail_window[fail_index].end = itap; + fail_window[fail_index].length++; + } + + if (curr_pass && !prev_pass) + fail_index++; + + prev_pass = curr_pass; } - /* - * Having determined the length of the failing window and start of - * the passing window calculate the length of the passing window and - * set the final value halfway through it considering the range as a - * circular buffer - */ - pass_len = ITAP_MAX - fail_len; - itap = (pass_window + (pass_len >> 1)) % ITAP_MAX; - am654_sdhci_write_itapdly(plat, itap); + + if (fail_window[fail_index].length != 0) + fail_index++; + + itap = am654_sdhci_calculate_itap(dev, fail_window, fail_index, + plat->dll_enable); + + /* Save ITAPDLY */ + plat->itap_del_sel[mode] = itap; + + am654_sdhci_write_itapdly(plat, itap, plat->itap_del_ena[mode]); return 0; } #endif const struct sdhci_ops am654_sdhci_ops = { -#ifdef MMC_SUPPORTS_TUNING +#if CONFIG_IS_ENABLED(MMC_SUPPORTS_TUNING) .platform_execute_tuning = am654_sdhci_execute_tuning, #endif .deferred_probe = am654_sdhci_deferred_probe, @@ -442,12 +551,29 @@ 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_plat(dev); - u32 otap_del_sel, mask, val; + int mode = host->mmc->selected_mode; + u32 otap_del_sel; + u32 itap_del_ena; + u32 itap_del_sel; + u32 mask, val; + + otap_del_sel = plat->otap_del_sel[mode]; - 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); + val = (1 << OTAPDLYENA_SHIFT) | + (otap_del_sel << OTAPDLYSEL_SHIFT); + + itap_del_ena = plat->itap_del_ena[mode]; + itap_del_sel = plat->itap_del_sel[mode]; + + mask |= ITAPDLYENA_MASK | ITAPDLYSEL_MASK; + val |= (itap_del_ena << ITAPDLYENA_SHIFT) | + (itap_del_sel << ITAPDLYSEL_SHIFT); + + regmap_update_bits(plat->base, PHY_CTRL4, ITAPCHGWIN_MASK, + 1 << ITAPCHGWIN_SHIFT); regmap_update_bits(plat->base, PHY_CTRL4, mask, val); + regmap_update_bits(plat->base, PHY_CTRL4, ITAPCHGWIN_MASK, 0); regmap_update_bits(plat->base, PHY_CTRL5, CLKBUFSEL_MASK, plat->clkbuf_sel); @@ -456,7 +582,7 @@ static int j721e_4bit_sdhci_set_ios_post(struct sdhci_host *host) } const struct sdhci_ops j721e_4bit_sdhci_ops = { -#ifdef MMC_SUPPORTS_TUNING +#if CONFIG_IS_ENABLED(MMC_SUPPORTS_TUNING) .platform_execute_tuning = am654_sdhci_execute_tuning, #endif .deferred_probe = am654_sdhci_deferred_probe, @@ -501,7 +627,7 @@ static int sdhci_am654_get_otap_delay(struct udevice *dev, * Remove the corresponding capability if an otap-del-sel * value is not found */ - for (i = MMC_HS; i <= MMC_HS_400; i++) { + for (i = MMC_LEGACY; i <= MMC_HS_400; i++) { ret = dev_read_u32(dev, td[i].otap_binding, &plat->otap_del_sel[i]); if (ret) { @@ -513,9 +639,13 @@ static int sdhci_am654_get_otap_delay(struct udevice *dev, cfg->host_caps &= ~td[i].capability; } - if (td[i].itap_binding) - dev_read_u32(dev, td[i].itap_binding, - &plat->itap_del_sel[i]); + if (td[i].itap_binding) { + ret = dev_read_u32(dev, td[i].itap_binding, + &plat->itap_del_sel[i]); + + if (!ret) + plat->itap_del_ena[i] = ENABLE; + } } return 0; @@ -572,6 +702,9 @@ static int am654_sdhci_probe(struct udevice *dev) regmap_init_mem_index(dev_ofnode(dev), &plat->base, 1); + if (plat->quirks & SDHCI_AM654_QUIRK_FORCE_CDTEST) + am654_sdhci_deferred_probe(host); + return 0; } @@ -621,6 +754,8 @@ static int am654_sdhci_of_to_plat(struct udevice *dev) dev_read_u32(dev, "ti,strobe-sel", &plat->strb_sel); dev_read_u32(dev, "ti,clkbuf-sel", &plat->clkbuf_sel); + if (dev_read_bool(dev, "ti,fails-without-test-cd")) + plat->quirks |= SDHCI_AM654_QUIRK_FORCE_CDTEST; ret = mmc_of_parse(dev, cfg); if (ret) diff --git a/drivers/mmc/arm_pl180_mmci.c b/drivers/mmc/arm_pl180_mmci.c index cecc7ad783d..f00b0ff0dc9 100644 --- a/drivers/mmc/arm_pl180_mmci.c +++ b/drivers/mmc/arm_pl180_mmci.c @@ -11,7 +11,6 @@ /* #define DEBUG */ -#include "common.h" #include <clk.h> #include <errno.h> #include <log.h> diff --git a/drivers/mmc/aspeed_sdhci.c b/drivers/mmc/aspeed_sdhci.c index c9626c6beb8..b1752d2f881 100644 --- a/drivers/mmc/aspeed_sdhci.c +++ b/drivers/mmc/aspeed_sdhci.c @@ -4,7 +4,6 @@ * Eddie James <eajames@linux.ibm.com> */ -#include <common.h> #include <clk.h> #include <dm.h> #include <malloc.h> @@ -94,7 +93,6 @@ U_BOOT_DRIVER(aspeed_sdhci_drv) = { .plat_auto = sizeof(struct aspeed_sdhci_plat), }; - static int aspeed_sdc_probe(struct udevice *parent) { struct clk clk; diff --git a/drivers/mmc/atmel_sdhci.c b/drivers/mmc/atmel_sdhci.c index d92bad97b71..0b265196f02 100644 --- a/drivers/mmc/atmel_sdhci.c +++ b/drivers/mmc/atmel_sdhci.c @@ -4,7 +4,6 @@ * Wenyou.Yang <wenyou.yang@atmel.com> */ -#include <common.h> #include <clk.h> #include <dm.h> #include <malloc.h> diff --git a/drivers/mmc/bcm2835_sdhci.c b/drivers/mmc/bcm2835_sdhci.c index 5e48394fd0f..598a51d914a 100644 --- a/drivers/mmc/bcm2835_sdhci.c +++ b/drivers/mmc/bcm2835_sdhci.c @@ -36,7 +36,6 @@ * Inspired by sdhci-pci.c, by Pierre Ossman */ -#include <common.h> #include <dm.h> #include <log.h> #include <malloc.h> diff --git a/drivers/mmc/bcm2835_sdhost.c b/drivers/mmc/bcm2835_sdhost.c index 5c23c03d10d..720127468d3 100644 --- a/drivers/mmc/bcm2835_sdhost.c +++ b/drivers/mmc/bcm2835_sdhost.c @@ -30,7 +30,6 @@ * sdhci.c and sdhci-pci.c by Pierre Ossman */ #include <clk.h> -#include <common.h> #include <dm.h> #include <mmc.h> #include <asm/arch/msg.h> diff --git a/drivers/mmc/bcmstb_sdhci.c b/drivers/mmc/bcmstb_sdhci.c index 49846adcf54..7bddbebb162 100644 --- a/drivers/mmc/bcmstb_sdhci.c +++ b/drivers/mmc/bcmstb_sdhci.c @@ -6,7 +6,6 @@ * Author: Thomas Fitzsimmons <fitzsim@fitzsim.org> */ -#include <common.h> #include <dm.h> #include <mach/sdhci.h> #include <malloc.h> diff --git a/drivers/mmc/ca_dw_mmc.c b/drivers/mmc/ca_dw_mmc.c index a17ed8c11cb..1af5ec0532e 100644 --- a/drivers/mmc/ca_dw_mmc.c +++ b/drivers/mmc/ca_dw_mmc.c @@ -4,7 +4,6 @@ * Arthur Li <arthur.li@cortina-access.com> */ -#include <common.h> #include <dwmmc.h> #include <fdtdec.h> #include <asm/global_data.h> @@ -87,7 +86,7 @@ unsigned int ca_dwmci_get_mmc_clock(struct dwmci_host *host, uint freq) clk_div = 1; } - return SD_SCLK_MAX / clk_div / (host->div + 1); + return SD_SCLK_MAX / clk_div; } static int ca_dwmmc_of_to_plat(struct udevice *dev) diff --git a/drivers/mmc/cv1800b_sdhci.c b/drivers/mmc/cv1800b_sdhci.c index 9af6b971984..4e75051c317 100644 --- a/drivers/mmc/cv1800b_sdhci.c +++ b/drivers/mmc/cv1800b_sdhci.c @@ -12,6 +12,8 @@ #define MMC_MAX_CLOCK 375000000 #define TUNE_MAX_PHCODE 128 +#define PHY_TX_SRC_INVERT BIT(8) + struct cv1800b_sdhci_plat { struct mmc_config cfg; struct mmc mmc; @@ -19,7 +21,7 @@ struct cv1800b_sdhci_plat { static void cv1800b_set_tap_delay(struct sdhci_host *host, u16 tap) { - sdhci_writel(host, tap << 16, SDHCI_PHY_TX_RX_DLY); + sdhci_writel(host, PHY_TX_SRC_INVERT | tap << 16, SDHCI_PHY_TX_RX_DLY); } static void cv1800b_sdhci_reset(struct sdhci_host *host, u8 mask) diff --git a/drivers/mmc/davinci_mmc.c b/drivers/mmc/davinci_mmc.c index 3a3d23aec00..e055026847f 100644 --- a/drivers/mmc/davinci_mmc.c +++ b/drivers/mmc/davinci_mmc.c @@ -6,7 +6,6 @@ */ #include <config.h> -#include <common.h> #include <dm.h> #include <errno.h> #include <mmc.h> @@ -474,7 +473,6 @@ int davinci_mmc_init(struct bd_info *bis, struct davinci_mmc *host) } #else - static int davinci_mmc_probe(struct udevice *dev) { struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c index e1036641452..8551eac7018 100644 --- a/drivers/mmc/dw_mmc.c +++ b/drivers/mmc/dw_mmc.c @@ -6,7 +6,6 @@ */ #include <bouncebuf.h> -#include <common.h> #include <cpu_func.h> #include <errno.h> #include <log.h> @@ -21,6 +20,47 @@ #define PAGE_SIZE 4096 +/* Internal DMA Controller (IDMAC) descriptor for 32-bit addressing mode */ +struct dwmci_idmac32 { + u32 des0; /* Control descriptor */ + u32 des1; /* Buffer size */ + u32 des2; /* Buffer physical address */ + u32 des3; /* Next descriptor physical address */ +} __aligned(ARCH_DMA_MINALIGN); + +/* Internal DMA Controller (IDMAC) descriptor for 64-bit addressing mode */ +struct dwmci_idmac64 { + u32 des0; /* Control descriptor */ + u32 des1; /* Reserved */ + u32 des2; /* Buffer sizes */ + u32 des3; /* Reserved */ + u32 des4; /* Lower 32-bits of Buffer Address Pointer 1 */ + u32 des5; /* Upper 32-bits of Buffer Address Pointer 1 */ + u32 des6; /* Lower 32-bits of Next Descriptor Address */ + u32 des7; /* Upper 32-bits of Next Descriptor Address */ +} __aligned(ARCH_DMA_MINALIGN); + +/* Register offsets for DW MMC blocks with 32-bit IDMAC */ +static const struct dwmci_idmac_regs dwmci_idmac_regs32 = { + .dbaddrl = DWMCI_DBADDR, + .idsts = DWMCI_IDSTS, + .idinten = DWMCI_IDINTEN, + .dscaddrl = DWMCI_DSCADDR, + .bufaddrl = DWMCI_BUFADDR, +}; + +/* Register offsets for DW MMC blocks with 64-bit IDMAC */ +static const struct dwmci_idmac_regs dwmci_idmac_regs64 = { + .dbaddrl = DWMCI_DBADDRL, + .dbaddru = DWMCI_DBADDRU, + .idsts = DWMCI_IDSTS64, + .idinten = DWMCI_IDINTEN64, + .dscaddrl = DWMCI_DSCADDRL, + .dscaddru = DWMCI_DSCADDRU, + .bufaddrl = DWMCI_BUFADDRL, + .bufaddru = DWMCI_BUFADDRU, +}; + static int dwmci_wait_reset(struct dwmci_host *host, u32 value) { unsigned long timeout = 1000; @@ -36,58 +76,98 @@ static int dwmci_wait_reset(struct dwmci_host *host, u32 value) return 0; } -static void dwmci_set_idma_desc(struct dwmci_idmac *idmac, - u32 desc0, u32 desc1, u32 desc2) +static void dwmci_set_idma_desc32(struct dwmci_idmac32 *desc, u32 control, + u32 buf_size, u32 buf_addr) { - struct dwmci_idmac *desc = idmac; + phys_addr_t desc_phys = virt_to_phys(desc); + u32 next_desc_phys = desc_phys + sizeof(struct dwmci_idmac32); - desc->flags = desc0; - desc->cnt = desc1; - desc->addr = desc2; - desc->next_addr = (ulong)desc + sizeof(struct dwmci_idmac); + desc->des0 = control; + desc->des1 = buf_size; + desc->des2 = buf_addr; + desc->des3 = next_desc_phys; } -static void dwmci_prepare_data(struct dwmci_host *host, - struct mmc_data *data, - struct dwmci_idmac *cur_idmac, - void *bounce_buffer) +static void dwmci_set_idma_desc64(struct dwmci_idmac64 *desc, u32 control, + u32 buf_size, u64 buf_addr) { - unsigned long ctrl; - unsigned int i = 0, flags, cnt, blk_cnt; - ulong data_start, data_end; + phys_addr_t desc_phys = virt_to_phys(desc); + u64 next_desc_phys = desc_phys + sizeof(struct dwmci_idmac64); + + desc->des0 = control; + desc->des1 = 0; + desc->des2 = buf_size; + desc->des3 = 0; + desc->des4 = buf_addr & 0xffffffff; + desc->des5 = buf_addr >> 32; + desc->des6 = next_desc_phys & 0xffffffff; + desc->des7 = next_desc_phys >> 32; +} +static void dwmci_prepare_desc(struct dwmci_host *host, struct mmc_data *data, + void *cur_idmac, void *bounce_buffer) +{ + struct dwmci_idmac32 *desc32 = cur_idmac; + struct dwmci_idmac64 *desc64 = cur_idmac; + ulong data_start, data_end; + unsigned int blk_cnt, i; + data_start = (ulong)cur_idmac; blk_cnt = data->blocks; - dwmci_wait_reset(host, DWMCI_CTRL_FIFO_RESET); + for (i = 0;; i++) { + phys_addr_t buf_phys = virt_to_phys(bounce_buffer); + unsigned int flags, cnt; - /* Clear IDMAC interrupt */ - dwmci_writel(host, DWMCI_IDSTS, 0xFFFFFFFF); - - data_start = (ulong)cur_idmac; - dwmci_writel(host, DWMCI_DBADDR, (ulong)cur_idmac); - - do { - flags = DWMCI_IDMAC_OWN | DWMCI_IDMAC_CH ; - flags |= (i == 0) ? DWMCI_IDMAC_FS : 0; + flags = DWMCI_IDMAC_OWN | DWMCI_IDMAC_CH; + if (i == 0) + flags |= DWMCI_IDMAC_FS; if (blk_cnt <= 8) { flags |= DWMCI_IDMAC_LD; cnt = data->blocksize * blk_cnt; - } else + } else { cnt = data->blocksize * 8; + } - dwmci_set_idma_desc(cur_idmac, flags, cnt, - (ulong)bounce_buffer + (i * PAGE_SIZE)); + if (host->dma_64bit_address) { + dwmci_set_idma_desc64(desc64, flags, cnt, + buf_phys + i * PAGE_SIZE); + desc64++; + } else { + dwmci_set_idma_desc32(desc32, flags, cnt, + buf_phys + i * PAGE_SIZE); + desc32++; + } - cur_idmac++; if (blk_cnt <= 8) break; blk_cnt -= 8; - i++; - } while(1); + } - data_end = (ulong)cur_idmac; + if (host->dma_64bit_address) + data_end = (ulong)desc64; + else + data_end = (ulong)desc32; flush_dcache_range(data_start, roundup(data_end, ARCH_DMA_MINALIGN)); +} + +static void dwmci_prepare_data(struct dwmci_host *host, struct mmc_data *data, + void *cur_idmac, void *bounce_buffer) +{ + const u32 idmacl = virt_to_phys(cur_idmac) & 0xffffffff; + const u32 idmacu = (u64)virt_to_phys(cur_idmac) >> 32; + unsigned long ctrl; + + dwmci_wait_reset(host, DWMCI_CTRL_FIFO_RESET); + + /* Clear IDMAC interrupt */ + dwmci_writel(host, host->regs->idsts, 0xffffffff); + + dwmci_writel(host, host->regs->dbaddrl, idmacl); + if (host->dma_64bit_address) + dwmci_writel(host, host->regs->dbaddru, idmacu); + + dwmci_prepare_desc(host, data, cur_idmac, bounce_buffer); ctrl = dwmci_readl(host, DWMCI_CTRL); ctrl |= DWMCI_IDMAC_EN | DWMCI_DMA_EN; @@ -134,90 +214,86 @@ static unsigned int dwmci_get_timeout(struct mmc *mmc, const unsigned int size) return timeout; } -static int dwmci_data_transfer(struct dwmci_host *host, struct mmc_data *data) +static int dwmci_data_transfer_fifo(struct dwmci_host *host, + struct mmc_data *data, u32 mask) { - struct mmc *mmc = host->mmc; + const u32 int_rx = mask & (DWMCI_INTMSK_RXDR | DWMCI_INTMSK_DTO); + const u32 int_tx = mask & DWMCI_INTMSK_TXDR; int ret = 0; - u32 timeout, mask, size, i, len = 0; - u32 *buf = NULL; - ulong start = get_timer(0); - u32 fifo_depth = (((host->fifoth_val & RX_WMARK_MASK) >> - RX_WMARK_SHIFT) + 1) * 2; + u32 len = 0, size, i; + u32 *buf; + + size = (data->blocksize * data->blocks) / 4; + if (!host->fifo_mode || !size) + return 0; - size = data->blocksize * data->blocks; if (data->flags == MMC_DATA_READ) buf = (unsigned int *)data->dest; else buf = (unsigned int *)data->src; - timeout = dwmci_get_timeout(mmc, size); + if (data->flags == MMC_DATA_READ && int_rx) { + dwmci_writel(host, DWMCI_RINTSTS, int_rx); + while (size) { + ret = dwmci_fifo_ready(host, DWMCI_FIFO_EMPTY, &len); + if (ret < 0) + break; + + len = (len >> DWMCI_FIFO_SHIFT) & DWMCI_FIFO_MASK; + len = min(size, len); + for (i = 0; i < len; i++) + *buf++ = dwmci_readl(host, DWMCI_DATA); + size = size > len ? (size - len) : 0; + } + } else if (data->flags == MMC_DATA_WRITE && int_tx) { + while (size) { + ret = dwmci_fifo_ready(host, DWMCI_FIFO_FULL, &len); + if (ret < 0) + break; + + len = host->fifo_depth - ((len >> DWMCI_FIFO_SHIFT) & + DWMCI_FIFO_MASK); + len = min(size, len); + for (i = 0; i < len; i++) + dwmci_writel(host, DWMCI_DATA, *buf++); + size = size > len ? (size - len) : 0; + } + dwmci_writel(host, DWMCI_RINTSTS, DWMCI_INTMSK_TXDR); + } + + return ret; +} - size /= 4; +static int dwmci_data_transfer(struct dwmci_host *host, struct mmc_data *data) +{ + struct mmc *mmc = host->mmc; + int ret = 0; + u32 timeout, mask, size; + ulong start = get_timer(0); + + size = data->blocksize * data->blocks; + timeout = dwmci_get_timeout(mmc, size); for (;;) { mask = dwmci_readl(host, DWMCI_RINTSTS); - /* Error during data transfer. */ + /* Error during data transfer */ if (mask & (DWMCI_DATA_ERR | DWMCI_DATA_TOUT)) { debug("%s: DATA ERROR!\n", __func__); ret = -EINVAL; break; } - if (host->fifo_mode && size) { - len = 0; - if (data->flags == MMC_DATA_READ && - (mask & (DWMCI_INTMSK_RXDR | DWMCI_INTMSK_DTO))) { - dwmci_writel(host, DWMCI_RINTSTS, - mask & (DWMCI_INTMSK_RXDR | - DWMCI_INTMSK_DTO)); - while (size) { - ret = dwmci_fifo_ready(host, - DWMCI_FIFO_EMPTY, - &len); - if (ret < 0) - break; - - len = (len >> DWMCI_FIFO_SHIFT) & - DWMCI_FIFO_MASK; - len = min(size, len); - for (i = 0; i < len; i++) - *buf++ = - dwmci_readl(host, DWMCI_DATA); - size = size > len ? (size - len) : 0; - } - } else if (data->flags == MMC_DATA_WRITE && - (mask & DWMCI_INTMSK_TXDR)) { - while (size) { - ret = dwmci_fifo_ready(host, - DWMCI_FIFO_FULL, - &len); - if (ret < 0) - break; - - len = fifo_depth - ((len >> - DWMCI_FIFO_SHIFT) & - DWMCI_FIFO_MASK); - len = min(size, len); - for (i = 0; i < len; i++) - dwmci_writel(host, DWMCI_DATA, - *buf++); - size = size > len ? (size - len) : 0; - } - dwmci_writel(host, DWMCI_RINTSTS, - DWMCI_INTMSK_TXDR); - } - } + ret = dwmci_data_transfer_fifo(host, data, mask); - /* Data arrived correctly. */ + /* Data arrived correctly */ if (mask & DWMCI_INTMSK_DTO) { ret = 0; break; } - /* Check for timeout. */ + /* Check for timeout */ if (get_timer(start) > timeout) { - debug("%s: Timeout waiting for data!\n", - __func__); + debug("%s: Timeout waiting for data!\n", __func__); ret = -ETIMEDOUT; break; } @@ -228,8 +304,35 @@ static int dwmci_data_transfer(struct dwmci_host *host, struct mmc_data *data) return ret; } +static int dwmci_dma_transfer(struct dwmci_host *host, uint flags, + struct bounce_buffer *bbstate) +{ + int ret; + u32 mask, ctrl; + + if (flags == MMC_DATA_READ) + mask = DWMCI_IDINTEN_RI; + else + mask = DWMCI_IDINTEN_TI; + + ret = wait_for_bit_le32(host->ioaddr + host->regs->idsts, mask, true, + 1000, false); + if (ret) + debug("%s: DWMCI_IDINTEN mask 0x%x timeout\n", __func__, mask); + + /* Clear interrupts */ + dwmci_writel(host, host->regs->idsts, DWMCI_IDINTEN_MASK); + + ctrl = dwmci_readl(host, DWMCI_CTRL); + ctrl &= ~DWMCI_DMA_EN; + dwmci_writel(host, DWMCI_CTRL, ctrl); + + bounce_buffer_stop(bbstate); + return ret; +} + static int dwmci_set_transfer_mode(struct dwmci_host *host, - struct mmc_data *data) + struct mmc_data *data) { unsigned long mode; @@ -240,33 +343,30 @@ static int dwmci_set_transfer_mode(struct dwmci_host *host, return mode; } -#ifdef CONFIG_DM_MMC -static int dwmci_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, - struct mmc_data *data) +static void dwmci_wait_while_busy(struct dwmci_host *host, struct mmc_cmd *cmd) { - struct mmc *mmc = mmc_get_mmc_dev(dev); -#else -static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, - struct mmc_data *data) -{ -#endif - struct dwmci_host *host = mmc->priv; - ALLOC_CACHE_ALIGN_BUFFER(struct dwmci_idmac, cur_idmac, - data ? DIV_ROUND_UP(data->blocks, 8) : 0); - int ret = 0, flags = 0, i; - unsigned int timeout = 500; - u32 retry = 100000; - u32 mask, ctrl; - ulong start = get_timer(0); - struct bounce_buffer bbstate; + unsigned int timeout = 500; /* msec */ + ulong start; + start = get_timer(0); while (dwmci_readl(host, DWMCI_STATUS) & DWMCI_BUSY) { if (get_timer(start) > timeout) { - debug("%s: Timeout on data busy, continue anyway\n", __func__); + debug("%s: Timeout on data busy, continue anyway\n", + __func__); break; } } +} +static int dwmci_send_cmd_common(struct dwmci_host *host, struct mmc_cmd *cmd, + struct mmc_data *data, void *cur_idmac) +{ + int ret, flags = 0, i; + u32 retry = 100000; + u32 mask; + struct bounce_buffer bbstate; + + dwmci_wait_while_busy(host, cmd); dwmci_writel(host, DWMCI_RINTSTS, DWMCI_INTMSK_ALL); if (data) { @@ -278,12 +378,12 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, } else { if (data->flags == MMC_DATA_READ) { ret = bounce_buffer_start(&bbstate, - (void*)data->dest, + (void *)data->dest, data->blocksize * data->blocks, GEN_BB_WRITE); } else { ret = bounce_buffer_start(&bbstate, - (void*)data->src, + (void *)data->src, data->blocksize * data->blocks, GEN_BB_READ); } @@ -318,9 +418,9 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, if (cmd->resp_type & MMC_RSP_CRC) flags |= DWMCI_CMD_CHECK_CRC; - flags |= (cmd->cmdidx | DWMCI_CMD_START | DWMCI_CMD_USE_HOLD_REG); + flags |= cmd->cmdidx | DWMCI_CMD_START | DWMCI_CMD_USE_HOLD_REG; - debug("Sending CMD%d\n",cmd->cmdidx); + debug("Sending CMD%d\n", cmd->cmdidx); dwmci_writel(host, DWMCI_CMD, flags); @@ -334,7 +434,7 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, } if (i == retry) { - debug("%s: Timeout.\n", __func__); + debug("%s: Timeout\n", __func__); return -ETIMEDOUT; } @@ -347,18 +447,17 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, * below shall be debug(). eMMC cards also do not favor * CMD8, please keep that in mind. */ - debug("%s: Response Timeout.\n", __func__); + debug("%s: Response Timeout\n", __func__); return -ETIMEDOUT; } else if (mask & DWMCI_INTMSK_RE) { - debug("%s: Response Error.\n", __func__); + debug("%s: Response Error\n", __func__); return -EIO; } else if ((cmd->resp_type & MMC_RSP_CRC) && (mask & DWMCI_INTMSK_RCRC)) { - debug("%s: Response CRC Error.\n", __func__); + debug("%s: Response CRC Error\n", __func__); return -EIO; } - if (cmd->resp_type & MMC_RSP_PRESENT) { if (cmd->resp_type & MMC_RSP_136) { cmd->response[0] = dwmci_readl(host, DWMCI_RESP3); @@ -372,26 +471,8 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, if (data) { ret = dwmci_data_transfer(host, data); - - /* only dma mode need it */ - if (!host->fifo_mode) { - if (data->flags == MMC_DATA_READ) - mask = DWMCI_IDINTEN_RI; - else - mask = DWMCI_IDINTEN_TI; - ret = wait_for_bit_le32(host->ioaddr + DWMCI_IDSTS, - mask, true, 1000, false); - if (ret) - debug("%s: DWMCI_IDINTEN mask 0x%x timeout.\n", - __func__, mask); - /* clear interrupts */ - dwmci_writel(host, DWMCI_IDSTS, DWMCI_IDINTEN_MASK); - - ctrl = dwmci_readl(host, DWMCI_CTRL); - ctrl &= ~(DWMCI_DMA_EN); - dwmci_writel(host, DWMCI_CTRL, ctrl); - bounce_buffer_stop(&bbstate); - } + if (!host->fifo_mode) + ret = dwmci_dma_transfer(host, data->flags, &bbstate); } udelay(100); @@ -399,40 +480,39 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, return ret; } -static int dwmci_setup_bus(struct dwmci_host *host, u32 freq) +#ifdef CONFIG_DM_MMC +static int dwmci_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, + struct mmc_data *data) { - u32 div, status; - int timeout = 10000; - unsigned long sclk; + struct mmc *mmc = mmc_get_mmc_dev(dev); +#else +static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, + struct mmc_data *data) +{ +#endif + struct dwmci_host *host = mmc->priv; + const size_t buf_size = data ? DIV_ROUND_UP(data->blocks, 8) : 0; - if ((freq == host->clock) || (freq == 0)) - return 0; - /* - * If host->get_mmc_clk isn't defined, - * then assume that host->bus_hz is source clock value. - * host->bus_hz should be set by user. - */ - if (host->get_mmc_clk) - sclk = host->get_mmc_clk(host, freq); - else if (host->bus_hz) - sclk = host->bus_hz; - else { - debug("%s: Didn't get source clock value.\n", __func__); - return -EINVAL; + if (host->dma_64bit_address) { + ALLOC_CACHE_ALIGN_BUFFER(struct dwmci_idmac64, idmac, buf_size); + return dwmci_send_cmd_common(host, cmd, data, idmac); + } else { + ALLOC_CACHE_ALIGN_BUFFER(struct dwmci_idmac32, idmac, buf_size); + return dwmci_send_cmd_common(host, cmd, data, idmac); } +} - if (sclk == freq) - div = 0; /* bypass mode */ - else - div = DIV_ROUND_UP(sclk, 2 * freq); - - dwmci_writel(host, DWMCI_CLKENA, 0); - dwmci_writel(host, DWMCI_CLKSRC, 0); +static int dwmci_control_clken(struct dwmci_host *host, bool on) +{ + const u32 val = on ? DWMCI_CLKEN_ENABLE | DWMCI_CLKEN_LOW_PWR : 0; + const u32 cmd_only_clk = DWMCI_CMD_PRV_DAT_WAIT | DWMCI_CMD_UPD_CLK; + int timeout = 10000; + u32 status; - dwmci_writel(host, DWMCI_CLKDIV, div); - dwmci_writel(host, DWMCI_CMD, DWMCI_CMD_PRV_DAT_WAIT | - DWMCI_CMD_UPD_CLK | DWMCI_CMD_START); + dwmci_writel(host, DWMCI_CLKENA, val); + /* Inform CIU */ + dwmci_writel(host, DWMCI_CMD, DWMCI_CMD_START | cmd_only_clk); do { status = dwmci_readl(host, DWMCI_CMD); if (timeout-- < 0) { @@ -441,20 +521,62 @@ static int dwmci_setup_bus(struct dwmci_host *host, u32 freq) } } while (status & DWMCI_CMD_START); - dwmci_writel(host, DWMCI_CLKENA, DWMCI_CLKEN_ENABLE | - DWMCI_CLKEN_LOW_PWR); + return 0; +} + +/* + * Update the clock divider. + * + * To prevent a clock glitch keep the clock stopped during the update of + * clock divider and clock source. + */ +static int dwmci_update_div(struct dwmci_host *host, u32 div) +{ + int ret; + + /* Disable clock */ + ret = dwmci_control_clken(host, false); + if (ret) + return ret; - dwmci_writel(host, DWMCI_CMD, DWMCI_CMD_PRV_DAT_WAIT | - DWMCI_CMD_UPD_CLK | DWMCI_CMD_START); + /* Set clock to desired speed */ + dwmci_writel(host, DWMCI_CLKDIV, div); + dwmci_writel(host, DWMCI_CLKSRC, 0); - timeout = 10000; - do { - status = dwmci_readl(host, DWMCI_CMD); - if (timeout-- < 0) { - debug("%s: Timeout!\n", __func__); - return -ETIMEDOUT; - } - } while (status & DWMCI_CMD_START); + /* Enable clock */ + return dwmci_control_clken(host, true); +} + +static int dwmci_setup_bus(struct dwmci_host *host, u32 freq) +{ + u32 div; + unsigned long sclk; + int ret; + + if (freq == host->clock || freq == 0) + return 0; + + /* + * If host->get_mmc_clk isn't defined, then assume that host->bus_hz is + * source clock value. host->bus_hz should be set by user. + */ + if (host->get_mmc_clk) { + sclk = host->get_mmc_clk(host, freq); + } else if (host->bus_hz) { + sclk = host->bus_hz; + } else { + debug("%s: Didn't get source clock value\n", __func__); + return -EINVAL; + } + + if (sclk == freq) + div = 0; /* bypass mode */ + else + div = DIV_ROUND_UP(sclk, 2 * freq); + + ret = dwmci_update_div(host, div); + if (ret) + return ret; host->clock = freq; @@ -472,7 +594,7 @@ static int dwmci_set_ios(struct mmc *mmc) struct dwmci_host *host = (struct dwmci_host *)mmc->priv; u32 ctype, regs; - debug("Buswidth = %d, clock: %d\n", mmc->bus_width, mmc->clock); + debug("Bus width = %d, clock: %d\n", mmc->bus_width, mmc->clock); dwmci_setup_bus(host, mmc->clock); switch (mmc->bus_width) { @@ -527,6 +649,48 @@ static int dwmci_set_ios(struct mmc *mmc) return 0; } +static void dwmci_init_fifo(struct dwmci_host *host) +{ + u32 fifo_thr, fifoth_val; + + if (!host->fifo_depth) { + u32 fifo_size; + + /* + * Automatically detect FIFO depth from FIFOTH register. + * Power-on value of RX_WMark is FIFO_DEPTH-1. + */ + fifo_size = dwmci_readl(host, DWMCI_FIFOTH); + fifo_size = ((fifo_size & RX_WMARK_MASK) >> RX_WMARK_SHIFT) + 1; + host->fifo_depth = fifo_size; + } + + fifo_thr = host->fifo_depth / 2; + fifoth_val = MSIZE(0x2) | RX_WMARK(fifo_thr - 1) | TX_WMARK(fifo_thr); + dwmci_writel(host, DWMCI_FIFOTH, fifoth_val); +} + +static void dwmci_init_dma(struct dwmci_host *host) +{ + int addr_config; + + if (host->fifo_mode) + return; + + addr_config = (dwmci_readl(host, DWMCI_HCON) >> 27) & 0x1; + if (addr_config == 1) { + host->dma_64bit_address = true; + host->regs = &dwmci_idmac_regs64; + debug("%s: IDMAC supports 64-bit address mode\n", __func__); + } else { + host->dma_64bit_address = false; + host->regs = &dwmci_idmac_regs32; + debug("%s: IDMAC supports 32-bit address mode\n", __func__); + } + + dwmci_writel(host, host->regs->idinten, DWMCI_IDINTEN_MASK); +} + static int dwmci_init(struct mmc *mmc) { struct dwmci_host *host = mmc->priv; @@ -544,30 +708,18 @@ static int dwmci_init(struct mmc *mmc) /* Enumerate at 400KHz */ dwmci_setup_bus(host, mmc->cfg->f_min); - dwmci_writel(host, DWMCI_RINTSTS, 0xFFFFFFFF); + dwmci_writel(host, DWMCI_RINTSTS, 0xffffffff); dwmci_writel(host, DWMCI_INTMASK, 0); - dwmci_writel(host, DWMCI_TMOUT, 0xFFFFFFFF); + dwmci_writel(host, DWMCI_TMOUT, 0xffffffff); - dwmci_writel(host, DWMCI_IDINTEN, 0); dwmci_writel(host, DWMCI_BMOD, 1); - - if (!host->fifoth_val) { - uint32_t fifo_size; - - fifo_size = dwmci_readl(host, DWMCI_FIFOTH); - fifo_size = ((fifo_size & RX_WMARK_MASK) >> RX_WMARK_SHIFT) + 1; - host->fifoth_val = MSIZE(0x2) | RX_WMARK(fifo_size / 2 - 1) | - TX_WMARK(fifo_size / 2); - } - dwmci_writel(host, DWMCI_FIFOTH, host->fifoth_val); + dwmci_init_fifo(host); + dwmci_init_dma(host); dwmci_writel(host, DWMCI_CLKENA, 0); dwmci_writel(host, DWMCI_CLKSRC, 0); - if (!host->fifo_mode) - dwmci_writel(host, DWMCI_IDINTEN, DWMCI_IDINTEN_MASK); - return 0; } @@ -593,7 +745,7 @@ static const struct mmc_ops dwmci_ops = { #endif void dwmci_setup_cfg(struct mmc_config *cfg, struct dwmci_host *host, - u32 max_clk, u32 min_clk) + u32 max_clk, u32 min_clk) { cfg->name = host->name; #ifndef CONFIG_DM_MMC @@ -629,7 +781,7 @@ int add_dwmci(struct dwmci_host *host, u32 max_clk, u32 min_clk) dwmci_setup_cfg(&host->cfg, host, max_clk, min_clk); host->mmc = mmc_create(&host->cfg, host); - if (host->mmc == NULL) + if (!host->mmc) return -1; return 0; diff --git a/drivers/mmc/exynos_dw_mmc.c b/drivers/mmc/exynos_dw_mmc.c index 2f849c43b12..c8bf89d6d35 100644 --- a/drivers/mmc/exynos_dw_mmc.c +++ b/drivers/mmc/exynos_dw_mmc.c @@ -4,11 +4,9 @@ * Jaehoon Chung <jh80.chung@samsung.com> */ -#include <common.h> +#include <clk.h> #include <dwmmc.h> -#include <fdtdec.h> #include <asm/global_data.h> -#include <linux/libfdt.h> #include <malloc.h> #include <errno.h> #include <asm/arch/dwmmc.h> @@ -16,6 +14,7 @@ #include <asm/arch/pinmux.h> #include <asm/arch/power.h> #include <asm/gpio.h> +#include <linux/err.h> #include <linux/printk.h> #define DWMMC_MAX_CH_NUM 4 @@ -24,6 +23,11 @@ #define DWMMC_MMC0_SDR_TIMING_VAL 0x03030001 #define DWMMC_MMC2_SDR_TIMING_VAL 0x03020001 +#define EXYNOS4412_FIXED_CIU_CLK_DIV 4 + +/* Quirks */ +#define DWMCI_QUIRK_DISABLE_SMU BIT(0) + #ifdef CONFIG_DM_MMC #include <dm.h> DECLARE_GLOBAL_DATA_PTR; @@ -34,35 +38,117 @@ struct exynos_mmc_plat { }; #endif -/* Exynos implmentation specific drver private data */ +/* Chip specific data */ +struct exynos_dwmmc_variant { + u32 clksel; /* CLKSEL register offset */ + u8 div; /* (optional) fixed clock divider value: 0..7 */ + u32 quirks; /* quirk flags - see DWMCI_QUIRK_... */ +}; + +/* Exynos implementation specific driver private data */ struct dwmci_exynos_priv_data { #ifdef CONFIG_DM_MMC struct dwmci_host host; #endif + struct clk clk; u32 sdr_timing; + u32 ddr_timing; + const struct exynos_dwmmc_variant *chip; }; -/* - * Function used as callback function to initialise the - * CLKSEL register for every mmc channel. - */ -static int exynos_dwmci_clksel(struct dwmci_host *host) +static struct dwmci_exynos_priv_data *exynos_dwmmc_get_priv( + struct dwmci_host *host) { #ifdef CONFIG_DM_MMC - struct dwmci_exynos_priv_data *priv = - container_of(host, struct dwmci_exynos_priv_data, host); + return container_of(host, struct dwmci_exynos_priv_data, host); #else - struct dwmci_exynos_priv_data *priv = host->priv; + return host->priv; #endif - dwmci_writel(host, DWMCI_CLKSEL, priv->sdr_timing); +} + +/** + * exynos_dwmmc_get_sclk - Get source clock (SDCLKIN) rate + * @host: MMC controller object + * @rate: Will contain clock rate, Hz + * + * Return: 0 on success or negative value on error + */ +static int exynos_dwmmc_get_sclk(struct dwmci_host *host, unsigned long *rate) +{ +#ifdef CONFIG_CPU_V7A + *rate = get_mmc_clk(host->dev_index); +#else + struct dwmci_exynos_priv_data *priv = exynos_dwmmc_get_priv(host); + + *rate = clk_get_rate(&priv->clk); +#endif + + if (IS_ERR_VALUE(*rate)) + return *rate; return 0; } -unsigned int exynos_dwmci_get_clk(struct dwmci_host *host, uint freq) +/** + * exynos_dwmmc_set_sclk - Set source clock (SDCLKIN) rate + * @host: MMC controller object + * @rate: Desired clock rate, Hz + * + * Return: 0 on success or negative value on error + */ +static int exynos_dwmmc_set_sclk(struct dwmci_host *host, unsigned long rate) { + int err; + +#ifdef CONFIG_CPU_V7A unsigned long sclk; - int8_t clk_div; + unsigned int div; + + err = exynos_dwmmc_get_sclk(host, &sclk); + if (err) + return err; + + div = DIV_ROUND_UP(sclk, rate); + set_mmc_clk(host->dev_index, div); +#else + struct dwmci_exynos_priv_data *priv = exynos_dwmmc_get_priv(host); + + err = clk_set_rate(&priv->clk, rate); + if (err < 0) + return err; +#endif + + return 0; +} + +/* Configure CLKSEL register with chosen timing values */ +static int exynos_dwmci_clksel(struct dwmci_host *host) +{ + struct dwmci_exynos_priv_data *priv = exynos_dwmmc_get_priv(host); + u32 timing; + + if (host->mmc->selected_mode == MMC_DDR_52) + timing = priv->ddr_timing; + else + timing = priv->sdr_timing; + + dwmci_writel(host, priv->chip->clksel, timing); + + return 0; +} + +/** + * exynos_dwmmc_get_ciu_div - Get internal clock divider value + * @host: MMC controller object + * + * Returns: Divider value, in range of 1..8 + */ +static u8 exynos_dwmmc_get_ciu_div(struct dwmci_host *host) +{ + struct dwmci_exynos_priv_data *priv = exynos_dwmmc_get_priv(host); + + if (priv->chip->div) + return priv->chip->div + 1; /* * Since SDCLKIN is divided inside controller by the DIVRATIO @@ -70,22 +156,42 @@ unsigned int exynos_dwmci_get_clk(struct dwmci_host *host, uint freq) * clock value to calculate the CLKDIV value. * as per user manual:cclk_in = SDCLKIN / (DIVRATIO + 1) */ - clk_div = ((dwmci_readl(host, DWMCI_CLKSEL) >> DWMCI_DIVRATIO_BIT) - & DWMCI_DIVRATIO_MASK) + 1; - sclk = get_mmc_clk(host->dev_index); + return ((dwmci_readl(host, priv->chip->clksel) >> DWMCI_DIVRATIO_BIT) + & DWMCI_DIVRATIO_MASK) + 1; +} - /* - * Assume to know divider value. - * When clock unit is broken, need to set "host->div" - */ - return sclk / clk_div / (host->div + 1); +static unsigned int exynos_dwmci_get_clk(struct dwmci_host *host, uint freq) +{ + unsigned long sclk; + u8 clk_div; + int err; + + /* Should be double rate for DDR mode */ + if (host->mmc->selected_mode == MMC_DDR_52 && host->mmc->bus_width == 8) + freq *= 2; + + clk_div = exynos_dwmmc_get_ciu_div(host); + err = exynos_dwmmc_set_sclk(host, freq * clk_div); + if (err) { + printf("DWMMC%d: failed to set clock rate (%d); " + "continue anyway\n", host->dev_index, err); + } + + err = exynos_dwmmc_get_sclk(host, &sclk); + if (err) { + printf("DWMMC%d: failed to get clock rate (%d)\n", + host->dev_index, err); + return 0; + } + + return sclk / clk_div; } static void exynos_dwmci_board_init(struct dwmci_host *host) { - struct dwmci_exynos_priv_data *priv = host->priv; + struct dwmci_exynos_priv_data *priv = exynos_dwmmc_get_priv(host); - if (host->quirks & DWMCI_QUIRK_DISABLE_SMU) { + if (priv->chip->quirks & DWMCI_QUIRK_DISABLE_SMU) { dwmci_writel(host, EMMCP_MPSBEGIN0, 0); dwmci_writel(host, EMMCP_SEND0, 0); dwmci_writel(host, EMMCP_CTRL0, @@ -95,73 +201,27 @@ static void exynos_dwmci_board_init(struct dwmci_host *host) MPSCTRL_NON_SECURE_WRITE_BIT | MPSCTRL_VALID); } - /* Set to timing value at initial time */ if (priv->sdr_timing) exynos_dwmci_clksel(host); } -static int exynos_dwmci_core_init(struct dwmci_host *host) -{ - unsigned int div; - unsigned long freq, sclk; - - if (host->bus_hz) - freq = host->bus_hz; - else - freq = DWMMC_MAX_FREQ; - - /* request mmc clock vlaue of 52MHz. */ - sclk = get_mmc_clk(host->dev_index); - div = DIV_ROUND_UP(sclk, freq); - /* set the clock divisor for mmc */ - set_mmc_clk(host->dev_index, div); - - host->name = "EXYNOS DWMMC"; -#ifdef CONFIG_EXYNOS5420 - host->quirks = DWMCI_QUIRK_DISABLE_SMU; -#endif - host->board_init = exynos_dwmci_board_init; - - host->caps = MMC_MODE_DDR_52MHz; - host->clksel = exynos_dwmci_clksel; - host->get_mmc_clk = exynos_dwmci_get_clk; - -#ifndef CONFIG_DM_MMC - /* Add the mmc channel to be registered with mmc core */ - if (add_dwmci(host, DWMMC_MAX_FREQ, DWMMC_MIN_FREQ)) { - printf("DWMMC%d registration failed\n", host->dev_index); - return -1; - } -#endif - - return 0; -} - -static int do_dwmci_init(struct dwmci_host *host) +#ifdef CONFIG_DM_MMC +static int exynos_dwmmc_of_to_plat(struct udevice *dev) { - int flag, err; - - flag = host->buswidth == 8 ? PINMUX_FLAG_8BIT_MODE : PINMUX_FLAG_NONE; - err = exynos_pinmux_config(host->dev_id, flag); - if (err) { - printf("DWMMC%d not configure\n", host->dev_index); - return err; - } + struct dwmci_exynos_priv_data *priv = dev_get_priv(dev); + struct dwmci_host *host = &priv->host; + u32 div, timing[2]; + int err; - return exynos_dwmci_core_init(host); -} + priv->chip = (struct exynos_dwmmc_variant *)dev_get_driver_data(dev); -static int exynos_dwmci_get_config(const void *blob, int node, - struct dwmci_host *host, - struct dwmci_exynos_priv_data *priv) -{ - int err = 0; - u32 base, timing[3]; +#ifdef CONFIG_CPU_V7A + const void *blob = gd->fdt_blob; + int node = dev_of_offset(dev); - /* Extract device id for each mmc channel */ + /* Obtain device ID for current MMC channel */ host->dev_id = pinmux_decode_periph_id(blob, node); - - host->dev_index = fdtdec_get_int(blob, node, "index", host->dev_id); + host->dev_index = dev_read_u32_default(dev, "index", host->dev_id); if (host->dev_index == host->dev_id) host->dev_index = host->dev_id - PERIPH_ID_SDMMC0; @@ -169,31 +229,34 @@ static int exynos_dwmci_get_config(const void *blob, int node, printf("DWMMC%d: Can't get the dev index\n", host->dev_index); return -EINVAL; } +#else + if (dev_read_bool(dev, "non-removable")) + host->dev_index = 0; /* eMMC */ + else + host->dev_index = 2; /* SD card */ +#endif - /* Get the bus width from the device node (Default is 4bit buswidth) */ - host->buswidth = fdtdec_get_int(blob, node, "samsung,bus-width", 4); - - /* Set the base address from the device node */ - base = fdtdec_get_addr(blob, node, "reg"); - if (!base) { + host->ioaddr = dev_read_addr_ptr(dev); + if (!host->ioaddr) { printf("DWMMC%d: Can't get base address\n", host->dev_index); return -EINVAL; } - host->ioaddr = (void *)base; - /* Extract the timing info from the node */ - err = fdtdec_get_int_array(blob, node, "samsung,timing", timing, 3); + if (priv->chip->div) + div = priv->chip->div; + else + div = dev_read_u32_default(dev, "samsung,dw-mshc-ciu-div", 0); + + err = dev_read_u32_array(dev, "samsung,dw-mshc-sdr-timing", timing, 2); if (err) { - printf("DWMMC%d: Can't get sdr-timings for devider\n", - host->dev_index); + printf("DWMMC%d: Can't get sdr-timings\n", host->dev_index); return -EINVAL; } + priv->sdr_timing = DWMCI_SET_SAMPLE_CLK(timing[0]) | + DWMCI_SET_DRV_CLK(timing[1]) | + DWMCI_SET_DIV_RATIO(div); - priv->sdr_timing = (DWMCI_SET_SAMPLE_CLK(timing[0]) | - DWMCI_SET_DRV_CLK(timing[1]) | - DWMCI_SET_DIV_RATIO(timing[2])); - - /* sdr_timing didn't assigned anything, use the default value */ + /* sdr_timing wasn't set, use the default value */ if (!priv->sdr_timing) { if (host->dev_index == 0) priv->sdr_timing = DWMMC_MMC0_SDR_TIMING_VAL; @@ -201,35 +264,82 @@ static int exynos_dwmci_get_config(const void *blob, int node, priv->sdr_timing = DWMMC_MMC2_SDR_TIMING_VAL; } - host->fifoth_val = fdtdec_get_int(blob, node, "fifoth_val", 0); - host->bus_hz = fdtdec_get_int(blob, node, "bus_hz", 0); - host->div = fdtdec_get_int(blob, node, "div", 0); + err = dev_read_u32_array(dev, "samsung,dw-mshc-ddr-timing", timing, 2); + if (err) { + debug("DWMMC%d: Can't get ddr-timings, using sdr-timings\n", + host->dev_index); + priv->ddr_timing = priv->sdr_timing; + } else { + priv->ddr_timing = DWMCI_SET_SAMPLE_CLK(timing[0]) | + DWMCI_SET_DRV_CLK(timing[1]) | + DWMCI_SET_DIV_RATIO(div); + } + + host->buswidth = dev_read_u32_default(dev, "bus-width", 4); + host->fifo_depth = dev_read_u32_default(dev, "fifo-depth", 0); + host->bus_hz = dev_read_u32_default(dev, "clock-frequency", 0); return 0; } -#ifdef CONFIG_DM_MMC static int exynos_dwmmc_probe(struct udevice *dev) { struct exynos_mmc_plat *plat = dev_get_plat(dev); struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); struct dwmci_exynos_priv_data *priv = dev_get_priv(dev); struct dwmci_host *host = &priv->host; + unsigned long freq; int err; - err = exynos_dwmci_get_config(gd->fdt_blob, dev_of_offset(dev), host, - priv); +#ifndef CONFIG_CPU_V7A + err = clk_get_by_index(dev, 1, &priv->clk); /* ciu */ if (err) return err; - err = do_dwmci_init(host); - if (err) +#endif + +#ifdef CONFIG_CPU_V7A + int flag; + + flag = host->buswidth == 8 ? PINMUX_FLAG_8BIT_MODE : PINMUX_FLAG_NONE; + err = exynos_pinmux_config(host->dev_id, flag); + if (err) { + printf("DWMMC%d not configure\n", host->dev_index); return err; + } +#endif + + if (host->bus_hz) + freq = host->bus_hz; + else + freq = DWMMC_MAX_FREQ; + err = exynos_dwmmc_set_sclk(host, freq); + if (err) { + printf("DWMMC%d: failed to set clock rate on probe (%d); " + "continue anyway\n", host->dev_index, err); + } + + host->name = dev->name; + host->board_init = exynos_dwmci_board_init; + host->caps = MMC_MODE_DDR_52MHz; + host->clksel = exynos_dwmci_clksel; + host->get_mmc_clk = exynos_dwmci_get_clk; + +#ifdef CONFIG_BLK dwmci_setup_cfg(&plat->cfg, host, DWMMC_MAX_FREQ, DWMMC_MIN_FREQ); host->mmc = &plat->mmc; +#else + err = add_dwmci(host, DWMMC_MAX_FREQ, DWMMC_MIN_FREQ); + if (err) { + printf("DWMMC%d registration failed\n", host->dev_index); + return err; + } +#endif + host->mmc->priv = &priv->host; - host->priv = dev; upriv->mmc = host->mmc; + host->mmc->dev = dev; + host->priv = dev; return dwmci_probe(dev); } @@ -241,9 +351,34 @@ static int exynos_dwmmc_bind(struct udevice *dev) return dwmci_bind(dev, &plat->mmc, &plat->cfg); } +static const struct exynos_dwmmc_variant exynos4_drv_data = { + .clksel = DWMCI_CLKSEL, + .div = EXYNOS4412_FIXED_CIU_CLK_DIV - 1, +}; + +static const struct exynos_dwmmc_variant exynos5_drv_data = { + .clksel = DWMCI_CLKSEL, +#ifdef CONFIG_EXYNOS5420 + .quirks = DWMCI_QUIRK_DISABLE_SMU, +#endif +}; + +static const struct exynos_dwmmc_variant exynos7_smu_drv_data = { + .clksel = DWMCI_CLKSEL64, + .quirks = DWMCI_QUIRK_DISABLE_SMU, +}; + static const struct udevice_id exynos_dwmmc_ids[] = { - { .compatible = "samsung,exynos4412-dw-mshc" }, - { .compatible = "samsung,exynos-dwmmc" }, + { + .compatible = "samsung,exynos4412-dw-mshc", + .data = (ulong)&exynos4_drv_data, + }, { + .compatible = "samsung,exynos-dwmmc", + .data = (ulong)&exynos5_drv_data, + }, { + .compatible = "samsung,exynos7-dw-mshc-smu", + .data = (ulong)&exynos7_smu_drv_data, + }, { } }; @@ -251,9 +386,10 @@ U_BOOT_DRIVER(exynos_dwmmc_drv) = { .name = "exynos_dwmmc", .id = UCLASS_MMC, .of_match = exynos_dwmmc_ids, + .of_to_plat = exynos_dwmmc_of_to_plat, .bind = exynos_dwmmc_bind, - .ops = &dm_dwmci_ops, .probe = exynos_dwmmc_probe, + .ops = &dm_dwmci_ops, .priv_auto = sizeof(struct dwmci_exynos_priv_data), .plat_auto = sizeof(struct exynos_mmc_plat), }; diff --git a/drivers/mmc/f_sdh30.c b/drivers/mmc/f_sdh30.c index 3d587a464d5..f47cf848521 100644 --- a/drivers/mmc/f_sdh30.c +++ b/drivers/mmc/f_sdh30.c @@ -5,7 +5,6 @@ * Copyright 2021 Socionext, Inc. */ -#include <common.h> #include <clk.h> #include <dm.h> #include <malloc.h> diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index 595d88bd562..683a7931c98 100644 --- a/drivers/mmc/fsl_esdhc.c +++ b/drivers/mmc/fsl_esdhc.c @@ -10,7 +10,6 @@ */ #include <config.h> -#include <common.h> #include <command.h> #include <cpu_func.h> #include <errno.h> @@ -851,7 +850,6 @@ __weak int esdhc_status_fixup(void *blob, const char *compat) return 0; } - #if CONFIG_IS_ENABLED(DM_MMC) static int fsl_esdhc_get_cd(struct udevice *dev); static void esdhc_disable_for_no_card(void *blob) @@ -1102,7 +1100,7 @@ static int fsl_esdhc_reinit(struct udevice *dev) return esdhc_init_common(priv, &plat->mmc); } -#ifdef MMC_SUPPORTS_TUNING +#if CONFIG_IS_ENABLED(MMC_SUPPORTS_TUNING) static int fsl_esdhc_execute_tuning(struct udevice *dev, uint32_t opcode) { struct fsl_esdhc_plat *plat = dev_get_plat(dev); @@ -1175,7 +1173,7 @@ static const struct dm_mmc_ops fsl_esdhc_ops = { .get_cd = fsl_esdhc_get_cd, .send_cmd = fsl_esdhc_send_cmd, .set_ios = fsl_esdhc_set_ios, -#ifdef MMC_SUPPORTS_TUNING +#if CONFIG_IS_ENABLED(MMC_SUPPORTS_TUNING) .execute_tuning = fsl_esdhc_execute_tuning, #endif .reinit = fsl_esdhc_reinit, diff --git a/drivers/mmc/fsl_esdhc_imx.c b/drivers/mmc/fsl_esdhc_imx.c index b74c0140020..fb410104c1f 100644 --- a/drivers/mmc/fsl_esdhc_imx.c +++ b/drivers/mmc/fsl_esdhc_imx.c @@ -11,7 +11,6 @@ */ #include <config.h> -#include <common.h> #include <command.h> #include <clk.h> #include <cpu_func.h> @@ -149,6 +148,7 @@ struct fsl_esdhc_priv { struct fsl_esdhc *esdhc_regs; unsigned int sdhc_clk; struct clk per_clk; + struct clk_bulk clk_bulk; unsigned int clock; unsigned int mode; #if !CONFIG_IS_ENABLED(DM_MMC) @@ -635,7 +635,7 @@ static void set_sysctl(struct fsl_esdhc_priv *priv, struct mmc *mmc, uint clock) priv->clock = clock; } -#ifdef MMC_SUPPORTS_TUNING +#if CONFIG_IS_ENABLED(MMC_SUPPORTS_TUNING) static int esdhc_change_pinstate(struct udevice *dev) { struct fsl_esdhc_priv *priv = dev_get_priv(dev); @@ -767,7 +767,7 @@ static int esdhc_set_voltage(struct mmc *mmc) ret = regulator_set_value(priv->vqmmc_dev, 3300000); if (ret) { - printf("Setting to 3.3V error"); + printf("Setting to 3.3V error: %d\n", ret); return -EIO; } mdelay(5); @@ -785,7 +785,7 @@ static int esdhc_set_voltage(struct mmc *mmc) ret = regulator_set_value(priv->vqmmc_dev, 1800000); if (ret) { - printf("Setting to 1.8V error"); + printf("Setting to 1.8V error: %d\n", ret); return -EIO; } } @@ -913,7 +913,7 @@ static int esdhc_set_ios_common(struct fsl_esdhc_priv *priv, struct mmc *mmc) int ret __maybe_unused; u32 clock; -#ifdef MMC_SUPPORTS_TUNING +#if CONFIG_IS_ENABLED(MMC_SUPPORTS_TUNING) /* * call esdhc_set_timing() before update the clock rate, * This is because current we support DDR and SDR mode, @@ -951,7 +951,7 @@ static int esdhc_set_ios_common(struct fsl_esdhc_priv *priv, struct mmc *mmc) esdhc_setbits32(®s->sysctl, SYSCTL_PEREN | SYSCTL_CKEN); } -#ifdef MMC_SUPPORTS_TUNING +#if CONFIG_IS_ENABLED(MMC_SUPPORTS_TUNING) /* * For HS400/HS400ES mode, make sure set the strobe dll in the * target clock rate. So call esdhc_set_strobe_dll() after the @@ -987,11 +987,11 @@ static int esdhc_init_common(struct fsl_esdhc_priv *priv, struct mmc *mmc) ulong start; /* Reset the entire host controller */ - esdhc_setbits32(®s->sysctl, SYSCTL_RSTA); + esdhc_setbits32(®s->sysctl, SYSCTL_RSTA | SYSCTL_RSTT); /* Wait until the controller is available */ start = get_timer(0); - while ((esdhc_read32(®s->sysctl) & SYSCTL_RSTA)) { + while ((esdhc_read32(®s->sysctl) & (SYSCTL_RSTA | SYSCTL_RSTT))) { if (get_timer(start) > 1000) return -ETIMEDOUT; } @@ -1035,6 +1035,11 @@ static int esdhc_init_common(struct fsl_esdhc_priv *priv, struct mmc *mmc) /* Set timout to the maximum value */ esdhc_clrsetbits32(®s->sysctl, SYSCTL_TIMEOUT_MASK, 14 << 16); + /* max 1ms delay with clock on for initialization */ + esdhc_setbits32(®s->vendorspec, VENDORSPEC_FRC_SDCLK_ON); + udelay(1000); + esdhc_clrbits32(®s->vendorspec, VENDORSPEC_FRC_SDCLK_ON); + return 0; } @@ -1090,11 +1095,11 @@ static int esdhc_reset(struct fsl_esdhc *regs) ulong start; /* reset the controller */ - esdhc_setbits32(®s->sysctl, SYSCTL_RSTA); + esdhc_setbits32(®s->sysctl, SYSCTL_RSTA | SYSCTL_RSTT); /* hardware clears the bit when it is done */ start = get_timer(0); - while ((esdhc_read32(®s->sysctl) & SYSCTL_RSTA)) { + while ((esdhc_read32(®s->sysctl) & (SYSCTL_RSTA | SYSCTL_RSTT))) { if (get_timer(start) > 100) { printf("MMC/SD: Reset never completed.\n"); return -ETIMEDOUT; @@ -1189,8 +1194,6 @@ static int fsl_esdhc_init(struct fsl_esdhc_priv *priv, esdhc_write32(®s->irqstaten, SDHCI_IRQ_EN_BITS); cfg = &plat->cfg; - if (!CONFIG_IS_ENABLED(DM_MMC)) - memset(cfg, '\0', sizeof(*cfg)); caps = esdhc_read32(®s->hostcapblt); @@ -1324,6 +1327,8 @@ int fsl_esdhc_initialize(struct bd_info *bis, struct fsl_esdhc_cfg *cfg) break; default: printf("invalid max bus width %u\n", cfg->max_bus_width); + free(plat); + free(priv); return -EINVAL; } @@ -1522,14 +1527,21 @@ static int fsl_esdhc_probe(struct udevice *dev) #if CONFIG_IS_ENABLED(CLK) /* Assigned clock already set clock */ - ret = clk_get_by_name(dev, "per", &priv->per_clk); + ret = clk_get_bulk(dev, &priv->clk_bulk); if (ret) { - printf("Failed to get per_clk\n"); + dev_err(dev, "Failed to get clks: %d\n", ret); + return ret; + } + + ret = clk_enable_bulk(&priv->clk_bulk); + if (ret) { + dev_err(dev, "Failed to enable clks: %d\n", ret); return ret; } - ret = clk_enable(&priv->per_clk); + + ret = clk_get_by_name(dev, "per", &priv->per_clk); if (ret) { - printf("Failed to enable per_clk\n"); + printf("Failed to get per_clk\n"); return ret; } @@ -1562,7 +1574,7 @@ static int fsl_esdhc_probe(struct udevice *dev) upriv->mmc = mmc; - return esdhc_init_common(priv, mmc); + return 0; } static int fsl_esdhc_get_cd(struct udevice *dev) @@ -1614,17 +1626,26 @@ static int fsl_esdhc_wait_dat0(struct udevice *dev, int state, return esdhc_wait_dat0_common(priv, state, timeout_us); } +static int fsl_esdhc_reinit(struct udevice *dev) +{ + struct fsl_esdhc_plat *plat = dev_get_plat(dev); + struct fsl_esdhc_priv *priv = dev_get_priv(dev); + + return esdhc_init_common(priv, &plat->mmc); +} + static const struct dm_mmc_ops fsl_esdhc_ops = { .get_cd = fsl_esdhc_get_cd, .send_cmd = fsl_esdhc_send_cmd, .set_ios = fsl_esdhc_set_ios, -#ifdef MMC_SUPPORTS_TUNING +#if CONFIG_IS_ENABLED(MMC_SUPPORTS_TUNING) .execute_tuning = fsl_esdhc_execute_tuning, #endif #if CONFIG_IS_ENABLED(MMC_HS400_ES_SUPPORT) .set_enhanced_strobe = fsl_esdhc_set_enhanced_strobe, #endif .wait_dat0 = fsl_esdhc_wait_dat0, + .reinit = fsl_esdhc_reinit, }; static struct esdhc_soc_data usdhc_imx7d_data = { diff --git a/drivers/mmc/fsl_esdhc_spl.c b/drivers/mmc/fsl_esdhc_spl.c index 6d7c0cff22a..3dd106bed4b 100644 --- a/drivers/mmc/fsl_esdhc_spl.c +++ b/drivers/mmc/fsl_esdhc_spl.c @@ -3,7 +3,7 @@ * Copyright 2013 Freescale Semiconductor, Inc. */ -#include <common.h> +#include <config.h> #include <cpu_func.h> #include <hang.h> #include <mmc.h> @@ -25,7 +25,6 @@ extern uchar mmc_u_boot_offs[]; #define MBRDBR_BOOT_SIG_55 0x1fe #define MBRDBR_BOOT_SIG_AA 0x1ff - void mmc_spl_load_image(uint32_t offs, unsigned int size, void *vdst) { uint blk_start, blk_cnt, err; diff --git a/drivers/mmc/ftsdc010_mci.c b/drivers/mmc/ftsdc010_mci.c index cabb747fbbd..11e44264e47 100644 --- a/drivers/mmc/ftsdc010_mci.c +++ b/drivers/mmc/ftsdc010_mci.c @@ -9,7 +9,6 @@ * Author: Rick Chen (rick@andestech.com) */ -#include <common.h> #include <clk.h> #include <log.h> #include <malloc.h> diff --git a/drivers/mmc/ftsdc010_mci.h b/drivers/mmc/ftsdc010_mci.h index 782d92be2f5..36187cfa04f 100644 --- a/drivers/mmc/ftsdc010_mci.h +++ b/drivers/mmc/ftsdc010_mci.h @@ -28,7 +28,6 @@ struct ftsdc010_chip { int dev_index; int dev_id; int buswidth; - u32 fifoth_val; struct mmc *mmc; void *priv; bool fifo_mode; diff --git a/drivers/mmc/gen_atmel_mci.c b/drivers/mmc/gen_atmel_mci.c index 3ee99558f6f..6a531fa0961 100644 --- a/drivers/mmc/gen_atmel_mci.c +++ b/drivers/mmc/gen_atmel_mci.c @@ -8,7 +8,7 @@ * Copyright (C) 2004-2006 Atmel Corporation */ -#include <common.h> +#include <config.h> #include <clk.h> #include <display_options.h> #include <dm.h> diff --git a/drivers/mmc/hi6220_dw_mmc.c b/drivers/mmc/hi6220_dw_mmc.c index dc0210402bd..0302f5c296b 100644 --- a/drivers/mmc/hi6220_dw_mmc.c +++ b/drivers/mmc/hi6220_dw_mmc.c @@ -4,7 +4,6 @@ * peter.griffin <peter.griffin@linaro.org> */ -#include <common.h> #include <clk.h> #include <dm.h> #include <dwmmc.h> @@ -37,7 +36,7 @@ struct hi6220_dwmmc_priv_data { struct hisi_mmc_data { unsigned int clock; bool use_fifo; - u32 fifoth_val; + u32 fifo_depth; }; static int hi6220_dwmmc_of_to_plat(struct udevice *dev) @@ -126,7 +125,7 @@ static int hi6220_dwmmc_probe(struct udevice *dev) host->mmc = &plat->mmc; host->fifo_mode = mmc_data->use_fifo; - host->fifoth_val = mmc_data->fifoth_val; + host->fifo_depth = mmc_data->fifo_depth; host->mmc->priv = &priv->host; upriv->mmc = host->mmc; host->mmc->dev = dev; @@ -159,8 +158,7 @@ static const struct hisi_mmc_data hi6220_mmc_data = { static const struct hisi_mmc_data hi3798mv2x_mmc_data = { .clock = 50000000, .use_fifo = false, - // FIFO depth is 256 - .fifoth_val = MSIZE(4) | RX_WMARK(0x7f) | TX_WMARK(0x80), + .fifo_depth = 256, }; static const struct udevice_id hi6220_dwmmc_ids[] = { diff --git a/drivers/mmc/iproc_sdhci.c b/drivers/mmc/iproc_sdhci.c index 11d86ad658f..7ab74ff117a 100644 --- a/drivers/mmc/iproc_sdhci.c +++ b/drivers/mmc/iproc_sdhci.c @@ -4,7 +4,6 @@ * */ -#include <common.h> #include <dm.h> #include <errno.h> #include <malloc.h> diff --git a/drivers/mmc/jz_mmc.c b/drivers/mmc/jz_mmc.c index 61e48ee0f62..fc10bb256a4 100644 --- a/drivers/mmc/jz_mmc.c +++ b/drivers/mmc/jz_mmc.c @@ -6,7 +6,6 @@ * Author: Paul Burton <paul.burton@imgtec.com> */ -#include <common.h> #include <malloc.h> #include <mmc.h> #include <asm/global_data.h> diff --git a/drivers/mmc/kona_sdhci.c b/drivers/mmc/kona_sdhci.c index 2bbe673b912..83f14122632 100644 --- a/drivers/mmc/kona_sdhci.c +++ b/drivers/mmc/kona_sdhci.c @@ -3,7 +3,6 @@ * Copyright 2013 Broadcom Corporation. */ -#include <common.h> #include <malloc.h> #include <sdhci.h> #include <linux/delay.h> diff --git a/drivers/mmc/meson_gx_mmc.c b/drivers/mmc/meson_gx_mmc.c index 0825c0a2a83..5852b24c6d2 100644 --- a/drivers/mmc/meson_gx_mmc.c +++ b/drivers/mmc/meson_gx_mmc.c @@ -3,7 +3,6 @@ * (C) Copyright 2016 Carlo Caione <carlo@caione.org> */ -#include <common.h> #include <clk.h> #include <cpu_func.h> #include <dm.h> diff --git a/drivers/mmc/mmc-pwrseq.c b/drivers/mmc/mmc-pwrseq.c index 2539f61323d..a1c9624a222 100644 --- a/drivers/mmc/mmc-pwrseq.c +++ b/drivers/mmc/mmc-pwrseq.c @@ -4,7 +4,6 @@ * Jaehoon Chung <jh80.chung@samsung.com> */ -#include <common.h> #include <dm.h> #include <mmc.h> #include <pwrseq.h> diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c index 24170c59ecc..83cdc9fd66d 100644 --- a/drivers/mmc/mmc-uclass.c +++ b/drivers/mmc/mmc-uclass.c @@ -7,7 +7,6 @@ #define LOG_CATEGORY UCLASS_MMC -#include <common.h> #include <bootdev.h> #include <log.h> #include <mmc.h> @@ -112,7 +111,7 @@ int mmc_getcd(struct mmc *mmc) return dm_mmc_get_cd(mmc->dev); } -#ifdef MMC_SUPPORTS_TUNING +#if CONFIG_IS_ENABLED(MMC_SUPPORTS_TUNING) static int dm_mmc_execute_tuning(struct udevice *dev, uint opcode) { struct dm_mmc_ops *ops = mmc_get_ops(dev); @@ -539,7 +538,6 @@ U_BOOT_DRIVER(mmc_blk) = { }; #endif /* CONFIG_BLK */ - UCLASS_DRIVER(mmc) = { .id = UCLASS_MMC, .name = "mmc", diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 7b068c71ff3..d4f2fd5bf89 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -8,7 +8,6 @@ */ #include <config.h> -#include <common.h> #include <blk.h> #include <command.h> #include <dm.h> @@ -17,6 +16,7 @@ #include <errno.h> #include <mmc.h> #include <part.h> +#include <time.h> #include <linux/bitops.h> #include <linux/delay.h> #include <linux/printk.h> @@ -24,11 +24,47 @@ #include <malloc.h> #include <memalign.h> #include <linux/list.h> +#include <linux/printk.h> #include <div64.h> #include "mmc_private.h" #define DEFAULT_CMD6_TIMEOUT_MS 500 +/** + * names of emmc BOOT_PARTITION_ENABLE values + * + * Boot Area Partitions - name consistent with Linux + */ +const char *emmc_boot_part_names[] = { + "default", /* EMMC_BOOT_PART_DEFAULT */ + "boot0", /* EMMC_BOOT_PART_BOOT1 */ + "boot1", /* EMMC_BOOT_PART_BOOT2 */ + "", + "", + "", + "", + "user", /* EMMC_BOOT_PART_USER */ +}; + +/** + * names of emmc 'hardware partitions' consistent with: + * - value used in mmc_switch() + * - value used by PARTITION_CONFIG PARTITION_ACCESS field + * + * Boot Area Partitions - name consistent with Linux + * General Perpose Partitions - name consistent with 'mmc hwpartition' usage + */ +const char *emmc_hwpart_names[] = { + "user", /* EMMC_HWPART_DEFAULT */ + "boot0", /* EMMC_HWPART_BOOT1 */ + "boot1", /* EMMC_HWPART_BOOT2 */ + "rpmb", /* EMMC_HWPART_RPMB */ + "gp1", /* EMMC_HWPART_GP1 */ + "gp2", /* EMMC_HWPART_GP2 */ + "gp3", /* EMMC_HWPART_GP3 */ + "gp4", /* EMMC_HWPART_GP4 */ +}; + static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage); #if !CONFIG_IS_ENABLED(DM_MMC) @@ -293,7 +329,7 @@ int mmc_poll_for_busy(struct mmc *mmc, int timeout_ms) if (status & MMC_STATUS_MASK) { #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) - pr_err("Status Error: 0x%08x\n", status); + log_err("Status Error: %#08x\n", status); #endif return -ECOMM; } @@ -306,7 +342,7 @@ int mmc_poll_for_busy(struct mmc *mmc, int timeout_ms) if (timeout_ms <= 0) { #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) - pr_err("Timeout waiting card ready\n"); + log_err("Timeout waiting card ready\n"); #endif return -ETIMEDOUT; } @@ -329,7 +365,7 @@ int mmc_set_blocklen(struct mmc *mmc, int len) MMC_QUIRK_RETRY_SET_BLOCKLEN, 4); } -#ifdef MMC_SUPPORTS_TUNING +#if CONFIG_IS_ENABLED(MMC_SUPPORTS_TUNING) static const u8 tuning_blk_pattern_4bit[] = { 0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc, 0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef, @@ -448,7 +484,7 @@ static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start, if (blkcnt > 1) { if (mmc_send_stop_transmission(mmc, false)) { #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) - pr_err("mmc fail to send stop cmd\n"); + log_err("mmc fail to send stop cmd\n"); #endif return 0; } @@ -499,8 +535,8 @@ ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt, if ((start + blkcnt) > block_dev->lba) { #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) - pr_err("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n", - start + blkcnt, block_dev->lba); + log_err("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n", + start + blkcnt, block_dev->lba); #endif return 0; } @@ -784,7 +820,6 @@ static int mmc_complete_op_cond(struct mmc *mmc) return 0; } - int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd) { struct mmc_cmd cmd; @@ -962,8 +997,8 @@ static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode, * Extended CSD. Reconfigure the controller to run at HS mode. */ if (hsdowngrade) { - mmc_select_mode(mmc, MMC_HS); - mmc_set_clock(mmc, mmc_mode2freq(mmc, MMC_HS), false); + mmc_select_mode(mmc, MMC_HS_52); + mmc_set_clock(mmc, mmc_mode2freq(mmc, MMC_HS_52), false); } #endif @@ -996,7 +1031,7 @@ static int mmc_get_capabilities(struct mmc *mmc) return 0; if (!ext_csd) { - pr_err("No ext_csd found!\n"); /* this should enver happen */ + log_err("No ext_csd found!\n"); /* this should never happen */ return -ENOTSUPP; } @@ -1108,17 +1143,17 @@ int mmc_hwpart_config(struct mmc *mmc, return -EINVAL; if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) { - pr_err("eMMC >= 4.4 required for enhanced user data area\n"); + log_err("eMMC >= 4.4 required for enhanced user data area\n"); return -EMEDIUMTYPE; } if (!(mmc->part_support & PART_SUPPORT)) { - pr_err("Card does not support partitioning\n"); + log_err("Card does not support partitioning\n"); return -EMEDIUMTYPE; } if (!mmc->hc_wp_grp_size) { - pr_err("Card does not define HC WP group size\n"); + log_err("Card does not define HC WP group size\n"); return -EMEDIUMTYPE; } @@ -1126,8 +1161,7 @@ int mmc_hwpart_config(struct mmc *mmc, if (conf->user.enh_size) { if (conf->user.enh_size % mmc->hc_wp_grp_size || conf->user.enh_start % mmc->hc_wp_grp_size) { - pr_err("User data enhanced area not HC WP group " - "size aligned\n"); + log_err("User data enhanced area not HC WP group size aligned\n"); return -EINVAL; } part_attrs |= EXT_CSD_ENH_USR; @@ -1145,8 +1179,8 @@ int mmc_hwpart_config(struct mmc *mmc, for (pidx = 0; pidx < 4; pidx++) { if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) { - pr_err("GP%i partition not HC WP group size " - "aligned\n", pidx+1); + log_err("GP%i partition not HC WP group-size aligned\n", + pidx + 1); return -EINVAL; } gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size; @@ -1157,7 +1191,7 @@ int mmc_hwpart_config(struct mmc *mmc, } if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) { - pr_err("Card does not support enhanced attribute\n"); + log_err("Card does not support enhanced attribute\n"); return -EMEDIUMTYPE; } @@ -1170,8 +1204,8 @@ int mmc_hwpart_config(struct mmc *mmc, (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) + ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT]; if (tot_enh_size_mult > max_enh_size_mult) { - pr_err("Total enhanced size exceeds maximum (%u > %u)\n", - tot_enh_size_mult, max_enh_size_mult); + log_err("Total enhanced size exceeds maximum (%#x > %#x)\n", + tot_enh_size_mult, max_enh_size_mult); return -EMEDIUMTYPE; } @@ -1204,7 +1238,7 @@ int mmc_hwpart_config(struct mmc *mmc, if (ext_csd[EXT_CSD_PARTITION_SETTING] & EXT_CSD_PARTITION_SETTING_COMPLETED) { - pr_err("Card already partitioned\n"); + log_err("Card already partitioned\n"); return -EPERM; } @@ -1621,7 +1655,7 @@ static inline int bus_width(uint cap) } #if !CONFIG_IS_ENABLED(DM_MMC) -#ifdef MMC_SUPPORTS_TUNING +#if CONFIG_IS_ENABLED(MMC_SUPPORTS_TUNING) static int mmc_execute_tuning(struct mmc *mmc, uint opcode) { return -ENOTSUPP; @@ -1702,7 +1736,7 @@ void mmc_dump_capabilities(const char *text, uint caps) struct mode_width_tuning { enum bus_mode mode; uint widths; -#ifdef MMC_SUPPORTS_TUNING +#if CONFIG_IS_ENABLED(MMC_SUPPORTS_TUNING) uint tuning; #endif }; @@ -1743,7 +1777,7 @@ static inline int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage) #if !CONFIG_IS_ENABLED(MMC_TINY) static const struct mode_width_tuning sd_modes_by_pref[] = { #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) -#ifdef MMC_SUPPORTS_TUNING +#if CONFIG_IS_ENABLED(MMC_SUPPORTS_TUNING) { .mode = UHS_SDR104, .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, @@ -1846,7 +1880,7 @@ static int sd_select_mode_and_width(struct mmc *mmc, uint card_caps) mmc_set_clock(mmc, mmc->tran_speed, MMC_CLK_ENABLE); -#ifdef MMC_SUPPORTS_TUNING +#if CONFIG_IS_ENABLED(MMC_SUPPORTS_TUNING) /* execute tuning if needed */ if (mwt->tuning && !mmc_host_is_spi(mmc)) { err = mmc_execute_tuning(mmc, @@ -1875,7 +1909,7 @@ error: } } - pr_err("unable to select a mode\n"); + log_err("unable to select a mode\n"); return -ENOTSUPP; } @@ -2043,7 +2077,7 @@ static int mmc_select_hs400(struct mmc *mmc) } /* Set back to HS */ - mmc_set_card_speed(mmc, MMC_HS, true); + mmc_set_card_speed(mmc, MMC_HS_52, true); err = mmc_hs400_prepare_ddr(mmc); if (err) @@ -2224,7 +2258,7 @@ static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps) mmc_select_mode(mmc, mwt->mode); mmc_set_clock(mmc, mmc->tran_speed, MMC_CLK_ENABLE); -#ifdef MMC_SUPPORTS_TUNING +#if CONFIG_IS_ENABLED(MMC_SUPPORTS_TUNING) /* execute tuning if needed */ if (mwt->tuning) { @@ -2253,7 +2287,7 @@ error: } } - pr_err("unable to select a mode : %d\n", err); + log_err("unable to select a mode: %d\n", err); return -ENOTSUPP; } @@ -2921,7 +2955,8 @@ retry: if (err) { #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) if (!quiet) - pr_err("Card did not respond to voltage select! : %d\n", err); + log_err("Card did not respond to voltage select! : %d\n", + err); #endif return -EOPNOTSUPP; } @@ -2954,7 +2989,7 @@ int mmc_start_init(struct mmc *mmc) | MMC_CAP(MMC_LEGACY) | MMC_MODE_1BIT); } else { - pr_err("bus_mode requested is not supported\n"); + log_err("bus_mode requested is not supported\n"); return -EINVAL; } } @@ -2974,7 +3009,7 @@ int mmc_start_init(struct mmc *mmc) if (no_card) { mmc->has_init = 0; #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) - pr_err("MMC: no card present\n"); + log_err("MMC: no card present\n"); #endif return -ENOMEDIUM; } @@ -3004,6 +3039,20 @@ static int mmc_complete_init(struct mmc *mmc) return err; } +static void __maybe_unused mmc_cyclic_cd_poll(struct cyclic_info *c) +{ + struct mmc *m = CONFIG_IS_ENABLED(CYCLIC, (container_of(c, struct mmc, cyclic)), (NULL)); + + if (!m->has_init) + return; + + if (mmc_getcd(m)) + return; + + mmc_deinit(m); + m->has_init = 0; +} + int mmc_init(struct mmc *mmc) { int err = 0; @@ -3026,6 +3075,14 @@ int mmc_init(struct mmc *mmc) if (err) pr_info("%s: %d, time %lu\n", __func__, err, get_timer(start)); + if (CONFIG_IS_ENABLED(CYCLIC, (!mmc->cyclic.func), (NULL))) { + /* Register cyclic function for card detect polling */ + CONFIG_IS_ENABLED(CYCLIC, (cyclic_register(&mmc->cyclic, + mmc_cyclic_cd_poll, + 100 * 1000, + mmc->cfg->name))); + } + return err; } @@ -3033,6 +3090,9 @@ int mmc_deinit(struct mmc *mmc) { u32 caps_filtered; + if (CONFIG_IS_ENABLED(CYCLIC, (mmc->cyclic.func), (NULL))) + CONFIG_IS_ENABLED(CYCLIC, (cyclic_unregister(&mmc->cyclic))); + if (!CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) && !CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) && !CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)) @@ -3103,7 +3163,7 @@ static int mmc_probe(struct bd_info *bis) uclass_foreach_dev(dev, uc) { ret = device_probe(dev); if (ret) - pr_err("%s - probe failed: %d\n", dev->name, ret); + log_err("%s - probe failed: %d\n", dev->name, ret); } return 0; @@ -3153,7 +3213,7 @@ int mmc_init_device(int num) if (uclass_get_device_by_seq(UCLASS_MMC, num, &dev)) { ret = uclass_get_device(UCLASS_MMC, num, &dev); if (ret) - return ret; + return log_msg_ret("ini", ret); } m = mmc_get_mmc_dev(dev); diff --git a/drivers/mmc/mmc_boot.c b/drivers/mmc/mmc_boot.c index 0a74b1fb776..367c957b518 100644 --- a/drivers/mmc/mmc_boot.c +++ b/drivers/mmc/mmc_boot.c @@ -4,7 +4,6 @@ * Written by Amar <amarendra.xt@samsung.com> */ -#include <common.h> #include <log.h> #include <mmc.h> #include "mmc_private.h" diff --git a/drivers/mmc/mmc_bootdev.c b/drivers/mmc/mmc_bootdev.c index 55ecead2ddf..5a1688b75d0 100644 --- a/drivers/mmc/mmc_bootdev.c +++ b/drivers/mmc/mmc_bootdev.c @@ -6,7 +6,6 @@ * Written by Simon Glass <sjg@chromium.org> */ -#include <common.h> #include <bootdev.h> #include <dm.h> #include <mmc.h> diff --git a/drivers/mmc/mmc_legacy.c b/drivers/mmc/mmc_legacy.c index a101ee43fde..a87d2276c1b 100644 --- a/drivers/mmc/mmc_legacy.c +++ b/drivers/mmc/mmc_legacy.c @@ -5,7 +5,6 @@ * Written by Simon Glass <sjg@chromium.org> */ -#include <common.h> #include <log.h> #include <malloc.h> #include <mmc.h> diff --git a/drivers/mmc/mmc_spi.c b/drivers/mmc/mmc_spi.c index bcea800e5f6..675e642efd0 100644 --- a/drivers/mmc/mmc_spi.c +++ b/drivers/mmc/mmc_spi.c @@ -6,7 +6,6 @@ * * Licensed under the GPL-2 or later. */ -#include <common.h> #include <errno.h> #include <log.h> #include <malloc.h> diff --git a/drivers/mmc/mmc_write.c b/drivers/mmc/mmc_write.c index a6f93380dd0..c023d15e52a 100644 --- a/drivers/mmc/mmc_write.c +++ b/drivers/mmc/mmc_write.c @@ -7,7 +7,6 @@ */ #include <config.h> -#include <common.h> #include <blk.h> #include <dm.h> #include <part.h> diff --git a/drivers/mmc/msm_sdhci.c b/drivers/mmc/msm_sdhci.c index 5e9d66526a8..4e5c932c071 100644 --- a/drivers/mmc/msm_sdhci.c +++ b/drivers/mmc/msm_sdhci.c @@ -7,7 +7,6 @@ * Based on Linux driver */ -#include <common.h> #include <clk.h> #include <dm.h> #include <malloc.h> @@ -33,6 +32,8 @@ #define SDCC_MCI_STATUS2_MCI_ACT 0x1 #define SDCC_MCI_HC_MODE 0x78 +#define CORE_VENDOR_SPEC_POR_VAL 0xa9c + struct msm_sdhc_plat { struct mmc_config cfg; struct mmc mmc; @@ -47,6 +48,7 @@ struct msm_sdhc { struct msm_sdhc_variant_info { bool mci_removed; + u32 core_vendor_spec; u32 core_vendor_spec_capabilities0; }; @@ -55,11 +57,14 @@ DECLARE_GLOBAL_DATA_PTR; static int msm_sdc_clk_init(struct udevice *dev) { struct msm_sdhc *prv = dev_get_priv(dev); + const struct msm_sdhc_variant_info *var_info; ofnode node = dev_ofnode(dev); ulong clk_rate; int ret, i = 0, n_clks; const char *clk_name; + var_info = (void *)dev_get_driver_data(dev); + ret = ofnode_read_u32(node, "clock-frequency", (uint *)(&clk_rate)); if (ret) clk_rate = 201500000; @@ -106,6 +111,9 @@ static int msm_sdc_clk_init(struct udevice *dev) return -EINVAL; } + writel_relaxed(CORE_VENDOR_SPEC_POR_VAL, + prv->host.ioaddr + var_info->core_vendor_spec); + return 0; } @@ -115,7 +123,6 @@ static int msm_sdc_mci_init(struct msm_sdhc *prv) writel(readl(prv->base + SDCC_MCI_POWER) | SDCC_MCI_POWER_SW_RST, prv->base + SDCC_MCI_POWER); - /* Wait for reset to be written to register */ if (wait_for_bit_le32(prv->base + SDCC_MCI_STATUS2, SDCC_MCI_STATUS2_MCI_ACT, false, 10, false)) { @@ -256,12 +263,14 @@ static int msm_sdc_bind(struct udevice *dev) static const struct msm_sdhc_variant_info msm_sdhc_mci_var = { .mci_removed = false, + .core_vendor_spec = 0x10c, .core_vendor_spec_capabilities0 = 0x11c, }; static const struct msm_sdhc_variant_info msm_sdhc_v5_var = { .mci_removed = true, + .core_vendor_spec = 0x20c, .core_vendor_spec_capabilities0 = 0x21c, }; diff --git a/drivers/mmc/mtk-sd.c b/drivers/mmc/mtk-sd.c index 296aaee7331..d676cf9e314 100644 --- a/drivers/mmc/mtk-sd.c +++ b/drivers/mmc/mtk-sd.c @@ -7,7 +7,6 @@ */ #include <clk.h> -#include <common.h> #include <dm.h> #include <mmc.h> #include <errno.h> @@ -336,6 +335,7 @@ struct msdc_compatible { bool enhance_rx; bool builtin_pad_ctrl; bool default_pad_dly; + bool use_internal_cd; }; struct msdc_delay_phase { @@ -366,6 +366,10 @@ struct msdc_host { struct clk src_clk_cg; /* optional, MSDC source clock control gate */ struct clk h_clk; /* MSDC core clock */ + /* upstream linux clock */ + struct clk axi_cg_clk; /* optional, AXI clock */ + struct clk ahb_cg_clk; /* optional, AHB clock */ + u32 src_clk_freq; /* source clock */ u32 mclk; /* mmc framework required bus clock */ u32 sclk; /* actual calculated bus clock */ @@ -1011,7 +1015,7 @@ static int msdc_ops_get_wp(struct udevice *dev) #endif } -#ifdef MMC_SUPPORTS_TUNING +#if CONFIG_IS_ENABLED(MMC_SUPPORTS_TUNING) static u32 test_delay_bit(u32 delay, u32 bit) { bit %= PAD_DELAY_MAX; @@ -1627,7 +1631,6 @@ static void msdc_init_hw(struct msdc_host *host) clrsetbits_le32(&host->base->sdc_cfg, SDC_CFG_DTOC_M, 3 << SDC_CFG_DTOC_S); - host->def_tune_para.iocon = readl(&host->base->msdc_iocon); host->def_tune_para.pad_tune = readl(&host->base->pad_tune); } @@ -1638,6 +1641,11 @@ static void msdc_ungate_clock(struct msdc_host *host) clk_enable(&host->h_clk); if (host->src_clk_cg.dev) clk_enable(&host->src_clk_cg); + + if (host->axi_cg_clk.dev) + clk_enable(&host->axi_cg_clk); + if (host->ahb_cg_clk.dev) + clk_enable(&host->ahb_cg_clk); } static int msdc_drv_probe(struct udevice *dev) @@ -1651,6 +1659,9 @@ static int msdc_drv_probe(struct udevice *dev) host->dev_comp = (struct msdc_compatible *)dev_get_driver_data(dev); + if (host->dev_comp->use_internal_cd) + host->builtin_cd = 1; + host->src_clk_freq = clk_get_rate(&host->src_clk); if (host->dev_comp->clk_div_bits == 8) @@ -1716,18 +1727,31 @@ static int msdc_of_to_plat(struct udevice *dev) clk_get_by_name(dev, "source_cg", &host->src_clk_cg); /* optional */ + /* upstream linux clock */ + clk_get_by_name(dev, "axi_cg", &host->axi_cg_clk); /* optional */ + clk_get_by_name(dev, "ahb_cg", &host->ahb_cg_clk); /* optional */ + #if CONFIG_IS_ENABLED(DM_GPIO) gpio_request_by_name(dev, "wp-gpios", 0, &host->gpio_wp, GPIOD_IS_IN); gpio_request_by_name(dev, "cd-gpios", 0, &host->gpio_cd, GPIOD_IS_IN); #endif host->hs400_ds_delay = dev_read_u32_default(dev, "hs400-ds-delay", 0); - host->hs200_cmd_int_delay = - dev_read_u32_default(dev, "cmd_int_delay", 0); + if (dev_read_u32(dev, "mediatek,hs200-cmd-int-delay", + &host->hs200_cmd_int_delay)) + host->hs200_cmd_int_delay = + dev_read_u32_default(dev, "cmd_int_delay", 0); + host->hs200_write_int_delay = dev_read_u32_default(dev, "write_int_delay", 0); - host->latch_ck = dev_read_u32_default(dev, "latch-ck", 0); + + if (dev_read_u32(dev, "mediatek,latch-ck", &host->latch_ck)) + host->latch_ck = dev_read_u32_default(dev, "latch-ck", 0); + host->r_smpl = dev_read_u32_default(dev, "r_smpl", 0); + if (dev_read_bool(dev, "mediatek,hs400-cmd-resp-sel-rising")) + host->r_smpl = 1; + host->builtin_cd = dev_read_u32_default(dev, "builtin-cd", 0); host->cd_active_high = dev_read_bool(dev, "cd-active-high"); @@ -1760,7 +1784,7 @@ static const struct dm_mmc_ops msdc_ops = { .set_ios = msdc_ops_set_ios, .get_cd = msdc_ops_get_cd, .get_wp = msdc_ops_get_wp, -#ifdef MMC_SUPPORTS_TUNING +#if CONFIG_IS_ENABLED(MMC_SUPPORTS_TUNING) .execute_tuning = msdc_execute_tuning, #endif .wait_dat0 = msdc_ops_wait_dat0, @@ -1776,6 +1800,7 @@ static const struct msdc_compatible mt7620_compat = { .enhance_rx = false, .builtin_pad_ctrl = true, .default_pad_dly = true, + .use_internal_cd = true, }; static const struct msdc_compatible mt7621_compat = { @@ -1806,7 +1831,7 @@ static const struct msdc_compatible mt7623_compat = { .data_tune = true, .busy_check = false, .stop_clk_fix = false, - .enhance_rx = false + .enhance_rx = false, }; static const struct msdc_compatible mt7986_compat = { diff --git a/drivers/mmc/mv_sdhci.c b/drivers/mmc/mv_sdhci.c index dbdd671c88b..2da5334c21f 100644 --- a/drivers/mmc/mv_sdhci.c +++ b/drivers/mmc/mv_sdhci.c @@ -3,7 +3,6 @@ * Marvell SD Host Controller Interface */ -#include <common.h> #include <dm.h> #include <malloc.h> #include <sdhci.h> diff --git a/drivers/mmc/mvebu_mmc.c b/drivers/mmc/mvebu_mmc.c index fea55c61ed7..5af1953cd14 100644 --- a/drivers/mmc/mvebu_mmc.c +++ b/drivers/mmc/mvebu_mmc.c @@ -7,7 +7,6 @@ * Written-by: Maen Suleiman, Gerald Kerma */ -#include <common.h> #include <errno.h> #include <log.h> #include <malloc.h> diff --git a/drivers/mmc/mxcmmc.c b/drivers/mmc/mxcmmc.c index 0057273a2a7..1acea6f820b 100644 --- a/drivers/mmc/mxcmmc.c +++ b/drivers/mmc/mxcmmc.c @@ -17,7 +17,6 @@ */ #include <config.h> -#include <common.h> #include <command.h> #include <mmc.h> #include <part.h> diff --git a/drivers/mmc/mxsmmc.c b/drivers/mmc/mxsmmc.c index 35a8e21058e..95390a5be7e 100644 --- a/drivers/mmc/mxsmmc.c +++ b/drivers/mmc/mxsmmc.c @@ -20,7 +20,6 @@ * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net */ -#include <common.h> #include <log.h> #include <malloc.h> #include <mmc.h> diff --git a/drivers/mmc/nexell_dw_mmc.c b/drivers/mmc/nexell_dw_mmc.c index 2723e4887cf..80df617e07e 100644 --- a/drivers/mmc/nexell_dw_mmc.c +++ b/drivers/mmc/nexell_dw_mmc.c @@ -6,7 +6,6 @@ * (C) Copyright 2019 Stefan Bosch <stefan_b@posteo.net> */ -#include <common.h> #include <dm.h> #include <dt-structs.h> #include <dwmmc.h> @@ -187,10 +186,7 @@ static int nexell_dwmmc_probe(struct udevice *dev) struct dwmci_host *host = &priv->host; struct udevice *pwr_dev __maybe_unused; - host->fifoth_val = MSIZE(0x2) | - RX_WMARK(priv->fifo_size / 2 - 1) | - TX_WMARK(priv->fifo_size / 2); - + host->fifo_depth = priv->fifo_size; host->fifo_mode = priv->fifo_mode; dwmci_setup_cfg(&plat->cfg, host, priv->max_freq, priv->min_freq); diff --git a/drivers/mmc/npcm_sdhci.c b/drivers/mmc/npcm_sdhci.c index d63521d6855..dff4732ea06 100644 --- a/drivers/mmc/npcm_sdhci.c +++ b/drivers/mmc/npcm_sdhci.c @@ -3,7 +3,6 @@ * Copyright (c) 2022 Nuvoton Technology Corp. */ -#include <common.h> #include <dm.h> #include <sdhci.h> #include <clk.h> diff --git a/drivers/mmc/octeontx_hsmmc.c b/drivers/mmc/octeontx_hsmmc.c index 7f9c4f4d36d..3b5e1221732 100644 --- a/drivers/mmc/octeontx_hsmmc.c +++ b/drivers/mmc/octeontx_hsmmc.c @@ -794,7 +794,7 @@ octeontx_mmc_get_cr_mods(struct mmc *mmc, const struct mmc_cmd *cmd, u8 desired_ctype = 0; if (IS_MMC(mmc)) { -#ifdef MMC_SUPPORTS_TUNING +#if CONFIG_IS_ENABLED(MMC_SUPPORTS_TUNING) if (cmd->cmdidx == MMC_CMD_SEND_TUNING_BLOCK_HS200) { if (cmd->resp_type == MMC_RSP_R1) cr.rtype_xor = 1; @@ -1631,7 +1631,7 @@ static int octeontx_mmc_dev_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, return octeontx_mmc_send_cmd(dev_to_mmc(dev), cmd, data); } -#ifdef MMC_SUPPORTS_TUNING +#if CONFIG_IS_ENABLED(MMC_SUPPORTS_TUNING) static int octeontx_mmc_test_cmd(struct mmc *mmc, u32 opcode, int *statp) { struct mmc_cmd cmd; @@ -2421,12 +2421,12 @@ static int octeontx_mmc_execute_tuning(struct udevice *dev, u32 opcode) return 0; } -#else /* MMC_SUPPORTS_TUNING */ +#else /* CONFIG_MMC_SUPPORTS_TUNING */ static void octeontx_mmc_set_emm_timing(struct mmc *mmc, union mio_emm_timing emm_timing) { } -#endif /* MMC_SUPPORTS_TUNING */ +#endif /* CONFIG_MMC_SUPPORTS_TUNING */ /** * Calculate the clock period with rounding up @@ -2573,7 +2573,7 @@ static int octeontx_mmc_set_ios(struct udevice *dev) err = octeontx_mmc_configure_delay(mmc); -#ifdef MMC_SUPPORTS_TUNING +#if CONFIG_IS_ENABLED(MMC_SUPPORTS_TUNING) if (!err && mmc->selected_mode == MMC_HS_400 && !slot->hs400_tuned) { debug("%s: Tuning HS400 mode\n", __func__); err = octeontx_tune_hs400(mmc); @@ -3776,7 +3776,7 @@ static const struct dm_mmc_ops octeontx_hsmmc_ops = { .set_ios = octeontx_mmc_set_ios, .get_cd = octeontx_mmc_get_cd, .get_wp = octeontx_mmc_get_wp, -#ifdef MMC_SUPPORTS_TUNING +#if CONFIG_IS_ENABLED(MMC_SUPPORTS_TUNING) .execute_tuning = octeontx_mmc_execute_tuning, #endif }; diff --git a/drivers/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c index 99f21b2c546..8e51453d2ae 100644 --- a/drivers/mmc/omap_hsmmc.c +++ b/drivers/mmc/omap_hsmmc.c @@ -23,7 +23,6 @@ */ #include <config.h> -#include <common.h> #include <cpu_func.h> #include <log.h> #include <malloc.h> @@ -31,7 +30,7 @@ #include <mmc.h> #include <part.h> #include <i2c.h> -#if defined(CONFIG_OMAP54XX) || defined(CONFIG_OMAP44XX) +#if defined(CONFIG_OMAP54XX) #include <palmas.h> #endif #include <asm/cache.h> @@ -271,8 +270,7 @@ static unsigned char mmc_board_init(struct mmc *mmc) &prcm_base->iclken1_core); #endif -#if (defined(CONFIG_OMAP54XX) || defined(CONFIG_OMAP44XX)) &&\ - !CONFIG_IS_ENABLED(DM_REGULATOR) +#if defined(CONFIG_OMAP54XX) && !CONFIG_IS_ENABLED(DM_REGULATOR) /* PBIAS config needed for MMC1 only */ if (mmc_get_blk_desc(mmc)->devnum == 0) vmmc_pbias_config(LDO_VOLT_3V3); @@ -542,8 +540,7 @@ static int omap_hsmmc_set_signal_voltage(struct mmc *mmc) #if CONFIG_IS_ENABLED(DM_REGULATOR) return omap_hsmmc_set_io_regulator(mmc, mv); -#elif (defined(CONFIG_OMAP54XX) || defined(CONFIG_OMAP44XX)) && \ - defined(CONFIG_PALMAS_POWER) +#elif defined(CONFIG_OMAP54XX) && defined(CONFIG_PALMAS_POWER) if (mmc_get_blk_desc(mmc)->devnum == 0) vmmc_pbias_config(palmas_ldo_volt); return 0; @@ -577,7 +574,7 @@ static uint32_t omap_hsmmc_set_capabilities(struct mmc *mmc) return val; } -#ifdef MMC_SUPPORTS_TUNING +#if CONFIG_IS_ENABLED(MMC_SUPPORTS_TUNING) static void omap_hsmmc_disable_tuning(struct mmc *mmc) { struct hsmmc *mmc_base; @@ -906,8 +903,7 @@ static void mmc_reset_controller_fsm(struct hsmmc *mmc_base, u32 bit) * 3. Wait until the SRC (SRD) bit returns to 0x0 * (reset procedure is completed). */ -#if defined(CONFIG_OMAP44XX) || defined(CONFIG_OMAP54XX) || \ - defined(CONFIG_AM33XX) || defined(CONFIG_AM43XX) +#if defined(CONFIG_OMAP54XX) || defined(CONFIG_AM33XX) || defined(CONFIG_AM43XX) if (!(readl(&mmc_base->sysctl) & bit)) { start = get_timer(0); while (!(readl(&mmc_base->sysctl) & bit)) { @@ -1518,7 +1514,7 @@ static const struct dm_mmc_ops omap_hsmmc_ops = { .get_cd = omap_hsmmc_getcd, .get_wp = omap_hsmmc_getwp, #endif -#ifdef MMC_SUPPORTS_TUNING +#if CONFIG_IS_ENABLED(MMC_SUPPORTS_TUNING) .execute_tuning = omap_hsmmc_execute_tuning, #endif .wait_dat0 = omap_hsmmc_wait_dat0, @@ -1557,7 +1553,7 @@ int omap_mmc_init(int dev_index, uint host_caps_mask, uint f_max, int cd_gpio, #ifdef OMAP_HSMMC2_BASE case 1: priv->base_addr = (struct hsmmc *)OMAP_HSMMC2_BASE; -#if (defined(CONFIG_OMAP44XX) || defined(CONFIG_OMAP54XX) || \ +#if (defined(CONFIG_OMAP54XX) || \ defined(CONFIG_DRA7XX) || defined(CONFIG_AM33XX) || \ defined(CONFIG_AM43XX) || defined(CONFIG_ARCH_KEYSTONE)) && \ defined(CONFIG_HSMMC2_8BIT) diff --git a/drivers/mmc/owl_mmc.c b/drivers/mmc/owl_mmc.c index e84171a661a..bd4906f58e7 100644 --- a/drivers/mmc/owl_mmc.c +++ b/drivers/mmc/owl_mmc.c @@ -11,7 +11,6 @@ * channel, and those special bits used in this driver is picked from vendor * source exclusively for MMC/SD. */ -#include <common.h> #include <clk.h> #include <cpu_func.h> #include <dm.h> diff --git a/drivers/mmc/pci_mmc.c b/drivers/mmc/pci_mmc.c index 4d163ccba04..d446c55f72b 100644 --- a/drivers/mmc/pci_mmc.c +++ b/drivers/mmc/pci_mmc.c @@ -4,7 +4,6 @@ * Copyright (C) 2014, Bin Meng <bmeng.cn@gmail.com> */ -#include <common.h> #include <dm.h> #include <errno.h> #include <log.h> diff --git a/drivers/mmc/piton_mmc.c b/drivers/mmc/piton_mmc.c index a330bbf8cbe..5ef2781eedf 100644 --- a/drivers/mmc/piton_mmc.c +++ b/drivers/mmc/piton_mmc.c @@ -11,7 +11,6 @@ #include <asm/gpio.h> #include <asm/io.h> -#include <common.h> #include <div64.h> #include <dm.h> #include <errno.h> @@ -23,7 +22,6 @@ #include <log.h> #include <mmc.h> - #define PITON_MMC_DUMMY_F_MAX 20000000 #define PITON_MMC_DUMMY_F_MIN 10000000 #define PITON_MMC_DUMMY_CAPACITY SZ_4G << 3 diff --git a/drivers/mmc/rockchip_dw_mmc.c b/drivers/mmc/rockchip_dw_mmc.c index ad4529d6afa..5ba99d68b7d 100644 --- a/drivers/mmc/rockchip_dw_mmc.c +++ b/drivers/mmc/rockchip_dw_mmc.c @@ -3,7 +3,6 @@ * Copyright (c) 2013 Google, Inc */ -#include <common.h> #include <clk.h> #include <dm.h> #include <dt-structs.h> @@ -81,7 +80,7 @@ static int rockchip_dwmmc_of_to_plat(struct udevice *dev) priv->fifo_depth = dev_read_u32_default(dev, "fifo-depth", 0); if (priv->fifo_depth < 0) - return -EINVAL; + return log_msg_ret("rkp", -EINVAL); priv->fifo_mode = dev_read_bool(dev, "fifo-mode"); #ifdef CONFIG_SPL_BUILD @@ -97,7 +96,7 @@ static int rockchip_dwmmc_of_to_plat(struct udevice *dev) int val = dev_read_u32_default(dev, "max-frequency", -EINVAL); if (val < 0) - return val; + return log_msg_ret("rkc", val); priv->minmax[0] = 400000; /* 400 kHz */ priv->minmax[1] = val; @@ -132,17 +131,12 @@ static int rockchip_dwmmc_probe(struct udevice *dev) priv->minmax[1] = dtplat->max_frequency; ret = clk_get_by_phandle(dev, &dtplat->clocks[1], &priv->clk); - if (ret < 0) - return ret; #else ret = clk_get_by_index(dev, 1, &priv->clk); - if (ret < 0) - return ret; #endif - host->fifoth_val = MSIZE(0x2) | - RX_WMARK(priv->fifo_depth / 2 - 1) | - TX_WMARK(priv->fifo_depth / 2); - + if (ret < 0 && ret != -ENOSYS) + return log_msg_ret("clk", ret); + host->fifo_depth = priv->fifo_depth; host->fifo_mode = priv->fifo_mode; #if CONFIG_IS_ENABLED(MMC_PWRSEQ) @@ -160,6 +154,10 @@ static int rockchip_dwmmc_probe(struct udevice *dev) host->mmc->dev = dev; upriv->mmc = host->mmc; + /* Hosts capable of 8-bit can also do 4 bits */ + if (host->buswidth == 8) + plat->cfg.host_caps |= MMC_MODE_4BIT; + return dwmci_probe(dev); } diff --git a/drivers/mmc/rockchip_sdhci.c b/drivers/mmc/rockchip_sdhci.c index c889c7bc985..4ea3307ed9c 100644 --- a/drivers/mmc/rockchip_sdhci.c +++ b/drivers/mmc/rockchip_sdhci.c @@ -5,7 +5,6 @@ * Rockchip SD Host Controller Interface */ -#include <common.h> #include <clk.h> #include <dm.h> #include <dm/ofnode.h> @@ -231,7 +230,7 @@ static int rk3399_emmc_get_phy(struct udevice *dev) grf_base = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); if (IS_ERR_OR_NULL(grf_base)) { - printf("%s Get syscon grf failed", __func__); + printf("%s: Get syscon grf failed\n", __func__); return -ENODEV; } grf_phy_offset = ofnode_read_u32_default(phy_node, "reg", 0); @@ -572,20 +571,19 @@ static int rockchip_sdhci_probe(struct udevice *dev) struct rockchip_sdhc *priv = dev_get_priv(dev); struct mmc_config *cfg = &plat->cfg; struct sdhci_host *host = &priv->host; - struct clk clk; + struct clk *clk = &priv->emmc_clk; int ret; host->max_clk = cfg->f_max; - ret = clk_get_by_index(dev, 0, &clk); + ret = clk_get_by_index(dev, 0, clk); if (!ret) { - ret = clk_set_rate(&clk, host->max_clk); + ret = clk_set_rate(clk, host->max_clk); if (IS_ERR_VALUE(ret)) printf("%s clk set rate fail!\n", __func__); - } else { + } else if (ret != -ENOSYS) { printf("%s fail to get clk\n", __func__); } - priv->emmc_clk = clk; priv->dev = dev; if (data->get_phy) { diff --git a/drivers/mmc/rpmb.c b/drivers/mmc/rpmb.c index b68d98573c9..fa3ac2d9e37 100644 --- a/drivers/mmc/rpmb.c +++ b/drivers/mmc/rpmb.c @@ -8,7 +8,6 @@ */ #include <config.h> -#include <common.h> #include <log.h> #include <memalign.h> #include <mmc.h> @@ -61,7 +60,6 @@ static const char * const rpmb_err_msg[] = { "Authentication key not yet programmed", }; - /* Structure of RPMB data frame. */ struct s_rpmb { unsigned char stuff[RPMB_SZ_STUFF]; diff --git a/drivers/mmc/s5p_sdhci.c b/drivers/mmc/s5p_sdhci.c index 3b74feae68c..278019f02ab 100644 --- a/drivers/mmc/s5p_sdhci.c +++ b/drivers/mmc/s5p_sdhci.c @@ -4,7 +4,6 @@ * Jaehoon Chung <jh80.chung@samsung.com> */ -#include <common.h> #include <dm.h> #include <log.h> #include <malloc.h> @@ -167,7 +166,7 @@ static int sdhci_get_config(const void *blob, int node, struct sdhci_host *host) host->index = dev_id - PERIPH_ID_SDMMC0; /* Get bus width */ - bus_width = fdtdec_get_int(blob, node, "samsung,bus-width", 0); + bus_width = fdtdec_get_int(blob, node, "bus-width", 0); if (bus_width <= 0) { debug("MMC: Can't get bus-width\n"); return -EINVAL; diff --git a/drivers/mmc/sandbox_mmc.c b/drivers/mmc/sandbox_mmc.c index 0ba7940a4db..a24520f2e78 100644 --- a/drivers/mmc/sandbox_mmc.c +++ b/drivers/mmc/sandbox_mmc.c @@ -4,7 +4,6 @@ * Written by Simon Glass <sjg@chromium.org> */ -#include <common.h> #include <dm.h> #include <errno.h> #include <fdtdec.h> diff --git a/drivers/mmc/sdhci-adma.c b/drivers/mmc/sdhci-adma.c index 283ba956deb..fdb189d71a6 100644 --- a/drivers/mmc/sdhci-adma.c +++ b/drivers/mmc/sdhci-adma.c @@ -3,7 +3,6 @@ * SDHCI ADMA2 helper functions. */ -#include <common.h> #include <cpu_func.h> #include <sdhci.h> #include <malloc.h> diff --git a/drivers/mmc/sdhci-cadence.c b/drivers/mmc/sdhci-cadence.c index c0a9f60b149..7d169efa476 100644 --- a/drivers/mmc/sdhci-cadence.c +++ b/drivers/mmc/sdhci-cadence.c @@ -4,7 +4,6 @@ * Author: Masahiro Yamada <yamada.masahiro@socionext.com> */ -#include <common.h> #include <dm.h> #include <asm/global_data.h> #include <dm/device_compat.h> @@ -17,56 +16,7 @@ #include <linux/libfdt.h> #include <mmc.h> #include <sdhci.h> - -/* HRS - Host Register Set (specific to Cadence) */ -#define SDHCI_CDNS_HRS04 0x10 /* PHY access port */ -#define SDHCI_CDNS_HRS04_ACK BIT(26) -#define SDHCI_CDNS_HRS04_RD BIT(25) -#define SDHCI_CDNS_HRS04_WR BIT(24) -#define SDHCI_CDNS_HRS04_RDATA GENMASK(23, 16) -#define SDHCI_CDNS_HRS04_WDATA GENMASK(15, 8) -#define SDHCI_CDNS_HRS04_ADDR GENMASK(5, 0) - -#define SDHCI_CDNS_HRS06 0x18 /* eMMC control */ -#define SDHCI_CDNS_HRS06_TUNE_UP BIT(15) -#define SDHCI_CDNS_HRS06_TUNE GENMASK(13, 8) -#define SDHCI_CDNS_HRS06_MODE GENMASK(2, 0) -#define SDHCI_CDNS_HRS06_MODE_SD 0x0 -#define SDHCI_CDNS_HRS06_MODE_MMC_SDR 0x2 -#define SDHCI_CDNS_HRS06_MODE_MMC_DDR 0x3 -#define SDHCI_CDNS_HRS06_MODE_MMC_HS200 0x4 -#define SDHCI_CDNS_HRS06_MODE_MMC_HS400 0x5 -#define SDHCI_CDNS_HRS06_MODE_MMC_HS400ES 0x6 - -/* SRS - Slot Register Set (SDHCI-compatible) */ -#define SDHCI_CDNS_SRS_BASE 0x200 - -/* PHY */ -#define SDHCI_CDNS_PHY_DLY_SD_HS 0x00 -#define SDHCI_CDNS_PHY_DLY_SD_DEFAULT 0x01 -#define SDHCI_CDNS_PHY_DLY_UHS_SDR12 0x02 -#define SDHCI_CDNS_PHY_DLY_UHS_SDR25 0x03 -#define SDHCI_CDNS_PHY_DLY_UHS_SDR50 0x04 -#define SDHCI_CDNS_PHY_DLY_UHS_DDR50 0x05 -#define SDHCI_CDNS_PHY_DLY_EMMC_LEGACY 0x06 -#define SDHCI_CDNS_PHY_DLY_EMMC_SDR 0x07 -#define SDHCI_CDNS_PHY_DLY_EMMC_DDR 0x08 -#define SDHCI_CDNS_PHY_DLY_SDCLK 0x0b -#define SDHCI_CDNS_PHY_DLY_HSMMC 0x0c -#define SDHCI_CDNS_PHY_DLY_STROBE 0x0d - -/* - * The tuned val register is 6 bit-wide, but not the whole of the range is - * available. The range 0-42 seems to be available (then 43 wraps around to 0) - * but I am not quite sure if it is official. Use only 0 to 39 for safety. - */ -#define SDHCI_CDNS_MAX_TUNING_LOOP 40 - -struct sdhci_cdns_plat { - struct mmc_config cfg; - struct mmc mmc; - void __iomem *hrs_addr; -}; +#include "sdhci-cadence.h" struct sdhci_cdns_phy_cfg { const char *property; @@ -163,6 +113,9 @@ static void sdhci_cdns_set_control_reg(struct sdhci_host *host) tmp &= ~SDHCI_CDNS_HRS06_MODE; tmp |= FIELD_PREP(SDHCI_CDNS_HRS06_MODE, mode); writel(tmp, plat->hrs_addr + SDHCI_CDNS_HRS06); + + if (device_is_compatible(mmc->dev, "cdns,sd6hc")) + sdhci_cdns6_phy_adj(mmc->dev, plat, mode); } static const struct sdhci_ops sdhci_cdns_ops = { @@ -176,6 +129,9 @@ static int sdhci_cdns_set_tune_val(struct sdhci_cdns_plat *plat, u32 tmp; int i, ret; + if (device_is_compatible(plat->mmc.dev, "cdns,sd6hc")) + return sdhci_cdns6_set_tune_val(plat, val); + if (WARN_ON(!FIELD_FIT(SDHCI_CDNS_HRS06_TUNE, val))) return -EINVAL; @@ -274,7 +230,7 @@ static int sdhci_cdns_probe(struct udevice *dev) host->ops = &sdhci_cdns_ops; host->quirks |= SDHCI_QUIRK_WAIT_SEND_CMD; sdhci_cdns_mmc_ops = sdhci_ops; -#ifdef MMC_SUPPORTS_TUNING +#if CONFIG_IS_ENABLED(MMC_SUPPORTS_TUNING) sdhci_cdns_mmc_ops.execute_tuning = sdhci_cdns_execute_tuning; #endif @@ -282,7 +238,10 @@ static int sdhci_cdns_probe(struct udevice *dev) if (ret) return ret; - ret = sdhci_cdns_phy_init(plat, gd->fdt_blob, dev_of_offset(dev)); + if (device_is_compatible(dev, "cdns,sd6hc")) + ret = sdhci_cdns6_phy_init(dev, plat); + else + ret = sdhci_cdns_phy_init(plat, gd->fdt_blob, dev_of_offset(dev)); if (ret) return ret; @@ -301,6 +260,7 @@ static int sdhci_cdns_probe(struct udevice *dev) static const struct udevice_id sdhci_cdns_match[] = { { .compatible = "socionext,uniphier-sd4hc" }, { .compatible = "cdns,sd4hc" }, + { .compatible = "cdns,sd6hc" }, { /* sentinel */ } }; diff --git a/drivers/mmc/sdhci-cadence.h b/drivers/mmc/sdhci-cadence.h new file mode 100644 index 00000000000..7101f00b75b --- /dev/null +++ b/drivers/mmc/sdhci-cadence.h @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2016 Socionext Inc. + * Author: Masahiro Yamada <yamada.masahiro@socionext.com> + */ + +#ifndef SDHCI_CADENCE_H_ +#define SDHCI_CADENCE_H_ + +/* HRS - Host Register Set (specific to Cadence) */ +/* PHY access port */ +#define SDHCI_CDNS_HRS04 0x10 +/* Cadence V4 HRS04 Description*/ +#define SDHCI_CDNS_HRS04_ACK BIT(26) +#define SDHCI_CDNS_HRS04_RD BIT(25) +#define SDHCI_CDNS_HRS04_WR BIT(24) +#define SDHCI_CDNS_HRS04_RDATA GENMASK(23, 16) +#define SDHCI_CDNS_HRS04_WDATA GENMASK(15, 8) +#define SDHCI_CDNS_HRS04_ADDR GENMASK(5, 0) + +#define SDHCI_CDNS_HRS05 0x14 + +/* eMMC control */ +#define SDHCI_CDNS_HRS06 0x18 +#define SDHCI_CDNS_HRS06_TUNE_UP BIT(15) +#define SDHCI_CDNS_HRS06_TUNE GENMASK(13, 8) +#define SDHCI_CDNS_HRS06_MODE GENMASK(2, 0) +#define SDHCI_CDNS_HRS06_MODE_SD 0x0 +#define SDHCI_CDNS_HRS06_MODE_MMC_SDR 0x2 +#define SDHCI_CDNS_HRS06_MODE_MMC_DDR 0x3 +#define SDHCI_CDNS_HRS06_MODE_MMC_HS200 0x4 +#define SDHCI_CDNS_HRS06_MODE_MMC_HS400 0x5 +#define SDHCI_CDNS_HRS06_MODE_MMC_HS400ES 0x6 + +/* SRS - Slot Register Set (SDHCI-compatible) */ +#define SDHCI_CDNS_SRS_BASE 0x200 + +/* Cadence V4 PHY Setting*/ +#define SDHCI_CDNS_PHY_DLY_SD_HS 0x00 +#define SDHCI_CDNS_PHY_DLY_SD_DEFAULT 0x01 +#define SDHCI_CDNS_PHY_DLY_UHS_SDR12 0x02 +#define SDHCI_CDNS_PHY_DLY_UHS_SDR25 0x03 +#define SDHCI_CDNS_PHY_DLY_UHS_SDR50 0x04 +#define SDHCI_CDNS_PHY_DLY_UHS_DDR50 0x05 +#define SDHCI_CDNS_PHY_DLY_EMMC_LEGACY 0x06 +#define SDHCI_CDNS_PHY_DLY_EMMC_SDR 0x07 +#define SDHCI_CDNS_PHY_DLY_EMMC_DDR 0x08 +#define SDHCI_CDNS_PHY_DLY_SDCLK 0x0b +#define SDHCI_CDNS_PHY_DLY_HSMMC 0x0c +#define SDHCI_CDNS_PHY_DLY_STROBE 0x0d + +/* + * The tuned val register is 6 bit-wide, but not the whole of the range is + * available. The range 0-42 seems to be available (then 43 wraps around to 0) + * but I am not quite sure if it is official. Use only 0 to 39 for safety. + */ +#define SDHCI_CDNS_MAX_TUNING_LOOP 40 + +struct sdhci_cdns_plat { + struct mmc_config cfg; + struct mmc mmc; + void __iomem *hrs_addr; +}; + +int sdhci_cdns6_phy_adj(struct udevice *dev, struct sdhci_cdns_plat *plat, u32 mode); +int sdhci_cdns6_phy_init(struct udevice *dev, struct sdhci_cdns_plat *plat); +int sdhci_cdns6_set_tune_val(struct sdhci_cdns_plat *plat, unsigned int val); + +#endif diff --git a/drivers/mmc/sdhci-cadence6.c b/drivers/mmc/sdhci-cadence6.c new file mode 100644 index 00000000000..a5ed87321ab --- /dev/null +++ b/drivers/mmc/sdhci-cadence6.c @@ -0,0 +1,293 @@ +// SPDX-License-Identifier: GPL-2.0-or-platform_driver +/* + * Copyright (C) 2023 Starfive. + * Author: Kuan Lim Lee <kuanlim.lee@starfivetech.com> + */ + +#include <dm.h> +#include <asm/global_data.h> +#include <dm/device_compat.h> +#include <linux/bitfield.h> +#include <linux/bitops.h> +#include <linux/bug.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/sizes.h> +#include <linux/libfdt.h> +#include <mmc.h> +#include <sdhci.h> +#include "sdhci-cadence.h" + +/* IO Delay Information */ +#define SDHCI_CDNS_HRS07 0X1C +#define SDHCI_CDNS_HRS07_RW_COMPENSATE GENMASK(20, 16) +#define SDHCI_CDNS_HRS07_IDELAY_VAL GENMASK(4, 0) + +/* PHY Control and Status */ +#define SDHCI_CDNS_HRS09 0x24 +#define SDHCI_CDNS_HRS09_RDDATA_EN BIT(16) +#define SDHCI_CDNS_HRS09_RDCMD_EN BIT(15) +#define SDHCI_CDNS_HRS09_EXTENDED_WR_MODE BIT(3) +#define SDHCI_CDNS_HRS09_EXTENDED_RD_MODE BIT(2) +#define SDHCI_CDNS_HRS09_PHY_INIT_COMPLETE BIT(1) +#define SDHCI_CDNS_HRS09_PHY_SW_RESET BIT(0) + +/* SDCLK adjustment */ +#define SDHCI_CDNS_HRS10 0x28 +#define SDHCI_CDNS_HRS10_HCSDCLKADJ GENMASK(19, 16) + +/* CMD/DAT output delay */ +#define SDHCI_CDNS_HRS16 0x40 + +/* PHY Special Function Registers */ +/* register to control the DQ related timing */ +#define PHY_DQ_TIMING_REG_ADDR 0x2000 + +/* register to control the DQS related timing */ +#define PHY_DQS_TIMING_REG_ADDR 0x2004 + +/* register to control the gate and loopback control related timing */ +#define PHY_GATE_LPBK_CTRL_REG_ADDR 0x2008 + +/* register to control the Master DLL logic */ +#define PHY_DLL_MASTER_CTRL_REG_ADDR 0x200C + +/* register to control the Slave DLL logic */ +#define PHY_DLL_SLAVE_CTRL_REG_ADDR 0x2010 +#define PHY_DLL_SLAVE_CTRL_REG_READ_DQS_CMD_DELAY GENMASK(31, 24) +#define PHY_DLL_SLAVE_CTRL_REG_READ_DQS_DELAY GENMASK(7, 0) + +#define SDHCI_CDNS6_PHY_CFG_NUM 4 +#define SDHCI_CDNS6_CTRL_CFG_NUM 4 + +struct sdhci_cdns6_phy_cfg { + const char *property; + u32 val; +}; + +struct sdhci_cdns6_ctrl_cfg { + const char *property; + u32 val; +}; + +static struct sdhci_cdns6_phy_cfg sd_ds_phy_cfgs[] = { + { "cdns,phy-dqs-timing-delay-sd-ds", 0x00380004, }, + { "cdns,phy-gate-lpbk_ctrl-delay-sd-ds", 0x01A00040, }, + { "cdns,phy-dll-slave-ctrl-sd-ds", 0x00000000, }, + { "cdns,phy-dq-timing-delay-sd-ds", 0x00000001, }, +}; + +static struct sdhci_cdns6_phy_cfg emmc_sdr_phy_cfgs[] = { + { "cdns,phy-dqs-timing-delay-semmc-sdr", 0x00380004, }, + { "cdns,phy-gate-lpbk_ctrl-delay-emmc-sdr", 0x01A00040, }, + { "cdns,phy-dll-slave-ctrl-emmc-sdr", 0x00000000, }, + { "cdns,phy-dq-timing-delay-emmc-sdr", 0x00000001, }, +}; + +static struct sdhci_cdns6_phy_cfg emmc_ddr_phy_cfgs[] = { + { "cdns,phy-dqs-timing-delay-emmc-ddr", 0x00380004, }, + { "cdns,phy-gate-lpbk_ctrl-delay-emmc-ddr", 0x01A00040, }, + { "cdns,phy-dll-slave-ctrl-emmc-ddr", 0x00000000, }, + { "cdns,phy-dq-timing-delay-emmc-ddr", 0x10000001, }, +}; + +static struct sdhci_cdns6_phy_cfg emmc_hs200_phy_cfgs[] = { + { "cdns,phy-dqs-timing-delay-emmc-hs200", 0x00380004, }, + { "cdns,phy-gate-lpbk_ctrl-delay-emmc-hs200", 0x01A00040, }, + { "cdns,phy-dll-slave-ctrl-emmc-hs200", 0x00DADA00, }, + { "cdns,phy-dq-timing-delay-emmc-hs200", 0x00000001, }, +}; + +static struct sdhci_cdns6_phy_cfg emmc_hs400_phy_cfgs[] = { + { "cdns,phy-dqs-timing-delay-emmc-hs400", 0x00280004, }, + { "cdns,phy-gate-lpbk_ctrl-delay-emmc-hs400", 0x01A00040, }, + { "cdns,phy-dll-slave-ctrl-emmc-hs400", 0x00DAD800, }, + { "cdns,phy-dq-timing-delay-emmc-hs400", 0x00000001, }, +}; + +static struct sdhci_cdns6_ctrl_cfg sd_ds_ctrl_cfgs[] = { + { "cdns,ctrl-hrs09-timing-delay-sd-ds", 0x0001800C, }, + { "cdns,ctrl-hrs10-lpbk_ctrl-delay-sd-ds", 0x00020000, }, + { "cdns,ctrl-hrs16-slave-ctrl-sd-ds", 0x00000000, }, + { "cdns,ctrl-hrs07-timing-delay-sd-ds", 0x00080000, }, +}; + +static struct sdhci_cdns6_ctrl_cfg emmc_sdr_ctrl_cfgs[] = { + { "cdns,ctrl-hrs09-timing-delay-emmc-sdr", 0x0001800C, }, + { "cdns,ctrl-hrs10-lpbk_ctrl-delay-emmc-sdr", 0x00030000, }, + { "cdns,ctrl-hrs16-slave-ctrl-emmc-sdr", 0x00000000, }, + { "cdns,ctrl-hrs07-timing-delay-emmc-sdr", 0x00080000, }, +}; + +static struct sdhci_cdns6_ctrl_cfg emmc_ddr_ctrl_cfgs[] = { + { "cdns,ctrl-hrs09-timing-delay-emmc-ddr", 0x0001800C, }, + { "cdns,ctrl-hrs10-lpbk_ctrl-delay-emmc-ddr", 0x00020000, }, + { "cdns,ctrl-hrs16-slave-ctrl-emmc-ddr", 0x11000001, }, + { "cdns,ctrl-hrs07-timing-delay-emmc-ddr", 0x00090001, }, +}; + +static struct sdhci_cdns6_ctrl_cfg emmc_hs200_ctrl_cfgs[] = { + { "cdns,ctrl-hrs09-timing-delay-emmc-hs200", 0x00018000, }, + { "cdns,ctrl-hrs10-lpbk_ctrl-delay-emmc-hs200", 0x00080000, }, + { "cdns,ctrl-hrs16-slave-ctrl-emmc-hs200", 0x00000000, }, + { "cdns,ctrl-hrs07-timing-delay-emmc-hs200", 0x00090000, }, +}; + +static struct sdhci_cdns6_ctrl_cfg emmc_hs400_ctrl_cfgs[] = { + { "cdns,ctrl-hrs09-timing-delay-emmc-hs400", 0x00018000, }, + { "cdns,ctrl-hrs10-lpbk_ctrl-delay-emmc-hs400", 0x00080000, }, + { "cdns,ctrl-hrs16-slave-ctrl-emmc-hs400", 0x11000000, }, + { "cdns,ctrl-hrs07-timing-delay-emmc-hs400", 0x00080000, }, +}; + +static u32 sdhci_cdns6_read_phy_reg(struct sdhci_cdns_plat *plat, u32 addr) +{ + writel(addr, plat->hrs_addr + SDHCI_CDNS_HRS04); + return readl(plat->hrs_addr + SDHCI_CDNS_HRS05); +} + +static void sdhci_cdns6_write_phy_reg(struct sdhci_cdns_plat *plat, u32 addr, u32 val) +{ + writel(addr, plat->hrs_addr + SDHCI_CDNS_HRS04); + writel(val, plat->hrs_addr + SDHCI_CDNS_HRS05); +} + +static int sdhci_cdns6_reset_phy_dll(struct sdhci_cdns_plat *plat, bool reset) +{ + void __iomem *reg = plat->hrs_addr + SDHCI_CDNS_HRS09; + u32 tmp; + int ret; + + tmp = readl(reg); + tmp &= ~SDHCI_CDNS_HRS09_PHY_SW_RESET; + + /* Switch On DLL Reset */ + if (reset) + tmp |= FIELD_PREP(SDHCI_CDNS_HRS09_PHY_SW_RESET, 0); + else + tmp |= FIELD_PREP(SDHCI_CDNS_HRS09_PHY_SW_RESET, 1); + + writel(tmp, reg); + + /* After reset, wait until HRS09.PHY_INIT_COMPLETE is set to 1 within 3000us*/ + if (!reset) { + ret = readl_poll_timeout(reg, tmp, (tmp & SDHCI_CDNS_HRS09_PHY_INIT_COMPLETE), + 3000); + } + + return ret; +} + +int sdhci_cdns6_phy_adj(struct udevice *dev, struct sdhci_cdns_plat *plat, u32 mode) +{ + DECLARE_GLOBAL_DATA_PTR; + struct sdhci_cdns6_phy_cfg *sdhci_cdns6_phy_cfgs; + struct sdhci_cdns6_ctrl_cfg *sdhci_cdns6_ctrl_cfgs; + const fdt32_t *prop; + u32 tmp; + int i, ret; + + switch (mode) { + case SDHCI_CDNS_HRS06_MODE_SD: + sdhci_cdns6_phy_cfgs = sd_ds_phy_cfgs; + sdhci_cdns6_ctrl_cfgs = sd_ds_ctrl_cfgs; + break; + + case SDHCI_CDNS_HRS06_MODE_MMC_SDR: + sdhci_cdns6_phy_cfgs = emmc_sdr_phy_cfgs; + sdhci_cdns6_ctrl_cfgs = emmc_sdr_ctrl_cfgs; + break; + + case SDHCI_CDNS_HRS06_MODE_MMC_DDR: + sdhci_cdns6_phy_cfgs = emmc_ddr_phy_cfgs; + sdhci_cdns6_ctrl_cfgs = emmc_ddr_ctrl_cfgs; + break; + + case SDHCI_CDNS_HRS06_MODE_MMC_HS200: + sdhci_cdns6_phy_cfgs = emmc_hs200_phy_cfgs; + sdhci_cdns6_ctrl_cfgs = emmc_hs200_ctrl_cfgs; + break; + + case SDHCI_CDNS_HRS06_MODE_MMC_HS400: + sdhci_cdns6_phy_cfgs = emmc_hs400_phy_cfgs; + sdhci_cdns6_ctrl_cfgs = emmc_hs400_ctrl_cfgs; + break; + default: + return -EINVAL; + } + + for (i = 0; i < SDHCI_CDNS6_PHY_CFG_NUM; i++) { + prop = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), + sdhci_cdns6_phy_cfgs[i].property, NULL); + if (prop) + sdhci_cdns6_phy_cfgs[i].val = *prop; + } + + for (i = 0; i < SDHCI_CDNS6_CTRL_CFG_NUM; i++) { + prop = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), + sdhci_cdns6_ctrl_cfgs[i].property, NULL); + if (prop) + sdhci_cdns6_ctrl_cfgs[i].val = *prop; + } + + /* Switch On the DLL Reset */ + sdhci_cdns6_reset_phy_dll(plat, true); + + sdhci_cdns6_write_phy_reg(plat, PHY_DQS_TIMING_REG_ADDR, sdhci_cdns6_phy_cfgs[0].val); + sdhci_cdns6_write_phy_reg(plat, PHY_GATE_LPBK_CTRL_REG_ADDR, sdhci_cdns6_phy_cfgs[1].val); + sdhci_cdns6_write_phy_reg(plat, PHY_DLL_SLAVE_CTRL_REG_ADDR, sdhci_cdns6_phy_cfgs[2].val); + + /* Switch Off the DLL Reset */ + ret = sdhci_cdns6_reset_phy_dll(plat, false); + if (ret) { + printf("sdhci_cdns6_reset_phy is not completed\n"); + return ret; + } + + /* Set PHY DQ TIMING control register */ + sdhci_cdns6_write_phy_reg(plat, PHY_DQ_TIMING_REG_ADDR, sdhci_cdns6_phy_cfgs[3].val); + + /* Set HRS09 register */ + tmp = readl(plat->hrs_addr + SDHCI_CDNS_HRS09); + tmp &= ~(SDHCI_CDNS_HRS09_EXTENDED_WR_MODE | + SDHCI_CDNS_HRS09_EXTENDED_RD_MODE | + SDHCI_CDNS_HRS09_RDDATA_EN | + SDHCI_CDNS_HRS09_RDCMD_EN); + tmp |= sdhci_cdns6_ctrl_cfgs[0].val; + writel(tmp, plat->hrs_addr + SDHCI_CDNS_HRS09); + + /* Set HRS10 register */ + tmp = readl(plat->hrs_addr + SDHCI_CDNS_HRS10); + tmp &= ~SDHCI_CDNS_HRS10_HCSDCLKADJ; + tmp |= sdhci_cdns6_ctrl_cfgs[1].val; + writel(tmp, plat->hrs_addr + SDHCI_CDNS_HRS10); + + /* Set HRS16 register */ + writel(sdhci_cdns6_ctrl_cfgs[2].val, plat->hrs_addr + SDHCI_CDNS_HRS16); + + /* Set HRS07 register */ + writel(sdhci_cdns6_ctrl_cfgs[3].val, plat->hrs_addr + SDHCI_CDNS_HRS07); + + return 0; +} + +int sdhci_cdns6_phy_init(struct udevice *dev, struct sdhci_cdns_plat *plat) +{ + return sdhci_cdns6_phy_adj(dev, plat, SDHCI_CDNS_HRS06_MODE_SD); +} + +int sdhci_cdns6_set_tune_val(struct sdhci_cdns_plat *plat, unsigned int val) +{ + u32 tmp, tuneval; + + tuneval = (val * 256) / SDHCI_CDNS_MAX_TUNING_LOOP; + + tmp = sdhci_cdns6_read_phy_reg(plat, PHY_DLL_SLAVE_CTRL_REG_ADDR); + tmp &= ~(PHY_DLL_SLAVE_CTRL_REG_READ_DQS_CMD_DELAY | + PHY_DLL_SLAVE_CTRL_REG_READ_DQS_DELAY); + tmp |= FIELD_PREP(PHY_DLL_SLAVE_CTRL_REG_READ_DQS_CMD_DELAY, tuneval) | + FIELD_PREP(PHY_DLL_SLAVE_CTRL_REG_READ_DQS_DELAY, tuneval); + sdhci_cdns6_write_phy_reg(plat, PHY_DLL_SLAVE_CTRL_REG_ADDR, tmp); + + return 0; +} diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index af654ea8d13..4833b5158c7 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -7,7 +7,6 @@ * Murray.Jensen@cmst.csiro.au, 27-Jan-01. */ -#include <common.h> #include <cpu_func.h> #include <dm.h> #include <errno.h> @@ -15,6 +14,7 @@ #include <malloc.h> #include <mmc.h> #include <sdhci.h> +#include <time.h> #include <asm/cache.h> #include <linux/bitops.h> #include <linux/delay.h> @@ -32,8 +32,7 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask) sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET); while (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask) { if (timeout == 0) { - printf("%s: Reset 0x%x never completed.\n", - __func__, (int)mask); + log_warning("Reset %#x never completed\n", mask); return; } timeout--; @@ -139,8 +138,7 @@ static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data) do { stat = sdhci_readl(host, SDHCI_INT_STATUS); if (stat & SDHCI_INT_ERROR) { - pr_debug("%s: Error detected in status(0x%X)!\n", - __func__, stat); + log_debug("Error detected in status(%#x)!\n", stat); return -EIO; } if (!transfer_done && (stat & rdy)) { @@ -173,7 +171,7 @@ static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data) if (timeout-- > 0) udelay(10); else { - printf("%s: Transfer data timeout\n", __func__); + log_err("Transfer data timeout\n"); return -ETIMEDOUT; } } while (!(stat & SDHCI_INT_DATA_END)); @@ -232,13 +230,13 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) { if (time >= cmd_timeout) { - printf("%s: MMC: %d busy ", __func__, mmc_dev); + log_warning("mmc%d busy ", mmc_dev); if (2 * cmd_timeout <= SDHCI_CMD_MAX_TIMEOUT) { cmd_timeout += cmd_timeout; - printf("timeout increasing to: %u ms.\n", - cmd_timeout); + log_warning("timeout increasing to: %u ms\n", + cmd_timeout); } else { - puts("timeout.\n"); + log_warning("timeout\n"); return -ECOMM; } } @@ -316,8 +314,8 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, } if (get_timer(start) >= SDHCI_READ_STATUS_TIMEOUT) { - printf("%s: Timeout for status update: %08x %08x\n", - __func__, stat, mask); + log_warning("Timeout for status update: %08x %08x\n", + stat, mask); return -ETIMEDOUT; } } while ((stat & mask) != mask); @@ -351,14 +349,14 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, return -ECOMM; } -#if defined(CONFIG_DM_MMC) && defined(MMC_SUPPORTS_TUNING) +#if defined(CONFIG_DM_MMC) && CONFIG_IS_ENABLED(MMC_SUPPORTS_TUNING) static int sdhci_execute_tuning(struct udevice *dev, uint opcode) { int err; struct mmc *mmc = mmc_get_mmc_dev(dev); struct sdhci_host *host = mmc->priv; - debug("%s\n", __func__); + log_debug("sdhci tuning\n"); if (host->ops && host->ops->platform_execute_tuning) { err = host->ops->platform_execute_tuning(mmc, opcode); @@ -380,8 +378,7 @@ int sdhci_set_clock(struct mmc *mmc, unsigned int clock) while (sdhci_readl(host, SDHCI_PRESENT_STATE) & (SDHCI_CMD_INHIBIT | SDHCI_DATA_INHIBIT)) { if (timeout == 0) { - printf("%s: Timeout to wait cmd & data inhibit\n", - __func__); + log_err("Timeout waiting for cmd & data inhibit\n"); return -EBUSY; } @@ -397,7 +394,7 @@ int sdhci_set_clock(struct mmc *mmc, unsigned int clock) if (host->ops && host->ops->set_delay) { ret = host->ops->set_delay(host); if (ret) { - printf("%s: Error while setting tap delay\n", __func__); + log_err("Error while setting tap delay\n"); return ret; } } @@ -405,7 +402,7 @@ int sdhci_set_clock(struct mmc *mmc, unsigned int clock) if (host->ops && host->ops->config_dll) { ret = host->ops->config_dll(host, clock, false); if (ret) { - printf("%s: Error while configuring dll\n", __func__); + log_err("Error configuring dll\n"); return ret; } } @@ -456,7 +453,7 @@ int sdhci_set_clock(struct mmc *mmc, unsigned int clock) if (host->ops && host->ops->config_dll) { ret = host->ops->config_dll(host, clock, true); if (ret) { - printf("%s: Error while configuring dll\n", __func__); + log_err("Error while configuring dll\n"); return ret; } } @@ -472,8 +469,7 @@ int sdhci_set_clock(struct mmc *mmc, unsigned int clock) while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL)) & SDHCI_CLOCK_INT_STABLE)) { if (timeout == 0) { - printf("%s: Internal clock never stabilised.\n", - __func__); + log_err("Internal clock never stabilised.\n"); return -EBUSY; } timeout--; @@ -738,8 +734,7 @@ static int sdhci_init(struct mmc *mmc) if (host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) { host->align_buffer = memalign(8, 512 * 1024); if (!host->align_buffer) { - printf("%s: Aligned buffer alloc failed!!!\n", - __func__); + log_err("Aligned buffer alloc failed\n"); return -ENOMEM; } } @@ -848,7 +843,7 @@ const struct dm_mmc_ops sdhci_ops = { .set_ios = sdhci_set_ios, .get_cd = sdhci_get_cd, .deferred_probe = sdhci_deferred_probe, -#ifdef MMC_SUPPORTS_TUNING +#if CONFIG_IS_ENABLED(MMC_SUPPORTS_TUNING) .execute_tuning = sdhci_execute_tuning, #endif .wait_dat0 = sdhci_wait_dat0, @@ -881,20 +876,18 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host, #else caps = sdhci_readl(host, SDHCI_CAPABILITIES); #endif - debug("%s, caps: 0x%x\n", __func__, caps); + log_debug("caps: %#x\n", caps); #if CONFIG_IS_ENABLED(MMC_SDHCI_SDMA) if ((caps & SDHCI_CAN_DO_SDMA)) { host->flags |= USE_SDMA; } else { - debug("%s: Your controller doesn't support SDMA!!\n", - __func__); + log_debug("Controller doesn't support SDMA\n"); } #endif #if CONFIG_IS_ENABLED(MMC_SDHCI_ADMA) if (!(caps & SDHCI_CAN_DO_ADMA2)) { - printf("%s: Your controller doesn't support ADMA!!\n", - __func__); + log_err("Controller doesn't support ADMA\n"); return -EINVAL; } if (!host->adma_desc_table) { @@ -927,7 +920,7 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host, #else caps_1 = sdhci_readl(host, SDHCI_CAPABILITIES_1); #endif - debug("%s, caps_1: 0x%x\n", __func__, caps_1); + log_debug("caps_1: %#x\n", caps_1); host->clk_mul = (caps_1 & SDHCI_CLOCK_MUL_MASK) >> SDHCI_CLOCK_MUL_SHIFT; @@ -953,8 +946,7 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host, host->max_clk *= host->clk_mul; } if (host->max_clk == 0) { - printf("%s: Hardware doesn't specify base clock frequency\n", - __func__); + log_err("Hardware doesn't specify base clock frequency\n"); return -EINVAL; } if (f_max && (f_max < host->max_clk)) @@ -1047,7 +1039,7 @@ int add_sdhci(struct sdhci_host *host, u32 f_max, u32 f_min) host->mmc = mmc_create(&host->cfg, host); if (host->mmc == NULL) { - printf("%s: mmc create fail!\n", __func__); + log_err("mmc create fail\n"); return -ENOMEM; } diff --git a/drivers/mmc/sh_mmcif.c b/drivers/mmc/sh_mmcif.c index 76dc1c68b82..06a30d5efb8 100644 --- a/drivers/mmc/sh_mmcif.c +++ b/drivers/mmc/sh_mmcif.c @@ -6,7 +6,6 @@ */ #include <config.h> -#include <common.h> #include <log.h> #include <watchdog.h> #include <command.h> diff --git a/drivers/mmc/snps_dw_mmc.c b/drivers/mmc/snps_dw_mmc.c index 0134399e393..47ab5654bd6 100644 --- a/drivers/mmc/snps_dw_mmc.c +++ b/drivers/mmc/snps_dw_mmc.c @@ -7,12 +7,12 @@ * Author: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com> */ -#include <common.h> #include <clk.h> #include <dm.h> #include <dwmmc.h> #include <errno.h> #include <fdtdec.h> +#include <asm/gpio.h> #include <dm/device_compat.h> #include <linux/libfdt.h> #include <linux/err.h> @@ -30,6 +30,7 @@ struct snps_dwmci_plat { struct snps_dwmci_priv_data { struct dwmci_host host; u32 f_max; + struct gpio_desc cd_gpio; }; static int snps_dwmmc_clk_setup(struct udevice *dev) @@ -82,7 +83,7 @@ static int snps_dwmmc_of_to_plat(struct udevice *dev) host->ioaddr = dev_read_addr_ptr(dev); /* - * If fifo-depth is unset don't set fifoth_val - we will try to + * If fifo-depth is unset don't set fifo_depth - we will try to * auto detect it. */ ret = dev_read_u32(dev, "fifo-depth", &fifo_depth); @@ -90,9 +91,7 @@ static int snps_dwmmc_of_to_plat(struct udevice *dev) if (fifo_depth < FIFO_MIN || fifo_depth > FIFO_MAX) return -EINVAL; - host->fifoth_val = MSIZE(0x2) | - RX_WMARK(fifo_depth / 2 - 1) | - TX_WMARK(fifo_depth / 2); + host->fifo_depth = fifo_depth; } host->buswidth = dev_read_u32_default(dev, "bus-width", 4); @@ -107,6 +106,10 @@ static int snps_dwmmc_of_to_plat(struct udevice *dev) if (!ret && priv->f_max < CLOCK_MIN) return -EINVAL; + if (CONFIG_IS_ENABLED(DM_GPIO)) + gpio_request_by_name(dev, "cd-gpios", 0, &priv->cd_gpio, + GPIOD_IS_IN); + host->fifo_mode = dev_read_bool(dev, "fifo-mode"); host->name = dev->name; host->dev_index = 0; @@ -120,6 +123,9 @@ int snps_dwmmc_getcd(struct udevice *dev) struct snps_dwmci_priv_data *priv = dev_get_priv(dev); struct dwmci_host *host = &priv->host; + if (CONFIG_IS_ENABLED(DM_GPIO) && dm_gpio_is_valid(&priv->cd_gpio)) + return dm_gpio_get_value(&priv->cd_gpio); + return !(dwmci_readl(host, DWMCI_CDETECT) & 1); } diff --git a/drivers/mmc/socfpga_dw_mmc.c b/drivers/mmc/socfpga_dw_mmc.c index 387cb8b6b50..3147d3019c0 100644 --- a/drivers/mmc/socfpga_dw_mmc.c +++ b/drivers/mmc/socfpga_dw_mmc.c @@ -3,7 +3,6 @@ * (C) Copyright 2013 Altera Corporation <www.altera.com> */ -#include <common.h> #include <log.h> #include <asm/arch/clock_manager.h> #include <asm/arch/secure_reg_helper.h> @@ -135,8 +134,8 @@ static int socfpga_dwmmc_of_to_plat(struct udevice *dev) * We only have one dwmmc block on gen5 SoCFPGA. */ host->dev_index = 0; - host->fifoth_val = MSIZE(0x2) | - RX_WMARK(fifo_depth / 2 - 1) | TX_WMARK(fifo_depth / 2); + + host->fifo_depth = fifo_depth; priv->drvsel = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev), "drvsel", 3); priv->smplsel = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev), diff --git a/drivers/mmc/sti_sdhci.c b/drivers/mmc/sti_sdhci.c index 23a1dd43c9b..91018b7e21a 100644 --- a/drivers/mmc/sti_sdhci.c +++ b/drivers/mmc/sti_sdhci.c @@ -4,7 +4,6 @@ * Author(s): Patrice Chotard, <patrice.chotard@foss.st.com> for STMicroelectronics. */ -#include <common.h> #include <dm.h> #include <log.h> #include <mmc.h> diff --git a/drivers/mmc/stm32_sdmmc2.c b/drivers/mmc/stm32_sdmmc2.c index 39ae79ba129..9483fb57daf 100644 --- a/drivers/mmc/stm32_sdmmc2.c +++ b/drivers/mmc/stm32_sdmmc2.c @@ -6,7 +6,6 @@ #define LOG_CATEGORY UCLASS_MMC -#include <common.h> #include <clk.h> #include <cpu_func.h> #include <dm.h> diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c index 714706d2411..0b56d1405be 100644 --- a/drivers/mmc/sunxi_mmc.c +++ b/drivers/mmc/sunxi_mmc.c @@ -13,7 +13,6 @@ * proper DM_MMC implementation at the end. */ -#include <common.h> #include <dm.h> #include <errno.h> #include <log.h> diff --git a/drivers/mmc/tangier_sdhci.c b/drivers/mmc/tangier_sdhci.c index 11564273324..ae65c310b68 100644 --- a/drivers/mmc/tangier_sdhci.c +++ b/drivers/mmc/tangier_sdhci.c @@ -2,7 +2,6 @@ /* * Copyright (c) 2017 Intel Corporation */ -#include <common.h> #include <dm.h> #include <dm/device.h> #include <linux/io.h> diff --git a/drivers/mmc/tegra_mmc.c b/drivers/mmc/tegra_mmc.c index c01fb3d0165..355991beb0f 100644 --- a/drivers/mmc/tegra_mmc.c +++ b/drivers/mmc/tegra_mmc.c @@ -7,7 +7,6 @@ */ #include <bouncebuf.h> -#include <common.h> #include <dm.h> #include <errno.h> #include <log.h> @@ -81,7 +80,6 @@ static void tegra_mmc_prepare_data(struct tegra_mmc_priv *priv, { unsigned char ctrl; - debug("buf: %p (%p), data->blocks: %u, data->blocksize: %u\n", bbstate->bounce_buffer, bbstate->user_buffer, data->blocks, data->blocksize); diff --git a/drivers/mmc/tmio-common.c b/drivers/mmc/tmio-common.c index 719c4830bc3..0b396122b46 100644 --- a/drivers/mmc/tmio-common.c +++ b/drivers/mmc/tmio-common.c @@ -4,7 +4,6 @@ * Author: Masahiro Yamada <yamada.masahiro@socionext.com> */ -#include <common.h> #include <clk.h> #include <cpu_func.h> #include <fdtdec.h> diff --git a/drivers/mmc/uniphier-sd.c b/drivers/mmc/uniphier-sd.c index 8cde4308aae..5b3650d52ee 100644 --- a/drivers/mmc/uniphier-sd.c +++ b/drivers/mmc/uniphier-sd.c @@ -4,7 +4,6 @@ * Author: Masahiro Yamada <yamada.masahiro@socionext.com> */ -#include <common.h> #include <clk.h> #include <fdtdec.h> #include <malloc.h> diff --git a/drivers/mmc/xenon_sdhci.c b/drivers/mmc/xenon_sdhci.c index 27dbe0404e0..0e4902fab77 100644 --- a/drivers/mmc/xenon_sdhci.c +++ b/drivers/mmc/xenon_sdhci.c @@ -14,7 +14,6 @@ * Stefan Roese <sr@denx.de> */ -#include <common.h> #include <dm.h> #include <fdtdec.h> #include <asm/global_data.h> diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c index 935540d1719..24d0556cd37 100644 --- a/drivers/mmc/zynq_sdhci.c +++ b/drivers/mmc/zynq_sdhci.c @@ -7,7 +7,6 @@ */ #include <clk.h> -#include <common.h> #include <dm.h> #include <fdtdec.h> #include <linux/delay.h> @@ -106,6 +105,19 @@ struct arasan_sdhci_priv { struct reset_ctl_bulk resets; }; +enum arasan_sdhci_compatible { + SDHCI_COMPATIBLE_SDHCI_89A, + SDHCI_COMPATIBLE_VERSAL_NET_EMMC, +}; + +static bool arasan_sdhci_is_compatible(struct udevice *dev, + enum arasan_sdhci_compatible family) +{ + enum arasan_sdhci_compatible compat = dev_get_driver_data(dev); + + return compat == family; +} + /* For Versal platforms zynqmp_mmio_write() won't be available */ __weak int zynqmp_mmio_write(const u32 address, const u32 mask, const u32 value) { @@ -123,7 +135,8 @@ __weak int zynqmp_pm_is_function_supported(const u32 api_id, const u32 id) return 1; } -#if defined(CONFIG_ARCH_ZYNQMP) || defined(CONFIG_ARCH_VERSAL) || defined(CONFIG_ARCH_VERSAL_NET) +#if defined(CONFIG_ARCH_ZYNQMP) || defined(CONFIG_ARCH_VERSAL) || \ + defined(CONFIG_ARCH_VERSAL_NET) || defined(CONFIG_ARCH_VERSAL2) /* Default settings for ZynqMP Clock Phases */ static const u32 zynqmp_iclk_phases[] = {0, 63, 63, 0, 63, 0, 0, 183, 54, 0, 0}; @@ -157,7 +170,7 @@ static const u8 mode2timing[] = { [MMC_HS_400] = MMC_TIMING_MMC_HS400, }; -#if defined(CONFIG_ARCH_VERSAL_NET) +#if defined(CONFIG_ARCH_VERSAL_NET) || defined(CONFIG_ARCH_VERSAL2) /** * arasan_phy_set_delaychain - Set eMMC delay chain based Input/Output clock * @@ -422,7 +435,7 @@ static int arasan_sdhci_execute_tuning(struct mmc *mmc, u8 opcode) mdelay(1); - if (device_is_compatible(mmc->dev, "xlnx,zynqmp-8.9a")) + if (arasan_sdhci_is_compatible(mmc->dev, SDHCI_COMPATIBLE_SDHCI_89A)) arasan_zynqmp_dll_reset(host, priv->node_id); sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_INT_ENABLE); @@ -470,7 +483,7 @@ static int arasan_sdhci_execute_tuning(struct mmc *mmc, u8 opcode) udelay(1); - if (device_is_compatible(mmc->dev, "xlnx,zynqmp-8.9a")) + if (arasan_sdhci_is_compatible(mmc->dev, SDHCI_COMPATIBLE_SDHCI_89A)) arasan_zynqmp_dll_reset(host, priv->node_id); /* Enable only interrupts served by the SD controller */ @@ -858,7 +871,7 @@ static int arasan_sdhci_set_tapdelay(struct sdhci_host *host) dev_dbg(dev, "%s, host:%s, mode:%d\n", __func__, host->name, timing); if (IS_ENABLED(CONFIG_ARCH_ZYNQMP) && - device_is_compatible(dev, "xlnx,zynqmp-8.9a")) { + arasan_sdhci_is_compatible(dev, SDHCI_COMPATIBLE_SDHCI_89A)) { ret = sdhci_zynqmp_sampleclk_set_phase(host, iclk_phase); if (ret) return ret; @@ -866,8 +879,10 @@ static int arasan_sdhci_set_tapdelay(struct sdhci_host *host) ret = sdhci_zynqmp_sdcardclk_set_phase(host, oclk_phase); if (ret) return ret; - } else if (IS_ENABLED(CONFIG_ARCH_VERSAL) && - device_is_compatible(dev, "xlnx,versal-8.9a")) { + } else if ((IS_ENABLED(CONFIG_ARCH_VERSAL) || + IS_ENABLED(CONFIG_ARCH_VERSAL_NET) || + IS_ENABLED(CONFIG_ARCH_VERSAL2)) && + arasan_sdhci_is_compatible(dev, SDHCI_COMPATIBLE_SDHCI_89A)) { ret = sdhci_versal_sampleclk_set_phase(host, iclk_phase); if (ret) return ret; @@ -875,8 +890,9 @@ static int arasan_sdhci_set_tapdelay(struct sdhci_host *host) ret = sdhci_versal_sdcardclk_set_phase(host, oclk_phase); if (ret) return ret; - } else if (IS_ENABLED(CONFIG_ARCH_VERSAL_NET) && - device_is_compatible(dev, "xlnx,versal-net-emmc")) { + } else if ((IS_ENABLED(CONFIG_ARCH_VERSAL_NET) || + IS_ENABLED(CONFIG_ARCH_VERSAL2)) && + arasan_sdhci_is_compatible(dev, SDHCI_COMPATIBLE_VERSAL_NET_EMMC)) { if (mmc->clock >= MIN_PHY_CLK_HZ) if (iclk_phase == VERSAL_NET_EMMC_ICLK_PHASE_DDR52_DLY_CHAIN) iclk_phase = VERSAL_NET_EMMC_ICLK_PHASE_DDR52_DLL; @@ -930,7 +946,7 @@ static void arasan_dt_parse_clk_phases(struct udevice *dev) int i; if (IS_ENABLED(CONFIG_ARCH_ZYNQMP) && - device_is_compatible(dev, "xlnx,zynqmp-8.9a")) { + arasan_sdhci_is_compatible(dev, SDHCI_COMPATIBLE_SDHCI_89A)) { for (i = 0; i <= MMC_TIMING_MMC_HS400; i++) { clk_data->clk_phase_in[i] = zynqmp_iclk_phases[i]; clk_data->clk_phase_out[i] = zynqmp_oclk_phases[i]; @@ -942,16 +958,19 @@ static void arasan_dt_parse_clk_phases(struct udevice *dev) } } - if (IS_ENABLED(CONFIG_ARCH_VERSAL) && - device_is_compatible(dev, "xlnx,versal-8.9a")) { + if ((IS_ENABLED(CONFIG_ARCH_VERSAL) || + IS_ENABLED(CONFIG_ARCH_VERSAL_NET) || + IS_ENABLED(CONFIG_ARCH_VERSAL2)) && + arasan_sdhci_is_compatible(dev, SDHCI_COMPATIBLE_SDHCI_89A)) { for (i = 0; i <= MMC_TIMING_MMC_HS400; i++) { clk_data->clk_phase_in[i] = versal_iclk_phases[i]; clk_data->clk_phase_out[i] = versal_oclk_phases[i]; } } - if (IS_ENABLED(CONFIG_ARCH_VERSAL_NET) && - device_is_compatible(dev, "xlnx,versal-net-emmc")) { + if ((IS_ENABLED(CONFIG_ARCH_VERSAL_NET) || + IS_ENABLED(CONFIG_ARCH_VERSAL2)) && + arasan_sdhci_is_compatible(dev, SDHCI_COMPATIBLE_VERSAL_NET_EMMC)) { for (i = 0; i <= MMC_TIMING_MMC_HS400; i++) { clk_data->clk_phase_in[i] = versal_net_emmc_iclk_phases[i]; clk_data->clk_phase_out[i] = versal_net_emmc_oclk_phases[i]; @@ -986,7 +1005,7 @@ static const struct sdhci_ops arasan_ops = { .platform_execute_tuning = &arasan_sdhci_execute_tuning, .set_delay = &arasan_sdhci_set_tapdelay, .set_control_reg = &sdhci_set_control_reg, -#if defined(CONFIG_ARCH_VERSAL_NET) +#if defined(CONFIG_ARCH_VERSAL_NET) || defined(CONFIG_ARCH_VERSAL2) .config_dll = &arasan_sdhci_config_dll, #endif }; @@ -1095,7 +1114,7 @@ static int arasan_sdhci_probe(struct udevice *dev) host = priv->host; #if defined(CONFIG_ARCH_ZYNQMP) && defined(CONFIG_ZYNQMP_FIRMWARE) - if (device_is_compatible(dev, "xlnx,zynqmp-8.9a")) { + if (arasan_sdhci_is_compatible(dev, SDHCI_COMPATIBLE_SDHCI_89A)) { ret = zynqmp_pm_is_function_supported(PM_IOCTL, IOCTL_SET_SD_CONFIG); if (!ret) { @@ -1105,7 +1124,7 @@ static int arasan_sdhci_probe(struct udevice *dev) } } #endif - if (device_is_compatible(dev, "xlnx,versal-net-emmc")) + if (arasan_sdhci_is_compatible(dev, SDHCI_COMPATIBLE_VERSAL_NET_EMMC)) priv->internal_phy_reg = true; ret = clk_get_by_index(dev, 0, &clk); @@ -1139,7 +1158,7 @@ static int arasan_sdhci_probe(struct udevice *dev) host->quirks |= SDHCI_QUIRK_NO_1_8_V; if (CONFIG_IS_ENABLED(ARCH_VERSAL_NET) && - device_is_compatible(dev, "xlnx,versal-net-emmc")) + arasan_sdhci_is_compatible(dev, SDHCI_COMPATIBLE_VERSAL_NET_EMMC)) host->quirks |= SDHCI_QUIRK_CAPS_BIT63_FOR_HS400; plat->cfg.f_max = CONFIG_ZYNQ_SDHCI_MAX_FREQ; @@ -1194,7 +1213,8 @@ static int arasan_sdhci_of_to_plat(struct udevice *dev) priv->host->name = dev->name; -#if defined(CONFIG_ARCH_ZYNQMP) || defined(CONFIG_ARCH_VERSAL) || defined(CONFIG_ARCH_VERSAL_NET) +#if defined(CONFIG_ARCH_ZYNQMP) || defined(CONFIG_ARCH_VERSAL) || defined(CONFIG_ARCH_VERSAL_NET) || \ + defined(CONFIG_ARCH_VERSAL2) priv->host->ops = &arasan_ops; arasan_dt_parse_clk_phases(dev); #endif @@ -1221,8 +1241,8 @@ static int arasan_sdhci_bind(struct udevice *dev) } static const struct udevice_id arasan_sdhci_ids[] = { - { .compatible = "arasan,sdhci-8.9a" }, - { .compatible = "xlnx,versal-net-emmc" }, + { .compatible = "arasan,sdhci-8.9a", .data = SDHCI_COMPATIBLE_SDHCI_89A }, + { .compatible = "xlnx,versal-net-emmc", .data = SDHCI_COMPATIBLE_VERSAL_NET_EMMC }, { } }; |