diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c index eb56f672eb0f..ce37d8173adb 100644 --- a/drivers/mmc/host/sdhci-of-dwcmshc.c +++ b/drivers/mmc/host/sdhci-of-dwcmshc.c @@ -27,11 +27,15 @@ /* DWCMSHC specific Mode Select value */ #define DWCMSHC_CTRL_HS400 0x7 -#define DWCMSHC_VER_ID 0x500 -#define DWCMSHC_VER_TYPE 0x504 -#define DWCMSHC_HOST_CTRL3 0x508 -#define DWCMSHC_EMMC_CONTROL 0x52c -#define DWCMSHC_EMMC_ATCTRL 0x540 +/* DWC IP vendor area 1 pointer */ +#define DWCMSHC_P_VENDOR_AREA1 0xe8 +#define DWCMSHC_AREA1_MASK GENMASK(11, 0) +/* Offset inside the vendor area 1 */ +#define DWCMSHC_HOST_CTRL3 0x8 +#define DWCMSHC_EMMC_CONTROL 0x2c +#define DWCMSHC_CARD_IS_EMMC BIT(0) +#define DWCMSHC_ENHANCED_STROBE BIT(8) +#define DWCMSHC_EMMC_ATCTRL 0x40 /* Rockchip specific Registers */ #define DWCMSHC_EMMC_DLL_CTRL 0x800 @@ -41,30 +45,28 @@ #define DECMSHC_EMMC_DLL_CMDOUT 0x810 #define DWCMSHC_EMMC_DLL_STATUS0 0x840 #define DWCMSHC_EMMC_DLL_STATUS1 0x844 - #define DWCMSHC_EMMC_DLL_START BIT(0) #define DWCMSHC_EMMC_DLL_LOCKED BIT(8) #define DWCMSHC_EMMC_DLL_TIMEOUT BIT(9) +#define DWCMSHC_EMMC_DLL_RXCLK_SRCSEL 29 #define DWCMSHC_EMMC_DLL_START_POINT 16 #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 0xA #define DLL_TXCLK_TAPNUM_FROM_SW BIT(24) -#define DLL_TXCLK_NO_INVERTER BIT(29) - +#define DLL_STRBIN_TAPNUM_DEFAULT 0x8 #define DLL_STRBIN_TAPNUM_FROM_SW BIT(24) #define DLL_STRBIN_DELAY_NUM_SEL BIT(26) #define DLL_STRBIN_DELAY_NUM_OFFSET 16 - +#define DLL_STRBIN_DELAY_NUM_DEFAULT 0x16 +#define DLL_RXCLK_NO_INVERTER 1 +#define DLL_RXCLK_INVERTER 0 +#define DLL_CMDOUT_TAPNUM_90_DEGREES 0x8 #define DLL_RXCLK_TAPNUM_FROM_SW BIT(24) -#define DLL_RXCLK_NO_INVERTER BIT(29) #define DLL_RXCLK_ORI_GATE BIT(31) #define DLL_RXCLK_MAX_TAP 32 - -#define DWCMSHC_CARD_IS_EMMC BIT(0) -#define DWCMSHC_ENHANCED_STROBE BIT(8) - #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) @@ -73,11 +75,16 @@ #define DLL_LOCK_WO_TMOUT(x) \ ((((x) & DWCMSHC_EMMC_DLL_LOCKED) == DWCMSHC_EMMC_DLL_LOCKED) && \ (((x) & DWCMSHC_EMMC_DLL_TIMEOUT) == 0)) -#define ROCKCHIP_MAX_CLKS 3 +#define RK35xx_MAX_CLKS 3 #define BOUNDARY_OK(addr, len) \ ((addr | (SZ_128M - 1)) == ((addr + len - 1) | (SZ_128M - 1))) +enum dwcmshc_rk_type { + DWCMSHC_RK3568, + DWCMSHC_RK3588, +}; + struct dwcmshc_driver_data { const struct sdhci_pltfm_data *pdata; u32 flags; @@ -93,19 +100,25 @@ struct dwcmshc_driver_data { u8 hs400_strbin_tap; }; -struct dwcmshc_priv { - struct clk *bus_clk; +struct rk35xx_priv { + /* Rockchip specified optional clocks */ + struct clk_bulk_data rockchip_clks[RK35xx_MAX_CLKS]; + struct reset_control *reset; + enum dwcmshc_rk_type devtype; + u8 txclk_tapnum; u32 cclk_rate; u8 hs200_rx_tap; - - /* Rockchip specified optional clocks */ - struct clk_bulk_data rockchip_clks[ROCKCHIP_MAX_CLKS]; - struct reset_control *reset; unsigned int actual_clk; const struct dwcmshc_driver_data *drv_data; u32 acpi_en; }; +struct dwcmshc_priv { + struct clk *bus_clk; + int vendor_specific_area1; /* P_VENDOR_SPECIFIC_AREA reg */ + void *priv; /* pointer to SoC private stuff */ +}; + /* * If DMA addr spans 128MB boundary, we split the DMA transfer into two * so that each DMA transfer doesn't exceed the boundary. @@ -129,6 +142,16 @@ static void dwcmshc_adma_write_desc(struct sdhci_host *host, void **desc, sdhci_adma_write_desc(host, desc, addr, len, cmd); } +static unsigned int dwcmshc_get_max_clock(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + + if (pltfm_host->clk) + return sdhci_pltfm_clk_get_max_clock(host); + else + return pltfm_host->clock; +} + static void dwcmshc_check_auto_cmd23(struct mmc_host *mmc, struct mmc_request *mrq) { @@ -155,7 +178,9 @@ static void dwcmshc_request(struct mmc_host *mmc, struct mmc_request *mrq) static void dwcmshc_set_uhs_signaling(struct sdhci_host *host, unsigned int timing) { - u16 ctrl_2, ctrl; + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); + u16 ctrl, ctrl_2; ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); /* Select Bus Speed Mode for host */ @@ -175,9 +200,9 @@ static void dwcmshc_set_uhs_signaling(struct sdhci_host *host, ctrl_2 |= SDHCI_CTRL_UHS_DDR50; else if (timing == MMC_TIMING_MMC_HS400) { /* set CARD_IS_EMMC bit to enable Data Strobe for HS400 */ - ctrl = sdhci_readw(host, DWCMSHC_EMMC_CONTROL); + ctrl = sdhci_readw(host, priv->vendor_specific_area1 + DWCMSHC_EMMC_CONTROL); ctrl |= DWCMSHC_CARD_IS_EMMC; - sdhci_writew(host, ctrl, DWCMSHC_EMMC_CONTROL); + sdhci_writew(host, ctrl, priv->vendor_specific_area1 + DWCMSHC_EMMC_CONTROL); ctrl_2 |= DWCMSHC_CTRL_HS400; } @@ -190,22 +215,28 @@ static void dwcmshc_hs400_enhanced_strobe(struct mmc_host *mmc, { u32 vendor; struct sdhci_host *host = mmc_priv(mmc); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); + int reg = priv->vendor_specific_area1 + DWCMSHC_EMMC_CONTROL; - vendor = sdhci_readl(host, DWCMSHC_EMMC_CONTROL); + vendor = sdhci_readl(host, reg); if (ios->enhanced_strobe) vendor |= DWCMSHC_ENHANCED_STROBE; else vendor &= ~DWCMSHC_ENHANCED_STROBE; - sdhci_writel(host, vendor, DWCMSHC_EMMC_CONTROL); + sdhci_writel(host, vendor, reg); } -static void dwcmshc_rk_set_clock(struct sdhci_host *host, unsigned int clock) +static void dwcmshc_rk3568_set_clock(struct sdhci_host *host, unsigned int clock) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); + struct dwcmshc_priv *dwc_priv = sdhci_pltfm_priv(pltfm_host); + struct rk35xx_priv *priv = dwc_priv->priv; const struct dwcmshc_driver_data *drv_data = priv->drv_data; - u32 txclk_tapnum, extra, rxclk_tapnum; + u8 rxclk_tapnum; + u8 txclk_tapnum = DLL_TXCLK_TAPNUM_DEFAULT; + u32 extra, reg; int err; host->mmc->actual_clock = 0; @@ -238,9 +269,10 @@ static void dwcmshc_rk_set_clock(struct sdhci_host *host, unsigned int clock) sdhci_set_clock(host, clock); /* Disable cmd conflict check */ - extra = sdhci_readl(host, DWCMSHC_HOST_CTRL3); + reg = dwc_priv->vendor_specific_area1 + DWCMSHC_HOST_CTRL3; + extra = sdhci_readl(host, reg); extra &= ~BIT(0); - sdhci_writel(host, extra, DWCMSHC_HOST_CTRL3); + sdhci_writel(host, extra, reg); if (clock <= 52000000) { /* @@ -270,6 +302,7 @@ static void dwcmshc_rk_set_clock(struct sdhci_host *host, unsigned int clock) /* Init DLL settings, clean start bit before resetting */ sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_CTRL); + /* Init DLL settings */ extra = 0x5 << DWCMSHC_EMMC_DLL_START_POINT | 0x2 << DWCMSHC_EMMC_DLL_INC | DWCMSHC_EMMC_DLL_START; @@ -285,7 +318,7 @@ static void dwcmshc_rk_set_clock(struct sdhci_host *host, unsigned int clock) extra = 0x1 << 16 | /* tune clock stop en */ 0x3 << 17 | /* pre-change delay */ 0x3 << 19; /* post-change delay */ - sdhci_writel(host, extra, DWCMSHC_EMMC_ATCTRL); + sdhci_writel(host, extra, dwc_priv->vendor_specific_area1 + DWCMSHC_EMMC_ATCTRL); rxclk_tapnum = priv->hs200_rx_tap; if ((drv_data->flags & RK_RXCLK_NO_INVERTER) && @@ -296,7 +329,7 @@ static void dwcmshc_rk_set_clock(struct sdhci_host *host, unsigned int clock) } extra = DWCMSHC_EMMC_DLL_DLYENA | DLL_RXCLK_ORI_GATE; if (drv_data->flags & RK_RXCLK_NO_INVERTER) - extra |= DLL_RXCLK_NO_INVERTER; + extra |= DLL_RXCLK_NO_INVERTER << DWCMSHC_EMMC_DLL_RXCLK_SRCSEL; if (drv_data->flags & RK_RXCLK_SW_TUNING && priv->hs200_rx_tap) extra |= DLL_RXCLK_TAPNUM_FROM_SW | rxclk_tapnum; sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_RXCLK); @@ -314,7 +347,7 @@ static void dwcmshc_rk_set_clock(struct sdhci_host *host, unsigned int clock) } extra = DWCMSHC_EMMC_DLL_DLYENA | DLL_TXCLK_TAPNUM_FROM_SW | - DLL_RXCLK_NO_INVERTER | + DLL_RXCLK_NO_INVERTER << DWCMSHC_EMMC_DLL_RXCLK_SRCSEL | txclk_tapnum; sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_TXCLK); @@ -324,19 +357,16 @@ static void dwcmshc_rk_set_clock(struct sdhci_host *host, unsigned int clock) sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_STRBIN); } -static void rockchip_sdhci_reset(struct sdhci_host *host, u8 mask) +static void rk35xx_sdhci_reset(struct sdhci_host *host, u8 mask) { - struct sdhci_pltfm_host *pltfm_host; - struct dwcmshc_priv *priv; + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct dwcmshc_priv *dwc_priv = sdhci_pltfm_priv(pltfm_host); + struct rk35xx_priv *priv = dwc_priv->priv; - if (mask & SDHCI_RESET_ALL) { - pltfm_host = sdhci_priv(host); - priv = sdhci_pltfm_priv(pltfm_host); - if (!IS_ERR_OR_NULL(priv->reset)) { - reset_control_assert(priv->reset); - udelay(1); - reset_control_deassert(priv->reset); - } + if (mask & SDHCI_RESET_ALL && priv->reset) { + reset_control_assert(priv->reset); + udelay(1); + reset_control_deassert(priv->reset); } sdhci_reset(host, mask); @@ -354,7 +384,8 @@ static int dwcmshc_rk_execute_tuning(struct mmc_host *mmc, u32 opcode) { struct sdhci_host *host = mmc_priv(mmc); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); + struct dwcmshc_priv *dwc_priv = sdhci_pltfm_priv(pltfm_host); + struct rk35xx_priv *priv = dwc_priv->priv; int rx_delay, dll_lock_num, ret; u32 extra; @@ -365,7 +396,7 @@ static int dwcmshc_rk_execute_tuning(struct mmc_host *mmc, u32 opcode) sdhci_reset_tuning(host); priv->hs200_rx_tap = rx_delay * 16 / dll_lock_num; extra = sdhci_readl(host, DWCMSHC_EMMC_DLL_RXCLK); - extra &= DLL_RXCLK_NO_INVERTER; + extra &= DLL_RXCLK_NO_INVERTER << DWCMSHC_EMMC_DLL_RXCLK_SRCSEL; extra |= DWCMSHC_EMMC_DLL_DLYENA | DLL_RXCLK_ORI_GATE | DLL_RXCLK_TAPNUM_FROM_SW | priv->hs200_rx_tap; sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_RXCLK); @@ -378,17 +409,17 @@ static const struct sdhci_ops sdhci_dwcmshc_ops = { .set_clock = sdhci_set_clock, .set_bus_width = sdhci_set_bus_width, .set_uhs_signaling = dwcmshc_set_uhs_signaling, - .get_max_clock = sdhci_pltfm_clk_get_max_clock, + .get_max_clock = dwcmshc_get_max_clock, .reset = sdhci_reset, .adma_write_desc = dwcmshc_adma_write_desc, }; -static const struct sdhci_ops sdhci_dwcmshc_rk_ops = { - .set_clock = dwcmshc_rk_set_clock, +static const struct sdhci_ops sdhci_dwcmshc_rk35xx_ops = { + .set_clock = dwcmshc_rk3568_set_clock, .set_bus_width = sdhci_set_bus_width, .set_uhs_signaling = dwcmshc_set_uhs_signaling, .get_max_clock = sdhci_pltfm_clk_get_max_clock, - .reset = rockchip_sdhci_reset, + .reset = rk35xx_sdhci_reset, .adma_write_desc = dwcmshc_adma_write_desc, .request_done = sdhci_dwcmshc_request_done, }; @@ -399,20 +430,84 @@ static const struct sdhci_pltfm_data sdhci_dwcmshc_pdata = { .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, }; -static const struct sdhci_pltfm_data sdhci_dwcmshc_rk_pdata = { - .ops = &sdhci_dwcmshc_rk_ops, +#ifdef CONFIG_ACPI +static const struct sdhci_pltfm_data sdhci_dwcmshc_bf3_pdata = { + .ops = &sdhci_dwcmshc_ops, + .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, + .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | + SDHCI_QUIRK2_ACMD23_BROKEN, +}; +#endif + +static const struct sdhci_pltfm_data sdhci_dwcmshc_rk35xx_pdata = { + .ops = &sdhci_dwcmshc_rk35xx_ops, .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL, .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN, }; +static int dwcmshc_rk35xx_init(struct sdhci_host *host, struct dwcmshc_priv *dwc_priv) +{ + int err; + struct rk35xx_priv *priv = dwc_priv->priv; + + priv->reset = devm_reset_control_array_get_optional_exclusive(mmc_dev(host->mmc)); + if (IS_ERR(priv->reset)) { + err = PTR_ERR(priv->reset); + dev_err(mmc_dev(host->mmc), "failed to get reset control %d\n", err); + return err; + } + + priv->rockchip_clks[0].id = "axi"; + priv->rockchip_clks[1].id = "block"; + priv->rockchip_clks[2].id = "timer"; + err = devm_clk_bulk_get_optional(mmc_dev(host->mmc), RK35xx_MAX_CLKS, + priv->rockchip_clks); + if (err) { + dev_err(mmc_dev(host->mmc), "failed to get clocks %d\n", err); + return err; + } + + err = clk_bulk_prepare_enable(RK35xx_MAX_CLKS, priv->rockchip_clks); + if (err) { + dev_err(mmc_dev(host->mmc), "failed to enable clocks %d\n", err); + return err; + } + + if (of_property_read_u8(mmc_dev(host->mmc)->of_node, "rockchip,txclk-tapnum", + &priv->txclk_tapnum)) + priv->txclk_tapnum = DLL_TXCLK_TAPNUM_DEFAULT; + + /* Disable cmd conflict check */ + sdhci_writel(host, 0x0, dwc_priv->vendor_specific_area1 + DWCMSHC_HOST_CTRL3); + /* Reset previous settings */ + sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_TXCLK); + sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_STRBIN); + + return 0; +} + +static void dwcmshc_rk35xx_postinit(struct sdhci_host *host, struct dwcmshc_priv *dwc_priv) +{ + /* + * Don't support highspeed bus mode with low clk speed as we + * cannot use DLL for this condition. + */ + if (host->mmc->f_max <= 52000000) { + dev_info(mmc_dev(host->mmc), "Disabling HS200/HS400, frequency too low (%d)\n", + host->mmc->f_max); + host->mmc->caps2 &= ~(MMC_CAP2_HS200 | MMC_CAP2_HS400); + host->mmc->caps &= ~(MMC_CAP_3_3V_DDR | MMC_CAP_1_8V_DDR); + } +} + static const struct dwcmshc_driver_data dwcmshc_drvdata = { .pdata = &sdhci_dwcmshc_pdata, .flags = 0, }; static const struct dwcmshc_driver_data rk3568_drvdata = { - .pdata = &sdhci_dwcmshc_rk_pdata, + .pdata = &sdhci_dwcmshc_rk35xx_pdata, .flags = RK_PLATFROM | RK_RXCLK_NO_INVERTER, .hs200_tx_tap = 16, .hs400_tx_tap = 8, @@ -422,7 +517,7 @@ static const struct dwcmshc_driver_data rk3568_drvdata = { }; static const struct dwcmshc_driver_data rk3588_drvdata = { - .pdata = &sdhci_dwcmshc_rk_pdata, + .pdata = &sdhci_dwcmshc_rk35xx_pdata, .flags = RK_PLATFROM | RK_DLL_CMD_OUT, .hs200_tx_tap = 16, .hs400_tx_tap = 9, @@ -432,7 +527,7 @@ static const struct dwcmshc_driver_data rk3588_drvdata = { }; static const struct dwcmshc_driver_data rk3528_drvdata = { - .pdata = &sdhci_dwcmshc_rk_pdata, + .pdata = &sdhci_dwcmshc_rk35xx_pdata, .flags = RK_PLATFROM | RK_DLL_CMD_OUT | RK_RXCLK_SW_TUNING | RK_RXCLK_NO_INVERTER, .hs200_tx_tap = 12, .hs400_tx_tap = 6, @@ -441,51 +536,13 @@ static const struct dwcmshc_driver_data rk3528_drvdata = { .ddr50_strbin_delay_num = 10, }; -static int rockchip_pltf_init(struct sdhci_host *host, struct dwcmshc_priv *priv) -{ - int err; - - priv->rockchip_clks[0].id = "axi"; - priv->rockchip_clks[1].id = "block"; - priv->rockchip_clks[2].id = "timer"; - err = devm_clk_bulk_get_optional(mmc_dev(host->mmc), ROCKCHIP_MAX_CLKS, - priv->rockchip_clks); - if (err) { - dev_err(mmc_dev(host->mmc), "failed to get clocks %d\n", err); - return err; - } - - err = clk_bulk_prepare_enable(ROCKCHIP_MAX_CLKS, priv->rockchip_clks); - if (err) { - dev_err(mmc_dev(host->mmc), "failed to enable clocks %d\n", err); - return err; - } - - /* Disable cmd conflict check */ - sdhci_writel(host, 0x0, DWCMSHC_HOST_CTRL3); - /* Reset previous settings */ - sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_TXCLK); - sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_STRBIN); - - /* - * Don't support highspeed bus mode with low clk speed as we - * cannot use DLL for this condition. - */ - if (host->mmc->f_max <= 52000000) { - host->mmc->caps2 &= ~(MMC_CAP2_HS200 | MMC_CAP2_HS400); - host->mmc->caps &= ~(MMC_CAP_3_3V_DDR | MMC_CAP_1_8V_DDR); - } - - return 0; -} - static const struct of_device_id sdhci_dwcmshc_dt_ids[] = { { - .compatible = "snps,dwcmshc-sdhci", - .data = &dwcmshc_drvdata, + .compatible = "rockchip,rk3588-dwcmshc", + .data = &rk3588_drvdata, }, { - .compatible = "rockchip,dwcmshc-sdhci", + .compatible = "rockchip,rk3568-dwcmshc", .data = &rk3568_drvdata, }, { @@ -493,17 +550,31 @@ static const struct of_device_id sdhci_dwcmshc_dt_ids[] = { .data = &rk3528_drvdata, }, { - .compatible = "rockchip,rk3588-dwcmshc", - .data = &rk3588_drvdata, + .compatible = "snps,dwcmshc-sdhci", + .data = &dwcmshc_drvdata, }, {}, }; +MODULE_DEVICE_TABLE(of, sdhci_dwcmshc_dt_ids); + +#ifdef CONFIG_ACPI +static const struct acpi_device_id sdhci_dwcmshc_acpi_ids[] = { + { + .id = "MLNXBF30", + .driver_data = (kernel_ulong_t)&sdhci_dwcmshc_bf3_pdata, + }, + {} +}; +#endif static int dwcmshc_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct sdhci_pltfm_host *pltfm_host; struct sdhci_host *host; struct dwcmshc_priv *priv; + struct rk35xx_priv *rk_priv = NULL; + const struct sdhci_pltfm_data *pltfm_data; const struct dwcmshc_driver_data *drv_data; struct mmc_hsq *hsq; int err; @@ -514,8 +585,9 @@ static int dwcmshc_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Error: No device match data found\n"); return -ENODEV; } + pltfm_data = drv_data->pdata; - host = sdhci_pltfm_init(pdev, drv_data->pdata, + host = sdhci_pltfm_init(pdev, pltfm_data, sizeof(struct dwcmshc_priv)); if (IS_ERR(host)) return PTR_ERR(host); @@ -523,30 +595,26 @@ static int dwcmshc_probe(struct platform_device *pdev) /* * extra adma table cnt for cross 128M boundary handling. */ - extra = DIV_ROUND_UP_ULL(dma_get_required_mask(&pdev->dev), SZ_128M); + extra = DIV_ROUND_UP_ULL(dma_get_required_mask(dev), SZ_128M); if (extra > SDHCI_MAX_SEGS) extra = SDHCI_MAX_SEGS; host->adma_table_cnt += extra; pltfm_host = sdhci_priv(host); priv = sdhci_pltfm_priv(pltfm_host); - priv->drv_data = drv_data; - priv->acpi_en = has_acpi_companion(&pdev->dev); - - if (!priv->acpi_en) { - priv->reset = devm_reset_control_array_get_exclusive(&pdev->dev); - pltfm_host->clk = devm_clk_get(&pdev->dev, "core"); + if (dev->of_node) { + pltfm_host->clk = devm_clk_get(dev, "core"); if (IS_ERR(pltfm_host->clk)) { err = PTR_ERR(pltfm_host->clk); - dev_err(&pdev->dev, "failed to get core clk: %d\n", err); + dev_err(dev, "failed to get core clk: %d\n", err); goto free_pltfm; } err = clk_prepare_enable(pltfm_host->clk); if (err) goto free_pltfm; - priv->bus_clk = devm_clk_get(&pdev->dev, "bus"); + priv->bus_clk = devm_clk_get(dev, "bus"); if (!IS_ERR(priv->bus_clk)) clk_prepare_enable(priv->bus_clk); } @@ -557,6 +625,9 @@ static int dwcmshc_probe(struct platform_device *pdev) sdhci_get_of_property(pdev); + priv->vendor_specific_area1 = + sdhci_readl(host, DWCMSHC_P_VENDOR_AREA1) & DWCMSHC_AREA1_MASK; + host->mmc_host_ops.request = dwcmshc_request; host->mmc_host_ops.hs400_enhanced_strobe = dwcmshc_hs400_enhanced_strobe; @@ -570,20 +641,45 @@ static int dwcmshc_probe(struct platform_device *pdev) if (err) goto err_clk; - err = sdhci_add_host(host); - if (err) - goto err_clk; - if (drv_data->flags & RK_PLATFROM) { - priv->hs200_rx_tap = 0; + rk_priv = devm_kzalloc(&pdev->dev, sizeof(struct rk35xx_priv), GFP_KERNEL); + if (!rk_priv) { + err = -ENOMEM; + goto err_clk; + } + + rk_priv->drv_data = drv_data; + rk_priv->hs200_rx_tap = 0; + rk_priv->acpi_en = has_acpi_companion(&pdev->dev); + + if (of_device_is_compatible(pdev->dev.of_node, "rockchip,rk3588-dwcmshc")) + rk_priv->devtype = DWCMSHC_RK3588; + else + rk_priv->devtype = DWCMSHC_RK3568; + + priv->priv = rk_priv; + if (drv_data->flags & RK_RXCLK_SW_TUNING) host->mmc_host_ops.execute_tuning = dwcmshc_rk_execute_tuning; - err = rockchip_pltf_init(host, priv); + err = dwcmshc_rk35xx_init(host, priv); if (err) goto err_clk; } - if (!priv->acpi_en) { + host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY; + + err = sdhci_setup_host(host); + if (err) + goto err_clk; + + if (rk_priv) + dwcmshc_rk35xx_postinit(host, priv); + + err = __sdhci_add_host(host); + if (err) + goto err_setup_host; + + if (rk_priv && !rk_priv->acpi_en) { pm_runtime_get_noresume(&pdev->dev); pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); @@ -594,10 +690,14 @@ static int dwcmshc_probe(struct platform_device *pdev) return 0; +err_setup_host: + sdhci_cleanup_host(host); err_clk: clk_disable_unprepare(pltfm_host->clk); clk_disable_unprepare(priv->bus_clk); - clk_bulk_disable_unprepare(ROCKCHIP_MAX_CLKS, priv->rockchip_clks); + if (rk_priv) + clk_bulk_disable_unprepare(RK35xx_MAX_CLKS, + rk_priv->rockchip_clks); free_pltfm: sdhci_pltfm_free(pdev); return err; @@ -608,13 +708,15 @@ static int dwcmshc_remove(struct platform_device *pdev) struct sdhci_host *host = platform_get_drvdata(pdev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); + struct rk35xx_priv *rk_priv = priv->priv; sdhci_remove_host(host, 0); clk_disable_unprepare(pltfm_host->clk); clk_disable_unprepare(priv->bus_clk); - clk_bulk_disable_unprepare(ROCKCHIP_MAX_CLKS, priv->rockchip_clks); - + if (rk_priv) + clk_bulk_disable_unprepare(RK35xx_MAX_CLKS, + rk_priv->rockchip_clks); sdhci_pltfm_free(pdev); return 0; @@ -626,6 +728,7 @@ static int dwcmshc_suspend(struct device *dev) struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); + struct rk35xx_priv *rk_priv = priv->priv; int ret; mmc_hsq_suspend(host->mmc); @@ -638,7 +741,10 @@ static int dwcmshc_suspend(struct device *dev) if (!IS_ERR(priv->bus_clk)) clk_disable_unprepare(priv->bus_clk); - clk_bulk_disable_unprepare(ROCKCHIP_MAX_CLKS, priv->rockchip_clks); + if (rk_priv) + clk_bulk_disable_unprepare(RK35xx_MAX_CLKS, + rk_priv->rockchip_clks); + return ret; } @@ -647,6 +753,7 @@ static int dwcmshc_resume(struct device *dev) struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); + struct rk35xx_priv *rk_priv = priv->priv; int ret; ret = clk_prepare_enable(pltfm_host->clk); @@ -659,9 +766,12 @@ static int dwcmshc_resume(struct device *dev) return ret; } - ret = clk_bulk_prepare_enable(ROCKCHIP_MAX_CLKS, priv->rockchip_clks); - if (ret) - return ret; + if (rk_priv) { + ret = clk_bulk_prepare_enable(RK35xx_MAX_CLKS, + rk_priv->rockchip_clks); + if (ret) + return ret; + } ret = sdhci_resume_host(host); if (ret) @@ -699,13 +809,13 @@ static const struct dev_pm_ops dwcmshc_pmops = { SET_SYSTEM_SLEEP_PM_OPS(dwcmshc_suspend, dwcmshc_resume) SET_RUNTIME_PM_OPS(dwcmshc_runtime_suspend, dwcmshc_runtime_resume, NULL) }; -MODULE_DEVICE_TABLE(of, sdhci_dwcmshc_dt_ids); static struct platform_driver sdhci_dwcmshc_driver = { .driver = { .name = "sdhci-dwcmshc", .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = sdhci_dwcmshc_dt_ids, + .acpi_match_table = ACPI_PTR(sdhci_dwcmshc_acpi_ids), .pm = &dwcmshc_pmops, }, .probe = dwcmshc_probe,