]>
Commit | Line | Data |
---|---|---|
a87d5638 | 1 | /* |
9d08428a | 2 | * Renesas SDHI |
a87d5638 | 3 | * |
87317c4d SH |
4 | * Copyright (C) 2015-17 Renesas Electronics Corporation |
5 | * Copyright (C) 2016-17 Sang Engineering, Wolfram Sang | |
6 | * Copyright (C) 2016-17 Horms Solutions, Simon Horman | |
a87d5638 MD |
7 | * Copyright (C) 2009 Magnus Damm |
8 | * | |
9 | * This program is free software; you can redistribute it and/or modify | |
10 | * it under the terms of the GNU General Public License version 2 as | |
11 | * published by the Free Software Foundation. | |
12 | * | |
13 | * Based on "Compaq ASIC3 support": | |
14 | * | |
15 | * Copyright 2001 Compaq Computer Corporation. | |
16 | * Copyright 2004-2005 Phil Blundell | |
17 | * Copyright 2007-2008 OpenedHand Ltd. | |
18 | * | |
19 | * Authors: Phil Blundell <pb@handhelds.org>, | |
20 | * Samuel Ortiz <sameo@openedhand.com> | |
21 | * | |
22 | */ | |
23 | ||
24 | #include <linux/kernel.h> | |
25 | #include <linux/clk.h> | |
5a0e3ad6 | 26 | #include <linux/slab.h> |
967a6a07 | 27 | #include <linux/module.h> |
5a00a971 | 28 | #include <linux/of_device.h> |
a87d5638 | 29 | #include <linux/platform_device.h> |
3c49e810 | 30 | #include <linux/mmc/host.h> |
a87d5638 | 31 | #include <linux/mfd/tmio.h> |
056676da | 32 | #include <linux/sh_dma.h> |
973ed3af | 33 | #include <linux/delay.h> |
057a4592 WS |
34 | #include <linux/pinctrl/consumer.h> |
35 | #include <linux/pinctrl/pinctrl-state.h> | |
36 | #include <linux/regulator/consumer.h> | |
a87d5638 | 37 | |
c2a96987 | 38 | #include "renesas_sdhi.h" |
42051e8a GL |
39 | #include "tmio_mmc.h" |
40 | ||
e3c418f1 KM |
41 | #define EXT_ACC 0xe4 |
42 | ||
a2a16c77 | 43 | #define SDHI_VER_GEN2_SDR50 0x490c |
c7825151 | 44 | #define SDHI_VER_RZ_A1 0x820b |
a2a16c77 WS |
45 | /* very old datasheets said 0x490c for SDR104, too. They are wrong! */ |
46 | #define SDHI_VER_GEN2_SDR104 0xcb0d | |
47 | #define SDHI_VER_GEN3_SD 0xcc10 | |
48 | #define SDHI_VER_GEN3_SDMMC 0xcd10 | |
49 | ||
2fe35968 SH |
50 | #define host_to_priv(host) \ |
51 | container_of((host)->pdata, struct renesas_sdhi, mmc_data) | |
16935250 | 52 | |
b5b6a5f4 | 53 | struct renesas_sdhi { |
a87d5638 | 54 | struct clk *clk; |
34a16547 | 55 | struct clk *clk_cd; |
a87d5638 | 56 | struct tmio_mmc_data mmc_data; |
056676da | 57 | struct tmio_mmc_dma dma_priv; |
057a4592 WS |
58 | struct pinctrl *pinctrl; |
59 | struct pinctrl_state *pins_default, *pins_uhs; | |
06f438dd | 60 | void __iomem *scc_ctl; |
a87d5638 MD |
61 | }; |
62 | ||
b5b6a5f4 | 63 | static void renesas_sdhi_sdbuf_width(struct tmio_mmc_host *host, int width) |
f45394d5 KM |
64 | { |
65 | u32 val; | |
66 | ||
67 | /* | |
68 | * see also | |
b5b6a5f4 | 69 | * renesas_sdhi_of_data :: dma_buswidth |
f45394d5 KM |
70 | */ |
71 | switch (sd_ctrl_read16(host, CTL_VERSION)) { | |
a2a16c77 | 72 | case SDHI_VER_GEN2_SDR50: |
f45394d5 KM |
73 | val = (width == 32) ? 0x0001 : 0x0000; |
74 | break; | |
a2a16c77 | 75 | case SDHI_VER_GEN2_SDR104: |
f45394d5 KM |
76 | val = (width == 32) ? 0x0000 : 0x0001; |
77 | break; | |
a2a16c77 WS |
78 | case SDHI_VER_GEN3_SD: |
79 | case SDHI_VER_GEN3_SDMMC: | |
a72e8b17 WS |
80 | if (width == 64) |
81 | val = 0x0000; | |
82 | else if (width == 32) | |
83 | val = 0x0101; | |
84 | else | |
85 | val = 0x0001; | |
86 | break; | |
f45394d5 KM |
87 | default: |
88 | /* nothing to do */ | |
89 | return; | |
90 | } | |
91 | ||
92 | sd_ctrl_write16(host, EXT_ACC, val); | |
93 | } | |
94 | ||
b5b6a5f4 | 95 | static int renesas_sdhi_clk_enable(struct tmio_mmc_host *host) |
56c49287 | 96 | { |
0ea28210 | 97 | struct mmc_host *mmc = host->mmc; |
b5b6a5f4 | 98 | struct renesas_sdhi *priv = host_to_priv(host); |
00fb3d2a | 99 | int ret = clk_prepare_enable(priv->clk); |
2fe35968 | 100 | |
56c49287 GL |
101 | if (ret < 0) |
102 | return ret; | |
103 | ||
34a16547 CB |
104 | ret = clk_prepare_enable(priv->clk_cd); |
105 | if (ret < 0) { | |
106 | clk_disable_unprepare(priv->clk); | |
107 | return ret; | |
108 | } | |
109 | ||
2fb55956 BH |
110 | /* |
111 | * The clock driver may not know what maximum frequency | |
112 | * actually works, so it should be set with the max-frequency | |
113 | * property which will already have been read to f_max. If it | |
114 | * was missing, assume the current frequency is the maximum. | |
115 | */ | |
116 | if (!mmc->f_max) | |
117 | mmc->f_max = clk_get_rate(priv->clk); | |
118 | ||
119 | /* | |
120 | * Minimum frequency is the minimum input clock frequency | |
121 | * divided by our maximum divider. | |
122 | */ | |
123 | mmc->f_min = max(clk_round_rate(priv->clk, 1) / 512, 1L); | |
f45394d5 KM |
124 | |
125 | /* enable 16bit data access on SDBUF as default */ | |
b5b6a5f4 | 126 | renesas_sdhi_sdbuf_width(host, 16); |
f45394d5 | 127 | |
56c49287 GL |
128 | return 0; |
129 | } | |
130 | ||
b5b6a5f4 | 131 | static unsigned int renesas_sdhi_clk_update(struct tmio_mmc_host *host, |
2fe35968 | 132 | unsigned int new_clock) |
2fb55956 | 133 | { |
b5b6a5f4 | 134 | struct renesas_sdhi *priv = host_to_priv(host); |
3072ba8c | 135 | unsigned int freq, diff, best_freq = 0, diff_min = ~0; |
f3f44d51 | 136 | int i, ret; |
2fb55956 | 137 | |
d63c2bf4 | 138 | /* tested only on R-Car Gen2+ currently; may work for others */ |
8fc00998 WS |
139 | if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2)) |
140 | return clk_get_rate(priv->clk); | |
141 | ||
2fb55956 BH |
142 | /* |
143 | * We want the bus clock to be as close as possible to, but no | |
144 | * greater than, new_clock. As we can divide by 1 << i for | |
145 | * any i in [0, 9] we want the input clock to be as close as | |
146 | * possible, but no greater than, new_clock << i. | |
147 | */ | |
148 | for (i = min(9, ilog2(UINT_MAX / new_clock)); i >= 0; i--) { | |
149 | freq = clk_round_rate(priv->clk, new_clock << i); | |
150 | if (freq > (new_clock << i)) { | |
151 | /* Too fast; look for a slightly slower option */ | |
152 | freq = clk_round_rate(priv->clk, | |
153 | (new_clock << i) / 4 * 3); | |
154 | if (freq > (new_clock << i)) | |
155 | continue; | |
156 | } | |
157 | ||
158 | diff = new_clock - (freq >> i); | |
159 | if (diff <= diff_min) { | |
160 | best_freq = freq; | |
161 | diff_min = diff; | |
162 | } | |
163 | } | |
164 | ||
f3f44d51 | 165 | ret = clk_set_rate(priv->clk, best_freq); |
2fb55956 | 166 | |
f3f44d51 | 167 | return ret == 0 ? best_freq : clk_get_rate(priv->clk); |
2fb55956 BH |
168 | } |
169 | ||
b5b6a5f4 | 170 | static void renesas_sdhi_clk_disable(struct tmio_mmc_host *host) |
56c49287 | 171 | { |
b5b6a5f4 | 172 | struct renesas_sdhi *priv = host_to_priv(host); |
0ea28210 | 173 | |
00fb3d2a | 174 | clk_disable_unprepare(priv->clk); |
34a16547 | 175 | clk_disable_unprepare(priv->clk_cd); |
56c49287 GL |
176 | } |
177 | ||
b5b6a5f4 | 178 | static int renesas_sdhi_card_busy(struct mmc_host *mmc) |
6a4679f3 WS |
179 | { |
180 | struct tmio_mmc_host *host = mmc_priv(mmc); | |
181 | ||
2fe35968 SH |
182 | return !(sd_ctrl_read16_and_16_as_32(host, CTL_STATUS) & |
183 | TMIO_STAT_DAT0); | |
6a4679f3 WS |
184 | } |
185 | ||
b5b6a5f4 | 186 | static int renesas_sdhi_start_signal_voltage_switch(struct mmc_host *mmc, |
2fe35968 | 187 | struct mmc_ios *ios) |
057a4592 WS |
188 | { |
189 | struct tmio_mmc_host *host = mmc_priv(mmc); | |
b5b6a5f4 | 190 | struct renesas_sdhi *priv = host_to_priv(host); |
057a4592 WS |
191 | struct pinctrl_state *pin_state; |
192 | int ret; | |
193 | ||
194 | switch (ios->signal_voltage) { | |
195 | case MMC_SIGNAL_VOLTAGE_330: | |
196 | pin_state = priv->pins_default; | |
197 | break; | |
198 | case MMC_SIGNAL_VOLTAGE_180: | |
199 | pin_state = priv->pins_uhs; | |
200 | break; | |
201 | default: | |
202 | return -EINVAL; | |
203 | } | |
204 | ||
205 | /* | |
206 | * If anything is missing, assume signal voltage is fixed at | |
207 | * 3.3V and succeed/fail accordingly. | |
208 | */ | |
209 | if (IS_ERR(priv->pinctrl) || IS_ERR(pin_state)) | |
210 | return ios->signal_voltage == | |
211 | MMC_SIGNAL_VOLTAGE_330 ? 0 : -EINVAL; | |
212 | ||
213 | ret = mmc_regulator_set_vqmmc(host->mmc, ios); | |
214 | if (ret) | |
215 | return ret; | |
216 | ||
2272c841 | 217 | return pinctrl_select_state(priv->pinctrl, pin_state); |
057a4592 WS |
218 | } |
219 | ||
06f438dd SH |
220 | /* SCC registers */ |
221 | #define SH_MOBILE_SDHI_SCC_DTCNTL 0x000 | |
222 | #define SH_MOBILE_SDHI_SCC_TAPSET 0x002 | |
223 | #define SH_MOBILE_SDHI_SCC_DT2FF 0x004 | |
224 | #define SH_MOBILE_SDHI_SCC_CKSEL 0x006 | |
225 | #define SH_MOBILE_SDHI_SCC_RVSCNTL 0x008 | |
226 | #define SH_MOBILE_SDHI_SCC_RVSREQ 0x00A | |
227 | ||
228 | /* Definitions for values the SH_MOBILE_SDHI_SCC_DTCNTL register */ | |
229 | #define SH_MOBILE_SDHI_SCC_DTCNTL_TAPEN BIT(0) | |
230 | #define SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_SHIFT 16 | |
231 | #define SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_MASK 0xff | |
232 | ||
233 | /* Definitions for values the SH_MOBILE_SDHI_SCC_CKSEL register */ | |
234 | #define SH_MOBILE_SDHI_SCC_CKSEL_DTSEL BIT(0) | |
235 | /* Definitions for values the SH_MOBILE_SDHI_SCC_RVSCNTL register */ | |
236 | #define SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN BIT(0) | |
237 | /* Definitions for values the SH_MOBILE_SDHI_SCC_RVSREQ register */ | |
238 | #define SH_MOBILE_SDHI_SCC_RVSREQ_RVSERR BIT(2) | |
239 | ||
240 | static inline u32 sd_scc_read32(struct tmio_mmc_host *host, | |
b5b6a5f4 | 241 | struct renesas_sdhi *priv, int addr) |
06f438dd SH |
242 | { |
243 | return readl(priv->scc_ctl + (addr << host->bus_shift)); | |
244 | } | |
245 | ||
246 | static inline void sd_scc_write32(struct tmio_mmc_host *host, | |
b5b6a5f4 | 247 | struct renesas_sdhi *priv, |
06f438dd SH |
248 | int addr, u32 val) |
249 | { | |
250 | writel(val, priv->scc_ctl + (addr << host->bus_shift)); | |
251 | } | |
252 | ||
b5b6a5f4 | 253 | static unsigned int renesas_sdhi_init_tuning(struct tmio_mmc_host *host) |
06f438dd | 254 | { |
b5b6a5f4 | 255 | struct renesas_sdhi *priv; |
06f438dd | 256 | |
06f438dd SH |
257 | priv = host_to_priv(host); |
258 | ||
259 | /* set sampling clock selection range */ | |
260 | sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DTCNTL, | |
261 | 0x8 << SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_SHIFT); | |
262 | ||
263 | /* Initialize SCC */ | |
264 | sd_ctrl_write32_as_16_and_16(host, CTL_STATUS, 0x0); | |
265 | ||
266 | sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DTCNTL, | |
267 | SH_MOBILE_SDHI_SCC_DTCNTL_TAPEN | | |
268 | sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_DTCNTL)); | |
269 | ||
270 | sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN & | |
271 | sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); | |
272 | ||
273 | sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_CKSEL, | |
274 | SH_MOBILE_SDHI_SCC_CKSEL_DTSEL | | |
275 | sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_CKSEL)); | |
276 | ||
277 | sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN | | |
278 | sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); | |
279 | ||
280 | sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL, | |
281 | ~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN & | |
282 | sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL)); | |
283 | ||
284 | sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DT2FF, host->scc_tappos); | |
285 | ||
286 | /* Read TAPNUM */ | |
287 | return (sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_DTCNTL) >> | |
288 | SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_SHIFT) & | |
289 | SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_MASK; | |
290 | } | |
291 | ||
b5b6a5f4 | 292 | static void renesas_sdhi_prepare_tuning(struct tmio_mmc_host *host, |
2fe35968 | 293 | unsigned long tap) |
06f438dd | 294 | { |
b5b6a5f4 | 295 | struct renesas_sdhi *priv = host_to_priv(host); |
06f438dd SH |
296 | |
297 | /* Set sampling clock position */ | |
298 | sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TAPSET, tap); | |
299 | } | |
300 | ||
301 | #define SH_MOBILE_SDHI_MAX_TAP 3 | |
302 | ||
b5b6a5f4 | 303 | static int renesas_sdhi_select_tuning(struct tmio_mmc_host *host) |
06f438dd | 304 | { |
b5b6a5f4 | 305 | struct renesas_sdhi *priv = host_to_priv(host); |
06f438dd SH |
306 | unsigned long tap_cnt; /* counter of tuning success */ |
307 | unsigned long tap_set; /* tap position */ | |
308 | unsigned long tap_start;/* start position of tuning success */ | |
309 | unsigned long tap_end; /* end position of tuning success */ | |
310 | unsigned long ntap; /* temporary counter of tuning success */ | |
311 | unsigned long i; | |
312 | ||
313 | /* Clear SCC_RVSREQ */ | |
314 | sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ, 0); | |
315 | ||
316 | /* | |
317 | * Find the longest consecutive run of successful probes. If that | |
318 | * is more than SH_MOBILE_SDHI_MAX_TAP probes long then use the | |
319 | * center index as the tap. | |
320 | */ | |
321 | tap_cnt = 0; | |
322 | ntap = 0; | |
323 | tap_start = 0; | |
324 | tap_end = 0; | |
325 | for (i = 0; i < host->tap_num * 2; i++) { | |
2fe35968 | 326 | if (test_bit(i, host->taps)) { |
06f438dd | 327 | ntap++; |
2fe35968 | 328 | } else { |
06f438dd SH |
329 | if (ntap > tap_cnt) { |
330 | tap_start = i - ntap; | |
331 | tap_end = i - 1; | |
332 | tap_cnt = ntap; | |
333 | } | |
334 | ntap = 0; | |
335 | } | |
336 | } | |
337 | ||
338 | if (ntap > tap_cnt) { | |
339 | tap_start = i - ntap; | |
340 | tap_end = i - 1; | |
341 | tap_cnt = ntap; | |
342 | } | |
343 | ||
344 | if (tap_cnt >= SH_MOBILE_SDHI_MAX_TAP) | |
345 | tap_set = (tap_start + tap_end) / 2 % host->tap_num; | |
346 | else | |
347 | return -EIO; | |
348 | ||
349 | /* Set SCC */ | |
350 | sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TAPSET, tap_set); | |
351 | ||
352 | /* Enable auto re-tuning */ | |
353 | sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL, | |
354 | SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN | | |
355 | sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL)); | |
356 | ||
357 | return 0; | |
358 | } | |
359 | ||
b5b6a5f4 | 360 | static bool renesas_sdhi_check_scc_error(struct tmio_mmc_host *host) |
06f438dd | 361 | { |
b5b6a5f4 | 362 | struct renesas_sdhi *priv = host_to_priv(host); |
06f438dd SH |
363 | |
364 | /* Check SCC error */ | |
365 | if (sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL) & | |
366 | SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN && | |
367 | sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ) & | |
368 | SH_MOBILE_SDHI_SCC_RVSREQ_RVSERR) { | |
369 | /* Clear SCC error */ | |
370 | sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ, 0); | |
371 | return true; | |
372 | } | |
373 | ||
374 | return false; | |
375 | } | |
376 | ||
b5b6a5f4 | 377 | static void renesas_sdhi_hw_reset(struct tmio_mmc_host *host) |
06f438dd | 378 | { |
b5b6a5f4 | 379 | struct renesas_sdhi *priv; |
06f438dd | 380 | |
06f438dd SH |
381 | priv = host_to_priv(host); |
382 | ||
383 | /* Reset SCC */ | |
384 | sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN & | |
385 | sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); | |
386 | ||
387 | sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_CKSEL, | |
388 | ~SH_MOBILE_SDHI_SCC_CKSEL_DTSEL & | |
389 | sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_CKSEL)); | |
390 | ||
391 | sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN | | |
392 | sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); | |
393 | ||
394 | sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL, | |
395 | ~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN & | |
396 | sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL)); | |
397 | ||
398 | sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL, | |
399 | ~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN & | |
400 | sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL)); | |
401 | } | |
402 | ||
4dc48a95 | 403 | static int renesas_sdhi_wait_idle(struct tmio_mmc_host *host, u32 bit) |
973ed3af SH |
404 | { |
405 | int timeout = 1000; | |
4dc48a95 WS |
406 | /* CBSY is set when busy, SCLKDIVEN is cleared when busy */ |
407 | u32 wait_state = (bit == TMIO_STAT_CMD_BUSY ? TMIO_STAT_CMD_BUSY : 0); | |
973ed3af | 408 | |
4dc48a95 WS |
409 | while (--timeout && (sd_ctrl_read16_and_16_as_32(host, CTL_STATUS) |
410 | & bit) == wait_state) | |
973ed3af SH |
411 | udelay(1); |
412 | ||
413 | if (!timeout) { | |
94b110af | 414 | dev_warn(&host->pdev->dev, "timeout waiting for SD bus idle\n"); |
973ed3af SH |
415 | return -EBUSY; |
416 | } | |
417 | ||
418 | return 0; | |
419 | } | |
420 | ||
b5b6a5f4 | 421 | static int renesas_sdhi_write16_hook(struct tmio_mmc_host *host, int addr) |
973ed3af | 422 | { |
4dc48a95 WS |
423 | u32 bit = TMIO_STAT_SCLKDIVEN; |
424 | ||
2fe35968 | 425 | switch (addr) { |
973ed3af SH |
426 | case CTL_SD_CMD: |
427 | case CTL_STOP_INTERNAL_ACTION: | |
428 | case CTL_XFER_BLK_COUNT: | |
973ed3af SH |
429 | case CTL_SD_XFER_LEN: |
430 | case CTL_SD_MEM_CARD_OPT: | |
431 | case CTL_TRANSACTION_CTL: | |
432 | case CTL_DMA_ENABLE: | |
ff741cfd | 433 | case EXT_ACC: |
5124b592 | 434 | if (host->pdata->flags & TMIO_MMC_HAVE_CBSY) |
4dc48a95 WS |
435 | bit = TMIO_STAT_CMD_BUSY; |
436 | /* fallthrough */ | |
437 | case CTL_SD_CARD_CLK_CTL: | |
438 | return renesas_sdhi_wait_idle(host, bit); | |
973ed3af SH |
439 | } |
440 | ||
441 | return 0; | |
442 | } | |
443 | ||
b5b6a5f4 | 444 | static int renesas_sdhi_multi_io_quirk(struct mmc_card *card, |
2fe35968 | 445 | unsigned int direction, int blk_size) |
8b4efe2f KM |
446 | { |
447 | /* | |
448 | * In Renesas controllers, when performing a | |
449 | * multiple block read of one or two blocks, | |
450 | * depending on the timing with which the | |
451 | * response register is read, the response | |
452 | * value may not be read properly. | |
453 | * Use single block read for this HW bug | |
454 | */ | |
455 | if ((direction == MMC_DATA_READ) && | |
456 | blk_size == 2) | |
457 | return 1; | |
458 | ||
459 | return blk_size; | |
460 | } | |
461 | ||
b5b6a5f4 | 462 | static void renesas_sdhi_enable_dma(struct tmio_mmc_host *host, bool enable) |
0c47f6ae | 463 | { |
41279f01 WS |
464 | /* Iff regs are 8 byte apart, sdbuf is 64 bit. Otherwise always 32. */ |
465 | int width = (host->bus_shift == 2) ? 64 : 32; | |
f45394d5 | 466 | |
41279f01 WS |
467 | sd_ctrl_write16(host, CTL_DMA_ENABLE, enable ? DMA_ENABLE_DMASDRW : 0); |
468 | renesas_sdhi_sdbuf_width(host, enable ? width : 16); | |
0c47f6ae KM |
469 | } |
470 | ||
9d08428a SH |
471 | int renesas_sdhi_probe(struct platform_device *pdev, |
472 | const struct tmio_mmc_dma_ops *dma_ops) | |
a87d5638 | 473 | { |
f33c9d65 | 474 | struct tmio_mmc_data *mmd = pdev->dev.platform_data; |
2fe35968 SH |
475 | const struct renesas_sdhi_of_data *of_data; |
476 | struct tmio_mmc_data *mmc_data; | |
477 | struct tmio_mmc_dma *dma_priv; | |
42051e8a | 478 | struct tmio_mmc_host *host; |
2fe35968 | 479 | struct renesas_sdhi *priv; |
3b159a6e | 480 | struct resource *res; |
06f438dd | 481 | int irq, ret, i; |
2fe35968 SH |
482 | |
483 | of_data = of_device_get_match_data(&pdev->dev); | |
a87d5638 | 484 | |
3b159a6e KM |
485 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
486 | if (!res) | |
487 | return -EINVAL; | |
488 | ||
2fe35968 SH |
489 | priv = devm_kzalloc(&pdev->dev, sizeof(struct renesas_sdhi), |
490 | GFP_KERNEL); | |
2bf8ab6b | 491 | if (!priv) |
a87d5638 | 492 | return -ENOMEM; |
a87d5638 | 493 | |
056676da | 494 | mmc_data = &priv->mmc_data; |
87ae7bbe | 495 | dma_priv = &priv->dma_priv; |
056676da | 496 | |
ac51b961 | 497 | priv->clk = devm_clk_get(&pdev->dev, NULL); |
a87d5638 | 498 | if (IS_ERR(priv->clk)) { |
a87d5638 | 499 | ret = PTR_ERR(priv->clk); |
56ae1adc | 500 | dev_err(&pdev->dev, "cannot get clock: %d\n", ret); |
010f4aa7 | 501 | goto eprobe; |
a87d5638 MD |
502 | } |
503 | ||
34a16547 CB |
504 | /* |
505 | * Some controllers provide a 2nd clock just to run the internal card | |
506 | * detection logic. Unfortunately, the existing driver architecture does | |
507 | * not support a separation of clocks for runtime PM usage. When | |
508 | * native hotplug is used, the tmio driver assumes that the core | |
509 | * must continue to run for card detect to stay active, so we cannot | |
510 | * disable it. | |
511 | * Additionally, it is prohibited to supply a clock to the core but not | |
512 | * to the card detect circuit. That leaves us with if separate clocks | |
513 | * are presented, we must treat them both as virtually 1 clock. | |
514 | */ | |
515 | priv->clk_cd = devm_clk_get(&pdev->dev, "cd"); | |
516 | if (IS_ERR(priv->clk_cd)) | |
517 | priv->clk_cd = NULL; | |
518 | ||
057a4592 WS |
519 | priv->pinctrl = devm_pinctrl_get(&pdev->dev); |
520 | if (!IS_ERR(priv->pinctrl)) { | |
521 | priv->pins_default = pinctrl_lookup_state(priv->pinctrl, | |
522 | PINCTRL_STATE_DEFAULT); | |
523 | priv->pins_uhs = pinctrl_lookup_state(priv->pinctrl, | |
524 | "state_uhs"); | |
525 | } | |
526 | ||
94b110af KM |
527 | host = tmio_mmc_host_alloc(pdev); |
528 | if (!host) { | |
529 | ret = -ENOMEM; | |
530 | goto eprobe; | |
531 | } | |
532 | ||
dc9f1a8d | 533 | if (of_data) { |
a72e8b17 | 534 | mmc_data->flags |= of_data->tmio_flags; |
f19417f3 | 535 | mmc_data->ocr_mask = of_data->tmio_ocr_mask; |
a72e8b17 WS |
536 | mmc_data->capabilities |= of_data->capabilities; |
537 | mmc_data->capabilities2 |= of_data->capabilities2; | |
538 | mmc_data->dma_rx_offset = of_data->dma_rx_offset; | |
603aa14d YS |
539 | mmc_data->max_blk_count = of_data->max_blk_count; |
540 | mmc_data->max_segs = of_data->max_segs; | |
a72e8b17 WS |
541 | dma_priv->dma_buswidth = of_data->dma_buswidth; |
542 | host->bus_shift = of_data->bus_shift; | |
543 | } | |
544 | ||
7ecc09ba | 545 | host->dma = dma_priv; |
b5b6a5f4 SH |
546 | host->write16_hook = renesas_sdhi_write16_hook; |
547 | host->clk_enable = renesas_sdhi_clk_enable; | |
548 | host->clk_update = renesas_sdhi_clk_update; | |
549 | host->clk_disable = renesas_sdhi_clk_disable; | |
550 | host->multi_io_quirk = renesas_sdhi_multi_io_quirk; | |
ff026099 WS |
551 | |
552 | /* SDR speeds are only available on Gen2+ */ | |
553 | if (mmc_data->flags & TMIO_MMC_MIN_RCAR2) { | |
554 | /* card_busy caused issues on r8a73a4 (pre-Gen2) CD-less SDHI */ | |
b5b6a5f4 | 555 | host->card_busy = renesas_sdhi_card_busy; |
ff026099 | 556 | host->start_signal_voltage_switch = |
b5b6a5f4 | 557 | renesas_sdhi_start_signal_voltage_switch; |
ff026099 | 558 | } |
a72e8b17 WS |
559 | |
560 | /* Orginally registers were 16 bit apart, could be 32 or 64 nowadays */ | |
561 | if (!host->bus_shift && resource_size(res) > 0x100) /* old way to determine the shift */ | |
95a7dc36 | 562 | host->bus_shift = 1; |
7ecc09ba | 563 | |
84f11d5b | 564 | if (mmd) |
f33c9d65 | 565 | *mmc_data = *mmd; |
84f11d5b | 566 | |
87ae7bbe | 567 | dma_priv->filter = shdma_chan_filter; |
b5b6a5f4 | 568 | dma_priv->enable = renesas_sdhi_enable_dma; |
87ae7bbe | 569 | |
e471df0b | 570 | mmc_data->alignment_shift = 1; /* 2-byte alignment */ |
f33c9d65 | 571 | mmc_data->capabilities |= MMC_CAP_MMC_HIGHSPEED; |
e471df0b | 572 | |
f1334fb3 YG |
573 | /* |
574 | * All SDHI blocks support 2-byte and larger block sizes in 4-bit | |
575 | * bus width mode. | |
576 | */ | |
577 | mmc_data->flags |= TMIO_MMC_BLKSZ_2BYTES; | |
578 | ||
23b66071 AH |
579 | /* |
580 | * All SDHI blocks support SDIO IRQ signalling. | |
581 | */ | |
582 | mmc_data->flags |= TMIO_MMC_SDIO_IRQ; | |
583 | ||
2fe35968 | 584 | /* All SDHI have CMD12 control bit */ |
b8d11962 SU |
585 | mmc_data->flags |= TMIO_MMC_HAVE_CMD12_CTRL; |
586 | ||
20dd0373 WS |
587 | /* All SDHI have SDIO status bits which must be 1 */ |
588 | mmc_data->flags |= TMIO_MMC_SDIO_STATUS_SETBITS; | |
6b98757e | 589 | |
9d08428a | 590 | ret = tmio_mmc_host_probe(host, mmc_data, dma_ops); |
42051e8a | 591 | if (ret < 0) |
94b110af | 592 | goto efree; |
a87d5638 | 593 | |
5124b592 WS |
594 | /* One Gen2 SDHI incarnation does NOT have a CBSY bit */ |
595 | if (sd_ctrl_read16(host, CTL_VERSION) == SDHI_VER_GEN2_SDR50) | |
596 | mmc_data->flags &= ~TMIO_MMC_HAVE_CBSY; | |
597 | ||
e831ead3 | 598 | /* Enable tuning iff we have an SCC and a supported mode */ |
b1c95170 WS |
599 | if (of_data && of_data->scc_offset && |
600 | (host->mmc->caps & MMC_CAP_UHS_SDR104 || | |
601 | host->mmc->caps2 & MMC_CAP2_HS200_1_8V_SDR)) { | |
b5b6a5f4 | 602 | const struct renesas_sdhi_scc *taps = of_data->taps; |
6ade9a2c WS |
603 | bool hit = false; |
604 | ||
06f438dd SH |
605 | host->mmc->caps |= MMC_CAP_HW_RESET; |
606 | ||
6ade9a2c WS |
607 | for (i = 0; i < of_data->taps_num; i++) { |
608 | if (taps[i].clk_rate == 0 || | |
609 | taps[i].clk_rate == host->mmc->f_max) { | |
610 | host->scc_tappos = taps->tap; | |
611 | hit = true; | |
612 | break; | |
06f438dd | 613 | } |
6ade9a2c | 614 | } |
06f438dd | 615 | |
6ade9a2c WS |
616 | if (!hit) |
617 | dev_warn(&host->pdev->dev, "Unknown clock rate for SDR104\n"); | |
06f438dd | 618 | |
6ade9a2c | 619 | priv->scc_ctl = host->ctl + of_data->scc_offset; |
b5b6a5f4 SH |
620 | host->init_tuning = renesas_sdhi_init_tuning; |
621 | host->prepare_tuning = renesas_sdhi_prepare_tuning; | |
622 | host->select_tuning = renesas_sdhi_select_tuning; | |
623 | host->check_scc_error = renesas_sdhi_check_scc_error; | |
624 | host->hw_reset = renesas_sdhi_hw_reset; | |
06f438dd SH |
625 | } |
626 | ||
627 | i = 0; | |
adcbc949 WS |
628 | while (1) { |
629 | irq = platform_get_irq(pdev, i); | |
630 | if (irq < 0) | |
631 | break; | |
632 | i++; | |
633 | ret = devm_request_irq(&pdev->dev, irq, tmio_mmc_irq, 0, | |
2fe35968 | 634 | dev_name(&pdev->dev), host); |
d5098cb6 | 635 | if (ret) |
ac51b961 | 636 | goto eirq; |
d5098cb6 SH |
637 | } |
638 | ||
adcbc949 WS |
639 | /* There must be at least one IRQ source */ |
640 | if (!i) { | |
d5098cb6 | 641 | ret = irq; |
ac51b961 | 642 | goto eirq; |
d5098cb6 SH |
643 | } |
644 | ||
2fb55956 | 645 | dev_info(&pdev->dev, "%s base at 0x%08lx max clock rate %u MHz\n", |
1f7d6819 | 646 | mmc_hostname(host->mmc), (unsigned long) |
58126c87 | 647 | (platform_get_resource(pdev, IORESOURCE_MEM, 0)->start), |
369213bd | 648 | host->mmc->f_max / 1000000); |
a87d5638 | 649 | |
42051e8a | 650 | return ret; |
a87d5638 | 651 | |
ac51b961 | 652 | eirq: |
8e7bfdb3 | 653 | tmio_mmc_host_remove(host); |
94b110af KM |
654 | efree: |
655 | tmio_mmc_host_free(host); | |
42051e8a | 656 | eprobe: |
a87d5638 MD |
657 | return ret; |
658 | } | |
9d08428a | 659 | EXPORT_SYMBOL_GPL(renesas_sdhi_probe); |
a87d5638 | 660 | |
9d08428a | 661 | int renesas_sdhi_remove(struct platform_device *pdev) |
a87d5638 | 662 | { |
42051e8a GL |
663 | struct mmc_host *mmc = platform_get_drvdata(pdev); |
664 | struct tmio_mmc_host *host = mmc_priv(mmc); | |
d6a1f863 | 665 | |
742a0c7c GL |
666 | tmio_mmc_host_remove(host); |
667 | ||
a87d5638 MD |
668 | return 0; |
669 | } | |
9d08428a | 670 | EXPORT_SYMBOL_GPL(renesas_sdhi_remove); |
967a6a07 MH |
671 | |
672 | MODULE_LICENSE("GPL v2"); |