From 701a51e1ef6c727e7a4b5a48b8681f42a447072b Mon Sep 17 00:00:00 2001 From: Andy Yan Date: Fri, 31 May 2019 15:44:39 +0800 Subject: dm: mmc: remove unused U_BOOT_DRIVER(mmc) When look through the code, I found this bare metal drives is not used, so remove it. Signed-off-by: Andy Yan Reviewed-by: Simon Glass --- drivers/mmc/mmc-uclass.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c index 2b146ea43c..4a12324c6a 100644 --- a/drivers/mmc/mmc-uclass.c +++ b/drivers/mmc/mmc-uclass.c @@ -427,10 +427,6 @@ U_BOOT_DRIVER(mmc_blk) = { }; #endif /* CONFIG_BLK */ -U_BOOT_DRIVER(mmc) = { - .name = "mmc", - .id = UCLASS_MMC, -}; UCLASS_DRIVER(mmc) = { .id = UCLASS_MMC, -- cgit v1.2.1 From 116cffeca6fe4de701d4cd5e2b5bfe5e0f1597a9 Mon Sep 17 00:00:00 2001 From: Sam Protsenko Date: Wed, 14 Aug 2019 22:52:50 +0300 Subject: mmc: Fix timeout values passed to mmc_wait_dat0() mmc_wait_dat0() expects timeout argument to be in usec units. But some overlying functions operate on timeout in msec units. Convert timeout from msec to usec when passing it to mmc_wait_dat0(). This fixes 'avb' commands on BeagleBoard X15, because next chain was failing: get_partition() -> mmc_switch_part() -> __mmc_switch() -> mmc_wait_dat0() when passing incorrect timeout from __mmc_switch() to mmc_wait_dat0(). Fixes: bb98b8c5c06a ("mmc: During a switch, poll on dat0 if available and check the final status") Signed-off-by: Sam Protsenko Reviewed-by: Eugeniu Rosca Tested-by: Eugeniu Rosca Reviewed-by: Peng Fan Tested-by: Igor Opaniuk Reviewed-by: Igor Opaniuk --- drivers/mmc/mmc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index eecc7d687e..e247730ff2 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -235,7 +235,7 @@ int mmc_poll_for_busy(struct mmc *mmc, int timeout) unsigned int status; int err; - err = mmc_wait_dat0(mmc, 1, timeout); + err = mmc_wait_dat0(mmc, 1, timeout * 1000); if (err != -ENOSYS) return err; @@ -778,7 +778,7 @@ static int __mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value, start = get_timer(0); /* poll dat0 for rdy/buys status */ - ret = mmc_wait_dat0(mmc, 1, timeout); + ret = mmc_wait_dat0(mmc, 1, timeout * 1000); if (ret && ret != -ENOSYS) return ret; -- cgit v1.2.1 From 6cf8a903c5e6723104b07b0fddc4a703556e558a Mon Sep 17 00:00:00 2001 From: Sam Protsenko Date: Wed, 14 Aug 2019 22:52:51 +0300 Subject: mmc: Rename timeout parameters for clarification It's quite hard to figure out time units for various function that have timeout parameters. This leads to possible errors when one forgets to convert ms to us, for example. Let's rename those parameters correspondingly to 'timeout_us' and 'timeout_ms' to prevent such issues further. While at it, add time units info as comments to struct mmc fields. This commit doesn't change the behavior, only renames parameters names. Buildman should report no changes at all. Signed-off-by: Sam Protsenko Reviewed-by: Peng Fan Reviewed-by: Igor Opaniuk --- drivers/mmc/mmc-uclass.c | 8 ++++---- drivers/mmc/mmc.c | 24 ++++++++++++------------ drivers/mmc/mmc_write.c | 8 ++++---- drivers/mmc/omap_hsmmc.c | 6 +++--- drivers/mmc/renesas-sdhi.c | 7 ++++--- include/mmc.h | 12 ++++++------ 6 files changed, 33 insertions(+), 32 deletions(-) diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c index 4a12324c6a..37c3843902 100644 --- a/drivers/mmc/mmc-uclass.c +++ b/drivers/mmc/mmc-uclass.c @@ -47,18 +47,18 @@ int mmc_set_ios(struct mmc *mmc) return dm_mmc_set_ios(mmc->dev); } -int dm_mmc_wait_dat0(struct udevice *dev, int state, int timeout) +int dm_mmc_wait_dat0(struct udevice *dev, int state, int timeout_us) { struct dm_mmc_ops *ops = mmc_get_ops(dev); if (!ops->wait_dat0) return -ENOSYS; - return ops->wait_dat0(dev, state, timeout); + return ops->wait_dat0(dev, state, timeout_us); } -int mmc_wait_dat0(struct mmc *mmc, int state, int timeout) +int mmc_wait_dat0(struct mmc *mmc, int state, int timeout_us) { - return dm_mmc_wait_dat0(mmc->dev, state, timeout); + return dm_mmc_wait_dat0(mmc->dev, state, timeout_us); } int dm_mmc_get_wp(struct udevice *dev) diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index e247730ff2..c8f71cd0c1 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -31,7 +31,7 @@ static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps); #if !CONFIG_IS_ENABLED(DM_MMC) -static int mmc_wait_dat0(struct mmc *mmc, int state, int timeout) +static int mmc_wait_dat0(struct mmc *mmc, int state, int timeout_us) { return -ENOSYS; } @@ -230,12 +230,12 @@ int mmc_send_status(struct mmc *mmc, unsigned int *status) return -ECOMM; } -int mmc_poll_for_busy(struct mmc *mmc, int timeout) +int mmc_poll_for_busy(struct mmc *mmc, int timeout_ms) { unsigned int status; int err; - err = mmc_wait_dat0(mmc, 1, timeout * 1000); + err = mmc_wait_dat0(mmc, 1, timeout_ms * 1000); if (err != -ENOSYS) return err; @@ -256,13 +256,13 @@ int mmc_poll_for_busy(struct mmc *mmc, int timeout) return -ECOMM; } - if (timeout-- <= 0) + if (timeout_ms-- <= 0) break; udelay(1000); } - if (timeout <= 0) { + if (timeout_ms <= 0) { #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) pr_err("Timeout waiting card ready\n"); #endif @@ -750,17 +750,17 @@ static int __mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value, { unsigned int status, start; struct mmc_cmd cmd; - int timeout = DEFAULT_CMD6_TIMEOUT_MS; + int timeout_ms = DEFAULT_CMD6_TIMEOUT_MS; bool is_part_switch = (set == EXT_CSD_CMD_SET_NORMAL) && (index == EXT_CSD_PART_CONF); int retries = 3; int ret; if (mmc->gen_cmd6_time) - timeout = mmc->gen_cmd6_time * 10; + timeout_ms = mmc->gen_cmd6_time * 10; if (is_part_switch && mmc->part_switch_time) - timeout = mmc->part_switch_time * 10; + timeout_ms = mmc->part_switch_time * 10; cmd.cmdidx = MMC_CMD_SWITCH; cmd.resp_type = MMC_RSP_R1b; @@ -778,7 +778,7 @@ static int __mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value, start = get_timer(0); /* poll dat0 for rdy/buys status */ - ret = mmc_wait_dat0(mmc, 1, timeout * 1000); + ret = mmc_wait_dat0(mmc, 1, timeout_ms * 1000); if (ret && ret != -ENOSYS) return ret; @@ -788,11 +788,11 @@ static int __mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value, * stated timeout to be sufficient. */ if (ret == -ENOSYS && !send_status) - mdelay(timeout); + mdelay(timeout_ms); /* Finally wait until the card is ready or indicates a failure * to switch. It doesn't hurt to use CMD13 here even if send_status - * is false, because by now (after 'timeout' ms) the bus should be + * is false, because by now (after 'timeout_ms' ms) the bus should be * reliable. */ do { @@ -806,7 +806,7 @@ static int __mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value, if (!ret && (status & MMC_STATUS_RDY_FOR_DATA)) return 0; udelay(100); - } while (get_timer(start) < timeout); + } while (get_timer(start) < timeout_ms); return -ETIMEDOUT; } diff --git a/drivers/mmc/mmc_write.c b/drivers/mmc/mmc_write.c index 02648b0f50..b52ff9f3bc 100644 --- a/drivers/mmc/mmc_write.c +++ b/drivers/mmc/mmc_write.c @@ -79,7 +79,7 @@ ulong mmc_berase(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt) u32 start_rem, blkcnt_rem; struct mmc *mmc = find_mmc_device(dev_num); lbaint_t blk = 0, blk_r = 0; - int timeout = 1000; + int timeout_ms = 1000; if (!mmc) return -1; @@ -119,7 +119,7 @@ ulong mmc_berase(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt) blk += blk_r; /* Waiting for the ready status */ - if (mmc_poll_for_busy(mmc, timeout)) + if (mmc_poll_for_busy(mmc, timeout_ms)) return 0; } @@ -131,7 +131,7 @@ static ulong mmc_write_blocks(struct mmc *mmc, lbaint_t start, { struct mmc_cmd cmd; struct mmc_data data; - int timeout = 1000; + int timeout_ms = 1000; if ((start + blkcnt) > mmc_get_blk_desc(mmc)->lba) { printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n", @@ -177,7 +177,7 @@ static ulong mmc_write_blocks(struct mmc *mmc, lbaint_t start, } /* Waiting for the ready status */ - if (mmc_poll_for_busy(mmc, timeout)) + if (mmc_poll_for_busy(mmc, timeout_ms)) return 0; return blkcnt; diff --git a/drivers/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c index 3ea7f4e173..bade129aea 100644 --- a/drivers/mmc/omap_hsmmc.c +++ b/drivers/mmc/omap_hsmmc.c @@ -430,7 +430,7 @@ static void omap_hsmmc_conf_bus_power(struct mmc *mmc, uint signal_voltage) writel(ac12, &mmc_base->ac12); } -static int omap_hsmmc_wait_dat0(struct udevice *dev, int state, int timeout) +static int omap_hsmmc_wait_dat0(struct udevice *dev, int state, int timeout_us) { int ret = -ETIMEDOUT; u32 con; @@ -442,8 +442,8 @@ static int omap_hsmmc_wait_dat0(struct udevice *dev, int state, int timeout) con = readl(&mmc_base->con); writel(con | CON_CLKEXTFREE | CON_PADEN, &mmc_base->con); - timeout = DIV_ROUND_UP(timeout, 10); /* check every 10 us. */ - while (timeout--) { + timeout_us = DIV_ROUND_UP(timeout_us, 10); /* check every 10 us. */ + while (timeout_us--) { dat0_high = !!(readl(&mmc_base->pstate) & PSTATE_DLEV_DAT0); if (dat0_high == target_dat0_high) { ret = 0; diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c index 7c53aa221e..0cb65b480d 100644 --- a/drivers/mmc/renesas-sdhi.c +++ b/drivers/mmc/renesas-sdhi.c @@ -499,15 +499,16 @@ static int renesas_sdhi_set_ios(struct udevice *dev) } #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) -static int renesas_sdhi_wait_dat0(struct udevice *dev, int state, int timeout) +static int renesas_sdhi_wait_dat0(struct udevice *dev, int state, + int timeout_us) { int ret = -ETIMEDOUT; bool dat0_high; bool target_dat0_high = !!state; struct tmio_sd_priv *priv = dev_get_priv(dev); - timeout = DIV_ROUND_UP(timeout, 10); /* check every 10 us. */ - while (timeout--) { + timeout_us = DIV_ROUND_UP(timeout_us, 10); /* check every 10 us. */ + while (timeout_us--) { dat0_high = !!(tmio_sd_readl(priv, TMIO_SD_INFO2) & TMIO_SD_INFO2_DAT0); if (dat0_high == target_dat0_high) { ret = 0; diff --git a/include/mmc.h b/include/mmc.h index 46422f41a4..686ba00656 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -457,10 +457,10 @@ struct dm_mmc_ops { * * @dev: Device to check * @state: target state - * @timeout: timeout in us + * @timeout_us: timeout in us * @return 0 if dat0 is in the target state, -ve on error */ - int (*wait_dat0)(struct udevice *dev, int state, int timeout); + int (*wait_dat0)(struct udevice *dev, int state, int timeout_us); #if CONFIG_IS_ENABLED(MMC_HS400_ES_SUPPORT) /* set_enhanced_strobe() - set HS400 enhanced strobe */ @@ -476,14 +476,14 @@ int dm_mmc_set_ios(struct udevice *dev); int dm_mmc_get_cd(struct udevice *dev); int dm_mmc_get_wp(struct udevice *dev); int dm_mmc_execute_tuning(struct udevice *dev, uint opcode); -int dm_mmc_wait_dat0(struct udevice *dev, int state, int timeout); +int dm_mmc_wait_dat0(struct udevice *dev, int state, int timeout_us); /* Transition functions for compatibility */ int mmc_set_ios(struct mmc *mmc); int mmc_getcd(struct mmc *mmc); int mmc_getwp(struct mmc *mmc); int mmc_execute_tuning(struct mmc *mmc, uint opcode); -int mmc_wait_dat0(struct mmc *mmc, int state, int timeout); +int mmc_wait_dat0(struct mmc *mmc, int state, int timeout_us); int mmc_set_enhanced_strobe(struct mmc *mmc); #else @@ -602,8 +602,8 @@ struct mmc { u8 part_attr; u8 wr_rel_set; u8 part_config; - u8 gen_cmd6_time; - u8 part_switch_time; + u8 gen_cmd6_time; /* units: 10 ms */ + u8 part_switch_time; /* units: 10 ms */ uint tran_speed; uint legacy_speed; /* speed for the legacy mode provided by the card */ uint read_bl_len; -- cgit v1.2.1 From 38c9f08b41ed9e6625b56320b78d4954cbf5fae6 Mon Sep 17 00:00:00 2001 From: Eddie James Date: Thu, 15 Aug 2019 14:29:37 -0500 Subject: clk: aspeed: Add support for SD clock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add code to enable the SD clock on the ast2500 SoC. Reviewed-by: Cédric Le Goater Signed-off-by: Eddie James --- arch/arm/include/asm/arch-aspeed/scu_ast2500.h | 3 +++ drivers/clk/aspeed/clk_ast2500.c | 27 ++++++++++++++++++++++++++ drivers/pinctrl/aspeed/pinctrl_ast2500.c | 2 ++ 3 files changed, 32 insertions(+) diff --git a/arch/arm/include/asm/arch-aspeed/scu_ast2500.h b/arch/arm/include/asm/arch-aspeed/scu_ast2500.h index 4988ced7dd..8db4901cc9 100644 --- a/arch/arm/include/asm/arch-aspeed/scu_ast2500.h +++ b/arch/arm/include/asm/arch-aspeed/scu_ast2500.h @@ -22,6 +22,8 @@ #define SCU_MPLL_POST_MASK (0x3f << SCU_MPLL_POST_SHIFT) #define SCU_PCLK_DIV_SHIFT 23 #define SCU_PCLK_DIV_MASK (7 << SCU_PCLK_DIV_SHIFT) +#define SCU_SDCLK_DIV_SHIFT 12 +#define SCU_SDCLK_DIV_MASK (7 << SCU_SDCLK_DIV_SHIFT) #define SCU_HPLL_DENUM_SHIFT 0 #define SCU_HPLL_DENUM_MASK 0x1f #define SCU_HPLL_NUM_SHIFT 5 @@ -107,6 +109,7 @@ #define SCU_CLKSTOP_MAC1 (1 << 20) #define SCU_CLKSTOP_MAC2 (1 << 21) +#define SCU_CLKSTOP_SDCLK (1 << 27) #define SCU_D2PLL_EXT1_OFF (1 << 0) #define SCU_D2PLL_EXT1_BYPASS (1 << 1) diff --git a/drivers/clk/aspeed/clk_ast2500.c b/drivers/clk/aspeed/clk_ast2500.c index dbee13a182..9249cf9cdf 100644 --- a/drivers/clk/aspeed/clk_ast2500.c +++ b/drivers/clk/aspeed/clk_ast2500.c @@ -143,6 +143,17 @@ static ulong ast2500_clk_get_rate(struct clk *clk) rate = rate / apb_div; } break; + case BCLK_SDCLK: + { + ulong apb_div = 4 + 4 * ((readl(&priv->scu->clk_sel1) + & SCU_SDCLK_DIV_MASK) + >> SCU_SDCLK_DIV_SHIFT); + rate = ast2500_get_hpll_rate(clkin, + readl(&priv-> + scu->h_pll_param)); + rate = rate / apb_div; + } + break; case PCLK_UART1: rate = ast2500_get_uart_clk_rate(priv->scu, 1); break; @@ -436,6 +447,22 @@ static int ast2500_clk_enable(struct clk *clk) struct ast2500_clk_priv *priv = dev_get_priv(clk->dev); switch (clk->id) { + case BCLK_SDCLK: + if (readl(&priv->scu->clk_stop_ctrl1) & SCU_CLKSTOP_SDCLK) { + ast_scu_unlock(priv->scu); + + setbits_le32(&priv->scu->sysreset_ctrl1, + SCU_SYSRESET_SDIO); + udelay(100); + clrbits_le32(&priv->scu->clk_stop_ctrl1, + SCU_CLKSTOP_SDCLK); + mdelay(10); + clrbits_le32(&priv->scu->sysreset_ctrl1, + SCU_SYSRESET_SDIO); + + ast_scu_lock(priv->scu); + } + break; /* * For MAC clocks the clock rate is * configured based on whether RGMII or RMII mode has been selected diff --git a/drivers/pinctrl/aspeed/pinctrl_ast2500.c b/drivers/pinctrl/aspeed/pinctrl_ast2500.c index ed333b9c5c..a6e9c0d933 100644 --- a/drivers/pinctrl/aspeed/pinctrl_ast2500.c +++ b/drivers/pinctrl/aspeed/pinctrl_ast2500.c @@ -58,6 +58,8 @@ static const struct ast2500_group_config ast2500_groups[] = { { "MDIO1", 3, (1 << 31) | (1 << 30) }, { "MAC2LINK", 1, (1 << 1) }, { "MDIO2", 5, (1 << 2) }, + { "SD1", 5, (1 << 0) }, + { "SD2", 5, (1 << 1) }, }; static int ast2500_pinctrl_get_groups_count(struct udevice *dev) -- cgit v1.2.1 From 7764ee2e832a2130e59cf030648b003ce5464560 Mon Sep 17 00:00:00 2001 From: Eddie James Date: Tue, 27 Aug 2019 09:48:03 -0500 Subject: mmc: Add Aspeed SD controller driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for the Aspeed SD host controller engine. Signed-off-by: Eddie James Reviewed-by: Cédric Le Goater --- arch/arm/include/asm/gpio.h | 3 +- drivers/mmc/Kconfig | 11 ++++++ drivers/mmc/Makefile | 1 + drivers/mmc/aspeed_sdhci.c | 90 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 drivers/mmc/aspeed_sdhci.c diff --git a/arch/arm/include/asm/gpio.h b/arch/arm/include/asm/gpio.h index b9461058ae..6ff5f42424 100644 --- a/arch/arm/include/asm/gpio.h +++ b/arch/arm/include/asm/gpio.h @@ -2,7 +2,8 @@ !defined(CONFIG_ARCH_K3) && !defined(CONFIG_ARCH_BCM6858) && \ !defined(CONFIG_ARCH_BCM63158) && !defined(CONFIG_ARCH_ROCKCHIP) && \ !defined(CONFIG_ARCH_LX2160A) && !defined(CONFIG_ARCH_LS1028A) && \ - !defined(CONFIG_ARCH_LS2080A) && !defined(CONFIG_ARCH_LS1088A) + !defined(CONFIG_ARCH_LS2080A) && !defined(CONFIG_ARCH_LS1088A) && \ + !defined(CONFIG_ARCH_ASPEED) #include #endif #include diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 0ccb1ea701..8fb2bfa444 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -421,6 +421,17 @@ config SPL_MMC_SDHCI_ADMA This enables support for the ADMA (Advanced DMA) defined in the SD Host Controller Standard Specification Version 3.00 in SPL. +config MMC_SDHCI_ASPEED + bool "Aspeed SDHCI controller" + depends on ARCH_ASPEED + depends on DM_MMC + depends on MMC_SDHCI + help + Enables support for the Aspeed SDHCI 2.0 controller present on Aspeed + SoCs. This device is compatible with SD 3.0 and/or MMC 4.3 + specifications. On the AST2600, the device is also compatible with + MMC 5.1 and eMMC 3.0. + config MMC_SDHCI_ATMEL bool "Atmel SDHCI controller support" depends on ARCH_AT91 diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 6cc018bb67..5594195528 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -46,6 +46,7 @@ obj-$(CONFIG_JZ47XX_MMC) += jz_mmc.o # SDHCI obj-$(CONFIG_MMC_SDHCI) += sdhci.o +obj-$(CONFIG_MMC_SDHCI_ASPEED) += aspeed_sdhci.o obj-$(CONFIG_MMC_SDHCI_ATMEL) += atmel_sdhci.o obj-$(CONFIG_MMC_SDHCI_BCM2835) += bcm2835_sdhci.o obj-$(CONFIG_MMC_SDHCI_BCMSTB) += bcmstb_sdhci.o diff --git a/drivers/mmc/aspeed_sdhci.c b/drivers/mmc/aspeed_sdhci.c new file mode 100644 index 0000000000..1321ec37e1 --- /dev/null +++ b/drivers/mmc/aspeed_sdhci.c @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2019 IBM Corp. + * Eddie James + */ + +#include +#include +#include +#include +#include + +struct aspeed_sdhci_plat { + struct mmc_config cfg; + struct mmc mmc; +}; + +static int aspeed_sdhci_probe(struct udevice *dev) +{ + struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); + struct aspeed_sdhci_plat *plat = dev_get_platdata(dev); + struct sdhci_host *host = dev_get_priv(dev); + u32 max_clk; + struct clk clk; + int ret; + + ret = clk_get_by_index(dev, 0, &clk); + if (ret) + return ret; + + ret = clk_enable(&clk); + if (ret) + goto free; + + host->name = dev->name; + host->ioaddr = (void *)devfdt_get_addr(dev); + + max_clk = clk_get_rate(&clk); + if (IS_ERR_VALUE(max_clk)) { + ret = max_clk; + goto err; + } + + host->max_clk = max_clk; + host->mmc = &plat->mmc; + host->mmc->dev = dev; + host->mmc->priv = host; + upriv->mmc = host->mmc; + + ret = sdhci_setup_cfg(&plat->cfg, host, 0, 0); + if (ret) + goto err; + + ret = sdhci_probe(dev); + if (ret) + goto err; + + return 0; + +err: + clk_disable(&clk); +free: + clk_free(&clk); + return ret; +} + +static int aspeed_sdhci_bind(struct udevice *dev) +{ + struct aspeed_sdhci_plat *plat = dev_get_platdata(dev); + + return sdhci_bind(dev, &plat->mmc, &plat->cfg); +} + +static const struct udevice_id aspeed_sdhci_ids[] = { + { .compatible = "aspeed,ast2400-sdhci" }, + { .compatible = "aspeed,ast2500-sdhci" }, + { .compatible = "aspeed,ast2600-sdhci" }, + { } +}; + +U_BOOT_DRIVER(aspeed_sdhci_drv) = { + .name = "aspeed_sdhci", + .id = UCLASS_MMC, + .of_match = aspeed_sdhci_ids, + .ops = &sdhci_ops, + .bind = aspeed_sdhci_bind, + .probe = aspeed_sdhci_probe, + .priv_auto_alloc_size = sizeof(struct sdhci_host), + .platdata_auto_alloc_size = sizeof(struct aspeed_sdhci_plat), +}; -- cgit v1.2.1 From c8bcd9b4b456e6a8f47f28f1d10cd74a83295e09 Mon Sep 17 00:00:00 2001 From: Eddie James Date: Thu, 15 Aug 2019 14:29:39 -0500 Subject: configs: AST2500 EVB: Enable SD controller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enable the MMC subsystem and the Aspeed SD controller. Also enable the use of the device tree for probing the controller. Signed-off-by: Eddie James Reviewed-by: Cédric Le Goater --- configs/evb-ast2500_defconfig | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/configs/evb-ast2500_defconfig b/configs/evb-ast2500_defconfig index 59d41cb568..b47ca5b52a 100644 --- a/configs/evb-ast2500_defconfig +++ b/configs/evb-ast2500_defconfig @@ -16,6 +16,7 @@ CONFIG_HUSH_PARSER=y CONFIG_CMD_I2C=y CONFIG_CMD_DHCP=y CONFIG_CMD_MII=y +CONFIG_CMD_MMC=y CONFIG_CMD_PING=y CONFIG_DEFAULT_DEVICE_TREE="ast2500-evb" CONFIG_NET_RANDOM_ETHADDR=y @@ -36,3 +37,10 @@ CONFIG_SYS_NS16550=y CONFIG_SYSRESET=y CONFIG_TIMER=y CONFIG_WDT=y +CONFIG_MMC=y +CONFIG_DM_MMC=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_ASPEED=y +CONFIG_MMC_VERBOSE=y +CONFIG_OF_CONTROL=y +CONFIG_OF_EMBED=y -- cgit v1.2.1 From 30231e0ddb84d689875958903ee48ddd6d28f37e Mon Sep 17 00:00:00 2001 From: Eddie James Date: Thu, 15 Aug 2019 14:29:40 -0500 Subject: ARM: dts: ast2500: Add SDHCI nodes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add nodes for the Aspeed SD controllers with their necessary properties. Reviewed-by: Cédric Le Goater Signed-off-by: Eddie James --- arch/arm/dts/ast2500-evb.dts | 14 ++++++++++++++ arch/arm/dts/ast2500-u-boot.dtsi | 16 ++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/arch/arm/dts/ast2500-evb.dts b/arch/arm/dts/ast2500-evb.dts index ebf44fd707..4796ed445f 100644 --- a/arch/arm/dts/ast2500-evb.dts +++ b/arch/arm/dts/ast2500-evb.dts @@ -59,3 +59,17 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_mac2link_default &pinctrl_mdio2_default>; }; + +&sdhci0 { + status = "okay"; + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sd1_default>; +}; + +&sdhci1 { + status = "okay"; + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sd2_default>; +}; diff --git a/arch/arm/dts/ast2500-u-boot.dtsi b/arch/arm/dts/ast2500-u-boot.dtsi index 7f80bad7d0..8ac4215745 100644 --- a/arch/arm/dts/ast2500-u-boot.dtsi +++ b/arch/arm/dts/ast2500-u-boot.dtsi @@ -34,6 +34,22 @@ apb { u-boot,dm-pre-reloc; + + sdhci0: sdhci@1e740100 { + compatible = "aspeed,ast2500-sdhci"; + reg = <0x1e740100>; + #reset-cells = <1>; + clocks = <&scu BCLK_SDCLK>; + resets = <&rst AST_RESET_SDIO>; + }; + + sdhci1: sdhci@1e740200 { + compatible = "aspeed,ast2500-sdhci"; + reg = <0x1e740200>; + #reset-cells = <1>; + clocks = <&scu BCLK_SDCLK>; + resets = <&rst AST_RESET_SDIO>; + }; }; }; -- cgit v1.2.1 From c077c057a49d47cdc029cce654e9895ea987fce5 Mon Sep 17 00:00:00 2001 From: Kever Yang Date: Thu, 29 Aug 2019 15:42:41 +0800 Subject: mmc: dw_mmc: fix timeout calculate method There are two cases not been considered: - use uint for timeout, it will overflow when size bigger than 512KB for it *8*1000 at the beginning, but we may use size up to 32MB; The 'timeout' will overflow if size bigger than 51.2MB after this fix, which should be enough for U-Boot; - The timeout is using clock speed for data rate, but the device may not have such high speed, eg. clock is 52MHz while the device write speed may be less than 10MB/s, and we may use up to 150MHz clock. Fix them in this patch, the max timeout is about 6500 when size is 32MB after fix. Signed-off-by: Kever Yang --- drivers/mmc/dw_mmc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c index 22f6c7eefd..ebe7bcdd90 100644 --- a/drivers/mmc/dw_mmc.c +++ b/drivers/mmc/dw_mmc.c @@ -119,11 +119,12 @@ static unsigned int dwmci_get_timeout(struct mmc *mmc, const unsigned int size) { unsigned int timeout; - timeout = size * 8 * 1000; /* counting in bits and msec */ - timeout *= 2; /* wait twice as long */ + timeout = size * 8; /* counting in bits */ + timeout *= 10; /* wait 10 times as long */ timeout /= mmc->clock; timeout /= mmc->bus_width; timeout /= mmc->ddr_mode ? 2 : 1; + timeout *= 1000; /* counting in msec */ timeout = (timeout < 1000) ? 1000 : timeout; return timeout; -- cgit v1.2.1 From d3302395e7b3deef1d7bb3eeb0c904e97ad7937d Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Fri, 30 Aug 2019 21:15:33 -0700 Subject: dm: mmc_spi: Fix NULL pointer dereference in mmc_spi_bind() The mmc_spi driver's priv is not available in its bind phase(). Use platdata instead. Fixes: 05e35d429745 ("mmc: mmc_spi: Re-write driver using DM framework") Signed-off-by: Bin Meng Reviewed-by: Peng Fan --- drivers/mmc/mmc_spi.c | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/drivers/mmc/mmc_spi.c b/drivers/mmc/mmc_spi.c index 350812a04b..c693fb2d17 100644 --- a/drivers/mmc/mmc_spi.c +++ b/drivers/mmc/mmc_spi.c @@ -58,12 +58,15 @@ #define READ_TIMEOUT 3000000 /* 1 sec */ #define WRITE_TIMEOUT 3000000 /* 1 sec */ -struct mmc_spi_priv { - struct spi_slave *spi; +struct mmc_spi_plat { struct mmc_config cfg; struct mmc mmc; }; +struct mmc_spi_priv { + struct spi_slave *spi; +}; + static int mmc_spi_sendcmd(struct udevice *dev, ushort cmdidx, u32 cmdarg, u32 resp_type, u8 *resp, u32 resp_size, @@ -370,6 +373,7 @@ done: static int mmc_spi_probe(struct udevice *dev) { struct mmc_spi_priv *priv = dev_get_priv(dev); + struct mmc_spi_plat *plat = dev_get_platdata(dev); struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); char *name; @@ -385,28 +389,28 @@ static int mmc_spi_probe(struct udevice *dev) return -ENOMEM; sprintf(name, "%s:%s", dev->parent->name, dev->name); - priv->cfg.name = name; - priv->cfg.host_caps = MMC_MODE_SPI; - priv->cfg.voltages = MMC_SPI_VOLTAGE; - priv->cfg.f_min = MMC_SPI_MIN_CLOCK; - priv->cfg.f_max = priv->spi->max_hz; - priv->cfg.part_type = PART_TYPE_DOS; - priv->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; + plat->cfg.name = name; + plat->cfg.host_caps = MMC_MODE_SPI; + plat->cfg.voltages = MMC_SPI_VOLTAGE; + plat->cfg.f_min = MMC_SPI_MIN_CLOCK; + plat->cfg.f_max = priv->spi->max_hz; + plat->cfg.part_type = PART_TYPE_DOS; + plat->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; - priv->mmc.cfg = &priv->cfg; - priv->mmc.priv = priv; - priv->mmc.dev = dev; + plat->mmc.cfg = &plat->cfg; + plat->mmc.priv = priv; + plat->mmc.dev = dev; - upriv->mmc = &priv->mmc; + upriv->mmc = &plat->mmc; return 0; } static int mmc_spi_bind(struct udevice *dev) { - struct mmc_spi_priv *priv = dev_get_priv(dev); + struct mmc_spi_plat *plat = dev_get_platdata(dev); - return mmc_bind(dev, &priv->mmc, &priv->cfg); + return mmc_bind(dev, &plat->mmc, &plat->cfg); } static const struct dm_mmc_ops mmc_spi_ops = { @@ -426,5 +430,6 @@ U_BOOT_DRIVER(mmc_spi) = { .ops = &mmc_spi_ops, .probe = mmc_spi_probe, .bind = mmc_spi_bind, + .platdata_auto_alloc_size = sizeof(struct mmc_spi_plat), .priv_auto_alloc_size = sizeof(struct mmc_spi_priv), }; -- cgit v1.2.1 From 3f3d77158b8452a16dca4a6966217b344f77f9b7 Mon Sep 17 00:00:00 2001 From: T Karthik Reddy Date: Mon, 2 Sep 2019 16:34:30 +0200 Subject: dm: core: Add functions to read 64-bit dt properties This patch adds functions dev_read_u64_default & dev_read_u64 to read unsigned 64-bit values from devicetree. Signed-off-by: T Karthik Reddy Signed-off-by: Michal Simek Reviewed-by: Bin Meng --- drivers/core/ofnode.c | 2 +- drivers/core/read.c | 10 ++++++++++ include/dm/ofnode.h | 2 +- include/dm/read.h | 33 +++++++++++++++++++++++++++++++++ 4 files changed, 45 insertions(+), 2 deletions(-) diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index e74a662d1d..7eca00cd66 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -79,7 +79,7 @@ int ofnode_read_u64(ofnode node, const char *propname, u64 *outp) return 0; } -int ofnode_read_u64_default(ofnode node, const char *propname, u64 def) +u64 ofnode_read_u64_default(ofnode node, const char *propname, u64 def) { assert(ofnode_valid(node)); ofnode_read_u64(node, propname, &def); diff --git a/drivers/core/read.c b/drivers/core/read.c index 8b5502de11..fb3dcd9a79 100644 --- a/drivers/core/read.c +++ b/drivers/core/read.c @@ -44,6 +44,16 @@ int dev_read_u32u(struct udevice *dev, const char *propname, uint *outp) return 0; } +int dev_read_u64(struct udevice *dev, const char *propname, u64 *outp) +{ + return ofnode_read_u64(dev_ofnode(dev), propname, outp); +} + +u64 dev_read_u64_default(struct udevice *dev, const char *propname, u64 def) +{ + return ofnode_read_u64_default(dev_ofnode(dev), propname, def); +} + const char *dev_read_string(struct udevice *dev, const char *propname) { return ofnode_read_string(dev_ofnode(dev), propname); diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h index 4f89db44c1..5c4cbf0998 100644 --- a/include/dm/ofnode.h +++ b/include/dm/ofnode.h @@ -254,7 +254,7 @@ int ofnode_read_u64(ofnode node, const char *propname, u64 *outp); * @def: default value to return if the property has no value * @return property value, or @def if not found */ -int ofnode_read_u64_default(ofnode node, const char *propname, u64 def); +u64 ofnode_read_u64_default(ofnode node, const char *propname, u64 def); /** * ofnode_read_string() - Read a string from a property diff --git a/include/dm/read.h b/include/dm/read.h index 0c62d62f11..803daf7620 100644 --- a/include/dm/read.h +++ b/include/dm/read.h @@ -44,6 +44,7 @@ static inline bool dev_of_valid(struct udevice *dev) } #ifndef CONFIG_DM_DEV_READ_INLINE + /** * dev_read_u32() - read a 32-bit integer from a device's DT property * @@ -96,6 +97,26 @@ int dev_read_s32_default(struct udevice *dev, const char *propname, int def); */ int dev_read_u32u(struct udevice *dev, const char *propname, uint *outp); +/** + * dev_read_u64() - read a 64-bit integer from a device's DT property + * + * @dev: device to read DT property from + * @propname: name of the property to read from + * @outp: place to put value (if found) + * @return 0 if OK, -ve on error + */ +int dev_read_u64(struct udevice *dev, const char *propname, u64 *outp); + +/** + * dev_read_u64_default() - read a 64-bit integer from a device's DT property + * + * @dev: device to read DT property from + * @propname: name of the property to read from + * @def: default value to return if the property has no value + * @return property value, or @def if not found + */ +u64 dev_read_u64_default(struct udevice *dev, const char *propname, u64 def); + /** * dev_read_string() - Read a string from a device's DT property * @@ -601,6 +622,18 @@ static inline int dev_read_u32u(struct udevice *dev, return 0; } +static inline int dev_read_u64(struct udevice *dev, + const char *propname, u64 *outp) +{ + return ofnode_read_u64(dev_ofnode(dev), propname, outp); +} + +static inline u64 dev_read_u64_default(struct udevice *dev, + const char *propname, u64 def) +{ + return ofnode_read_u64_default(dev_ofnode(dev), propname, def); +} + static inline const char *dev_read_string(struct udevice *dev, const char *propname) { -- cgit v1.2.1 From cd45d6f3955c919b7f10793014db3dbcfd7df3bb Mon Sep 17 00:00:00 2001 From: T Karthik Reddy Date: Mon, 2 Sep 2019 16:34:31 +0200 Subject: mmc: sdhci: Add support for dt caps & caps mask The sdhci capabilities registers can be incorrect. The sdhci-caps-mask and sdhci-caps dt properties specify which bits of the registers are incorrect and what their values should be. This patch makes the sdhci driver use those properties to correct the caps. Also use "dev_read_u64_default" instead of "dev_read_u32_array" for caps mask. Signed-off-by: T Karthik Reddy Signed-off-by: Michal Simek --- drivers/mmc/sdhci.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 2779bca93f..fbc576fd72 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -711,17 +711,19 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host, { u32 caps, caps_1 = 0; #if CONFIG_IS_ENABLED(DM_MMC) - u32 mask[2] = {0}; - int ret; - ret = dev_read_u32_array(host->mmc->dev, "sdhci-caps-mask", - mask, 2); - if (ret && ret != -1) - return ret; - - caps = ~mask[1] & sdhci_readl(host, SDHCI_CAPABILITIES); + u64 dt_caps, dt_caps_mask; + + dt_caps_mask = dev_read_u64_default(host->mmc->dev, + "sdhci-caps-mask", 0); + dt_caps = dev_read_u64_default(host->mmc->dev, + "sdhci-caps", 0); + caps = ~(u32)dt_caps_mask & + sdhci_readl(host, SDHCI_CAPABILITIES); + caps |= (u32)dt_caps; #else caps = sdhci_readl(host, SDHCI_CAPABILITIES); #endif + debug("%s, caps: 0x%x\n", __func__, caps); #ifdef CONFIG_MMC_SDHCI_SDMA if (!(caps & SDHCI_CAN_DO_SDMA)) { @@ -762,10 +764,13 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host, /* Check whether the clock multiplier is supported or not */ if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) { #if CONFIG_IS_ENABLED(DM_MMC) - caps_1 = ~mask[0] & sdhci_readl(host, SDHCI_CAPABILITIES_1); + caps_1 = ~(u32)(dt_caps_mask >> 32) & + sdhci_readl(host, SDHCI_CAPABILITIES_1); + caps_1 |= (u32)(dt_caps >> 32); #else caps_1 = sdhci_readl(host, SDHCI_CAPABILITIES_1); #endif + debug("%s, caps_1: 0x%x\n", __func__, caps_1); host->clk_mul = (caps_1 & SDHCI_CLOCK_MUL_MASK) >> SDHCI_CLOCK_MUL_SHIFT; } -- cgit v1.2.1