From 9df731a176aab8e03b984b681b1bea01ccff6644 Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Mon, 06 Nov 2023 07:23:06 +0000 Subject: [PATCH] rk3568 rt uboot init --- u-boot/drivers/mmc/rockchip_sdhci.c | 212 ++++++++++++++++++++++++++++++++++++++++++---------- 1 files changed, 169 insertions(+), 43 deletions(-) diff --git a/u-boot/drivers/mmc/rockchip_sdhci.c b/u-boot/drivers/mmc/rockchip_sdhci.c index d6224da..327c0d2 100644 --- a/u-boot/drivers/mmc/rockchip_sdhci.c +++ b/u-boot/drivers/mmc/rockchip_sdhci.c @@ -39,6 +39,12 @@ ((((x) >> PHYCTRL_DLLRDY_SHIFT) & PHYCTRL_DLLRDY_MASK) ==\ PHYCTRL_DLLRDY_DONE) +#define ARASAN_VENDOR_REGISTER 0x78 +#define ARASAN_VENDOR_ENHANCED_STROBE BIT(0) + +/* DWC IP vendor area 1 pointer */ +#define DWCMSHC_P_VENDOR_AREA1 0xe8 +#define DWCMSHC_AREA1_MASK GENMASK(11, 0) /* Rockchip specific Registers */ #define DWCMSHC_CTRL_HS400 0x7 #define DWCMSHC_CARD_IS_EMMC BIT(0) @@ -46,6 +52,7 @@ #define DWCMSHC_HOST_CTRL3 0x508 #define DWCMSHC_EMMC_CONTROL 0x52c +#define DWCMSHC_EMMC_ATCTRL 0x540 #define DWCMSHC_EMMC_DLL_CTRL 0x800 #define DWCMSHC_EMMC_DLL_CTRL_RESET BIT(1) #define DWCMSHC_EMMC_DLL_RXCLK 0x804 @@ -55,25 +62,31 @@ #define DWCMSHC_EMMC_DLL_STATUS0 0x840 #define DWCMSHC_EMMC_DLL_STATUS1 0x844 #define DWCMSHC_EMMC_DLL_START BIT(0) -#define DWCMSHC_EMMC_DLL_RXCLK_SRCSEL 29 #define DWCMSHC_EMMC_DLL_START_POINT 16 #define DWCMSHC_EMMC_DLL_START_DEFAULT 5 #define DWCMSHC_EMMC_DLL_INC_VALUE 2 #define DWCMSHC_EMMC_DLL_INC 8 +#define DWCMSHC_EMMC_DLL_BYPASS BIT(24) #define DWCMSHC_EMMC_DLL_DLYENA BIT(27) #define DLL_TXCLK_TAPNUM_DEFAULT 0x10 -#define DLL_TXCLK_TAPNUM_90_DEGREES 0x8 -#define DLL_STRBIN_TAPNUM_DEFAULT 0x3 +#define DLL_TXCLK_TAPNUM_90_DEGREES 0x9 +#define DLL_STRBIN_TAPNUM_DEFAULT 0x4 +#define DLL_STRBIN_DELAY_NUM_OFFSET 16 +#define DLL_STRBIN_TAPNUM_FROM_SW BIT(24) +#define DLL_STRBIN_DELAY_NUM_SEL BIT(26) #define DLL_TXCLK_TAPNUM_FROM_SW BIT(24) #define DLL_TXCLK_NO_INVERTER BIT(29) #define DWCMSHC_EMMC_DLL_LOCKED BIT(8) #define DWCMSHC_EMMC_DLL_TIMEOUT BIT(9) -#define DLL_RXCLK_NO_INVERTER 1 -#define DLL_RXCLK_INVERTER 0 +#define DLL_TAP_VALUE_SEL BIT(25) +#define DLL_TAP_VALUE_OFFSET 8 +#define DLL_RXCLK_NO_INVERTER BIT(29) +#define DLL_RXCLK_ORI_GATE BIT(31) #define DLL_CMDOUT_TAPNUM_90_DEGREES 0x8 #define DLL_CMDOUT_TAPNUM_FROM_SW BIT(24) #define DLL_CMDOUT_SRC_CLK_NEG BIT(28) #define DLL_CMDOUT_EN_SRC_CLK_NEG BIT(29) +#define DLL_CMDOUT_BOTH_CLK_EDGE BIT(30) #define DWCMSHC_ENHANCED_STROBE BIT(8) #define DLL_LOCK_WO_TMOUT(x) \ @@ -106,10 +119,18 @@ struct sdhci_data { int (*emmc_set_clock)(struct sdhci_host *host, unsigned int clock); void (*set_ios_post)(struct sdhci_host *host); + int (*set_enhanced_strobe)(struct sdhci_host *host); int (*get_phy)(struct udevice *dev); u32 flags; #define RK_DLL_CMD_OUT BIT(1) #define RK_RXCLK_NO_INVERTER BIT(2) +#define RK_TAP_VALUE_SEL BIT(3) + + u8 hs200_tx_tap; + u8 hs400_tx_tap; + u8 hs400_cmd_tap; + u8 hs400_strbin_tap; + u8 ddr50_strbin_delay_num; }; static void rk3399_emmc_phy_power_on(struct rockchip_emmc_phy *phy, u32 clock) @@ -254,21 +275,7 @@ clk |= SDHCI_CLOCK_INT_EN; sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); - /* Wait max 20 ms */ - timeout = 20; - while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL)) - & SDHCI_CLOCK_INT_STABLE)) { - if (timeout == 0) { - printf("%s: Internal clock never stabilised.\n", - __func__); - return -EBUSY; - } - timeout--; - udelay(1000); - } - clk |= SDHCI_CLOCK_CARD_EN; - sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); - host->clock = clock; + sdhci_enable_clk(host, clk); return 0; } @@ -323,16 +330,24 @@ { struct rockchip_sdhc *priv = container_of(host, struct rockchip_sdhc, host); struct sdhci_data *data = (struct sdhci_data *)dev_get_driver_data(priv->dev); - u32 extra; + u32 txclk_tapnum, extra, dll_lock_value; int timeout = 500, ret; ret = rockchip_emmc_set_clock(host, clock); + + /* Disable output clock while config DLL */ + sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); if (clock >= 100 * MHz) { /* reset DLL */ sdhci_writel(host, DWCMSHC_EMMC_DLL_CTRL_RESET, DWCMSHC_EMMC_DLL_CTRL); udelay(1); sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_CTRL); + + extra = 0x1 << 16 | /* tune clock stop en */ + 0x2 << 17 | /* pre-change delay */ + 0x3 << 19; /* post-change delay */ + sdhci_writel(host, extra, DWCMSHC_EMMC_ATCTRL); /* Init DLL settings */ extra = DWCMSHC_EMMC_DLL_START_DEFAULT << DWCMSHC_EMMC_DLL_START_POINT | @@ -341,48 +356,106 @@ sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_CTRL); while (1) { - if (timeout < 0) - return -ETIMEDOUT; + if (timeout < 0) { + ret = -ETIMEDOUT; + goto exit; + } if (DLL_LOCK_WO_TMOUT((sdhci_readl(host, DWCMSHC_EMMC_DLL_STATUS0)))) break; udelay(1); timeout--; } - extra = DWCMSHC_EMMC_DLL_DLYENA; + dll_lock_value = ((sdhci_readl(host, DWCMSHC_EMMC_DLL_STATUS0) & 0xFF) * 2 ) & 0xFF; + extra = DWCMSHC_EMMC_DLL_DLYENA | DLL_RXCLK_ORI_GATE; if (data->flags & RK_RXCLK_NO_INVERTER) - extra |= DLL_RXCLK_NO_INVERTER << DWCMSHC_EMMC_DLL_RXCLK_SRCSEL; + extra |= DLL_RXCLK_NO_INVERTER; + if (data->flags & RK_TAP_VALUE_SEL) + extra |= DLL_TAP_VALUE_SEL | (dll_lock_value << DLL_TAP_VALUE_OFFSET); sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_RXCLK); + + txclk_tapnum = data->hs200_tx_tap; + if ((data->flags & RK_DLL_CMD_OUT) && + (host->mmc->timing == MMC_TIMING_MMC_HS400 || + host->mmc->timing == MMC_TIMING_MMC_HS400ES)) { + txclk_tapnum = data->hs400_tx_tap; + + extra = DLL_CMDOUT_SRC_CLK_NEG | + DLL_CMDOUT_BOTH_CLK_EDGE | + DWCMSHC_EMMC_DLL_DLYENA | + data->hs400_cmd_tap | + DLL_CMDOUT_TAPNUM_FROM_SW; + if (data->flags & RK_TAP_VALUE_SEL) + extra |= DLL_TAP_VALUE_SEL | (dll_lock_value << DLL_TAP_VALUE_OFFSET); + sdhci_writel(host, extra, DECMSHC_EMMC_DLL_CMDOUT); + } extra = DWCMSHC_EMMC_DLL_DLYENA | DLL_TXCLK_TAPNUM_FROM_SW | DLL_TXCLK_NO_INVERTER| - DLL_TXCLK_TAPNUM_DEFAULT; - + txclk_tapnum; + if (data->flags & RK_TAP_VALUE_SEL) + extra |= DLL_TAP_VALUE_SEL | (dll_lock_value << DLL_TAP_VALUE_OFFSET); sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_TXCLK); extra = DWCMSHC_EMMC_DLL_DLYENA | - DLL_STRBIN_TAPNUM_DEFAULT; + data->hs400_strbin_tap | + DLL_STRBIN_TAPNUM_FROM_SW; + if (data->flags & RK_TAP_VALUE_SEL) + extra |= DLL_TAP_VALUE_SEL | (dll_lock_value << DLL_TAP_VALUE_OFFSET); sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_STRBIN); } else { + /* disable dll */ + sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_CTRL); + /* Disable cmd conflict check */ extra = sdhci_readl(host, DWCMSHC_HOST_CTRL3); extra &= ~BIT(0); sdhci_writel(host, extra, DWCMSHC_HOST_CTRL3); /* reset the clock phase when the frequency is lower than 100MHz */ - sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_CTRL); - sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_RXCLK); + sdhci_writel(host, DWCMSHC_EMMC_DLL_BYPASS | DWCMSHC_EMMC_DLL_START, DWCMSHC_EMMC_DLL_CTRL); + sdhci_writel(host, DLL_RXCLK_ORI_GATE, DWCMSHC_EMMC_DLL_RXCLK); sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_TXCLK); - sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_STRBIN); sdhci_writel(host, 0, DECMSHC_EMMC_DLL_CMDOUT); + /* + * Before switching to hs400es mode, the driver will enable + * enhanced strobe first. PHY needs to configure the parameters + * of enhanced strobe first. + */ + extra = DWCMSHC_EMMC_DLL_DLYENA | + DLL_STRBIN_DELAY_NUM_SEL | + data->ddr50_strbin_delay_num << DLL_STRBIN_DELAY_NUM_OFFSET; + sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_STRBIN); } + +exit: + /* enable output clock */ + sdhci_enable_clk(host, 0); + return ret; +} + +static int dwcmshc_sdhci_set_enhanced_strobe(struct sdhci_host *host) +{ + struct mmc *mmc = host->mmc; + u32 vendor; + + vendor = sdhci_readl(host, DWCMSHC_EMMC_CONTROL); + if (mmc->timing == MMC_TIMING_MMC_HS400ES) + vendor |= DWCMSHC_ENHANCED_STROBE; + else + vendor &= ~DWCMSHC_ENHANCED_STROBE; + sdhci_writel(host, vendor, DWCMSHC_EMMC_CONTROL); + + /* some emmc device need a delay before send command */ + udelay(100); + + return 0; } static void dwcmshc_sdhci_set_ios_post(struct sdhci_host *host) { u16 ctrl; - u32 extra; u32 timing = host->mmc->timing; if (timing == MMC_TIMING_MMC_HS400 || timing == MMC_TIMING_MMC_HS400ES) { @@ -395,16 +468,6 @@ ctrl = sdhci_readw(host, DWCMSHC_EMMC_CONTROL); ctrl |= DWCMSHC_CARD_IS_EMMC; sdhci_writew(host, ctrl, DWCMSHC_EMMC_CONTROL); - - extra = DLL_CMDOUT_SRC_CLK_NEG | - DLL_CMDOUT_EN_SRC_CLK_NEG; - sdhci_writel(host, extra, DECMSHC_EMMC_DLL_CMDOUT); - - extra = DWCMSHC_EMMC_DLL_DLYENA | - DLL_TXCLK_TAPNUM_FROM_SW | - DLL_TXCLK_NO_INVERTER| - DLL_TXCLK_TAPNUM_90_DEGREES; - sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_TXCLK); } } @@ -434,9 +497,21 @@ data->set_ios_post(host); } +static int rockchip_sdhci_set_enhanced_strobe(struct sdhci_host *host) +{ + struct rockchip_sdhc *priv = container_of(host, struct rockchip_sdhc, host); + struct sdhci_data *data = (struct sdhci_data *)dev_get_driver_data(priv->dev); + + if (data->set_enhanced_strobe) + return data->set_enhanced_strobe(host); + + return -ENOTSUPP; +} + static struct sdhci_ops rockchip_sdhci_ops = { .set_clock = rockchip_sdhci_set_clock, .set_ios_post = rockchip_sdhci_set_ios_post, + .set_enhanced_strobe = rockchip_sdhci_set_enhanced_strobe, }; static int rockchip_sdhci_probe(struct udevice *dev) @@ -496,7 +571,13 @@ host->host_caps |= MMC_MODE_HS200; else if (dev_read_bool(dev, "mmc-hs400-1_8v")) host->host_caps |= MMC_MODE_HS400; + + if (data->set_enhanced_strobe && dev_read_bool(dev, "mmc-hs400-enhanced-strobe")) + host->host_caps |= MMC_MODE_HS400ES; + ret = sdhci_setup_cfg(&plat->cfg, host, 0, EMMC_MIN_FREQ); + + plat->cfg.fixed_drv_type = dev_read_u32_default(dev, "fixed-emmc-driver-type", 0); host->mmc = &plat->mmc; if (ret) @@ -536,13 +617,50 @@ .emmc_set_clock = dwcmshc_sdhci_emmc_set_clock, .get_phy = dwcmshc_emmc_get_phy, .flags = RK_RXCLK_NO_INVERTER, + .hs200_tx_tap = 16, + .hs400_tx_tap = 8, + .hs400_cmd_tap = 8, + .hs400_strbin_tap = 3, + .ddr50_strbin_delay_num = 16, }; static const struct sdhci_data rk3588_data = { .emmc_set_clock = dwcmshc_sdhci_emmc_set_clock, .get_phy = dwcmshc_emmc_get_phy, .set_ios_post = dwcmshc_sdhci_set_ios_post, - .flags = RK_DLL_CMD_OUT | RK_RXCLK_NO_INVERTER, + .set_enhanced_strobe = dwcmshc_sdhci_set_enhanced_strobe, + .flags = RK_DLL_CMD_OUT, + .hs200_tx_tap = 16, + .hs400_tx_tap = 9, + .hs400_cmd_tap = 8, + .hs400_strbin_tap = 3, + .ddr50_strbin_delay_num = 16, +}; + +static const struct sdhci_data rk3528_data = { + .emmc_set_clock = dwcmshc_sdhci_emmc_set_clock, + .get_phy = dwcmshc_emmc_get_phy, + .set_ios_post = dwcmshc_sdhci_set_ios_post, + .set_enhanced_strobe = dwcmshc_sdhci_set_enhanced_strobe, + .flags = RK_DLL_CMD_OUT | RK_TAP_VALUE_SEL, + .hs200_tx_tap = 12, + .hs400_tx_tap = 6, + .hs400_cmd_tap = 6, + .hs400_strbin_tap = 3, + .ddr50_strbin_delay_num = 10, +}; + +static const struct sdhci_data rk3562_data = { + .emmc_set_clock = dwcmshc_sdhci_emmc_set_clock, + .get_phy = dwcmshc_emmc_get_phy, + .set_ios_post = dwcmshc_sdhci_set_ios_post, + .set_enhanced_strobe = dwcmshc_sdhci_set_enhanced_strobe, + .flags = RK_DLL_CMD_OUT | RK_TAP_VALUE_SEL, + .hs200_tx_tap = 12, + .hs400_tx_tap = 6, + .hs400_cmd_tap = 6, + .hs400_strbin_tap = 3, + .ddr50_strbin_delay_num = 10, }; static const struct udevice_id sdhci_ids[] = { @@ -555,6 +673,14 @@ .data = (ulong)&rk3568_data, }, { + .compatible = "rockchip,rk3528-dwcmshc", + .data = (ulong)&rk3528_data, + }, + { + .compatible = "rockchip,rk3562-dwcmshc", + .data = (ulong)&rk3562_data, + }, + { .compatible = "rockchip,rk3588-dwcmshc", .data = (ulong)&rk3588_data, }, -- Gitblit v1.6.2