hc
2023-11-06 e3e12f52b214121840b44c91de5b3e5af5d3eb84
kernel/drivers/mmc/host/sdhci-of-dwcmshc.c
....@@ -39,6 +39,7 @@
3939 #define DWCMSHC_EMMC_DLL_STRBIN 0x80c
4040 #define DECMSHC_EMMC_DLL_CMDOUT 0x810
4141 #define DWCMSHC_EMMC_DLL_STATUS0 0x840
42
+#define DWCMSHC_EMMC_DLL_STATUS1 0x844
4243
4344 #define DWCMSHC_EMMC_DLL_START BIT(0)
4445 #define DWCMSHC_EMMC_DLL_LOCKED BIT(8)
....@@ -48,26 +49,26 @@
4849 #define DWCMSHC_EMMC_DLL_BYPASS BIT(24)
4950 #define DWCMSHC_EMMC_DLL_DLYENA BIT(27)
5051
51
-#define DLL_TXCLK_TAPNUM_DEFAULT 0x10
52
-#define DLL_TXCLK_TAPNUM_90_DEGREES 0x9
52
+#define DLL_TAP_VALUE_SEL BIT(25)
53
+#define DLL_TAP_VALUE_OFFSET 8
54
+
5355 #define DLL_TXCLK_TAPNUM_FROM_SW BIT(24)
5456 #define DLL_TXCLK_NO_INVERTER BIT(29)
5557
56
-#define DLL_STRBIN_TAPNUM_DEFAULT 0x4
5758 #define DLL_STRBIN_TAPNUM_FROM_SW BIT(24)
5859 #define DLL_STRBIN_DELAY_NUM_SEL BIT(26)
5960 #define DLL_STRBIN_DELAY_NUM_OFFSET 16
60
-#define DLL_STRBIN_DELAY_NUM_DEFAULT 0x10
6161
6262 #define DLL_RXCLK_NO_INVERTER BIT(29)
63
+#define DLL_RXCLK_ORI_GATE BIT(31)
6364
6465 #define DWCMSHC_CARD_IS_EMMC BIT(0)
6566 #define DWCMSHC_ENHANCED_STROBE BIT(8)
6667
67
-#define DLL_CMDOUT_TAPNUM_90_DEGREES 0x8
6868 #define DLL_CMDOUT_TAPNUM_FROM_SW BIT(24)
6969 #define DLL_CMDOUT_SRC_CLK_NEG BIT(28)
7070 #define DLL_CMDOUT_EN_SRC_CLK_NEG BIT(29)
71
+#define DLL_CMDOUT_BOTH_CLK_EDGE BIT(30)
7172
7273 #define DLL_LOCK_WO_TMOUT(x) \
7374 ((((x) & DWCMSHC_EMMC_DLL_LOCKED) == DWCMSHC_EMMC_DLL_LOCKED) && \
....@@ -77,6 +78,21 @@
7778 #define BOUNDARY_OK(addr, len) \
7879 ((addr | (SZ_128M - 1)) == ((addr + len - 1) | (SZ_128M - 1)))
7980
81
+struct dwcmshc_driver_data {
82
+ const struct sdhci_pltfm_data *pdata;
83
+ u32 flags;
84
+#define RK_PLATFROM BIT(0)
85
+#define RK_DLL_CMD_OUT BIT(1)
86
+#define RK_RXCLK_NO_INVERTER BIT(2)
87
+#define RK_TAP_VALUE_SEL BIT(3)
88
+
89
+ u8 hs200_tx_tap;
90
+ u8 hs400_tx_tap;
91
+ u8 hs400_cmd_tap;
92
+ u8 ddr50_strbin_delay_num;
93
+ u8 hs400_strbin_tap;
94
+};
95
+
8096 struct dwcmshc_priv {
8197 struct clk *bus_clk;
8298 u32 cclk_rate;
....@@ -84,17 +100,8 @@
84100 /* Rockchip specified optional clocks */
85101 struct clk_bulk_data rockchip_clks[ROCKCHIP_MAX_CLKS];
86102 struct reset_control *reset;
87
- int txclk_tapnum;
88103 unsigned int actual_clk;
89
- u32 flags;
90
-};
91
-
92
-struct dwcmshc_driver_data {
93
- const struct sdhci_pltfm_data *pdata;
94
- u32 flags;
95
-#define RK_PLATFROM BIT(0)
96
-#define RK_DLL_CMD_OUT BIT(1)
97
-#define RK_RXCLK_NO_INVERTER BIT(2)
104
+ const struct dwcmshc_driver_data *drv_data;
98105 };
99106
100107 /*
....@@ -195,7 +202,8 @@
195202 {
196203 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
197204 struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
198
- u32 txclk_tapnum, extra;
205
+ const struct dwcmshc_driver_data *drv_data = priv->drv_data;
206
+ u32 txclk_tapnum, extra, dll_lock_value;
199207 int err;
200208
201209 host->mmc->actual_clock = 0;
....@@ -221,13 +229,18 @@
221229 extra &= ~BIT(0);
222230 sdhci_writel(host, extra, DWCMSHC_HOST_CTRL3);
223231
232
+ /* Disable output clock while config DLL */
233
+ sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
234
+
224235 if (clock <= 52000000) {
236
+ /* Disable DLL */
237
+ sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_CTRL);
225238 /*
226
- * Disable DLL and reset both of sample and drive clock.
239
+ * Config DLL BYPASS and Reset both of sample and drive clock.
227240 * The bypass bit and start bit need to set if DLL is not locked.
228241 */
229242 sdhci_writel(host, DWCMSHC_EMMC_DLL_BYPASS | DWCMSHC_EMMC_DLL_START, DWCMSHC_EMMC_DLL_CTRL);
230
- sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_RXCLK);
243
+ sdhci_writel(host, DLL_RXCLK_ORI_GATE, DWCMSHC_EMMC_DLL_RXCLK);
231244 sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_TXCLK);
232245 sdhci_writel(host, 0, DECMSHC_EMMC_DLL_CMDOUT);
233246 /*
....@@ -237,24 +250,15 @@
237250 */
238251 extra = DWCMSHC_EMMC_DLL_DLYENA |
239252 DLL_STRBIN_DELAY_NUM_SEL |
240
- DLL_STRBIN_DELAY_NUM_DEFAULT << DLL_STRBIN_DELAY_NUM_OFFSET;
253
+ drv_data->ddr50_strbin_delay_num << DLL_STRBIN_DELAY_NUM_OFFSET;
241254 sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_STRBIN);
242
- return;
255
+ goto exit;
243256 }
244257
245258 /* Reset DLL */
246259 sdhci_writel(host, BIT(1), DWCMSHC_EMMC_DLL_CTRL);
247260 udelay(1);
248261 sdhci_writel(host, 0x0, DWCMSHC_EMMC_DLL_CTRL);
249
-
250
- /*
251
- * We shouldn't set DLL_RXCLK_NO_INVERTER for identify mode but
252
- * we must set it in higher speed mode.
253
- */
254
- extra = DWCMSHC_EMMC_DLL_DLYENA;
255
- if (priv->flags & RK_RXCLK_NO_INVERTER)
256
- extra |= DLL_RXCLK_NO_INVERTER;
257
- sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_RXCLK);
258262
259263 /* Init DLL settings, clean start bit before resetting */
260264 sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_CTRL);
....@@ -267,38 +271,56 @@
267271 500 * USEC_PER_MSEC);
268272 if (err) {
269273 dev_err(mmc_dev(host->mmc), "DLL lock timeout!\n");
270
- return;
274
+ goto exit;
271275 }
272276
277
+ dll_lock_value = ((sdhci_readl(host, DWCMSHC_EMMC_DLL_STATUS0) & 0xFF) * 2) & 0xFF;
278
+
273279 extra = 0x1 << 16 | /* tune clock stop en */
274
- 0x2 << 17 | /* pre-change delay */
280
+ 0x3 << 17 | /* pre-change delay */
275281 0x3 << 19; /* post-change delay */
276282 sdhci_writel(host, extra, DWCMSHC_EMMC_ATCTRL);
277283
278
- txclk_tapnum = priv->txclk_tapnum;
284
+ extra = DWCMSHC_EMMC_DLL_DLYENA | DLL_RXCLK_ORI_GATE;
285
+ if (drv_data->flags & RK_RXCLK_NO_INVERTER)
286
+ extra |= DLL_RXCLK_NO_INVERTER;
287
+ if (drv_data->flags & RK_TAP_VALUE_SEL)
288
+ extra |= DLL_TAP_VALUE_SEL | dll_lock_value << DLL_TAP_VALUE_OFFSET;
289
+ sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_RXCLK);
279290
280
- if ((priv->flags & RK_DLL_CMD_OUT) &&
281
- host->mmc->ios.timing == MMC_TIMING_MMC_HS400) {
282
- txclk_tapnum = DLL_TXCLK_TAPNUM_90_DEGREES;
291
+ txclk_tapnum = drv_data->hs200_tx_tap;
292
+ if (host->mmc->ios.timing == MMC_TIMING_MMC_HS400) {
293
+ txclk_tapnum = drv_data->hs400_tx_tap;
283294
284
- extra = DLL_CMDOUT_SRC_CLK_NEG |
285
- DLL_CMDOUT_EN_SRC_CLK_NEG |
286
- DWCMSHC_EMMC_DLL_DLYENA |
287
- DLL_CMDOUT_TAPNUM_90_DEGREES |
288
- DLL_CMDOUT_TAPNUM_FROM_SW;
289
- sdhci_writel(host, extra, DECMSHC_EMMC_DLL_CMDOUT);
295
+ if (drv_data->flags & RK_DLL_CMD_OUT) {
296
+ extra = DLL_CMDOUT_SRC_CLK_NEG |
297
+ DLL_CMDOUT_BOTH_CLK_EDGE |
298
+ DWCMSHC_EMMC_DLL_DLYENA |
299
+ drv_data->hs400_cmd_tap |
300
+ DLL_CMDOUT_TAPNUM_FROM_SW;
301
+ if (drv_data->flags & RK_TAP_VALUE_SEL)
302
+ extra |= DLL_TAP_VALUE_SEL | dll_lock_value << DLL_TAP_VALUE_OFFSET;
303
+ sdhci_writel(host, extra, DECMSHC_EMMC_DLL_CMDOUT);
304
+ }
290305 }
291
-
292306 extra = DWCMSHC_EMMC_DLL_DLYENA |
293307 DLL_TXCLK_TAPNUM_FROM_SW |
294308 DLL_RXCLK_NO_INVERTER |
295309 txclk_tapnum;
310
+ if (drv_data->flags & RK_TAP_VALUE_SEL)
311
+ extra |= DLL_TAP_VALUE_SEL | dll_lock_value << DLL_TAP_VALUE_OFFSET;
296312 sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_TXCLK);
297313
298314 extra = DWCMSHC_EMMC_DLL_DLYENA |
299
- DLL_STRBIN_TAPNUM_DEFAULT |
315
+ drv_data->hs400_strbin_tap |
300316 DLL_STRBIN_TAPNUM_FROM_SW;
317
+ if (drv_data->flags & RK_TAP_VALUE_SEL)
318
+ extra |= DLL_TAP_VALUE_SEL | dll_lock_value << DLL_TAP_VALUE_OFFSET;
301319 sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_STRBIN);
320
+
321
+exit:
322
+ /* enable output clock */
323
+ sdhci_enable_clk(host, 0);
302324 }
303325
304326 static void rockchip_sdhci_reset(struct sdhci_host *host, u8 mask)
....@@ -367,11 +389,31 @@
367389 static const struct dwcmshc_driver_data rk3568_drvdata = {
368390 .pdata = &sdhci_dwcmshc_rk_pdata,
369391 .flags = RK_PLATFROM | RK_RXCLK_NO_INVERTER,
392
+ .hs200_tx_tap = 16,
393
+ .hs400_tx_tap = 8,
394
+ .hs400_cmd_tap = 8,
395
+ .hs400_strbin_tap = 4,
396
+ .ddr50_strbin_delay_num = 16,
370397 };
371398
372399 static const struct dwcmshc_driver_data rk3588_drvdata = {
373400 .pdata = &sdhci_dwcmshc_rk_pdata,
374401 .flags = RK_PLATFROM | RK_DLL_CMD_OUT,
402
+ .hs200_tx_tap = 16,
403
+ .hs400_tx_tap = 9,
404
+ .hs400_cmd_tap = 8,
405
+ .hs400_strbin_tap = 4,
406
+ .ddr50_strbin_delay_num = 16,
407
+};
408
+
409
+static const struct dwcmshc_driver_data rk3528_drvdata = {
410
+ .pdata = &sdhci_dwcmshc_rk_pdata,
411
+ .flags = RK_PLATFROM | RK_DLL_CMD_OUT | RK_TAP_VALUE_SEL,
412
+ .hs200_tx_tap = 12,
413
+ .hs400_tx_tap = 6,
414
+ .hs400_cmd_tap = 6,
415
+ .hs400_strbin_tap = 3,
416
+ .ddr50_strbin_delay_num = 10,
375417 };
376418
377419 static int rockchip_pltf_init(struct sdhci_host *host, struct dwcmshc_priv *priv)
....@@ -393,10 +435,6 @@
393435 dev_err(mmc_dev(host->mmc), "failed to enable clocks %d\n", err);
394436 return err;
395437 }
396
-
397
- if (of_property_read_u32(mmc_dev(host->mmc)->of_node, "rockchip,txclk-tapnum",
398
- &priv->txclk_tapnum))
399
- priv->txclk_tapnum = DLL_TXCLK_TAPNUM_DEFAULT;
400438
401439 /* Disable cmd conflict check */
402440 sdhci_writel(host, 0x0, DWCMSHC_HOST_CTRL3);
....@@ -424,6 +462,10 @@
424462 {
425463 .compatible = "rockchip,dwcmshc-sdhci",
426464 .data = &rk3568_drvdata,
465
+ },
466
+ {
467
+ .compatible = "rockchip,rk3528-dwcmshc",
468
+ .data = &rk3528_drvdata,
427469 },
428470 {
429471 .compatible = "rockchip,rk3588-dwcmshc",
....@@ -463,7 +505,7 @@
463505
464506 pltfm_host = sdhci_priv(host);
465507 priv = sdhci_pltfm_priv(pltfm_host);
466
-
508
+ priv->drv_data = drv_data;
467509 priv->reset = devm_reset_control_array_get_exclusive(&pdev->dev);
468510 pltfm_host->clk = devm_clk_get(&pdev->dev, "core");
469511 if (IS_ERR(pltfm_host->clk)) {
....@@ -502,7 +544,6 @@
502544 if (err)
503545 goto err_clk;
504546
505
- priv->flags = drv_data->flags;
506547 if (drv_data->flags & RK_PLATFROM) {
507548 err = rockchip_pltf_init(host, priv);
508549 if (err)