forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-05-13 9d77db3c730780c8ef5ccd4b66403ff5675cfe4e
kernel/drivers/mmc/host/sdhci-cadence.c
....@@ -1,25 +1,17 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * Copyright (C) 2016 Socionext Inc.
34 * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
4
- *
5
- * This program is free software; you can redistribute it and/or modify
6
- * it under the terms of the GNU General Public License as published by
7
- * the Free Software Foundation; either version 2 of the License, or
8
- * (at your option) any later version.
9
- *
10
- * This program is distributed in the hope that it will be useful,
11
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
- * GNU General Public License for more details.
145 */
156
167 #include <linux/bitfield.h>
17
-#include <linux/bitops.h>
8
+#include <linux/bits.h>
189 #include <linux/iopoll.h>
1910 #include <linux/module.h>
2011 #include <linux/mmc/host.h>
2112 #include <linux/mmc/mmc.h>
2213 #include <linux/of.h>
14
+#include <linux/of_device.h>
2315
2416 #include "sdhci-pltfm.h"
2517
....@@ -76,7 +68,7 @@
7668 void __iomem *hrs_addr;
7769 bool enhanced_strobe;
7870 unsigned int nr_phy_params;
79
- struct sdhci_cdns_phy_param phy_params[0];
71
+ struct sdhci_cdns_phy_param phy_params[];
8072 };
8173
8274 struct sdhci_cdns_phy_cfg {
....@@ -105,6 +97,11 @@
10597 u32 tmp;
10698 int ret;
10799
100
+ ret = readl_poll_timeout(reg, tmp, !(tmp & SDHCI_CDNS_HRS04_ACK),
101
+ 0, 10);
102
+ if (ret)
103
+ return ret;
104
+
108105 tmp = FIELD_PREP(SDHCI_CDNS_HRS04_WDATA, data) |
109106 FIELD_PREP(SDHCI_CDNS_HRS04_ADDR, addr);
110107 writel(tmp, reg);
....@@ -119,7 +116,10 @@
119116 tmp &= ~SDHCI_CDNS_HRS04_WR;
120117 writel(tmp, reg);
121118
122
- return 0;
119
+ ret = readl_poll_timeout(reg, tmp, !(tmp & SDHCI_CDNS_HRS04_ACK),
120
+ 0, 10);
121
+
122
+ return ret;
123123 }
124124
125125 static unsigned int sdhci_cdns_phy_param_count(struct device_node *np)
....@@ -167,7 +167,7 @@
167167 return 0;
168168 }
169169
170
-static inline void *sdhci_cdns_priv(struct sdhci_host *host)
170
+static void *sdhci_cdns_priv(struct sdhci_host *host)
171171 {
172172 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
173173
....@@ -200,6 +200,79 @@
200200
201201 tmp = readl(priv->hrs_addr + SDHCI_CDNS_HRS06);
202202 return FIELD_GET(SDHCI_CDNS_HRS06_MODE, tmp);
203
+}
204
+
205
+static int sdhci_cdns_set_tune_val(struct sdhci_host *host, unsigned int val)
206
+{
207
+ struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
208
+ void __iomem *reg = priv->hrs_addr + SDHCI_CDNS_HRS06;
209
+ u32 tmp;
210
+ int i, ret;
211
+
212
+ if (WARN_ON(!FIELD_FIT(SDHCI_CDNS_HRS06_TUNE, val)))
213
+ return -EINVAL;
214
+
215
+ tmp = readl(reg);
216
+ tmp &= ~SDHCI_CDNS_HRS06_TUNE;
217
+ tmp |= FIELD_PREP(SDHCI_CDNS_HRS06_TUNE, val);
218
+
219
+ /*
220
+ * Workaround for IP errata:
221
+ * The IP6116 SD/eMMC PHY design has a timing issue on receive data
222
+ * path. Send tune request twice.
223
+ */
224
+ for (i = 0; i < 2; i++) {
225
+ tmp |= SDHCI_CDNS_HRS06_TUNE_UP;
226
+ writel(tmp, reg);
227
+
228
+ ret = readl_poll_timeout(reg, tmp,
229
+ !(tmp & SDHCI_CDNS_HRS06_TUNE_UP),
230
+ 0, 1);
231
+ if (ret)
232
+ return ret;
233
+ }
234
+
235
+ return 0;
236
+}
237
+
238
+/*
239
+ * In SD mode, software must not use the hardware tuning and instead perform
240
+ * an almost identical procedure to eMMC.
241
+ */
242
+static int sdhci_cdns_execute_tuning(struct sdhci_host *host, u32 opcode)
243
+{
244
+ int cur_streak = 0;
245
+ int max_streak = 0;
246
+ int end_of_streak = 0;
247
+ int i;
248
+
249
+ /*
250
+ * Do not execute tuning for UHS_SDR50 or UHS_DDR50.
251
+ * The delay is set by probe, based on the DT properties.
252
+ */
253
+ if (host->timing != MMC_TIMING_MMC_HS200 &&
254
+ host->timing != MMC_TIMING_UHS_SDR104)
255
+ return 0;
256
+
257
+ for (i = 0; i < SDHCI_CDNS_MAX_TUNING_LOOP; i++) {
258
+ if (sdhci_cdns_set_tune_val(host, i) ||
259
+ mmc_send_tuning(host->mmc, opcode, NULL)) { /* bad */
260
+ cur_streak = 0;
261
+ } else { /* good */
262
+ cur_streak++;
263
+ if (cur_streak > max_streak) {
264
+ max_streak = cur_streak;
265
+ end_of_streak = i;
266
+ }
267
+ }
268
+ }
269
+
270
+ if (!max_streak) {
271
+ dev_err(mmc_dev(host->mmc), "no tuning point found\n");
272
+ return -EIO;
273
+ }
274
+
275
+ return sdhci_cdns_set_tune_val(host, end_of_streak - max_streak / 2);
203276 }
204277
205278 static void sdhci_cdns_set_uhs_signaling(struct sdhci_host *host,
....@@ -241,84 +314,18 @@
241314 .get_timeout_clock = sdhci_cdns_get_timeout_clock,
242315 .set_bus_width = sdhci_set_bus_width,
243316 .reset = sdhci_reset,
317
+ .platform_execute_tuning = sdhci_cdns_execute_tuning,
244318 .set_uhs_signaling = sdhci_cdns_set_uhs_signaling,
319
+};
320
+
321
+static const struct sdhci_pltfm_data sdhci_cdns_uniphier_pltfm_data = {
322
+ .ops = &sdhci_cdns_ops,
323
+ .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
245324 };
246325
247326 static const struct sdhci_pltfm_data sdhci_cdns_pltfm_data = {
248327 .ops = &sdhci_cdns_ops,
249328 };
250
-
251
-static int sdhci_cdns_set_tune_val(struct sdhci_host *host, unsigned int val)
252
-{
253
- struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
254
- void __iomem *reg = priv->hrs_addr + SDHCI_CDNS_HRS06;
255
- u32 tmp;
256
- int i, ret;
257
-
258
- if (WARN_ON(!FIELD_FIT(SDHCI_CDNS_HRS06_TUNE, val)))
259
- return -EINVAL;
260
-
261
- tmp = readl(reg);
262
- tmp &= ~SDHCI_CDNS_HRS06_TUNE;
263
- tmp |= FIELD_PREP(SDHCI_CDNS_HRS06_TUNE, val);
264
-
265
- /*
266
- * Workaround for IP errata:
267
- * The IP6116 SD/eMMC PHY design has a timing issue on receive data
268
- * path. Send tune request twice.
269
- */
270
- for (i = 0; i < 2; i++) {
271
- tmp |= SDHCI_CDNS_HRS06_TUNE_UP;
272
- writel(tmp, reg);
273
-
274
- ret = readl_poll_timeout(reg, tmp,
275
- !(tmp & SDHCI_CDNS_HRS06_TUNE_UP),
276
- 0, 1);
277
- if (ret)
278
- return ret;
279
- }
280
-
281
- return 0;
282
-}
283
-
284
-static int sdhci_cdns_execute_tuning(struct mmc_host *mmc, u32 opcode)
285
-{
286
- struct sdhci_host *host = mmc_priv(mmc);
287
- int cur_streak = 0;
288
- int max_streak = 0;
289
- int end_of_streak = 0;
290
- int i;
291
-
292
- /*
293
- * This handler only implements the eMMC tuning that is specific to
294
- * this controller. Fall back to the standard method for SD timing.
295
- */
296
- if (host->timing != MMC_TIMING_MMC_HS200)
297
- return sdhci_execute_tuning(mmc, opcode);
298
-
299
- if (WARN_ON(opcode != MMC_SEND_TUNING_BLOCK_HS200))
300
- return -EINVAL;
301
-
302
- for (i = 0; i < SDHCI_CDNS_MAX_TUNING_LOOP; i++) {
303
- if (sdhci_cdns_set_tune_val(host, i) ||
304
- mmc_send_tuning(host->mmc, opcode, NULL)) { /* bad */
305
- cur_streak = 0;
306
- } else { /* good */
307
- cur_streak++;
308
- if (cur_streak > max_streak) {
309
- max_streak = cur_streak;
310
- end_of_streak = i;
311
- }
312
- }
313
- }
314
-
315
- if (!max_streak) {
316
- dev_err(mmc_dev(host->mmc), "no tuning point found\n");
317
- return -EIO;
318
- }
319
-
320
- return sdhci_cdns_set_tune_val(host, end_of_streak - max_streak / 2);
321
-}
322329
323330 static void sdhci_cdns_hs400_enhanced_strobe(struct mmc_host *mmc,
324331 struct mmc_ios *ios)
....@@ -343,13 +350,14 @@
343350 static int sdhci_cdns_probe(struct platform_device *pdev)
344351 {
345352 struct sdhci_host *host;
353
+ const struct sdhci_pltfm_data *data;
346354 struct sdhci_pltfm_host *pltfm_host;
347355 struct sdhci_cdns_priv *priv;
348356 struct clk *clk;
349
- size_t priv_size;
350357 unsigned int nr_phy_params;
351358 int ret;
352359 struct device *dev = &pdev->dev;
360
+ static const u16 version = SDHCI_SPEC_400 << SDHCI_SPEC_VER_SHIFT;
353361
354362 clk = devm_clk_get(dev, NULL);
355363 if (IS_ERR(clk))
....@@ -359,9 +367,13 @@
359367 if (ret)
360368 return ret;
361369
370
+ data = of_device_get_match_data(dev);
371
+ if (!data)
372
+ data = &sdhci_cdns_pltfm_data;
373
+
362374 nr_phy_params = sdhci_cdns_phy_param_count(dev->of_node);
363
- priv_size = sizeof(*priv) + sizeof(priv->phy_params[0]) * nr_phy_params;
364
- host = sdhci_pltfm_init(pdev, &sdhci_cdns_pltfm_data, priv_size);
375
+ host = sdhci_pltfm_init(pdev, data,
376
+ struct_size(priv, phy_params, nr_phy_params));
365377 if (IS_ERR(host)) {
366378 ret = PTR_ERR(host);
367379 goto disable_clk;
....@@ -375,9 +387,10 @@
375387 priv->hrs_addr = host->ioaddr;
376388 priv->enhanced_strobe = false;
377389 host->ioaddr += SDHCI_CDNS_SRS_BASE;
378
- host->mmc_host_ops.execute_tuning = sdhci_cdns_execute_tuning;
379390 host->mmc_host_ops.hs400_enhanced_strobe =
380391 sdhci_cdns_hs400_enhanced_strobe;
392
+ sdhci_enable_v4_mode(host);
393
+ __sdhci_read_caps(host, &version, NULL, NULL);
381394
382395 sdhci_get_of_property(pdev);
383396
....@@ -438,7 +451,10 @@
438451 };
439452
440453 static const struct of_device_id sdhci_cdns_match[] = {
441
- { .compatible = "socionext,uniphier-sd4hc" },
454
+ {
455
+ .compatible = "socionext,uniphier-sd4hc",
456
+ .data = &sdhci_cdns_uniphier_pltfm_data,
457
+ },
442458 { .compatible = "cdns,sd4hc" },
443459 { /* sentinel */ }
444460 };
....@@ -447,6 +463,7 @@
447463 static struct platform_driver sdhci_cdns_driver = {
448464 .driver = {
449465 .name = "sdhci-cdns",
466
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
450467 .pm = &sdhci_cdns_pm_ops,
451468 .of_match_table = sdhci_cdns_match,
452469 },