829b75683b2c80c680aab56a12162949b38c8585
[oweals/u-boot.git] / drivers / mmc / xenon_sdhci.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Driver for Marvell SOC Platform Group Xenon SDHC as a platform device
4  *
5  * Copyright (C) 2016 Marvell, All Rights Reserved.
6  *
7  * Author:      Victor Gu <xigu@marvell.com>
8  * Date:        2016-8-24
9  *
10  * Included parts of the Linux driver version which was written by:
11  * Hu Ziji <huziji@marvell.com>
12  *
13  * Ported to from Marvell 2015.01 to mainline U-Boot 2017.01:
14  * Stefan Roese <sr@denx.de>
15  */
16
17 #include <common.h>
18 #include <dm.h>
19 #include <fdtdec.h>
20 #include <linux/libfdt.h>
21 #include <malloc.h>
22 #include <sdhci.h>
23
24 DECLARE_GLOBAL_DATA_PTR;
25
26 /* Register Offset of SD Host Controller SOCP self-defined register */
27 #define SDHC_SYS_CFG_INFO                       0x0104
28 #define SLOT_TYPE_SDIO_SHIFT                    24
29 #define SLOT_TYPE_EMMC_MASK                     0xFF
30 #define SLOT_TYPE_EMMC_SHIFT                    16
31 #define SLOT_TYPE_SD_SDIO_MMC_MASK              0xFF
32 #define SLOT_TYPE_SD_SDIO_MMC_SHIFT             8
33 #define NR_SUPPORTED_SLOT_MASK                  0x7
34
35 #define SDHC_SYS_OP_CTRL                        0x0108
36 #define AUTO_CLKGATE_DISABLE_MASK               BIT(20)
37 #define SDCLK_IDLEOFF_ENABLE_SHIFT              8
38 #define SLOT_ENABLE_SHIFT                       0
39
40 #define SDHC_SYS_EXT_OP_CTRL                    0x010C
41 #define MASK_CMD_CONFLICT_ERROR                 BIT(8)
42
43 #define SDHC_SLOT_RETUNING_REQ_CTRL             0x0144
44 /* retuning compatible */
45 #define RETUNING_COMPATIBLE                     0x1
46
47 /* Xenon specific Mode Select value */
48 #define XENON_SDHCI_CTRL_HS200                  0x5
49 #define XENON_SDHCI_CTRL_HS400                  0x6
50
51 #define EMMC_PHY_REG_BASE                       0x170
52 #define EMMC_PHY_TIMING_ADJUST                  EMMC_PHY_REG_BASE
53 #define OUTPUT_QSN_PHASE_SELECT                 BIT(17)
54 #define SAMPL_INV_QSP_PHASE_SELECT              BIT(18)
55 #define SAMPL_INV_QSP_PHASE_SELECT_SHIFT        18
56 #define EMMC_PHY_SLOW_MODE                      BIT(29)
57 #define PHY_INITIALIZAION                       BIT(31)
58 #define WAIT_CYCLE_BEFORE_USING_MASK            0xf
59 #define WAIT_CYCLE_BEFORE_USING_SHIFT           12
60 #define FC_SYNC_EN_DURATION_MASK                0xf
61 #define FC_SYNC_EN_DURATION_SHIFT               8
62 #define FC_SYNC_RST_EN_DURATION_MASK            0xf
63 #define FC_SYNC_RST_EN_DURATION_SHIFT           4
64 #define FC_SYNC_RST_DURATION_MASK               0xf
65 #define FC_SYNC_RST_DURATION_SHIFT              0
66
67 #define EMMC_PHY_FUNC_CONTROL                   (EMMC_PHY_REG_BASE + 0x4)
68 #define DQ_ASYNC_MODE                           BIT(4)
69 #define DQ_DDR_MODE_SHIFT                       8
70 #define DQ_DDR_MODE_MASK                        0xff
71 #define CMD_DDR_MODE                            BIT(16)
72
73 #define EMMC_PHY_PAD_CONTROL                    (EMMC_PHY_REG_BASE + 0x8)
74 #define REC_EN_SHIFT                            24
75 #define REC_EN_MASK                             0xf
76 #define FC_DQ_RECEN                             BIT(24)
77 #define FC_CMD_RECEN                            BIT(25)
78 #define FC_QSP_RECEN                            BIT(26)
79 #define FC_QSN_RECEN                            BIT(27)
80 #define OEN_QSN                                 BIT(28)
81 #define AUTO_RECEN_CTRL                         BIT(30)
82
83 #define EMMC_PHY_PAD_CONTROL1                   (EMMC_PHY_REG_BASE + 0xc)
84 #define EMMC5_1_FC_QSP_PD                       BIT(9)
85 #define EMMC5_1_FC_QSP_PU                       BIT(25)
86 #define EMMC5_1_FC_CMD_PD                       BIT(8)
87 #define EMMC5_1_FC_CMD_PU                       BIT(24)
88 #define EMMC5_1_FC_DQ_PD                        0xff
89 #define EMMC5_1_FC_DQ_PU                        (0xff << 16)
90
91 #define SDHCI_RETUNE_EVT_INTSIG                 0x00001000
92
93 /* Hyperion only have one slot 0 */
94 #define XENON_MMC_SLOT_ID_HYPERION              0
95
96 #define MMC_TIMING_LEGACY       0
97 #define MMC_TIMING_MMC_HS       1
98 #define MMC_TIMING_SD_HS        2
99 #define MMC_TIMING_UHS_SDR12    3
100 #define MMC_TIMING_UHS_SDR25    4
101 #define MMC_TIMING_UHS_SDR50    5
102 #define MMC_TIMING_UHS_SDR104   6
103 #define MMC_TIMING_UHS_DDR50    7
104 #define MMC_TIMING_MMC_DDR52    8
105 #define MMC_TIMING_MMC_HS200    9
106 #define MMC_TIMING_MMC_HS400    10
107
108 #define XENON_MMC_MAX_CLK       400000000
109
110 enum soc_pad_ctrl_type {
111         SOC_PAD_SD,
112         SOC_PAD_FIXED_1_8V,
113 };
114
115 struct xenon_sdhci_plat {
116         struct mmc_config cfg;
117         struct mmc mmc;
118 };
119
120 struct xenon_sdhci_priv {
121         struct sdhci_host host;
122
123         u8 timing;
124
125         unsigned int clock;
126
127         void *pad_ctrl_reg;
128         int pad_type;
129 };
130
131 static int xenon_mmc_phy_init(struct sdhci_host *host)
132 {
133         struct xenon_sdhci_priv *priv = host->mmc->priv;
134         u32 clock = priv->clock;
135         u32 time;
136         u32 var;
137
138         /* Enable QSP PHASE SELECT */
139         var = sdhci_readl(host, EMMC_PHY_TIMING_ADJUST);
140         var |= SAMPL_INV_QSP_PHASE_SELECT;
141         if ((priv->timing == MMC_TIMING_UHS_SDR50) ||
142             (priv->timing == MMC_TIMING_UHS_SDR25) ||
143             (priv->timing == MMC_TIMING_UHS_SDR12) ||
144             (priv->timing == MMC_TIMING_SD_HS) ||
145             (priv->timing == MMC_TIMING_LEGACY))
146                 var |= EMMC_PHY_SLOW_MODE;
147         sdhci_writel(host, var, EMMC_PHY_TIMING_ADJUST);
148
149         /* Poll for host MMC PHY clock init to be stable */
150         /* Wait up to 10ms */
151         time = 100;
152         while (time--) {
153                 var = sdhci_readl(host, SDHCI_CLOCK_CONTROL);
154                 if (var & SDHCI_CLOCK_INT_STABLE)
155                         break;
156
157                 udelay(100);
158         }
159
160         if (time <= 0) {
161                 pr_err("Failed to enable MMC internal clock in time\n");
162                 return -ETIMEDOUT;
163         }
164
165         /* Init PHY */
166         var = sdhci_readl(host, EMMC_PHY_TIMING_ADJUST);
167         var |= PHY_INITIALIZAION;
168         sdhci_writel(host, var, EMMC_PHY_TIMING_ADJUST);
169
170         if (clock == 0) {
171                 /* Use the possibly slowest bus frequency value */
172                 clock = 100000;
173         }
174
175         /* Poll for host eMMC PHY init to complete */
176         /* Wait up to 10ms */
177         time = 100;
178         while (time--) {
179                 var = sdhci_readl(host, EMMC_PHY_TIMING_ADJUST);
180                 var &= PHY_INITIALIZAION;
181                 if (!var)
182                         break;
183
184                 /* wait for host eMMC PHY init to complete */
185                 udelay(100);
186         }
187
188         if (time <= 0) {
189                 pr_err("Failed to init MMC PHY in time\n");
190                 return -ETIMEDOUT;
191         }
192
193         return 0;
194 }
195
196 #define ARMADA_3700_SOC_PAD_1_8V        0x1
197 #define ARMADA_3700_SOC_PAD_3_3V        0x0
198
199 static void armada_3700_soc_pad_voltage_set(struct sdhci_host *host)
200 {
201         struct xenon_sdhci_priv *priv = host->mmc->priv;
202
203         if (priv->pad_type == SOC_PAD_FIXED_1_8V)
204                 writel(ARMADA_3700_SOC_PAD_1_8V, priv->pad_ctrl_reg);
205         else if (priv->pad_type == SOC_PAD_SD)
206                 writel(ARMADA_3700_SOC_PAD_3_3V, priv->pad_ctrl_reg);
207 }
208
209 static void xenon_mmc_phy_set(struct sdhci_host *host)
210 {
211         struct xenon_sdhci_priv *priv = host->mmc->priv;
212         u32 var;
213
214         /* Setup pad, set bit[30], bit[28] and bits[26:24] */
215         var = sdhci_readl(host, EMMC_PHY_PAD_CONTROL);
216         var |= AUTO_RECEN_CTRL | OEN_QSN | FC_QSP_RECEN |
217                 FC_CMD_RECEN | FC_DQ_RECEN;
218         sdhci_writel(host, var, EMMC_PHY_PAD_CONTROL);
219
220         /* Set CMD and DQ Pull Up */
221         var = sdhci_readl(host, EMMC_PHY_PAD_CONTROL1);
222         var |= (EMMC5_1_FC_CMD_PU | EMMC5_1_FC_DQ_PU);
223         var &= ~(EMMC5_1_FC_CMD_PD | EMMC5_1_FC_DQ_PD);
224         sdhci_writel(host, var, EMMC_PHY_PAD_CONTROL1);
225
226         /*
227          * If timing belongs to high speed, set bit[17] of
228          * EMMC_PHY_TIMING_ADJUST register
229          */
230         if ((priv->timing == MMC_TIMING_MMC_HS400) ||
231             (priv->timing == MMC_TIMING_MMC_HS200) ||
232             (priv->timing == MMC_TIMING_UHS_SDR50) ||
233             (priv->timing == MMC_TIMING_UHS_SDR104) ||
234             (priv->timing == MMC_TIMING_UHS_DDR50) ||
235             (priv->timing == MMC_TIMING_UHS_SDR25) ||
236             (priv->timing == MMC_TIMING_MMC_DDR52)) {
237                 var = sdhci_readl(host, EMMC_PHY_TIMING_ADJUST);
238                 var |= OUTPUT_QSN_PHASE_SELECT;
239                 sdhci_writel(host, var, EMMC_PHY_TIMING_ADJUST);
240         }
241
242         /*
243          * When setting EMMC_PHY_FUNC_CONTROL register,
244          * SD clock should be disabled
245          */
246         var = sdhci_readl(host, SDHCI_CLOCK_CONTROL);
247         var &= ~SDHCI_CLOCK_CARD_EN;
248         sdhci_writew(host, var, SDHCI_CLOCK_CONTROL);
249
250         var = sdhci_readl(host, EMMC_PHY_FUNC_CONTROL);
251         if (host->mmc->ddr_mode) {
252                 var |= (DQ_DDR_MODE_MASK << DQ_DDR_MODE_SHIFT) | CMD_DDR_MODE;
253         } else {
254                 var &= ~((DQ_DDR_MODE_MASK << DQ_DDR_MODE_SHIFT) |
255                          CMD_DDR_MODE);
256         }
257         sdhci_writel(host, var, EMMC_PHY_FUNC_CONTROL);
258
259         /* Enable bus clock */
260         var = sdhci_readl(host, SDHCI_CLOCK_CONTROL);
261         var |= SDHCI_CLOCK_CARD_EN;
262         sdhci_writew(host, var, SDHCI_CLOCK_CONTROL);
263
264         xenon_mmc_phy_init(host);
265 }
266
267 /* Enable/Disable the Auto Clock Gating function of this slot */
268 static void xenon_mmc_set_acg(struct sdhci_host *host, bool enable)
269 {
270         u32 var;
271
272         var = sdhci_readl(host, SDHC_SYS_OP_CTRL);
273         if (enable)
274                 var &= ~AUTO_CLKGATE_DISABLE_MASK;
275         else
276                 var |= AUTO_CLKGATE_DISABLE_MASK;
277
278         sdhci_writel(host, var, SDHC_SYS_OP_CTRL);
279 }
280
281 #define SLOT_MASK(slot)         BIT(slot)
282
283 /* Enable specific slot */
284 static void xenon_mmc_enable_slot(struct sdhci_host *host, u8 slot)
285 {
286         u32 var;
287
288         var = sdhci_readl(host, SDHC_SYS_OP_CTRL);
289         var |= SLOT_MASK(slot) << SLOT_ENABLE_SHIFT;
290         sdhci_writel(host, var, SDHC_SYS_OP_CTRL);
291 }
292
293 /* Enable Parallel Transfer Mode */
294 static void xenon_mmc_enable_parallel_tran(struct sdhci_host *host, u8 slot)
295 {
296         u32 var;
297
298         var = sdhci_readl(host, SDHC_SYS_EXT_OP_CTRL);
299         var |= SLOT_MASK(slot);
300         sdhci_writel(host, var, SDHC_SYS_EXT_OP_CTRL);
301 }
302
303 static void xenon_mmc_disable_tuning(struct sdhci_host *host, u8 slot)
304 {
305         u32 var;
306
307         /* Clear the Re-Tuning Request functionality */
308         var = sdhci_readl(host, SDHC_SLOT_RETUNING_REQ_CTRL);
309         var &= ~RETUNING_COMPATIBLE;
310         sdhci_writel(host, var, SDHC_SLOT_RETUNING_REQ_CTRL);
311
312         /* Clear the Re-tuning Event Signal Enable */
313         var = sdhci_readl(host, SDHCI_SIGNAL_ENABLE);
314         var &= ~SDHCI_RETUNE_EVT_INTSIG;
315         sdhci_writel(host, var, SDHCI_SIGNAL_ENABLE);
316 }
317
318 /* Mask command conflict error */
319 static void xenon_mask_cmd_conflict_err(struct sdhci_host *host)
320 {
321         u32  reg;
322
323         reg = sdhci_readl(host, SDHC_SYS_EXT_OP_CTRL);
324         reg |= MASK_CMD_CONFLICT_ERROR;
325         sdhci_writel(host, reg, SDHC_SYS_EXT_OP_CTRL);
326 }
327
328 /* Platform specific function for post set_ios configuration */
329 static int xenon_sdhci_set_ios_post(struct sdhci_host *host)
330 {
331         struct xenon_sdhci_priv *priv = host->mmc->priv;
332         uint speed = host->mmc->tran_speed;
333         int pwr_18v = 0;
334
335         if ((sdhci_readb(host, SDHCI_POWER_CONTROL) & ~SDHCI_POWER_ON) ==
336             SDHCI_POWER_180)
337                 pwr_18v = 1;
338
339         /* Set timing variable according to the configured speed */
340         if (IS_SD(host->mmc)) {
341                 /* SD/SDIO */
342                 if (pwr_18v) {
343                         if (host->mmc->ddr_mode)
344                                 priv->timing = MMC_TIMING_UHS_DDR50;
345                         else if (speed <= 25000000)
346                                 priv->timing = MMC_TIMING_UHS_SDR25;
347                         else
348                                 priv->timing = MMC_TIMING_UHS_SDR50;
349                 } else {
350                         if (speed <= 25000000)
351                                 priv->timing = MMC_TIMING_LEGACY;
352                         else
353                                 priv->timing = MMC_TIMING_SD_HS;
354                 }
355         } else {
356                 /* eMMC */
357                 if (host->mmc->ddr_mode)
358                         priv->timing = MMC_TIMING_MMC_DDR52;
359                 else if (speed <= 26000000)
360                         priv->timing = MMC_TIMING_LEGACY;
361                 else
362                         priv->timing = MMC_TIMING_MMC_HS;
363         }
364
365         /* Re-init the PHY */
366         xenon_mmc_phy_set(host);
367
368         return 0;
369 }
370
371 /* Install a driver specific handler for post set_ios configuration */
372 static const struct sdhci_ops xenon_sdhci_ops = {
373         .set_ios_post = xenon_sdhci_set_ios_post
374 };
375
376 static int xenon_sdhci_probe(struct udevice *dev)
377 {
378         struct xenon_sdhci_plat *plat = dev_get_platdata(dev);
379         struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
380         struct xenon_sdhci_priv *priv = dev_get_priv(dev);
381         struct sdhci_host *host = dev_get_priv(dev);
382         int ret;
383
384         host->mmc = &plat->mmc;
385         host->mmc->priv = host;
386         host->mmc->dev = dev;
387         upriv->mmc = host->mmc;
388
389         /* Set quirks */
390         host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD | SDHCI_QUIRK_32BIT_DMA_ADDR;
391
392         /* Set default timing */
393         priv->timing = MMC_TIMING_LEGACY;
394
395         /* Disable auto clock gating during init */
396         xenon_mmc_set_acg(host, false);
397
398         /* Enable slot */
399         xenon_mmc_enable_slot(host, XENON_MMC_SLOT_ID_HYPERION);
400
401         /*
402          * Set default power on SoC PHY PAD register (currently only
403          * available on the Armada 3700)
404          */
405         if (priv->pad_ctrl_reg)
406                 armada_3700_soc_pad_voltage_set(host);
407
408         host->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_DDR_52MHz;
409         switch (fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "bus-width",
410                 1)) {
411         case 8:
412                 host->host_caps |= MMC_MODE_8BIT;
413                 break;
414         case 4:
415                 host->host_caps |= MMC_MODE_4BIT;
416                 break;
417         case 1:
418                 break;
419         default:
420                 printf("Invalid \"bus-width\" value\n");
421                 return -EINVAL;
422         }
423
424         host->ops = &xenon_sdhci_ops;
425
426         host->max_clk = XENON_MMC_MAX_CLK;
427         ret = sdhci_setup_cfg(&plat->cfg, host, 0, 0);
428         if (ret)
429                 return ret;
430
431         ret = sdhci_probe(dev);
432         if (ret)
433                 return ret;
434
435         /* Enable parallel transfer */
436         xenon_mmc_enable_parallel_tran(host, XENON_MMC_SLOT_ID_HYPERION);
437
438         /* Disable tuning functionality of this slot */
439         xenon_mmc_disable_tuning(host, XENON_MMC_SLOT_ID_HYPERION);
440
441         /* Enable auto clock gating after init */
442         xenon_mmc_set_acg(host, true);
443
444         xenon_mask_cmd_conflict_err(host);
445
446         return ret;
447 }
448
449 static int xenon_sdhci_ofdata_to_platdata(struct udevice *dev)
450 {
451         struct sdhci_host *host = dev_get_priv(dev);
452         struct xenon_sdhci_priv *priv = dev_get_priv(dev);
453         const char *name;
454
455         host->name = dev->name;
456         host->ioaddr = (void *)devfdt_get_addr(dev);
457
458         if (device_is_compatible(dev, "marvell,armada-3700-sdhci"))
459                 priv->pad_ctrl_reg = (void *)devfdt_get_addr_index(dev, 1);
460
461         name = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "marvell,pad-type",
462                            NULL);
463         if (name) {
464                 if (0 == strncmp(name, "sd", 2)) {
465                         priv->pad_type = SOC_PAD_SD;
466                 } else if (0 == strncmp(name, "fixed-1-8v", 10)) {
467                         priv->pad_type = SOC_PAD_FIXED_1_8V;
468                 } else {
469                         printf("Unsupported SOC PHY PAD ctrl type %s\n", name);
470                         return -EINVAL;
471                 }
472         }
473
474         return 0;
475 }
476
477 static int xenon_sdhci_bind(struct udevice *dev)
478 {
479         struct xenon_sdhci_plat *plat = dev_get_platdata(dev);
480
481         return sdhci_bind(dev, &plat->mmc, &plat->cfg);
482 }
483
484 static const struct udevice_id xenon_sdhci_ids[] = {
485         { .compatible = "marvell,armada-8k-sdhci",},
486         { .compatible = "marvell,armada-3700-sdhci",},
487         { }
488 };
489
490 U_BOOT_DRIVER(xenon_sdhci_drv) = {
491         .name           = "xenon_sdhci",
492         .id             = UCLASS_MMC,
493         .of_match       = xenon_sdhci_ids,
494         .ofdata_to_platdata = xenon_sdhci_ofdata_to_platdata,
495         .ops            = &sdhci_ops,
496         .bind           = xenon_sdhci_bind,
497         .probe          = xenon_sdhci_probe,
498         .priv_auto_alloc_size = sizeof(struct xenon_sdhci_priv),
499         .platdata_auto_alloc_size = sizeof(struct xenon_sdhci_plat),
500 };