blob: 1ea6e1066f2b881c3189b5a1f5df29918ae50a90 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Marek Vasut06485cf2018-04-08 15:22:58 +02002/*
3 * Copyright (C) 2018 Marek Vasut <marek.vasut@gmail.com>
Marek Vasut06485cf2018-04-08 15:22:58 +02004 */
5
6#include <common.h>
Marek Vasut9f7baeb2020-04-04 12:45:04 +02007#include <bouncebuf.h>
Marek Vasut06485cf2018-04-08 15:22:58 +02008#include <clk.h>
9#include <fdtdec.h>
Simon Glass0f2af882020-05-10 11:40:05 -060010#include <log.h>
Simon Glass9bc15642020-02-03 07:36:16 -070011#include <malloc.h>
Marek Vasut06485cf2018-04-08 15:22:58 +020012#include <mmc.h>
13#include <dm.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060014#include <asm/global_data.h>
Simon Glass9bc15642020-02-03 07:36:16 -070015#include <dm/device_compat.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -060016#include <linux/bitops.h>
Marek Vasut06485cf2018-04-08 15:22:58 +020017#include <linux/compat.h>
Simon Glassdbd79542020-05-10 11:40:11 -060018#include <linux/delay.h>
Marek Vasut06485cf2018-04-08 15:22:58 +020019#include <linux/dma-direction.h>
20#include <linux/io.h>
21#include <linux/sizes.h>
22#include <power/regulator.h>
Paul Barkere22d1a02023-10-16 10:25:38 +010023#include <reset.h>
Marek Vasut06485cf2018-04-08 15:22:58 +020024#include <asm/unaligned.h>
Marek Vasutfd83e762018-04-13 23:51:33 +020025#include "tmio-common.h"
Marek Vasut06485cf2018-04-08 15:22:58 +020026
Marek Vasut10d77ed2018-06-13 08:02:55 +020027#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || \
28 CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \
29 CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
Marek Vasute0781e42018-04-08 19:09:17 +020030
31/* SCC registers */
32#define RENESAS_SDHI_SCC_DTCNTL 0x800
Marek Vasutb1d442b2019-05-19 02:33:06 +020033#define RENESAS_SDHI_SCC_DTCNTL_TAPEN BIT(0)
34#define RENESAS_SDHI_SCC_DTCNTL_TAPNUM_SHIFT 16
35#define RENESAS_SDHI_SCC_DTCNTL_TAPNUM_MASK 0xff
Marek Vasute0781e42018-04-08 19:09:17 +020036#define RENESAS_SDHI_SCC_TAPSET 0x804
37#define RENESAS_SDHI_SCC_DT2FF 0x808
38#define RENESAS_SDHI_SCC_CKSEL 0x80c
Marek Vasutb1d442b2019-05-19 02:33:06 +020039#define RENESAS_SDHI_SCC_CKSEL_DTSEL BIT(0)
40#define RENESAS_SDHI_SCC_RVSCNTL 0x810
41#define RENESAS_SDHI_SCC_RVSCNTL_RVSEN BIT(0)
Marek Vasute0781e42018-04-08 19:09:17 +020042#define RENESAS_SDHI_SCC_RVSREQ 0x814
Marek Vasutb1d442b2019-05-19 02:33:06 +020043#define RENESAS_SDHI_SCC_RVSREQ_RVSERR BIT(2)
Marek Vasut52647a02019-11-23 13:36:23 +010044#define RENESAS_SDHI_SCC_RVSREQ_REQTAPUP BIT(1)
45#define RENESAS_SDHI_SCC_RVSREQ_REQTAPDOWN BIT(0)
Marek Vasute0781e42018-04-08 19:09:17 +020046#define RENESAS_SDHI_SCC_SMPCMP 0x818
Marek Vasut52647a02019-11-23 13:36:23 +010047#define RENESAS_SDHI_SCC_SMPCMP_CMD_ERR (BIT(24) | BIT(8))
48#define RENESAS_SDHI_SCC_SMPCMP_CMD_REQUP BIT(24)
49#define RENESAS_SDHI_SCC_SMPCMP_CMD_REQDOWN BIT(8)
Marek Vasutb1d442b2019-05-19 02:33:06 +020050#define RENESAS_SDHI_SCC_TMPPORT2 0x81c
51#define RENESAS_SDHI_SCC_TMPPORT2_HS400EN BIT(31)
52#define RENESAS_SDHI_SCC_TMPPORT2_HS400OSEL BIT(4)
Marek Vasutfee0c682019-05-19 03:47:07 +020053#define RENESAS_SDHI_SCC_TMPPORT3 0x828
54#define RENESAS_SDHI_SCC_TMPPORT3_OFFSET_0 3
55#define RENESAS_SDHI_SCC_TMPPORT3_OFFSET_1 2
56#define RENESAS_SDHI_SCC_TMPPORT3_OFFSET_2 1
57#define RENESAS_SDHI_SCC_TMPPORT3_OFFSET_3 0
58#define RENESAS_SDHI_SCC_TMPPORT3_OFFSET_MASK 0x3
59#define RENESAS_SDHI_SCC_TMPPORT4 0x82c
60#define RENESAS_SDHI_SCC_TMPPORT4_DLL_ACC_START BIT(0)
61#define RENESAS_SDHI_SCC_TMPPORT5 0x830
62#define RENESAS_SDHI_SCC_TMPPORT5_DLL_RW_SEL_R BIT(8)
63#define RENESAS_SDHI_SCC_TMPPORT5_DLL_RW_SEL_W (0 << 8)
64#define RENESAS_SDHI_SCC_TMPPORT5_DLL_ADR_MASK 0x3F
65#define RENESAS_SDHI_SCC_TMPPORT6 0x834
66#define RENESAS_SDHI_SCC_TMPPORT7 0x838
67#define RENESAS_SDHI_SCC_TMPPORT_DISABLE_WP_CODE 0xa5000000
68#define RENESAS_SDHI_SCC_TMPPORT_CALIB_CODE_MASK 0x1f
69#define RENESAS_SDHI_SCC_TMPPORT_MANUAL_MODE BIT(7)
Marek Vasute0781e42018-04-08 19:09:17 +020070
71#define RENESAS_SDHI_MAX_TAP 3
72
Marek Vasut7b461762019-11-23 13:36:25 +010073#define CALIB_TABLE_MAX (RENESAS_SDHI_SCC_TMPPORT_CALIB_CODE_MASK + 1)
74
Hai Phamf0d3c072023-01-26 21:05:56 +010075static const u8 r8a7796_rev13_calib_table[2][CALIB_TABLE_MAX] = {
Hai Phama12185f2023-01-26 21:05:57 +010076 { 3, 3, 3, 3, 3, 3, 3, 4, 4, 5, 6, 7, 8, 9, 10, 15,
77 16, 16, 16, 16, 16, 16, 17, 18, 18, 19, 20, 21, 22, 23, 24, 25 },
78 { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 7, 8, 11,
79 12, 17, 18, 18, 18, 18, 18, 18, 18, 19, 20, 21, 22, 23, 25, 25 }
Marek Vasut7b461762019-11-23 13:36:25 +010080};
81
82static const u8 r8a77965_calib_table[2][CALIB_TABLE_MAX] = {
Hai Phama12185f2023-01-26 21:05:57 +010083 { 1, 2, 6, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15, 15, 16,
84 17, 18, 19, 20, 21, 22, 23, 24, 25, 25, 26, 27, 28, 29, 30, 31 },
85 { 2, 3, 4, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 16, 17,
86 17, 17, 20, 21, 22, 23, 24, 25, 27, 28, 29, 30, 31, 31, 31, 31 }
Marek Vasut7b461762019-11-23 13:36:25 +010087};
88
89static const u8 r8a77990_calib_table[2][CALIB_TABLE_MAX] = {
90 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
91 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
Hai Phama12185f2023-01-26 21:05:57 +010092 { 0, 0, 0, 1, 2, 3, 3, 4, 4, 4, 5, 5, 6, 8, 9, 10,
93 11, 12, 13, 15, 16, 17, 17, 18, 18, 19, 20, 22, 24, 25, 26, 26 }
Marek Vasut7b461762019-11-23 13:36:25 +010094};
95
96static int rmobile_is_gen3_mmc0(struct tmio_sd_priv *priv)
97{
98 /* On R-Car Gen3, MMC0 is at 0xee140000 */
99 return (uintptr_t)(priv->regbase) == 0xee140000;
100}
101
Marek Vasutfee0c682019-05-19 03:47:07 +0200102static u32 sd_scc_tmpport_read32(struct tmio_sd_priv *priv, u32 addr)
103{
104 /* read mode */
105 tmio_sd_writel(priv, RENESAS_SDHI_SCC_TMPPORT5_DLL_RW_SEL_R |
106 (RENESAS_SDHI_SCC_TMPPORT5_DLL_ADR_MASK & addr),
107 RENESAS_SDHI_SCC_TMPPORT5);
108
109 /* access start and stop */
110 tmio_sd_writel(priv, RENESAS_SDHI_SCC_TMPPORT4_DLL_ACC_START,
111 RENESAS_SDHI_SCC_TMPPORT4);
112 tmio_sd_writel(priv, 0, RENESAS_SDHI_SCC_TMPPORT4);
113
114 return tmio_sd_readl(priv, RENESAS_SDHI_SCC_TMPPORT7);
115}
116
117static void sd_scc_tmpport_write32(struct tmio_sd_priv *priv, u32 addr, u32 val)
118{
119 /* write mode */
120 tmio_sd_writel(priv, RENESAS_SDHI_SCC_TMPPORT5_DLL_RW_SEL_W |
121 (RENESAS_SDHI_SCC_TMPPORT5_DLL_ADR_MASK & addr),
122 RENESAS_SDHI_SCC_TMPPORT5);
123 tmio_sd_writel(priv, val, RENESAS_SDHI_SCC_TMPPORT6);
124
125 /* access start and stop */
126 tmio_sd_writel(priv, RENESAS_SDHI_SCC_TMPPORT4_DLL_ACC_START,
127 RENESAS_SDHI_SCC_TMPPORT4);
128 tmio_sd_writel(priv, 0, RENESAS_SDHI_SCC_TMPPORT4);
129}
130
Marek Vasut52647a02019-11-23 13:36:23 +0100131static bool renesas_sdhi_check_scc_error(struct udevice *dev)
132{
133 struct tmio_sd_priv *priv = dev_get_priv(dev);
134 struct mmc *mmc = mmc_get_mmc_dev(dev);
135 unsigned long new_tap = priv->tap_set;
Marek Vasut531fc992019-11-23 13:36:24 +0100136 unsigned long error_tap = priv->tap_set;
Marek Vasut52647a02019-11-23 13:36:23 +0100137 u32 reg, smpcmp;
138
139 if ((priv->caps & TMIO_SD_CAP_RCAR_UHS) &&
140 (mmc->selected_mode != UHS_SDR104) &&
141 (mmc->selected_mode != MMC_HS_200) &&
142 (mmc->selected_mode != MMC_HS_400) &&
143 (priv->nrtaps != 4))
144 return false;
145
146 reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_RVSCNTL);
147 /* Handle automatic tuning correction */
148 if (reg & RENESAS_SDHI_SCC_RVSCNTL_RVSEN) {
149 reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_RVSREQ);
150 if (reg & RENESAS_SDHI_SCC_RVSREQ_RVSERR) {
151 tmio_sd_writel(priv, 0, RENESAS_SDHI_SCC_RVSREQ);
152 return true;
153 }
154
155 return false;
156 }
157
158 /* Handle manual tuning correction */
159 reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_RVSREQ);
160 if (!reg) /* No error */
161 return false;
162
163 tmio_sd_writel(priv, 0, RENESAS_SDHI_SCC_RVSREQ);
164
165 if (mmc->selected_mode == MMC_HS_400) {
166 /*
167 * Correction Error Status contains CMD and DAT signal status.
168 * In HS400, DAT signal based on DS signal, not CLK.
169 * Therefore, use only CMD status.
170 */
171 smpcmp = tmio_sd_readl(priv, RENESAS_SDHI_SCC_SMPCMP) &
172 RENESAS_SDHI_SCC_SMPCMP_CMD_ERR;
173
174 switch (smpcmp) {
175 case 0:
176 return false; /* No error in CMD signal */
177 case RENESAS_SDHI_SCC_SMPCMP_CMD_REQUP:
178 new_tap = (priv->tap_set +
179 priv->tap_num + 1) % priv->tap_num;
Marek Vasut531fc992019-11-23 13:36:24 +0100180 error_tap = (priv->tap_set +
181 priv->tap_num - 1) % priv->tap_num;
Marek Vasut52647a02019-11-23 13:36:23 +0100182 break;
183 case RENESAS_SDHI_SCC_SMPCMP_CMD_REQDOWN:
184 new_tap = (priv->tap_set +
185 priv->tap_num - 1) % priv->tap_num;
Marek Vasut531fc992019-11-23 13:36:24 +0100186 error_tap = (priv->tap_set +
187 priv->tap_num + 1) % priv->tap_num;
Marek Vasut52647a02019-11-23 13:36:23 +0100188 break;
189 default:
190 return true; /* Need re-tune */
191 }
192
Marek Vasut531fc992019-11-23 13:36:24 +0100193 if (priv->hs400_bad_tap & BIT(new_tap)) {
194 /*
195 * New tap is bad tap (cannot change).
196 * Compare with HS200 tuning result.
197 * In HS200 tuning, when smpcmp[error_tap]
198 * is OK, retune is executed.
199 */
200 if (priv->smpcmp & BIT(error_tap))
201 return true; /* Need retune */
202
203 return false; /* cannot change */
204 }
205
Marek Vasut52647a02019-11-23 13:36:23 +0100206 priv->tap_set = new_tap;
207 } else {
208 if (reg & RENESAS_SDHI_SCC_RVSREQ_RVSERR)
209 return true; /* Need re-tune */
210 else if (reg & RENESAS_SDHI_SCC_RVSREQ_REQTAPUP)
211 priv->tap_set = (priv->tap_set +
212 priv->tap_num + 1) % priv->tap_num;
213 else if (reg & RENESAS_SDHI_SCC_RVSREQ_REQTAPDOWN)
214 priv->tap_set = (priv->tap_set +
215 priv->tap_num - 1) % priv->tap_num;
216 else
217 return false;
218 }
219
220 /* Set TAP position */
221 tmio_sd_writel(priv, priv->tap_set >> ((priv->nrtaps == 4) ? 1 : 0),
222 RENESAS_SDHI_SCC_TAPSET);
223
224 return false;
225}
226
Marek Vasutfee0c682019-05-19 03:47:07 +0200227static void renesas_sdhi_adjust_hs400_mode_enable(struct tmio_sd_priv *priv)
228{
229 u32 calib_code;
230
231 if (!priv->adjust_hs400_enable)
232 return;
233
234 if (!priv->needs_adjust_hs400)
235 return;
236
Marek Vasut7b461762019-11-23 13:36:25 +0100237 if (!priv->adjust_hs400_calib_table)
238 return;
239
Marek Vasutfee0c682019-05-19 03:47:07 +0200240 /*
241 * Enabled Manual adjust HS400 mode
242 *
243 * 1) Disabled Write Protect
244 * W(addr=0x00, WP_DISABLE_CODE)
Marek Vasut7b461762019-11-23 13:36:25 +0100245 *
246 * 2) Read Calibration code
247 * read_value = R(addr=0x26)
248 * 3) Refer to calibration table
249 * Calibration code = table[read_value]
250 * 4) Enabled Manual Calibration
Marek Vasutfee0c682019-05-19 03:47:07 +0200251 * W(addr=0x22, manual mode | Calibration code)
Marek Vasut7b461762019-11-23 13:36:25 +0100252 * 5) Set Offset value to TMPPORT3 Reg
Marek Vasutfee0c682019-05-19 03:47:07 +0200253 */
254 sd_scc_tmpport_write32(priv, 0x00,
255 RENESAS_SDHI_SCC_TMPPORT_DISABLE_WP_CODE);
256 calib_code = sd_scc_tmpport_read32(priv, 0x26);
257 calib_code &= RENESAS_SDHI_SCC_TMPPORT_CALIB_CODE_MASK;
Marek Vasutfee0c682019-05-19 03:47:07 +0200258 sd_scc_tmpport_write32(priv, 0x22,
259 RENESAS_SDHI_SCC_TMPPORT_MANUAL_MODE |
Marek Vasut7b461762019-11-23 13:36:25 +0100260 priv->adjust_hs400_calib_table[calib_code]);
Marek Vasutfee0c682019-05-19 03:47:07 +0200261 tmio_sd_writel(priv, priv->adjust_hs400_offset,
262 RENESAS_SDHI_SCC_TMPPORT3);
263
264 /* Clear flag */
265 priv->needs_adjust_hs400 = false;
266}
267
268static void renesas_sdhi_adjust_hs400_mode_disable(struct tmio_sd_priv *priv)
269{
270
271 /* Disabled Manual adjust HS400 mode
272 *
273 * 1) Disabled Write Protect
274 * W(addr=0x00, WP_DISABLE_CODE)
275 * 2) Disabled Manual Calibration
276 * W(addr=0x22, 0)
277 * 3) Clear offset value to TMPPORT3 Reg
278 */
279 sd_scc_tmpport_write32(priv, 0x00,
280 RENESAS_SDHI_SCC_TMPPORT_DISABLE_WP_CODE);
281 sd_scc_tmpport_write32(priv, 0x22, 0);
282 tmio_sd_writel(priv, 0, RENESAS_SDHI_SCC_TMPPORT3);
283}
284
Marek Vasutfd83e762018-04-13 23:51:33 +0200285static unsigned int renesas_sdhi_init_tuning(struct tmio_sd_priv *priv)
Marek Vasute0781e42018-04-08 19:09:17 +0200286{
287 u32 reg;
288
289 /* Initialize SCC */
Marek Vasutfd83e762018-04-13 23:51:33 +0200290 tmio_sd_writel(priv, 0, TMIO_SD_INFO1);
Marek Vasute0781e42018-04-08 19:09:17 +0200291
Marek Vasutfd83e762018-04-13 23:51:33 +0200292 reg = tmio_sd_readl(priv, TMIO_SD_CLKCTL);
293 reg &= ~TMIO_SD_CLKCTL_SCLKEN;
294 tmio_sd_writel(priv, reg, TMIO_SD_CLKCTL);
Marek Vasute0781e42018-04-08 19:09:17 +0200295
296 /* Set sampling clock selection range */
Marek Vasutda4873d2018-06-13 08:02:55 +0200297 tmio_sd_writel(priv, (0x8 << RENESAS_SDHI_SCC_DTCNTL_TAPNUM_SHIFT) |
298 RENESAS_SDHI_SCC_DTCNTL_TAPEN,
299 RENESAS_SDHI_SCC_DTCNTL);
Marek Vasute0781e42018-04-08 19:09:17 +0200300
Marek Vasutfd83e762018-04-13 23:51:33 +0200301 reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_CKSEL);
Marek Vasute0781e42018-04-08 19:09:17 +0200302 reg |= RENESAS_SDHI_SCC_CKSEL_DTSEL;
Marek Vasutfd83e762018-04-13 23:51:33 +0200303 tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_CKSEL);
Marek Vasute0781e42018-04-08 19:09:17 +0200304
Marek Vasutfd83e762018-04-13 23:51:33 +0200305 reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_RVSCNTL);
Marek Vasute0781e42018-04-08 19:09:17 +0200306 reg &= ~RENESAS_SDHI_SCC_RVSCNTL_RVSEN;
Marek Vasutfd83e762018-04-13 23:51:33 +0200307 tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_RVSCNTL);
Marek Vasute0781e42018-04-08 19:09:17 +0200308
Marek Vasutfd83e762018-04-13 23:51:33 +0200309 tmio_sd_writel(priv, 0x300 /* scc_tappos */,
Marek Vasute0781e42018-04-08 19:09:17 +0200310 RENESAS_SDHI_SCC_DT2FF);
311
Marek Vasutfd83e762018-04-13 23:51:33 +0200312 reg = tmio_sd_readl(priv, TMIO_SD_CLKCTL);
313 reg |= TMIO_SD_CLKCTL_SCLKEN;
314 tmio_sd_writel(priv, reg, TMIO_SD_CLKCTL);
Marek Vasute0781e42018-04-08 19:09:17 +0200315
316 /* Read TAPNUM */
Marek Vasutfd83e762018-04-13 23:51:33 +0200317 return (tmio_sd_readl(priv, RENESAS_SDHI_SCC_DTCNTL) >>
Marek Vasute0781e42018-04-08 19:09:17 +0200318 RENESAS_SDHI_SCC_DTCNTL_TAPNUM_SHIFT) &
319 RENESAS_SDHI_SCC_DTCNTL_TAPNUM_MASK;
320}
321
Marek Vasutfd83e762018-04-13 23:51:33 +0200322static void renesas_sdhi_reset_tuning(struct tmio_sd_priv *priv)
Marek Vasute0781e42018-04-08 19:09:17 +0200323{
324 u32 reg;
325
326 /* Reset SCC */
Marek Vasutfd83e762018-04-13 23:51:33 +0200327 reg = tmio_sd_readl(priv, TMIO_SD_CLKCTL);
328 reg &= ~TMIO_SD_CLKCTL_SCLKEN;
329 tmio_sd_writel(priv, reg, TMIO_SD_CLKCTL);
Marek Vasute0781e42018-04-08 19:09:17 +0200330
Marek Vasutfd83e762018-04-13 23:51:33 +0200331 reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_CKSEL);
Marek Vasute0781e42018-04-08 19:09:17 +0200332 reg &= ~RENESAS_SDHI_SCC_CKSEL_DTSEL;
Marek Vasutfd83e762018-04-13 23:51:33 +0200333 tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_CKSEL);
Marek Vasute0781e42018-04-08 19:09:17 +0200334
Marek Vasutefea7a82018-06-13 08:02:55 +0200335 reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_TMPPORT2);
336 reg &= ~(RENESAS_SDHI_SCC_TMPPORT2_HS400EN |
337 RENESAS_SDHI_SCC_TMPPORT2_HS400OSEL);
338 tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_TMPPORT2);
339
Marek Vasutfee0c682019-05-19 03:47:07 +0200340 /* Disable HS400 mode adjustment */
341 renesas_sdhi_adjust_hs400_mode_disable(priv);
342
Marek Vasutfd83e762018-04-13 23:51:33 +0200343 reg = tmio_sd_readl(priv, TMIO_SD_CLKCTL);
344 reg |= TMIO_SD_CLKCTL_SCLKEN;
345 tmio_sd_writel(priv, reg, TMIO_SD_CLKCTL);
Marek Vasute0781e42018-04-08 19:09:17 +0200346
Marek Vasutfd83e762018-04-13 23:51:33 +0200347 reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_RVSCNTL);
Marek Vasute0781e42018-04-08 19:09:17 +0200348 reg &= ~RENESAS_SDHI_SCC_RVSCNTL_RVSEN;
Marek Vasutfd83e762018-04-13 23:51:33 +0200349 tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_RVSCNTL);
Marek Vasute0781e42018-04-08 19:09:17 +0200350
Marek Vasutfd83e762018-04-13 23:51:33 +0200351 reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_RVSCNTL);
Marek Vasute0781e42018-04-08 19:09:17 +0200352 reg &= ~RENESAS_SDHI_SCC_RVSCNTL_RVSEN;
Marek Vasutfd83e762018-04-13 23:51:33 +0200353 tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_RVSCNTL);
Marek Vasute0781e42018-04-08 19:09:17 +0200354}
355
Marek Vasut10d77ed2018-06-13 08:02:55 +0200356static int renesas_sdhi_hs400(struct udevice *dev)
357{
358 struct tmio_sd_priv *priv = dev_get_priv(dev);
359 struct mmc *mmc = mmc_get_mmc_dev(dev);
360 bool hs400 = (mmc->selected_mode == MMC_HS_400);
361 int ret, taps = hs400 ? priv->nrtaps : 8;
Hai Pham4dae0762023-01-29 02:50:22 +0100362 const u32 sdn_rate = 200000000;
363 u32 sdnh_rate = 800000000;
Marek Vasut531fc992019-11-23 13:36:24 +0100364 unsigned long new_tap;
Marek Vasut10d77ed2018-06-13 08:02:55 +0200365 u32 reg;
366
Hai Pham4dae0762023-01-29 02:50:22 +0100367 if (clk_valid(&priv->clkh) && !priv->needs_clkh_fallback) {
368 /* HS400 on 4tap SoC => SDnH=400 MHz, SDn=200 MHz */
369 if (taps == 4)
370 sdnh_rate /= 2;
371 ret = clk_set_rate(&priv->clkh, sdnh_rate);
372 if (ret < 0)
373 return ret;
374 }
375
376 ret = clk_set_rate(&priv->clk, sdn_rate);
Marek Vasut10d77ed2018-06-13 08:02:55 +0200377 if (ret < 0)
378 return ret;
379
Marek Vasut242c63d2019-11-23 13:36:22 +0100380 reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_RVSCNTL);
381 reg &= ~RENESAS_SDHI_SCC_RVSCNTL_RVSEN;
382 tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_RVSCNTL);
Marek Vasut10d77ed2018-06-13 08:02:55 +0200383
384 reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_TMPPORT2);
385 if (hs400) {
386 reg |= RENESAS_SDHI_SCC_TMPPORT2_HS400EN |
387 RENESAS_SDHI_SCC_TMPPORT2_HS400OSEL;
388 } else {
389 reg &= ~(RENESAS_SDHI_SCC_TMPPORT2_HS400EN |
390 RENESAS_SDHI_SCC_TMPPORT2_HS400OSEL);
391 }
392
393 tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_TMPPORT2);
394
Marek Vasutfee0c682019-05-19 03:47:07 +0200395 /* Disable HS400 mode adjustment */
396 if (!hs400)
397 renesas_sdhi_adjust_hs400_mode_disable(priv);
398
Marek Vasut3d42a072019-02-19 19:32:28 +0100399 tmio_sd_writel(priv, (0x8 << RENESAS_SDHI_SCC_DTCNTL_TAPNUM_SHIFT) |
Marek Vasut10d77ed2018-06-13 08:02:55 +0200400 RENESAS_SDHI_SCC_DTCNTL_TAPEN,
401 RENESAS_SDHI_SCC_DTCNTL);
402
Marek Vasut531fc992019-11-23 13:36:24 +0100403 /* Avoid bad TAP */
404 if (priv->hs400_bad_tap & BIT(priv->tap_set)) {
405 new_tap = (priv->tap_set +
406 priv->tap_num + 1) % priv->tap_num;
407
408 if (priv->hs400_bad_tap & BIT(new_tap))
409 new_tap = (priv->tap_set +
410 priv->tap_num - 1) % priv->tap_num;
411
412 if (priv->hs400_bad_tap & BIT(new_tap)) {
413 new_tap = priv->tap_set;
414 debug("Three consecutive bad tap is prohibited\n");
415 }
416
417 priv->tap_set = new_tap;
418 tmio_sd_writel(priv, priv->tap_set, RENESAS_SDHI_SCC_TAPSET);
419 }
420
Marek Vasut10d77ed2018-06-13 08:02:55 +0200421 if (taps == 4) {
422 tmio_sd_writel(priv, priv->tap_set >> 1,
423 RENESAS_SDHI_SCC_TAPSET);
Marek Vasut1a953032019-11-23 13:36:20 +0100424 tmio_sd_writel(priv, hs400 ? 0x100 : 0x300,
425 RENESAS_SDHI_SCC_DT2FF);
Marek Vasut10d77ed2018-06-13 08:02:55 +0200426 } else {
427 tmio_sd_writel(priv, priv->tap_set, RENESAS_SDHI_SCC_TAPSET);
Marek Vasut1a953032019-11-23 13:36:20 +0100428 tmio_sd_writel(priv, 0x300, RENESAS_SDHI_SCC_DT2FF);
Marek Vasut10d77ed2018-06-13 08:02:55 +0200429 }
430
431 reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_CKSEL);
432 reg |= RENESAS_SDHI_SCC_CKSEL_DTSEL;
433 tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_CKSEL);
434
Marek Vasutfee0c682019-05-19 03:47:07 +0200435 /* Execute adjust hs400 offset after setting to HS400 mode */
436 if (hs400)
437 priv->needs_adjust_hs400 = true;
438
Marek Vasut10d77ed2018-06-13 08:02:55 +0200439 return 0;
440}
441
Marek Vasutfd83e762018-04-13 23:51:33 +0200442static void renesas_sdhi_prepare_tuning(struct tmio_sd_priv *priv,
Marek Vasute0781e42018-04-08 19:09:17 +0200443 unsigned long tap)
444{
445 /* Set sampling clock position */
Marek Vasutfd83e762018-04-13 23:51:33 +0200446 tmio_sd_writel(priv, tap, RENESAS_SDHI_SCC_TAPSET);
Marek Vasute0781e42018-04-08 19:09:17 +0200447}
448
Marek Vasutfd83e762018-04-13 23:51:33 +0200449static unsigned int renesas_sdhi_compare_scc_data(struct tmio_sd_priv *priv)
Marek Vasute0781e42018-04-08 19:09:17 +0200450{
451 /* Get comparison of sampling data */
Marek Vasutfd83e762018-04-13 23:51:33 +0200452 return tmio_sd_readl(priv, RENESAS_SDHI_SCC_SMPCMP);
Marek Vasute0781e42018-04-08 19:09:17 +0200453}
454
Marek Vasutfd83e762018-04-13 23:51:33 +0200455static int renesas_sdhi_select_tuning(struct tmio_sd_priv *priv,
Marek Vasut0555dc62019-11-23 13:36:18 +0100456 unsigned int taps)
Marek Vasute0781e42018-04-08 19:09:17 +0200457{
458 unsigned long tap_cnt; /* counter of tuning success */
Marek Vasute0781e42018-04-08 19:09:17 +0200459 unsigned long tap_start;/* start position of tuning success */
460 unsigned long tap_end; /* end position of tuning success */
461 unsigned long ntap; /* temporary counter of tuning success */
462 unsigned long match_cnt;/* counter of matching data */
463 unsigned long i;
464 bool select = false;
465 u32 reg;
466
Marek Vasutfee0c682019-05-19 03:47:07 +0200467 priv->needs_adjust_hs400 = false;
468
Marek Vasute0781e42018-04-08 19:09:17 +0200469 /* Clear SCC_RVSREQ */
Marek Vasutfd83e762018-04-13 23:51:33 +0200470 tmio_sd_writel(priv, 0, RENESAS_SDHI_SCC_RVSREQ);
Marek Vasute0781e42018-04-08 19:09:17 +0200471
472 /* Merge the results */
Marek Vasutd9d09e32019-11-23 13:36:17 +0100473 for (i = 0; i < priv->tap_num * 2; i++) {
Marek Vasute0781e42018-04-08 19:09:17 +0200474 if (!(taps & BIT(i))) {
Marek Vasutd9d09e32019-11-23 13:36:17 +0100475 taps &= ~BIT(i % priv->tap_num);
476 taps &= ~BIT((i % priv->tap_num) + priv->tap_num);
Marek Vasute0781e42018-04-08 19:09:17 +0200477 }
Marek Vasut0555dc62019-11-23 13:36:18 +0100478 if (!(priv->smpcmp & BIT(i))) {
479 priv->smpcmp &= ~BIT(i % priv->tap_num);
480 priv->smpcmp &= ~BIT((i % priv->tap_num) + priv->tap_num);
Marek Vasute0781e42018-04-08 19:09:17 +0200481 }
482 }
483
484 /*
485 * Find the longest consecutive run of successful probes. If that
486 * is more than RENESAS_SDHI_MAX_TAP probes long then use the
487 * center index as the tap.
488 */
489 tap_cnt = 0;
490 ntap = 0;
491 tap_start = 0;
492 tap_end = 0;
Marek Vasutd9d09e32019-11-23 13:36:17 +0100493 for (i = 0; i < priv->tap_num * 2; i++) {
Marek Vasute0781e42018-04-08 19:09:17 +0200494 if (taps & BIT(i))
495 ntap++;
496 else {
497 if (ntap > tap_cnt) {
498 tap_start = i - ntap;
499 tap_end = i - 1;
500 tap_cnt = ntap;
501 }
502 ntap = 0;
503 }
504 }
505
506 if (ntap > tap_cnt) {
507 tap_start = i - ntap;
508 tap_end = i - 1;
509 tap_cnt = ntap;
510 }
511
512 /*
513 * If all of the TAP is OK, the sampling clock position is selected by
514 * identifying the change point of data.
515 */
Marek Vasutd9d09e32019-11-23 13:36:17 +0100516 if (tap_cnt == priv->tap_num * 2) {
Marek Vasute0781e42018-04-08 19:09:17 +0200517 match_cnt = 0;
518 ntap = 0;
519 tap_start = 0;
520 tap_end = 0;
Marek Vasutd9d09e32019-11-23 13:36:17 +0100521 for (i = 0; i < priv->tap_num * 2; i++) {
Marek Vasut0555dc62019-11-23 13:36:18 +0100522 if (priv->smpcmp & BIT(i))
Marek Vasute0781e42018-04-08 19:09:17 +0200523 ntap++;
524 else {
525 if (ntap > match_cnt) {
526 tap_start = i - ntap;
527 tap_end = i - 1;
528 match_cnt = ntap;
529 }
530 ntap = 0;
531 }
532 }
533 if (ntap > match_cnt) {
534 tap_start = i - ntap;
535 tap_end = i - 1;
536 match_cnt = ntap;
537 }
538 if (match_cnt)
539 select = true;
540 } else if (tap_cnt >= RENESAS_SDHI_MAX_TAP)
541 select = true;
542
543 if (select)
Marek Vasutd9d09e32019-11-23 13:36:17 +0100544 priv->tap_set = ((tap_start + tap_end) / 2) % priv->tap_num;
Marek Vasute0781e42018-04-08 19:09:17 +0200545 else
546 return -EIO;
547
548 /* Set SCC */
Marek Vasut1ebb9d62018-06-13 08:02:55 +0200549 tmio_sd_writel(priv, priv->tap_set, RENESAS_SDHI_SCC_TAPSET);
Marek Vasute0781e42018-04-08 19:09:17 +0200550
551 /* Enable auto re-tuning */
Marek Vasutfd83e762018-04-13 23:51:33 +0200552 reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_RVSCNTL);
Marek Vasute0781e42018-04-08 19:09:17 +0200553 reg |= RENESAS_SDHI_SCC_RVSCNTL_RVSEN;
Marek Vasutfd83e762018-04-13 23:51:33 +0200554 tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_RVSCNTL);
Marek Vasute0781e42018-04-08 19:09:17 +0200555
556 return 0;
557}
558
559int renesas_sdhi_execute_tuning(struct udevice *dev, uint opcode)
560{
Marek Vasutfd83e762018-04-13 23:51:33 +0200561 struct tmio_sd_priv *priv = dev_get_priv(dev);
Marek Vasute0781e42018-04-08 19:09:17 +0200562 struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
563 struct mmc *mmc = upriv->mmc;
564 unsigned int tap_num;
Marek Vasut0555dc62019-11-23 13:36:18 +0100565 unsigned int taps = 0;
Marek Vasute0781e42018-04-08 19:09:17 +0200566 int i, ret = 0;
567 u32 caps;
568
569 /* Only supported on Renesas RCar */
Marek Vasutfd83e762018-04-13 23:51:33 +0200570 if (!(priv->caps & TMIO_SD_CAP_RCAR_UHS))
Marek Vasute0781e42018-04-08 19:09:17 +0200571 return -EINVAL;
572
573 /* clock tuning is not needed for upto 52MHz */
574 if (!((mmc->selected_mode == MMC_HS_200) ||
Marek Vasut10d77ed2018-06-13 08:02:55 +0200575 (mmc->selected_mode == MMC_HS_400) ||
Marek Vasute0781e42018-04-08 19:09:17 +0200576 (mmc->selected_mode == UHS_SDR104) ||
577 (mmc->selected_mode == UHS_SDR50)))
578 return 0;
579
580 tap_num = renesas_sdhi_init_tuning(priv);
581 if (!tap_num)
582 /* Tuning is not supported */
583 goto out;
584
Marek Vasutd9d09e32019-11-23 13:36:17 +0100585 priv->tap_num = tap_num;
586
587 if (priv->tap_num * 2 >= sizeof(taps) * 8) {
Marek Vasute0781e42018-04-08 19:09:17 +0200588 dev_err(dev,
589 "Too many taps, skipping tuning. Please consider updating size of taps field of tmio_mmc_host\n");
590 goto out;
591 }
592
Marek Vasut0555dc62019-11-23 13:36:18 +0100593 priv->smpcmp = 0;
594
Marek Vasute0781e42018-04-08 19:09:17 +0200595 /* Issue CMD19 twice for each tap */
Marek Vasutd9d09e32019-11-23 13:36:17 +0100596 for (i = 0; i < 2 * priv->tap_num; i++) {
597 renesas_sdhi_prepare_tuning(priv, i % priv->tap_num);
Marek Vasute0781e42018-04-08 19:09:17 +0200598
599 /* Force PIO for the tuning */
600 caps = priv->caps;
Marek Vasutfd83e762018-04-13 23:51:33 +0200601 priv->caps &= ~TMIO_SD_CAP_DMA_INTERNAL;
Marek Vasute0781e42018-04-08 19:09:17 +0200602
603 ret = mmc_send_tuning(mmc, opcode, NULL);
604
605 priv->caps = caps;
606
607 if (ret == 0)
608 taps |= BIT(i);
609
610 ret = renesas_sdhi_compare_scc_data(priv);
611 if (ret == 0)
Marek Vasut0555dc62019-11-23 13:36:18 +0100612 priv->smpcmp |= BIT(i);
Marek Vasute0781e42018-04-08 19:09:17 +0200613
614 mdelay(1);
Hai Pham021f7f72023-06-20 00:38:25 +0200615
616 /*
617 * eMMC specification specifies that CMD12 can be used to stop a tuning
618 * command, but SD specification does not, so do nothing unless it is
619 * eMMC.
620 */
621 if (ret && (opcode == MMC_CMD_SEND_TUNING_BLOCK_HS200)) {
622 ret = mmc_send_stop_transmission(mmc, false);
623 if (ret < 0)
624 dev_dbg(dev, "Tuning abort fail (%d)\n", ret);
625 }
Marek Vasute0781e42018-04-08 19:09:17 +0200626 }
627
Marek Vasut0555dc62019-11-23 13:36:18 +0100628 ret = renesas_sdhi_select_tuning(priv, taps);
Marek Vasute0781e42018-04-08 19:09:17 +0200629
630out:
631 if (ret < 0) {
632 dev_warn(dev, "Tuning procedure failed\n");
633 renesas_sdhi_reset_tuning(priv);
634 }
635
636 return ret;
637}
Marek Vasut10d77ed2018-06-13 08:02:55 +0200638#else
639static int renesas_sdhi_hs400(struct udevice *dev)
640{
641 return 0;
642}
Marek Vasute0781e42018-04-08 19:09:17 +0200643#endif
644
645static int renesas_sdhi_set_ios(struct udevice *dev)
646{
Marek Vasut10d77ed2018-06-13 08:02:55 +0200647 struct tmio_sd_priv *priv = dev_get_priv(dev);
648 u32 tmp;
649 int ret;
Marek Vasut33d38182018-04-09 20:47:31 +0200650
Marek Vasut10d77ed2018-06-13 08:02:55 +0200651 /* Stop the clock before changing its rate to avoid a glitch signal */
652 tmp = tmio_sd_readl(priv, TMIO_SD_CLKCTL);
653 tmp &= ~TMIO_SD_CLKCTL_SCLKEN;
654 tmio_sd_writel(priv, tmp, TMIO_SD_CLKCTL);
Marek Vasut33d38182018-04-09 20:47:31 +0200655
Marek Vasut10d77ed2018-06-13 08:02:55 +0200656 ret = renesas_sdhi_hs400(dev);
657 if (ret)
658 return ret;
Marek Vasute0781e42018-04-08 19:09:17 +0200659
Marek Vasut10d77ed2018-06-13 08:02:55 +0200660 ret = tmio_sd_set_ios(dev);
661
662 mdelay(10);
663
664#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || \
665 CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \
666 CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
667 struct mmc *mmc = mmc_get_mmc_dev(dev);
668 if ((priv->caps & TMIO_SD_CAP_RCAR_UHS) &&
669 (mmc->selected_mode != UHS_SDR104) &&
670 (mmc->selected_mode != MMC_HS_200) &&
671 (mmc->selected_mode != MMC_HS_400)) {
Marek Vasut35773802018-10-28 15:30:06 +0100672 renesas_sdhi_reset_tuning(priv);
Marek Vasut10d77ed2018-06-13 08:02:55 +0200673 }
Marek Vasute0781e42018-04-08 19:09:17 +0200674#endif
675
676 return ret;
677}
678
Marek Vasut576a6d92018-10-28 19:28:56 +0100679#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
Sam Protsenkodb174c62019-08-14 22:52:51 +0300680static int renesas_sdhi_wait_dat0(struct udevice *dev, int state,
681 int timeout_us)
Marek Vasut576a6d92018-10-28 19:28:56 +0100682{
683 int ret = -ETIMEDOUT;
684 bool dat0_high;
685 bool target_dat0_high = !!state;
686 struct tmio_sd_priv *priv = dev_get_priv(dev);
687
Sam Protsenkodb174c62019-08-14 22:52:51 +0300688 timeout_us = DIV_ROUND_UP(timeout_us, 10); /* check every 10 us. */
689 while (timeout_us--) {
Marek Vasut576a6d92018-10-28 19:28:56 +0100690 dat0_high = !!(tmio_sd_readl(priv, TMIO_SD_INFO2) & TMIO_SD_INFO2_DAT0);
691 if (dat0_high == target_dat0_high) {
692 ret = 0;
693 break;
694 }
695 udelay(10);
696 }
697
698 return ret;
699}
700#endif
701
Marek Vasut9f7baeb2020-04-04 12:45:04 +0200702#define RENESAS_SDHI_DMA_ALIGNMENT 128
703
Marek Vasut3d5256e2020-04-04 12:45:06 +0200704static int renesas_sdhi_addr_aligned_gen(uintptr_t ubuf,
705 size_t len, size_t len_aligned)
Marek Vasut9f7baeb2020-04-04 12:45:04 +0200706{
Marek Vasut9f7baeb2020-04-04 12:45:04 +0200707 /* Check if start is aligned */
708 if (!IS_ALIGNED(ubuf, RENESAS_SDHI_DMA_ALIGNMENT)) {
Marek Vasut3d5256e2020-04-04 12:45:06 +0200709 debug("Unaligned buffer address %lx\n", ubuf);
Marek Vasut9f7baeb2020-04-04 12:45:04 +0200710 return 0;
711 }
712
713 /* Check if length is aligned */
Marek Vasut3d5256e2020-04-04 12:45:06 +0200714 if (len != len_aligned) {
715 debug("Unaligned buffer length %zu\n", len);
Marek Vasut9f7baeb2020-04-04 12:45:04 +0200716 return 0;
717 }
718
719#ifdef CONFIG_PHYS_64BIT
720 /* Check if below 32bit boundary */
Marek Vasut3d5256e2020-04-04 12:45:06 +0200721 if ((ubuf >> 32) || (ubuf + len_aligned) >> 32) {
722 debug("Buffer above 32bit boundary %lx-%lx\n",
723 ubuf, ubuf + len_aligned);
Marek Vasut9f7baeb2020-04-04 12:45:04 +0200724 return 0;
725 }
726#endif
727
728 /* Aligned */
729 return 1;
730}
731
Marek Vasut3d5256e2020-04-04 12:45:06 +0200732static int renesas_sdhi_addr_aligned(struct bounce_buffer *state)
733{
734 uintptr_t ubuf = (uintptr_t)state->user_buffer;
735
736 return renesas_sdhi_addr_aligned_gen(ubuf, state->len,
737 state->len_aligned);
738}
739
Marek Vasutfee0c682019-05-19 03:47:07 +0200740static int renesas_sdhi_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
741 struct mmc_data *data)
742{
Marek Vasut9f7baeb2020-04-04 12:45:04 +0200743 struct bounce_buffer bbstate;
744 unsigned int bbflags;
745 bool bbok = false;
746 size_t len;
747 void *buf;
Marek Vasutfee0c682019-05-19 03:47:07 +0200748 int ret;
749
Marek Vasut9f7baeb2020-04-04 12:45:04 +0200750 if (data) {
751 if (data->flags & MMC_DATA_READ) {
752 buf = data->dest;
753 bbflags = GEN_BB_WRITE;
754 } else {
755 buf = (void *)data->src;
756 bbflags = GEN_BB_READ;
757 }
758 len = data->blocks * data->blocksize;
759
760 ret = bounce_buffer_start_extalign(&bbstate, buf, len, bbflags,
761 RENESAS_SDHI_DMA_ALIGNMENT,
762 renesas_sdhi_addr_aligned);
763 /*
764 * If the amount of data to transfer is too large, we can get
765 * -ENOMEM when starting the bounce buffer. If that happens,
766 * fall back to PIO as it was before, otherwise use the BB.
767 */
768 if (!ret) {
769 bbok = true;
770 if (data->flags & MMC_DATA_READ)
771 data->dest = bbstate.bounce_buffer;
772 else
773 data->src = bbstate.bounce_buffer;
774 }
775 }
776
Marek Vasutfee0c682019-05-19 03:47:07 +0200777 ret = tmio_sd_send_cmd(dev, cmd, data);
Marek Vasut9f7baeb2020-04-04 12:45:04 +0200778
779 if (data && bbok) {
780 buf = bbstate.user_buffer;
781
782 bounce_buffer_stop(&bbstate);
783
784 if (data->flags & MMC_DATA_READ)
785 data->dest = buf;
786 else
787 data->src = buf;
788 }
789
Marek Vasutfee0c682019-05-19 03:47:07 +0200790 if (ret)
791 return ret;
792
793#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || \
794 CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \
795 CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
796 struct tmio_sd_priv *priv = dev_get_priv(dev);
797
Marek Vasut52647a02019-11-23 13:36:23 +0100798 renesas_sdhi_check_scc_error(dev);
799
Marek Vasutfee0c682019-05-19 03:47:07 +0200800 if (cmd->cmdidx == MMC_CMD_SEND_STATUS)
801 renesas_sdhi_adjust_hs400_mode_enable(priv);
802#endif
803
804 return 0;
805}
806
Marek Vasut3d5256e2020-04-04 12:45:06 +0200807int renesas_sdhi_get_b_max(struct udevice *dev, void *dst, lbaint_t blkcnt)
808{
809 struct tmio_sd_priv *priv = dev_get_priv(dev);
810 struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
811 struct mmc *mmc = upriv->mmc;
812 size_t len = blkcnt * mmc->read_bl_len;
813 size_t len_align = roundup(len, RENESAS_SDHI_DMA_ALIGNMENT);
814
815 if (renesas_sdhi_addr_aligned_gen((uintptr_t)dst, len, len_align)) {
816 if (priv->quirks & TMIO_SD_CAP_16BIT)
817 return U16_MAX;
818 else
819 return U32_MAX;
820 } else {
821 return (CONFIG_SYS_MALLOC_LEN / 4) / mmc->read_bl_len;
822 }
823}
824
Marek Vasut06485cf2018-04-08 15:22:58 +0200825static const struct dm_mmc_ops renesas_sdhi_ops = {
Marek Vasutfee0c682019-05-19 03:47:07 +0200826 .send_cmd = renesas_sdhi_send_cmd,
Marek Vasute0781e42018-04-08 19:09:17 +0200827 .set_ios = renesas_sdhi_set_ios,
Marek Vasutfd83e762018-04-13 23:51:33 +0200828 .get_cd = tmio_sd_get_cd,
Marek Vasut10d77ed2018-06-13 08:02:55 +0200829#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || \
830 CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \
831 CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
Marek Vasute0781e42018-04-08 19:09:17 +0200832 .execute_tuning = renesas_sdhi_execute_tuning,
833#endif
Marek Vasut576a6d92018-10-28 19:28:56 +0100834#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
835 .wait_dat0 = renesas_sdhi_wait_dat0,
836#endif
Marek Vasut3d5256e2020-04-04 12:45:06 +0200837 .get_b_max = renesas_sdhi_get_b_max,
Marek Vasut06485cf2018-04-08 15:22:58 +0200838};
839
Marek Vasutfd83e762018-04-13 23:51:33 +0200840#define RENESAS_GEN2_QUIRKS TMIO_SD_CAP_RCAR_GEN2
Marek Vasut9db9e6a2018-04-08 18:49:52 +0200841#define RENESAS_GEN3_QUIRKS \
Marek Vasutfd83e762018-04-13 23:51:33 +0200842 TMIO_SD_CAP_64BIT | TMIO_SD_CAP_RCAR_GEN3 | TMIO_SD_CAP_RCAR_UHS
Marek Vasut9db9e6a2018-04-08 18:49:52 +0200843
Marek Vasut06485cf2018-04-08 15:22:58 +0200844static const struct udevice_id renesas_sdhi_match[] = {
Marek Vasut9db9e6a2018-04-08 18:49:52 +0200845 { .compatible = "renesas,sdhi-r8a7790", .data = RENESAS_GEN2_QUIRKS },
846 { .compatible = "renesas,sdhi-r8a7791", .data = RENESAS_GEN2_QUIRKS },
847 { .compatible = "renesas,sdhi-r8a7792", .data = RENESAS_GEN2_QUIRKS },
848 { .compatible = "renesas,sdhi-r8a7793", .data = RENESAS_GEN2_QUIRKS },
849 { .compatible = "renesas,sdhi-r8a7794", .data = RENESAS_GEN2_QUIRKS },
850 { .compatible = "renesas,sdhi-r8a7795", .data = RENESAS_GEN3_QUIRKS },
851 { .compatible = "renesas,sdhi-r8a7796", .data = RENESAS_GEN3_QUIRKS },
Hai Pham7e631b02023-01-26 21:05:59 +0100852 { .compatible = "renesas,sdhi-r8a77961", .data = RENESAS_GEN3_QUIRKS },
Adam Ford71283612020-06-30 09:30:10 -0500853 { .compatible = "renesas,rcar-gen3-sdhi", .data = RENESAS_GEN3_QUIRKS },
Marek Vasut9db9e6a2018-04-08 18:49:52 +0200854 { .compatible = "renesas,sdhi-r8a77965", .data = RENESAS_GEN3_QUIRKS },
855 { .compatible = "renesas,sdhi-r8a77970", .data = RENESAS_GEN3_QUIRKS },
Marek Vasut8b2ae7d2018-04-26 13:19:29 +0200856 { .compatible = "renesas,sdhi-r8a77990", .data = RENESAS_GEN3_QUIRKS },
Marek Vasut9db9e6a2018-04-08 18:49:52 +0200857 { .compatible = "renesas,sdhi-r8a77995", .data = RENESAS_GEN3_QUIRKS },
Hai Pham206dc912023-02-28 22:24:06 +0100858 { .compatible = "renesas,rcar-gen4-sdhi", .data = RENESAS_GEN3_QUIRKS },
Marek Vasut06485cf2018-04-08 15:22:58 +0200859 { /* sentinel */ }
860};
861
Marek Vasutda90a1b2018-06-13 08:02:55 +0200862static ulong renesas_sdhi_clk_get_rate(struct tmio_sd_priv *priv)
863{
864 return clk_get_rate(&priv->clk);
865}
866
Marek Vasutb59180a2018-06-13 08:02:55 +0200867static void renesas_sdhi_filter_caps(struct udevice *dev)
868{
Marek Vasutb59180a2018-06-13 08:02:55 +0200869 struct tmio_sd_priv *priv = dev_get_priv(dev);
870
871 if (!(priv->caps & TMIO_SD_CAP_RCAR_GEN3))
872 return;
873
Marek Vasutd6e2f872021-01-03 11:38:25 +0100874 if (priv->caps & TMIO_SD_CAP_DMA_INTERNAL)
875 priv->idma_bus_width = TMIO_SD_DMA_MODE_BUS_WIDTH;
876
Marek Vasut7b461762019-11-23 13:36:25 +0100877#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || \
878 CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \
879 CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
Simon Glassfa20e932020-12-03 16:55:20 -0700880 struct tmio_sd_plat *plat = dev_get_plat(dev);
Marek Vasut7b461762019-11-23 13:36:25 +0100881
Hai Phamf0d3c072023-01-26 21:05:56 +0100882 /* HS400 is not supported on H3 ES1.x, M3W ES1.[012], V3M, V3H ES1.x, D3 */
Marek Vasutb59180a2018-06-13 08:02:55 +0200883 if (((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A7795) &&
884 (rmobile_get_cpu_rev_integer() <= 1)) ||
885 ((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A7796) &&
886 (rmobile_get_cpu_rev_integer() == 1) &&
Hai Phamf0d3c072023-01-26 21:05:56 +0100887 (rmobile_get_cpu_rev_fraction() <= 2)) ||
888 (rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A77970) ||
889 ((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A77980) &&
890 (rmobile_get_cpu_rev_integer() <= 1)) ||
891 (rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A77995))
Marek Vasutb59180a2018-06-13 08:02:55 +0200892 plat->cfg.host_caps &= ~MMC_MODE_HS400;
Marek Vasut10d77ed2018-06-13 08:02:55 +0200893
Marek Vasut531fc992019-11-23 13:36:24 +0100894 /* H3 ES2.0, ES3.0 and M3W ES1.2 and M3N bad taps */
895 if (((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A7795) &&
896 (rmobile_get_cpu_rev_integer() >= 2)) ||
897 ((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A7796) &&
898 (rmobile_get_cpu_rev_integer() == 1) &&
899 (rmobile_get_cpu_rev_fraction() == 2)) ||
900 (rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A77965))
901 priv->hs400_bad_tap = BIT(2) | BIT(3) | BIT(6) | BIT(7);
902
903 /* M3W ES1.x for x>2 can use HS400 with manual adjustment and taps */
Marek Vasutfee0c682019-05-19 03:47:07 +0200904 if ((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A7796) &&
905 (rmobile_get_cpu_rev_integer() == 1) &&
906 (rmobile_get_cpu_rev_fraction() > 2)) {
907 priv->adjust_hs400_enable = true;
Hai Phame4eaa822023-01-26 21:05:58 +0100908 priv->adjust_hs400_offset = 3;
Marek Vasut531fc992019-11-23 13:36:24 +0100909 priv->hs400_bad_tap = BIT(1) | BIT(3) | BIT(5) | BIT(7);
Marek Vasut7b461762019-11-23 13:36:25 +0100910 priv->adjust_hs400_calib_table =
Hai Phamf0d3c072023-01-26 21:05:56 +0100911 r8a7796_rev13_calib_table[!rmobile_is_gen3_mmc0(priv)];
Marek Vasutfee0c682019-05-19 03:47:07 +0200912 }
913
Hai Pham7e631b02023-01-26 21:05:59 +0100914 /* M3W+ bad taps */
915 if ((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A7796) &&
916 (rmobile_get_cpu_rev_integer() == 3))
917 priv->hs400_bad_tap = BIT(1) | BIT(3) | BIT(5) | BIT(7);
918
Marek Vasutfee0c682019-05-19 03:47:07 +0200919 /* M3N can use HS400 with manual adjustment */
920 if (rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A77965) {
921 priv->adjust_hs400_enable = true;
Marek Vasutcf643b02019-11-23 13:36:21 +0100922 priv->adjust_hs400_offset = 3;
Marek Vasut7b461762019-11-23 13:36:25 +0100923 priv->adjust_hs400_calib_table =
924 r8a77965_calib_table[!rmobile_is_gen3_mmc0(priv)];
Marek Vasutfee0c682019-05-19 03:47:07 +0200925 }
926
927 /* E3 can use HS400 with manual adjustment */
928 if (rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A77990) {
929 priv->adjust_hs400_enable = true;
Marek Vasutcf643b02019-11-23 13:36:21 +0100930 priv->adjust_hs400_offset = 3;
Marek Vasut7b461762019-11-23 13:36:25 +0100931 priv->adjust_hs400_calib_table =
932 r8a77990_calib_table[!rmobile_is_gen3_mmc0(priv)];
Marek Vasutfee0c682019-05-19 03:47:07 +0200933 }
934
Hai Pham5c86e062023-01-26 21:05:55 +0100935 /* H3 ES1.x, ES2.0 and M3W ES1.[0123] uses 4 tuning taps */
Marek Vasut715b3252019-11-23 13:36:19 +0100936 if (((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A7795) &&
937 (rmobile_get_cpu_rev_integer() <= 2)) ||
938 ((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A7796) &&
939 (rmobile_get_cpu_rev_integer() == 1) &&
Hai Pham5c86e062023-01-26 21:05:55 +0100940 (rmobile_get_cpu_rev_fraction() <= 3)))
Marek Vasut10d77ed2018-06-13 08:02:55 +0200941 priv->nrtaps = 4;
942 else
943 priv->nrtaps = 8;
Marek Vasut7b461762019-11-23 13:36:25 +0100944#endif
Marek Vasute9a28222019-01-11 23:45:54 +0100945 /* H3 ES1.x and M3W ES1.0 uses bit 17 for DTRAEND */
946 if (((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A7795) &&
947 (rmobile_get_cpu_rev_integer() <= 1)) ||
948 ((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A7796) &&
949 (rmobile_get_cpu_rev_integer() == 1) &&
950 (rmobile_get_cpu_rev_fraction() == 0)))
951 priv->read_poll_flag = TMIO_SD_DMA_INFO1_END_RD;
952 else
953 priv->read_poll_flag = TMIO_SD_DMA_INFO1_END_RD2;
Hai Pham5587caa2023-01-26 21:06:01 +0100954
955 /* V3M handles SD0H differently than other Gen3 SoCs */
956 if (rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A77970)
957 priv->needs_clkh_fallback = true;
958 else
959 priv->needs_clkh_fallback = false;
Marek Vasutb59180a2018-06-13 08:02:55 +0200960}
961
Paul Barkere22d1a02023-10-16 10:25:38 +0100962static int rzg2l_sdhi_setup(struct udevice *dev)
963{
964 struct tmio_sd_priv *priv = dev_get_priv(dev);
965 struct clk imclk2, aclk;
966 struct reset_ctl rst;
967 int ret;
968
969 /*
970 * On members of the RZ/G2L SoC family, we need to enable
971 * additional chip detect and bus clocks, then release the SDHI
972 * module from reset.
973 */
974 ret = clk_get_by_name(dev, "cd", &imclk2);
975 if (ret < 0) {
976 dev_err(dev, "failed to get imclk2 (chip detect clk)\n");
977 goto err_get_imclk2;
978 }
979
980 ret = clk_get_by_name(dev, "aclk", &aclk);
981 if (ret < 0) {
982 dev_err(dev, "failed to get aclk\n");
983 goto err_get_aclk;
984 }
985
986 ret = clk_enable(&imclk2);
987 if (ret < 0) {
988 dev_err(dev, "failed to enable imclk2 (chip detect clk)\n");
989 goto err_imclk2;
990 }
991
992 ret = clk_enable(&aclk);
993 if (ret < 0) {
994 dev_err(dev, "failed to enable aclk\n");
995 goto err_aclk;
996 }
997
998 ret = reset_get_by_index(dev, 0, &rst);
999 if (ret < 0) {
1000 dev_err(dev, "failed to get reset line\n");
1001 goto err_reset;
1002 }
1003
1004 ret = reset_deassert(&rst);
1005 if (ret < 0) {
1006 dev_err(dev, "failed to de-assert reset line\n");
1007 goto err_reset;
1008 }
1009
1010 ret = tmio_sd_probe(dev, priv->quirks);
1011 if (ret)
1012 goto err_tmio_probe;
1013
1014 return 0;
1015
1016err_tmio_probe:
1017 reset_assert(&rst);
1018err_reset:
1019 clk_disable(&aclk);
1020err_aclk:
1021 clk_disable(&imclk2);
1022err_imclk2:
1023 clk_free(&aclk);
1024err_get_aclk:
1025 clk_free(&imclk2);
1026err_get_imclk2:
1027 return ret;
1028}
1029
Marek Vasutabe3e952018-04-08 17:45:23 +02001030static int renesas_sdhi_probe(struct udevice *dev)
1031{
Masahiro Yamada19989d832018-04-20 18:14:24 +09001032 struct tmio_sd_priv *priv = dev_get_priv(dev);
Marek Vasut1949d482018-04-08 18:14:22 +02001033 struct fdt_resource reg_res;
1034 DECLARE_GLOBAL_DATA_PTR;
1035 int ret;
1036
Marek Vasutda90a1b2018-06-13 08:02:55 +02001037 priv->clk_get_rate = renesas_sdhi_clk_get_rate;
1038
Paul Barker110f32d2023-10-16 10:25:37 +01001039 priv->quirks = dev_get_driver_data(dev);
1040 if (priv->quirks == RENESAS_GEN2_QUIRKS) {
Marek Vasut9db9e6a2018-04-08 18:49:52 +02001041 ret = fdt_get_resource(gd->fdt_blob, dev_of_offset(dev),
1042 "reg", 0, &reg_res);
1043 if (ret < 0) {
1044 dev_err(dev, "\"reg\" resource not found, ret=%i\n",
1045 ret);
1046 return ret;
1047 }
Marek Vasut1949d482018-04-08 18:14:22 +02001048
Marek Vasut9db9e6a2018-04-08 18:49:52 +02001049 if (fdt_resource_size(&reg_res) == 0x100)
Paul Barker110f32d2023-10-16 10:25:37 +01001050 priv->quirks |= TMIO_SD_CAP_16BIT;
Marek Vasut9db9e6a2018-04-08 18:49:52 +02001051 }
Marek Vasutabe3e952018-04-08 17:45:23 +02001052
Marek Vasutda90a1b2018-06-13 08:02:55 +02001053 ret = clk_get_by_index(dev, 0, &priv->clk);
Masahiro Yamada19989d832018-04-20 18:14:24 +09001054 if (ret < 0) {
1055 dev_err(dev, "failed to get host clock\n");
1056 return ret;
1057 }
1058
Hai Pham4dae0762023-01-29 02:50:22 +01001059 /* optional SDnH clock */
1060 ret = clk_get_by_name(dev, "clkh", &priv->clkh);
Marek Vasutdcfa1ad2023-02-27 23:49:27 +01001061 if (ret < 0) {
Hai Pham4dae0762023-01-29 02:50:22 +01001062 dev_dbg(dev, "failed to get clkh\n");
Marek Vasutdcfa1ad2023-02-27 23:49:27 +01001063 } else {
1064 ret = clk_set_rate(&priv->clkh, 800000000);
1065 if (ret < 0) {
Marek Vasut3ce49932023-02-27 23:49:28 +01001066 dev_err(dev, "failed to set rate for SDnH clock (%d)\n", ret);
1067 goto err_clk;
Marek Vasutdcfa1ad2023-02-27 23:49:27 +01001068 }
1069 }
Hai Pham4dae0762023-01-29 02:50:22 +01001070
Masahiro Yamada19989d832018-04-20 18:14:24 +09001071 /* set to max rate */
Marek Vasutda90a1b2018-06-13 08:02:55 +02001072 ret = clk_set_rate(&priv->clk, 200000000);
1073 if (ret < 0) {
Marek Vasut3ce49932023-02-27 23:49:28 +01001074 dev_err(dev, "failed to set rate for SDn clock (%d)\n", ret);
1075 goto err_clkh;
Masahiro Yamada19989d832018-04-20 18:14:24 +09001076 }
1077
Marek Vasutda90a1b2018-06-13 08:02:55 +02001078 ret = clk_enable(&priv->clk);
Masahiro Yamada19989d832018-04-20 18:14:24 +09001079 if (ret) {
Marek Vasut3ce49932023-02-27 23:49:28 +01001080 dev_err(dev, "failed to enable SDn clock (%d)\n", ret);
1081 goto err_clkh;
Masahiro Yamada19989d832018-04-20 18:14:24 +09001082 }
1083
Paul Barkere22d1a02023-10-16 10:25:38 +01001084 if (device_is_compatible(dev, "renesas,sdhi-r9a07g044"))
1085 ret = rzg2l_sdhi_setup(dev);
1086 else
1087 ret = tmio_sd_probe(dev, priv->quirks);
Marek Vasut3ce49932023-02-27 23:49:28 +01001088 if (ret)
1089 goto err_tmio_probe;
Marek Vasutb59180a2018-06-13 08:02:55 +02001090
1091 renesas_sdhi_filter_caps(dev);
1092
Marek Vasut10d77ed2018-06-13 08:02:55 +02001093#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || \
1094 CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \
1095 CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
Marek Vasut3ce49932023-02-27 23:49:28 +01001096 if (priv->caps & TMIO_SD_CAP_RCAR_UHS)
Marek Vasutda70ebb2018-08-30 15:27:26 +02001097 renesas_sdhi_reset_tuning(priv);
Marek Vasute0781e42018-04-08 19:09:17 +02001098#endif
Marek Vasut3ce49932023-02-27 23:49:28 +01001099 return 0;
1100
1101err_tmio_probe:
1102 clk_disable(&priv->clk);
1103err_clkh:
1104 clk_free(&priv->clkh);
1105err_clk:
1106 clk_free(&priv->clk);
Marek Vasute0781e42018-04-08 19:09:17 +02001107 return ret;
Marek Vasutabe3e952018-04-08 17:45:23 +02001108}
1109
Marek Vasut06485cf2018-04-08 15:22:58 +02001110U_BOOT_DRIVER(renesas_sdhi) = {
1111 .name = "renesas-sdhi",
1112 .id = UCLASS_MMC,
1113 .of_match = renesas_sdhi_match,
Marek Vasutfd83e762018-04-13 23:51:33 +02001114 .bind = tmio_sd_bind,
Marek Vasutabe3e952018-04-08 17:45:23 +02001115 .probe = renesas_sdhi_probe,
Simon Glass8a2b47f2020-12-03 16:55:17 -07001116 .priv_auto = sizeof(struct tmio_sd_priv),
Simon Glass71fa5b42020-12-03 16:55:18 -07001117 .plat_auto = sizeof(struct tmio_sd_plat),
Marek Vasut06485cf2018-04-08 15:22:58 +02001118 .ops = &renesas_sdhi_ops,
1119};