mmc: sdhci-of-dwcmshc: Sync code with upstream as possible

To make backport and upstream work easier. After this patch,
we just need to focus some rk specific additional code.

Sync to upstream commit a0753ef66c ("mmc: sdhci-of-dwcmshc: Re-enable support for the BlueField-3 SoC").

Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
Change-Id: Ie3b76ea2848ac3570bb9bc0be09c6f6a67685658
This commit is contained in:
Shawn Lin
2023-01-29 17:56:33 +08:00
committed by Tao Huang
parent 8e4a5fef5b
commit 9fbb9ccaf7

View File

@@ -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,