Skip to content

Commit b095f4f

Browse files
Swati AgarwalUlf Hansson
authored andcommitted
mmc: sdhci-of-arasan: Add support for eMMC5.1 on Xilinx Versal Net platform
Add support for eMMC5.1 on Xilinx Versal Net platform - Add new compatible string(xlnx,versal-net-emmc). - Add support for PHY which is part of Host Controller register space. - Add DLL and Delay Chain mode support and corresponding tap delays for all eMMC modes. - Add Strobe select tap for HS400 mode. Signed-off-by: Swati Agarwal <swati.agarwal@amd.com> Co-developed-by: Sai Krishna Potthuri <sai.krishna.potthuri@amd.com> Signed-off-by: Sai Krishna Potthuri <sai.krishna.potthuri@amd.com> Acked-by: Adrian Hunter <adrian.hunter@intel.com> Link: https://lore.kernel.org/r/20230403102551.3763054-3-sai.krishna.potthuri@amd.com Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
1 parent 8aa7206 commit b095f4f

1 file changed

Lines changed: 235 additions & 0 deletions

File tree

drivers/mmc/host/sdhci-of-arasan.c

Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,18 +41,53 @@
4141
#define VENDOR_ENHANCED_STROBE BIT(0)
4242

4343
#define PHY_CLK_TOO_SLOW_HZ 400000
44+
#define MIN_PHY_CLK_HZ 50000000
4445

4546
#define SDHCI_ITAPDLY_CHGWIN 0x200
4647
#define SDHCI_ITAPDLY_ENABLE 0x100
4748
#define SDHCI_OTAPDLY_ENABLE 0x40
4849

50+
#define PHY_CTRL_REG1 0x270
51+
#define PHY_CTRL_ITAPDLY_ENA_MASK BIT(0)
52+
#define PHY_CTRL_ITAPDLY_SEL_MASK GENMASK(5, 1)
53+
#define PHY_CTRL_ITAPDLY_SEL_SHIFT 1
54+
#define PHY_CTRL_ITAP_CHG_WIN_MASK BIT(6)
55+
#define PHY_CTRL_OTAPDLY_ENA_MASK BIT(8)
56+
#define PHY_CTRL_OTAPDLY_SEL_MASK GENMASK(15, 12)
57+
#define PHY_CTRL_OTAPDLY_SEL_SHIFT 12
58+
#define PHY_CTRL_STRB_SEL_MASK GENMASK(23, 16)
59+
#define PHY_CTRL_STRB_SEL_SHIFT 16
60+
#define PHY_CTRL_TEST_CTRL_MASK GENMASK(31, 24)
61+
62+
#define PHY_CTRL_REG2 0x274
63+
#define PHY_CTRL_EN_DLL_MASK BIT(0)
64+
#define PHY_CTRL_DLL_RDY_MASK BIT(1)
65+
#define PHY_CTRL_FREQ_SEL_MASK GENMASK(6, 4)
66+
#define PHY_CTRL_FREQ_SEL_SHIFT 4
67+
#define PHY_CTRL_SEL_DLY_TX_MASK BIT(16)
68+
#define PHY_CTRL_SEL_DLY_RX_MASK BIT(17)
69+
#define FREQSEL_200M_170M 0x0
70+
#define FREQSEL_170M_140M 0x1
71+
#define FREQSEL_140M_110M 0x2
72+
#define FREQSEL_110M_80M 0x3
73+
#define FREQSEL_80M_50M 0x4
74+
#define FREQSEL_275M_250M 0x5
75+
#define FREQSEL_250M_225M 0x6
76+
#define FREQSEL_225M_200M 0x7
77+
#define PHY_DLL_TIMEOUT_MS 100
78+
4979
/* Default settings for ZynqMP Clock Phases */
5080
#define ZYNQMP_ICLK_PHASE {0, 63, 63, 0, 63, 0, 0, 183, 54, 0, 0}
5181
#define ZYNQMP_OCLK_PHASE {0, 72, 60, 0, 60, 72, 135, 48, 72, 135, 0}
5282

5383
#define VERSAL_ICLK_PHASE {0, 132, 132, 0, 132, 0, 0, 162, 90, 0, 0}
5484
#define VERSAL_OCLK_PHASE {0, 60, 48, 0, 48, 72, 90, 36, 60, 90, 0}
5585

86+
#define VERSAL_NET_EMMC_ICLK_PHASE {0, 0, 0, 0, 0, 0, 0, 0, 39, 0, 0}
87+
#define VERSAL_NET_EMMC_OCLK_PHASE {0, 113, 0, 0, 0, 0, 0, 0, 113, 79, 45}
88+
89+
#define VERSAL_NET_PHY_CTRL_STRB90_STRB180_VAL 0X77
90+
5691
/*
5792
* On some SoCs the syscon area has a feature where the upper 16-bits of
5893
* each 32-bit register act as a write mask for the lower 16-bits. This allows
@@ -135,6 +170,7 @@ struct sdhci_arasan_clk_data {
135170
* @clk_ahb: Pointer to the AHB clock
136171
* @phy: Pointer to the generic phy
137172
* @is_phy_on: True if the PHY is on; false if not.
173+
* @internal_phy_reg: True if the PHY is within the Host controller.
138174
* @has_cqe: True if controller has command queuing engine.
139175
* @clk_data: Struct for the Arasan Controller Clock Data.
140176
* @clk_ops: Struct for the Arasan Controller Clock Operations.
@@ -147,6 +183,7 @@ struct sdhci_arasan_data {
147183
struct clk *clk_ahb;
148184
struct phy *phy;
149185
bool is_phy_on;
186+
bool internal_phy_reg;
150187

151188
bool has_cqe;
152189
struct sdhci_arasan_clk_data clk_data;
@@ -200,6 +237,61 @@ static const struct sdhci_arasan_soc_ctl_map intel_keembay_soc_ctl_map = {
200237
.hiword_update = false,
201238
};
202239

240+
static void sdhci_arasan_phy_set_delaychain(struct sdhci_host *host, bool enable)
241+
{
242+
u32 reg;
243+
244+
reg = readl(host->ioaddr + PHY_CTRL_REG2);
245+
if (enable)
246+
reg |= (PHY_CTRL_SEL_DLY_TX_MASK | PHY_CTRL_SEL_DLY_RX_MASK);
247+
else
248+
reg &= ~(PHY_CTRL_SEL_DLY_TX_MASK | PHY_CTRL_SEL_DLY_RX_MASK);
249+
250+
writel(reg, host->ioaddr + PHY_CTRL_REG2);
251+
}
252+
253+
static int sdhci_arasan_phy_set_dll(struct sdhci_host *host, bool enable)
254+
{
255+
u32 reg;
256+
257+
reg = readl(host->ioaddr + PHY_CTRL_REG2);
258+
if (enable)
259+
reg |= PHY_CTRL_EN_DLL_MASK;
260+
else
261+
reg &= ~PHY_CTRL_EN_DLL_MASK;
262+
263+
writel(reg, host->ioaddr + PHY_CTRL_REG2);
264+
265+
if (!enable)
266+
return 0;
267+
268+
return readl_relaxed_poll_timeout(host->ioaddr + PHY_CTRL_REG2, reg,
269+
(reg & PHY_CTRL_DLL_RDY_MASK), 10,
270+
1000 * PHY_DLL_TIMEOUT_MS);
271+
}
272+
273+
static void sdhci_arasan_phy_dll_set_freq(struct sdhci_host *host, int clock)
274+
{
275+
u32 reg, freq_sel, freq;
276+
277+
freq = DIV_ROUND_CLOSEST(clock, 1000000);
278+
if (freq <= 200 && freq > 170)
279+
freq_sel = FREQSEL_200M_170M;
280+
else if (freq <= 170 && freq > 140)
281+
freq_sel = FREQSEL_170M_140M;
282+
else if (freq <= 140 && freq > 110)
283+
freq_sel = FREQSEL_140M_110M;
284+
else if (freq <= 110 && freq > 80)
285+
freq_sel = FREQSEL_110M_80M;
286+
else
287+
freq_sel = FREQSEL_80M_50M;
288+
289+
reg = readl(host->ioaddr + PHY_CTRL_REG2);
290+
reg &= ~PHY_CTRL_FREQ_SEL_MASK;
291+
reg |= (freq_sel << PHY_CTRL_FREQ_SEL_SHIFT);
292+
writel(reg, host->ioaddr + PHY_CTRL_REG2);
293+
}
294+
203295
/**
204296
* sdhci_arasan_syscon_write - Write to a field in soc_ctl registers
205297
*
@@ -317,8 +409,21 @@ static void sdhci_arasan_set_clock(struct sdhci_host *host, unsigned int clock)
317409
if (clk_data->set_clk_delays)
318410
clk_data->set_clk_delays(host);
319411

412+
if (sdhci_arasan->internal_phy_reg && clock >= MIN_PHY_CLK_HZ) {
413+
sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
414+
sdhci_arasan_phy_set_dll(host, 0);
415+
sdhci_arasan_phy_set_delaychain(host, 0);
416+
sdhci_arasan_phy_dll_set_freq(host, clock);
417+
} else if (sdhci_arasan->internal_phy_reg) {
418+
sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
419+
sdhci_arasan_phy_set_delaychain(host, 1);
420+
}
421+
320422
sdhci_set_clock(host, clock);
321423

424+
if (sdhci_arasan->internal_phy_reg && clock >= MIN_PHY_CLK_HZ)
425+
sdhci_arasan_phy_set_dll(host, 1);
426+
322427
if (sdhci_arasan->quirks & SDHCI_ARASAN_QUIRK_CLOCK_UNSTABLE)
323428
/*
324429
* Some controllers immediately report SDHCI_CLOCK_INT_STABLE
@@ -881,6 +986,101 @@ static const struct clk_ops versal_sampleclk_ops = {
881986
.set_phase = sdhci_versal_sampleclk_set_phase,
882987
};
883988

989+
static int sdhci_versal_net_emmc_sdcardclk_set_phase(struct clk_hw *hw, int degrees)
990+
{
991+
struct sdhci_arasan_clk_data *clk_data =
992+
container_of(hw, struct sdhci_arasan_clk_data, sdcardclk_hw);
993+
struct sdhci_arasan_data *sdhci_arasan =
994+
container_of(clk_data, struct sdhci_arasan_data, clk_data);
995+
struct sdhci_host *host = sdhci_arasan->host;
996+
u8 tap_delay, tap_max = 0;
997+
998+
switch (host->timing) {
999+
case MMC_TIMING_MMC_HS:
1000+
case MMC_TIMING_MMC_DDR52:
1001+
tap_max = 16;
1002+
break;
1003+
case MMC_TIMING_MMC_HS200:
1004+
case MMC_TIMING_MMC_HS400:
1005+
/* For 200MHz clock, 32 Taps are available */
1006+
tap_max = 32;
1007+
break;
1008+
default:
1009+
break;
1010+
}
1011+
1012+
tap_delay = (degrees * tap_max) / 360;
1013+
1014+
/* Set the Clock Phase */
1015+
if (tap_delay) {
1016+
u32 regval;
1017+
1018+
regval = sdhci_readl(host, PHY_CTRL_REG1);
1019+
regval |= PHY_CTRL_OTAPDLY_ENA_MASK;
1020+
sdhci_writel(host, regval, PHY_CTRL_REG1);
1021+
regval &= ~PHY_CTRL_OTAPDLY_SEL_MASK;
1022+
regval |= tap_delay << PHY_CTRL_OTAPDLY_SEL_SHIFT;
1023+
sdhci_writel(host, regval, PHY_CTRL_REG1);
1024+
}
1025+
1026+
return 0;
1027+
}
1028+
1029+
static const struct clk_ops versal_net_sdcardclk_ops = {
1030+
.recalc_rate = sdhci_arasan_sdcardclk_recalc_rate,
1031+
.set_phase = sdhci_versal_net_emmc_sdcardclk_set_phase,
1032+
};
1033+
1034+
static int sdhci_versal_net_emmc_sampleclk_set_phase(struct clk_hw *hw, int degrees)
1035+
{
1036+
struct sdhci_arasan_clk_data *clk_data =
1037+
container_of(hw, struct sdhci_arasan_clk_data, sampleclk_hw);
1038+
struct sdhci_arasan_data *sdhci_arasan =
1039+
container_of(clk_data, struct sdhci_arasan_data, clk_data);
1040+
struct sdhci_host *host = sdhci_arasan->host;
1041+
u8 tap_delay, tap_max = 0;
1042+
u32 regval;
1043+
1044+
switch (host->timing) {
1045+
case MMC_TIMING_MMC_HS:
1046+
case MMC_TIMING_MMC_DDR52:
1047+
tap_max = 32;
1048+
break;
1049+
case MMC_TIMING_MMC_HS400:
1050+
/* Strobe select tap point for strb90 and strb180 */
1051+
regval = sdhci_readl(host, PHY_CTRL_REG1);
1052+
regval &= ~PHY_CTRL_STRB_SEL_MASK;
1053+
regval |= VERSAL_NET_PHY_CTRL_STRB90_STRB180_VAL << PHY_CTRL_STRB_SEL_SHIFT;
1054+
sdhci_writel(host, regval, PHY_CTRL_REG1);
1055+
break;
1056+
default:
1057+
break;
1058+
}
1059+
1060+
tap_delay = (degrees * tap_max) / 360;
1061+
1062+
/* Set the Clock Phase */
1063+
if (tap_delay) {
1064+
regval = sdhci_readl(host, PHY_CTRL_REG1);
1065+
regval |= PHY_CTRL_ITAP_CHG_WIN_MASK;
1066+
sdhci_writel(host, regval, PHY_CTRL_REG1);
1067+
regval |= PHY_CTRL_ITAPDLY_ENA_MASK;
1068+
sdhci_writel(host, regval, PHY_CTRL_REG1);
1069+
regval &= ~PHY_CTRL_ITAPDLY_SEL_MASK;
1070+
regval |= tap_delay << PHY_CTRL_ITAPDLY_SEL_SHIFT;
1071+
sdhci_writel(host, regval, PHY_CTRL_REG1);
1072+
regval &= ~PHY_CTRL_ITAP_CHG_WIN_MASK;
1073+
sdhci_writel(host, regval, PHY_CTRL_REG1);
1074+
}
1075+
1076+
return 0;
1077+
}
1078+
1079+
static const struct clk_ops versal_net_sampleclk_ops = {
1080+
.recalc_rate = sdhci_arasan_sampleclk_recalc_rate,
1081+
.set_phase = sdhci_versal_net_emmc_sampleclk_set_phase,
1082+
};
1083+
8841084
static void arasan_zynqmp_dll_reset(struct sdhci_host *host, u32 deviceid)
8851085
{
8861086
u16 clk;
@@ -1091,7 +1291,17 @@ static void arasan_dt_parse_clk_phases(struct device *dev,
10911291
clk_data->clk_phase_out[i] = versal_oclk_phase[i];
10921292
}
10931293
}
1294+
if (of_device_is_compatible(dev->of_node, "xlnx,versal-net-emmc")) {
1295+
u32 versal_net_iclk_phase[MMC_TIMING_MMC_HS400 + 1] =
1296+
VERSAL_NET_EMMC_ICLK_PHASE;
1297+
u32 versal_net_oclk_phase[MMC_TIMING_MMC_HS400 + 1] =
1298+
VERSAL_NET_EMMC_OCLK_PHASE;
10941299

1300+
for (i = 0; i <= MMC_TIMING_MMC_HS400; i++) {
1301+
clk_data->clk_phase_in[i] = versal_net_iclk_phase[i];
1302+
clk_data->clk_phase_out[i] = versal_net_oclk_phase[i];
1303+
}
1304+
}
10951305
arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_LEGACY,
10961306
"clk-phase-legacy");
10971307
arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_HS,
@@ -1203,6 +1413,14 @@ static const struct sdhci_pltfm_data sdhci_arasan_zynqmp_pdata = {
12031413
SDHCI_QUIRK2_STOP_WITH_TC,
12041414
};
12051415

1416+
static const struct sdhci_pltfm_data sdhci_arasan_versal_net_pdata = {
1417+
.ops = &sdhci_arasan_ops,
1418+
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
1419+
SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN |
1420+
SDHCI_QUIRK2_STOP_WITH_TC |
1421+
SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400,
1422+
};
1423+
12061424
static const struct sdhci_arasan_clk_ops zynqmp_clk_ops = {
12071425
.sdcardclk_ops = &zynqmp_sdcardclk_ops,
12081426
.sampleclk_ops = &zynqmp_sampleclk_ops,
@@ -1223,6 +1441,16 @@ static struct sdhci_arasan_of_data sdhci_arasan_versal_data = {
12231441
.clk_ops = &versal_clk_ops,
12241442
};
12251443

1444+
static const struct sdhci_arasan_clk_ops versal_net_clk_ops = {
1445+
.sdcardclk_ops = &versal_net_sdcardclk_ops,
1446+
.sampleclk_ops = &versal_net_sampleclk_ops,
1447+
};
1448+
1449+
static struct sdhci_arasan_of_data sdhci_arasan_versal_net_data = {
1450+
.pdata = &sdhci_arasan_versal_net_pdata,
1451+
.clk_ops = &versal_net_clk_ops,
1452+
};
1453+
12261454
static struct sdhci_arasan_of_data intel_keembay_emmc_data = {
12271455
.soc_ctl_map = &intel_keembay_soc_ctl_map,
12281456
.pdata = &sdhci_keembay_emmc_pdata,
@@ -1288,6 +1516,10 @@ static const struct of_device_id sdhci_arasan_of_match[] = {
12881516
.compatible = "xlnx,versal-8.9a",
12891517
.data = &sdhci_arasan_versal_data,
12901518
},
1519+
{
1520+
.compatible = "xlnx,versal-net-emmc",
1521+
.data = &sdhci_arasan_versal_net_data,
1522+
},
12911523
{ /* sentinel */ }
12921524
};
12931525
MODULE_DEVICE_TABLE(of, sdhci_arasan_of_match);
@@ -1761,6 +1993,9 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
17611993
host->mmc->caps2 |= MMC_CAP2_CQE_DCMD;
17621994
}
17631995

1996+
if (of_device_is_compatible(np, "xlnx,versal-net-emmc"))
1997+
sdhci_arasan->internal_phy_reg = true;
1998+
17641999
ret = sdhci_arasan_add_host(sdhci_arasan);
17652000
if (ret)
17662001
goto err_add_host;

0 commit comments

Comments
 (0)