From 9d77db3c730780c8ef5ccd4b66403ff5675cfe4e Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Mon, 13 May 2024 10:30:14 +0000 Subject: [PATCH] modify sin led gpio --- kernel/drivers/mmc/host/sdhci-of-dwcmshc.c | 413 +++++++++++++++++++++++++++++++++++++++------------------- 1 files changed, 278 insertions(+), 135 deletions(-) diff --git a/kernel/drivers/mmc/host/sdhci-of-dwcmshc.c b/kernel/drivers/mmc/host/sdhci-of-dwcmshc.c index c1d95d7..ae9a2a9 100644 --- a/kernel/drivers/mmc/host/sdhci-of-dwcmshc.c +++ b/kernel/drivers/mmc/host/sdhci-of-dwcmshc.c @@ -7,6 +7,7 @@ * Author: Jisheng Zhang <jszhang@kernel.org> */ +#include <linux/acpi.h> #include <linux/clk.h> #include <linux/dma-mapping.h> #include <linux/iopoll.h> @@ -26,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 @@ -40,31 +45,30 @@ #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_TAP_VALUE_SEL BIT(25) #define DLL_TAP_VALUE_OFFSET 8 - +#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_RXCLK_NO_INVERTER BIT(29) +#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_ORI_GATE BIT(31) - -#define DWCMSHC_CARD_IS_EMMC BIT(0) -#define DWCMSHC_ENHANCED_STROBE BIT(8) - +#define DLL_RXCLK_MAX_TAP 32 #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,10 +77,15 @@ #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; @@ -93,15 +102,22 @@ u8 hs400_strbin_tap; }; -struct dwcmshc_priv { - struct clk *bus_clk; - u32 cclk_rate; - +struct rk35xx_priv { /* Rockchip specified optional clocks */ - struct clk_bulk_data rockchip_clks[ROCKCHIP_MAX_CLKS]; + struct clk_bulk_data rockchip_clks[RK35xx_MAX_CLKS]; struct reset_control *reset; + enum dwcmshc_rk_type devtype; + u8 txclk_tapnum; + u32 cclk_rate; 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 */ }; /* @@ -125,6 +141,16 @@ addr += tmplen; len -= tmplen; 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, @@ -153,7 +179,9 @@ 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 */ @@ -173,9 +201,9 @@ 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; } @@ -188,22 +216,27 @@ { 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, dll_lock_value; + u8 txclk_tapnum = DLL_TXCLK_TAPNUM_DEFAULT; + u32 extra, reg, dll_lock_value; int err; host->mmc->actual_clock = 0; @@ -218,16 +251,28 @@ if (clock <= 400000) clock = 375000; - err = clk_set_rate(pltfm_host->clk, clock); - if (err) - dev_err(mmc_dev(host->mmc), "fail to set clock %d", clock); + if (priv->acpi_en) { + union acpi_object params[1]; + struct acpi_object_list param_objects; + + params[0].type = ACPI_TYPE_INTEGER; + params[0].integer.value = clock; + param_objects.count = 1; + param_objects.pointer = params; + acpi_evaluate_object(ACPI_HANDLE(mmc_dev(host->mmc)), "SCLK", ¶m_objects, NULL); + } else { + err = clk_set_rate(pltfm_host->clk, clock); + if (err) + dev_err(mmc_dev(host->mmc), "fail to set clock %d", 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); /* Disable output clock while config DLL */ sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); @@ -262,6 +307,7 @@ /* 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; @@ -279,11 +325,11 @@ 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); 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_TAP_VALUE_SEL) extra |= DLL_TAP_VALUE_SEL | dll_lock_value << DLL_TAP_VALUE_OFFSET; sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_RXCLK); @@ -305,7 +351,7 @@ } 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; if (drv_data->flags & RK_TAP_VALUE_SEL) extra |= DLL_TAP_VALUE_SEL | dll_lock_value << DLL_TAP_VALUE_OFFSET; @@ -323,19 +369,16 @@ sdhci_enable_clk(host, 0); } -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); @@ -353,17 +396,17 @@ .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, }; @@ -374,12 +417,76 @@ .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, @@ -387,7 +494,7 @@ }; 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, @@ -397,7 +504,7 @@ }; 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, @@ -407,7 +514,7 @@ }; 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_TAP_VALUE_SEL, .hs200_tx_tap = 12, .hs400_tx_tap = 6, @@ -416,51 +523,23 @@ .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 dwcmshc_driver_data rk3562_drvdata = { + .pdata = &sdhci_dwcmshc_rk35xx_pdata, + .flags = RK_PLATFROM | 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 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, }, { @@ -468,17 +547,35 @@ .data = &rk3528_drvdata, }, { - .compatible = "rockchip,rk3588-dwcmshc", - .data = &rk3588_drvdata, + .compatible = "rockchip,rk3562-dwcmshc", + .data = &rk3562_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; @@ -489,8 +586,9 @@ 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); @@ -498,34 +596,38 @@ /* * 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->reset = devm_reset_control_array_get_exclusive(&pdev->dev); - pltfm_host->clk = devm_clk_get(&pdev->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); - goto free_pltfm; - } - err = clk_prepare_enable(pltfm_host->clk); - if (err) - goto free_pltfm; - priv->bus_clk = devm_clk_get(&pdev->dev, "bus"); - if (!IS_ERR(priv->bus_clk)) - clk_prepare_enable(priv->bus_clk); + 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(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(dev, "bus"); + if (!IS_ERR(priv->bus_clk)) + clk_prepare_enable(priv->bus_clk); + } err = mmc_of_parse(host->mmc); if (err) goto err_clk; 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; @@ -540,29 +642,60 @@ if (err) goto err_clk; - err = sdhci_add_host(host); - if (err) - goto err_clk; - if (drv_data->flags & RK_PLATFROM) { - err = rockchip_pltf_init(host, priv); + 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->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; + + err = dwcmshc_rk35xx_init(host, priv); if (err) goto err_clk; } - pm_runtime_get_noresume(&pdev->dev); - pm_runtime_set_active(&pdev->dev); - pm_runtime_enable(&pdev->dev); - pm_runtime_set_autosuspend_delay(&pdev->dev, 50); - pm_runtime_use_autosuspend(&pdev->dev); - pm_runtime_put_autosuspend(&pdev->dev); + 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); + pm_runtime_set_autosuspend_delay(&pdev->dev, 50); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_put_autosuspend(&pdev->dev); + } 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; @@ -573,13 +706,15 @@ 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; @@ -591,6 +726,7 @@ 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); @@ -603,7 +739,10 @@ 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; } @@ -612,6 +751,7 @@ 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); @@ -624,9 +764,12 @@ 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) @@ -664,13 +807,13 @@ 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, -- Gitblit v1.6.2