Commit | Line | Data |
---|---|---|
a87d5638 MD |
1 | /* |
2 | * SuperH Mobile SDHI | |
3 | * | |
a72e8b17 WS |
4 | * Copyright (C) 2016 Sang Engineering, Wolfram Sang |
5 | * Copyright (C) 2015-16 Renesas Electronics Corporation | |
a87d5638 MD |
6 | * Copyright (C) 2009 Magnus Damm |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License version 2 as | |
10 | * published by the Free Software Foundation. | |
11 | * | |
12 | * Based on "Compaq ASIC3 support": | |
13 | * | |
14 | * Copyright 2001 Compaq Computer Corporation. | |
15 | * Copyright 2004-2005 Phil Blundell | |
16 | * Copyright 2007-2008 OpenedHand Ltd. | |
17 | * | |
18 | * Authors: Phil Blundell <pb@handhelds.org>, | |
19 | * Samuel Ortiz <sameo@openedhand.com> | |
20 | * | |
21 | */ | |
22 | ||
23 | #include <linux/kernel.h> | |
24 | #include <linux/clk.h> | |
5a0e3ad6 | 25 | #include <linux/slab.h> |
c7bb4487 | 26 | #include <linux/mod_devicetable.h> |
88b47679 | 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 | |
42051e8a GL |
38 | #include "tmio_mmc.h" |
39 | ||
e3c418f1 KM |
40 | #define EXT_ACC 0xe4 |
41 | ||
a2a16c77 WS |
42 | #define SDHI_VER_GEN2_SDR50 0x490c |
43 | /* very old datasheets said 0x490c for SDR104, too. They are wrong! */ | |
44 | #define SDHI_VER_GEN2_SDR104 0xcb0d | |
45 | #define SDHI_VER_GEN3_SD 0xcc10 | |
46 | #define SDHI_VER_GEN3_SDMMC 0xcd10 | |
47 | ||
16935250 KM |
48 | #define host_to_priv(host) container_of((host)->pdata, struct sh_mobile_sdhi, mmc_data) |
49 | ||
06f438dd SH |
50 | struct sh_mobile_sdhi_scc { |
51 | unsigned long clk_rate; /* clock rate for SDR104 */ | |
52 | u32 tap; /* sampling clock position for SDR104 */ | |
53 | }; | |
54 | ||
5a00a971 GL |
55 | struct sh_mobile_sdhi_of_data { |
56 | unsigned long tmio_flags; | |
f19417f3 | 57 | u32 tmio_ocr_mask; |
b3a5d4ce | 58 | unsigned long capabilities; |
423f6c2e | 59 | unsigned long capabilities2; |
f45394d5 | 60 | enum dma_slave_buswidth dma_buswidth; |
384b2cbd | 61 | dma_addr_t dma_rx_offset; |
a72e8b17 | 62 | unsigned bus_shift; |
06f438dd SH |
63 | int scc_offset; |
64 | struct sh_mobile_sdhi_scc *taps; | |
65 | int taps_num; | |
5a00a971 GL |
66 | }; |
67 | ||
13bbd8af WS |
68 | static const struct sh_mobile_sdhi_of_data of_default_cfg = { |
69 | .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT, | |
5a00a971 GL |
70 | }; |
71 | ||
0963dd56 CB |
72 | static const struct sh_mobile_sdhi_of_data of_rz_compatible = { |
73 | .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_32BIT_DATA_PORT, | |
74 | .tmio_ocr_mask = MMC_VDD_32_33, | |
75 | .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ, | |
76 | }; | |
77 | ||
b3a5d4ce | 78 | static const struct sh_mobile_sdhi_of_data of_rcar_gen1_compatible = { |
da29fe2b SU |
79 | .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE | |
80 | TMIO_MMC_CLK_ACTUAL, | |
b3a5d4ce KM |
81 | .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ, |
82 | }; | |
83 | ||
06f438dd SH |
84 | /* Definitions for sampling clocks */ |
85 | static struct sh_mobile_sdhi_scc rcar_gen2_scc_taps[] = { | |
86 | { | |
87 | .clk_rate = 156000000, | |
88 | .tap = 0x00000703, | |
89 | }, | |
90 | { | |
91 | .clk_rate = 0, | |
92 | .tap = 0x00000300, | |
93 | }, | |
94 | }; | |
95 | ||
423f6c2e | 96 | static const struct sh_mobile_sdhi_of_data of_rcar_gen2_compatible = { |
da29fe2b | 97 | .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE | |
3d376fb2 | 98 | TMIO_MMC_CLK_ACTUAL | TMIO_MMC_MIN_RCAR2, |
423f6c2e | 99 | .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ, |
f45394d5 | 100 | .dma_buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES, |
384b2cbd | 101 | .dma_rx_offset = 0x2000, |
06f438dd SH |
102 | .scc_offset = 0x0300, |
103 | .taps = rcar_gen2_scc_taps, | |
104 | .taps_num = ARRAY_SIZE(rcar_gen2_scc_taps), | |
105 | }; | |
106 | ||
107 | /* Definitions for sampling clocks */ | |
108 | static struct sh_mobile_sdhi_scc rcar_gen3_scc_taps[] = { | |
109 | { | |
110 | .clk_rate = 0, | |
111 | .tap = 0x00000300, | |
112 | }, | |
423f6c2e KM |
113 | }; |
114 | ||
a72e8b17 WS |
115 | static const struct sh_mobile_sdhi_of_data of_rcar_gen3_compatible = { |
116 | .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE | | |
3d376fb2 | 117 | TMIO_MMC_CLK_ACTUAL | TMIO_MMC_MIN_RCAR2, |
685d29ef | 118 | .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ, |
a72e8b17 | 119 | .bus_shift = 2, |
06f438dd SH |
120 | .scc_offset = 0x1000, |
121 | .taps = rcar_gen3_scc_taps, | |
122 | .taps_num = ARRAY_SIZE(rcar_gen3_scc_taps), | |
a72e8b17 WS |
123 | }; |
124 | ||
2772ef30 KM |
125 | static const struct of_device_id sh_mobile_sdhi_of_match[] = { |
126 | { .compatible = "renesas,sdhi-shmobile" }, | |
13bbd8af WS |
127 | { .compatible = "renesas,sdhi-sh73a0", .data = &of_default_cfg, }, |
128 | { .compatible = "renesas,sdhi-r8a73a4", .data = &of_default_cfg, }, | |
129 | { .compatible = "renesas,sdhi-r8a7740", .data = &of_default_cfg, }, | |
0963dd56 | 130 | { .compatible = "renesas,sdhi-r7s72100", .data = &of_rz_compatible, }, |
b3a5d4ce | 131 | { .compatible = "renesas,sdhi-r8a7778", .data = &of_rcar_gen1_compatible, }, |
81bbbc72 | 132 | { .compatible = "renesas,sdhi-r8a7779", .data = &of_rcar_gen1_compatible, }, |
423f6c2e | 133 | { .compatible = "renesas,sdhi-r8a7790", .data = &of_rcar_gen2_compatible, }, |
81918d25 | 134 | { .compatible = "renesas,sdhi-r8a7791", .data = &of_rcar_gen2_compatible, }, |
a6386403 GU |
135 | { .compatible = "renesas,sdhi-r8a7792", .data = &of_rcar_gen2_compatible, }, |
136 | { .compatible = "renesas,sdhi-r8a7793", .data = &of_rcar_gen2_compatible, }, | |
137 | { .compatible = "renesas,sdhi-r8a7794", .data = &of_rcar_gen2_compatible, }, | |
a72e8b17 | 138 | { .compatible = "renesas,sdhi-r8a7795", .data = &of_rcar_gen3_compatible, }, |
7428e0bf | 139 | { .compatible = "renesas,sdhi-r8a7796", .data = &of_rcar_gen3_compatible, }, |
2772ef30 KM |
140 | {}, |
141 | }; | |
142 | MODULE_DEVICE_TABLE(of, sh_mobile_sdhi_of_match); | |
143 | ||
a87d5638 MD |
144 | struct sh_mobile_sdhi { |
145 | struct clk *clk; | |
146 | struct tmio_mmc_data mmc_data; | |
056676da | 147 | struct tmio_mmc_dma dma_priv; |
057a4592 WS |
148 | struct pinctrl *pinctrl; |
149 | struct pinctrl_state *pins_default, *pins_uhs; | |
06f438dd | 150 | void __iomem *scc_ctl; |
a87d5638 MD |
151 | }; |
152 | ||
f45394d5 KM |
153 | static void sh_mobile_sdhi_sdbuf_width(struct tmio_mmc_host *host, int width) |
154 | { | |
155 | u32 val; | |
156 | ||
157 | /* | |
158 | * see also | |
159 | * sh_mobile_sdhi_of_data :: dma_buswidth | |
160 | */ | |
161 | switch (sd_ctrl_read16(host, CTL_VERSION)) { | |
a2a16c77 | 162 | case SDHI_VER_GEN2_SDR50: |
f45394d5 KM |
163 | val = (width == 32) ? 0x0001 : 0x0000; |
164 | break; | |
a2a16c77 | 165 | case SDHI_VER_GEN2_SDR104: |
f45394d5 KM |
166 | val = (width == 32) ? 0x0000 : 0x0001; |
167 | break; | |
a2a16c77 WS |
168 | case SDHI_VER_GEN3_SD: |
169 | case SDHI_VER_GEN3_SDMMC: | |
a72e8b17 WS |
170 | if (width == 64) |
171 | val = 0x0000; | |
172 | else if (width == 32) | |
173 | val = 0x0101; | |
174 | else | |
175 | val = 0x0001; | |
176 | break; | |
f45394d5 KM |
177 | default: |
178 | /* nothing to do */ | |
179 | return; | |
180 | } | |
181 | ||
182 | sd_ctrl_write16(host, EXT_ACC, val); | |
183 | } | |
184 | ||
0ea28210 | 185 | static int sh_mobile_sdhi_clk_enable(struct tmio_mmc_host *host) |
56c49287 | 186 | { |
0ea28210 | 187 | struct mmc_host *mmc = host->mmc; |
16935250 | 188 | struct sh_mobile_sdhi *priv = host_to_priv(host); |
00fb3d2a | 189 | int ret = clk_prepare_enable(priv->clk); |
56c49287 GL |
190 | if (ret < 0) |
191 | return ret; | |
192 | ||
2fb55956 BH |
193 | /* |
194 | * The clock driver may not know what maximum frequency | |
195 | * actually works, so it should be set with the max-frequency | |
196 | * property which will already have been read to f_max. If it | |
197 | * was missing, assume the current frequency is the maximum. | |
198 | */ | |
199 | if (!mmc->f_max) | |
200 | mmc->f_max = clk_get_rate(priv->clk); | |
201 | ||
202 | /* | |
203 | * Minimum frequency is the minimum input clock frequency | |
204 | * divided by our maximum divider. | |
205 | */ | |
206 | mmc->f_min = max(clk_round_rate(priv->clk, 1) / 512, 1L); | |
f45394d5 KM |
207 | |
208 | /* enable 16bit data access on SDBUF as default */ | |
209 | sh_mobile_sdhi_sdbuf_width(host, 16); | |
210 | ||
56c49287 GL |
211 | return 0; |
212 | } | |
213 | ||
2fb55956 BH |
214 | static unsigned int sh_mobile_sdhi_clk_update(struct tmio_mmc_host *host, |
215 | unsigned int new_clock) | |
216 | { | |
217 | struct sh_mobile_sdhi *priv = host_to_priv(host); | |
3072ba8c | 218 | unsigned int freq, diff, best_freq = 0, diff_min = ~0; |
f3f44d51 | 219 | int i, ret; |
2fb55956 | 220 | |
8fc00998 WS |
221 | /* tested only on RCar Gen2+ currently; may work for others */ |
222 | if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2)) | |
223 | return clk_get_rate(priv->clk); | |
224 | ||
2fb55956 BH |
225 | /* |
226 | * We want the bus clock to be as close as possible to, but no | |
227 | * greater than, new_clock. As we can divide by 1 << i for | |
228 | * any i in [0, 9] we want the input clock to be as close as | |
229 | * possible, but no greater than, new_clock << i. | |
230 | */ | |
231 | for (i = min(9, ilog2(UINT_MAX / new_clock)); i >= 0; i--) { | |
232 | freq = clk_round_rate(priv->clk, new_clock << i); | |
233 | if (freq > (new_clock << i)) { | |
234 | /* Too fast; look for a slightly slower option */ | |
235 | freq = clk_round_rate(priv->clk, | |
236 | (new_clock << i) / 4 * 3); | |
237 | if (freq > (new_clock << i)) | |
238 | continue; | |
239 | } | |
240 | ||
241 | diff = new_clock - (freq >> i); | |
242 | if (diff <= diff_min) { | |
243 | best_freq = freq; | |
244 | diff_min = diff; | |
245 | } | |
246 | } | |
247 | ||
f3f44d51 | 248 | ret = clk_set_rate(priv->clk, best_freq); |
2fb55956 | 249 | |
f3f44d51 | 250 | return ret == 0 ? best_freq : clk_get_rate(priv->clk); |
2fb55956 BH |
251 | } |
252 | ||
0ea28210 | 253 | static void sh_mobile_sdhi_clk_disable(struct tmio_mmc_host *host) |
56c49287 | 254 | { |
16935250 | 255 | struct sh_mobile_sdhi *priv = host_to_priv(host); |
0ea28210 | 256 | |
00fb3d2a | 257 | clk_disable_unprepare(priv->clk); |
56c49287 GL |
258 | } |
259 | ||
6a4679f3 WS |
260 | static int sh_mobile_sdhi_card_busy(struct mmc_host *mmc) |
261 | { | |
262 | struct tmio_mmc_host *host = mmc_priv(mmc); | |
263 | ||
264 | return !(sd_ctrl_read16_and_16_as_32(host, CTL_STATUS) & TMIO_STAT_DAT0); | |
265 | } | |
266 | ||
057a4592 WS |
267 | static int sh_mobile_sdhi_start_signal_voltage_switch(struct mmc_host *mmc, |
268 | struct mmc_ios *ios) | |
269 | { | |
270 | struct tmio_mmc_host *host = mmc_priv(mmc); | |
271 | struct sh_mobile_sdhi *priv = host_to_priv(host); | |
272 | struct pinctrl_state *pin_state; | |
273 | int ret; | |
274 | ||
275 | switch (ios->signal_voltage) { | |
276 | case MMC_SIGNAL_VOLTAGE_330: | |
277 | pin_state = priv->pins_default; | |
278 | break; | |
279 | case MMC_SIGNAL_VOLTAGE_180: | |
280 | pin_state = priv->pins_uhs; | |
281 | break; | |
282 | default: | |
283 | return -EINVAL; | |
284 | } | |
285 | ||
286 | /* | |
287 | * If anything is missing, assume signal voltage is fixed at | |
288 | * 3.3V and succeed/fail accordingly. | |
289 | */ | |
290 | if (IS_ERR(priv->pinctrl) || IS_ERR(pin_state)) | |
291 | return ios->signal_voltage == | |
292 | MMC_SIGNAL_VOLTAGE_330 ? 0 : -EINVAL; | |
293 | ||
294 | ret = mmc_regulator_set_vqmmc(host->mmc, ios); | |
295 | if (ret) | |
296 | return ret; | |
297 | ||
2272c841 | 298 | return pinctrl_select_state(priv->pinctrl, pin_state); |
057a4592 WS |
299 | } |
300 | ||
06f438dd SH |
301 | /* SCC registers */ |
302 | #define SH_MOBILE_SDHI_SCC_DTCNTL 0x000 | |
303 | #define SH_MOBILE_SDHI_SCC_TAPSET 0x002 | |
304 | #define SH_MOBILE_SDHI_SCC_DT2FF 0x004 | |
305 | #define SH_MOBILE_SDHI_SCC_CKSEL 0x006 | |
306 | #define SH_MOBILE_SDHI_SCC_RVSCNTL 0x008 | |
307 | #define SH_MOBILE_SDHI_SCC_RVSREQ 0x00A | |
308 | ||
309 | /* Definitions for values the SH_MOBILE_SDHI_SCC_DTCNTL register */ | |
310 | #define SH_MOBILE_SDHI_SCC_DTCNTL_TAPEN BIT(0) | |
311 | #define SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_SHIFT 16 | |
312 | #define SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_MASK 0xff | |
313 | ||
314 | /* Definitions for values the SH_MOBILE_SDHI_SCC_CKSEL register */ | |
315 | #define SH_MOBILE_SDHI_SCC_CKSEL_DTSEL BIT(0) | |
316 | /* Definitions for values the SH_MOBILE_SDHI_SCC_RVSCNTL register */ | |
317 | #define SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN BIT(0) | |
318 | /* Definitions for values the SH_MOBILE_SDHI_SCC_RVSREQ register */ | |
319 | #define SH_MOBILE_SDHI_SCC_RVSREQ_RVSERR BIT(2) | |
320 | ||
321 | static inline u32 sd_scc_read32(struct tmio_mmc_host *host, | |
322 | struct sh_mobile_sdhi *priv, int addr) | |
323 | { | |
324 | return readl(priv->scc_ctl + (addr << host->bus_shift)); | |
325 | } | |
326 | ||
327 | static inline void sd_scc_write32(struct tmio_mmc_host *host, | |
328 | struct sh_mobile_sdhi *priv, | |
329 | int addr, u32 val) | |
330 | { | |
331 | writel(val, priv->scc_ctl + (addr << host->bus_shift)); | |
332 | } | |
333 | ||
334 | static unsigned int sh_mobile_sdhi_init_tuning(struct tmio_mmc_host *host) | |
335 | { | |
336 | struct sh_mobile_sdhi *priv; | |
337 | ||
06f438dd SH |
338 | priv = host_to_priv(host); |
339 | ||
340 | /* set sampling clock selection range */ | |
341 | sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DTCNTL, | |
342 | 0x8 << SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_SHIFT); | |
343 | ||
344 | /* Initialize SCC */ | |
345 | sd_ctrl_write32_as_16_and_16(host, CTL_STATUS, 0x0); | |
346 | ||
347 | sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DTCNTL, | |
348 | SH_MOBILE_SDHI_SCC_DTCNTL_TAPEN | | |
349 | sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_DTCNTL)); | |
350 | ||
351 | sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN & | |
352 | sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); | |
353 | ||
354 | sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_CKSEL, | |
355 | SH_MOBILE_SDHI_SCC_CKSEL_DTSEL | | |
356 | sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_CKSEL)); | |
357 | ||
358 | sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN | | |
359 | sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); | |
360 | ||
361 | sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL, | |
362 | ~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN & | |
363 | sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL)); | |
364 | ||
365 | sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DT2FF, host->scc_tappos); | |
366 | ||
367 | /* Read TAPNUM */ | |
368 | return (sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_DTCNTL) >> | |
369 | SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_SHIFT) & | |
370 | SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_MASK; | |
371 | } | |
372 | ||
373 | static void sh_mobile_sdhi_prepare_tuning(struct tmio_mmc_host *host, | |
374 | unsigned long tap) | |
375 | { | |
376 | struct sh_mobile_sdhi *priv = host_to_priv(host); | |
377 | ||
378 | /* Set sampling clock position */ | |
379 | sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TAPSET, tap); | |
380 | } | |
381 | ||
382 | #define SH_MOBILE_SDHI_MAX_TAP 3 | |
383 | ||
384 | static int sh_mobile_sdhi_select_tuning(struct tmio_mmc_host *host) | |
385 | { | |
386 | struct sh_mobile_sdhi *priv = host_to_priv(host); | |
387 | unsigned long tap_cnt; /* counter of tuning success */ | |
388 | unsigned long tap_set; /* tap position */ | |
389 | unsigned long tap_start;/* start position of tuning success */ | |
390 | unsigned long tap_end; /* end position of tuning success */ | |
391 | unsigned long ntap; /* temporary counter of tuning success */ | |
392 | unsigned long i; | |
393 | ||
394 | /* Clear SCC_RVSREQ */ | |
395 | sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ, 0); | |
396 | ||
397 | /* | |
398 | * Find the longest consecutive run of successful probes. If that | |
399 | * is more than SH_MOBILE_SDHI_MAX_TAP probes long then use the | |
400 | * center index as the tap. | |
401 | */ | |
402 | tap_cnt = 0; | |
403 | ntap = 0; | |
404 | tap_start = 0; | |
405 | tap_end = 0; | |
406 | for (i = 0; i < host->tap_num * 2; i++) { | |
407 | if (test_bit(i, host->taps)) | |
408 | ntap++; | |
409 | else { | |
410 | if (ntap > tap_cnt) { | |
411 | tap_start = i - ntap; | |
412 | tap_end = i - 1; | |
413 | tap_cnt = ntap; | |
414 | } | |
415 | ntap = 0; | |
416 | } | |
417 | } | |
418 | ||
419 | if (ntap > tap_cnt) { | |
420 | tap_start = i - ntap; | |
421 | tap_end = i - 1; | |
422 | tap_cnt = ntap; | |
423 | } | |
424 | ||
425 | if (tap_cnt >= SH_MOBILE_SDHI_MAX_TAP) | |
426 | tap_set = (tap_start + tap_end) / 2 % host->tap_num; | |
427 | else | |
428 | return -EIO; | |
429 | ||
430 | /* Set SCC */ | |
431 | sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TAPSET, tap_set); | |
432 | ||
433 | /* Enable auto re-tuning */ | |
434 | sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL, | |
435 | SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN | | |
436 | sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL)); | |
437 | ||
438 | return 0; | |
439 | } | |
440 | ||
441 | ||
442 | static bool sh_mobile_sdhi_check_scc_error(struct tmio_mmc_host *host) | |
443 | { | |
03c5b0d9 | 444 | struct sh_mobile_sdhi *priv = host_to_priv(host); |
06f438dd SH |
445 | |
446 | /* Check SCC error */ | |
447 | if (sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL) & | |
448 | SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN && | |
449 | sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ) & | |
450 | SH_MOBILE_SDHI_SCC_RVSREQ_RVSERR) { | |
451 | /* Clear SCC error */ | |
452 | sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ, 0); | |
453 | return true; | |
454 | } | |
455 | ||
456 | return false; | |
457 | } | |
458 | ||
459 | static void sh_mobile_sdhi_hw_reset(struct tmio_mmc_host *host) | |
460 | { | |
461 | struct sh_mobile_sdhi *priv; | |
462 | ||
06f438dd SH |
463 | priv = host_to_priv(host); |
464 | ||
465 | /* Reset SCC */ | |
466 | sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN & | |
467 | sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); | |
468 | ||
469 | sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_CKSEL, | |
470 | ~SH_MOBILE_SDHI_SCC_CKSEL_DTSEL & | |
471 | sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_CKSEL)); | |
472 | ||
473 | sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN | | |
474 | sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); | |
475 | ||
476 | sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL, | |
477 | ~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN & | |
478 | sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL)); | |
479 | ||
480 | sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL, | |
481 | ~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN & | |
482 | sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL)); | |
483 | } | |
484 | ||
973ed3af SH |
485 | static int sh_mobile_sdhi_wait_idle(struct tmio_mmc_host *host) |
486 | { | |
487 | int timeout = 1000; | |
488 | ||
a21553c9 WS |
489 | while (--timeout && !(sd_ctrl_read16_and_16_as_32(host, CTL_STATUS) |
490 | & TMIO_STAT_SCLKDIVEN)) | |
973ed3af SH |
491 | udelay(1); |
492 | ||
493 | if (!timeout) { | |
94b110af | 494 | dev_warn(&host->pdev->dev, "timeout waiting for SD bus idle\n"); |
973ed3af SH |
495 | return -EBUSY; |
496 | } | |
497 | ||
498 | return 0; | |
499 | } | |
500 | ||
501 | static int sh_mobile_sdhi_write16_hook(struct tmio_mmc_host *host, int addr) | |
502 | { | |
503 | switch (addr) | |
504 | { | |
505 | case CTL_SD_CMD: | |
506 | case CTL_STOP_INTERNAL_ACTION: | |
507 | case CTL_XFER_BLK_COUNT: | |
508 | case CTL_SD_CARD_CLK_CTL: | |
509 | case CTL_SD_XFER_LEN: | |
510 | case CTL_SD_MEM_CARD_OPT: | |
511 | case CTL_TRANSACTION_CTL: | |
512 | case CTL_DMA_ENABLE: | |
ff741cfd | 513 | case EXT_ACC: |
973ed3af SH |
514 | return sh_mobile_sdhi_wait_idle(host); |
515 | } | |
516 | ||
517 | return 0; | |
518 | } | |
519 | ||
8b4efe2f KM |
520 | static int sh_mobile_sdhi_multi_io_quirk(struct mmc_card *card, |
521 | unsigned int direction, int blk_size) | |
522 | { | |
523 | /* | |
524 | * In Renesas controllers, when performing a | |
525 | * multiple block read of one or two blocks, | |
526 | * depending on the timing with which the | |
527 | * response register is read, the response | |
528 | * value may not be read properly. | |
529 | * Use single block read for this HW bug | |
530 | */ | |
531 | if ((direction == MMC_DATA_READ) && | |
532 | blk_size == 2) | |
533 | return 1; | |
534 | ||
535 | return blk_size; | |
536 | } | |
537 | ||
0c47f6ae KM |
538 | static void sh_mobile_sdhi_enable_dma(struct tmio_mmc_host *host, bool enable) |
539 | { | |
540 | sd_ctrl_write16(host, CTL_DMA_ENABLE, enable ? 2 : 0); | |
f45394d5 KM |
541 | |
542 | /* enable 32bit access if DMA mode if possibile */ | |
543 | sh_mobile_sdhi_sdbuf_width(host, enable ? 32 : 16); | |
0c47f6ae KM |
544 | } |
545 | ||
c3be1efd | 546 | static int sh_mobile_sdhi_probe(struct platform_device *pdev) |
a87d5638 | 547 | { |
dc9f1a8d | 548 | const struct sh_mobile_sdhi_of_data *of_data = of_device_get_match_data(&pdev->dev); |
a87d5638 | 549 | struct sh_mobile_sdhi *priv; |
056676da | 550 | struct tmio_mmc_data *mmc_data; |
f33c9d65 | 551 | struct tmio_mmc_data *mmd = pdev->dev.platform_data; |
42051e8a | 552 | struct tmio_mmc_host *host; |
3b159a6e | 553 | struct resource *res; |
06f438dd | 554 | int irq, ret, i; |
87ae7bbe | 555 | struct tmio_mmc_dma *dma_priv; |
a87d5638 | 556 | |
3b159a6e KM |
557 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
558 | if (!res) | |
559 | return -EINVAL; | |
560 | ||
ac51b961 | 561 | priv = devm_kzalloc(&pdev->dev, sizeof(struct sh_mobile_sdhi), GFP_KERNEL); |
2bf8ab6b | 562 | if (!priv) |
a87d5638 | 563 | return -ENOMEM; |
a87d5638 | 564 | |
056676da | 565 | mmc_data = &priv->mmc_data; |
87ae7bbe | 566 | dma_priv = &priv->dma_priv; |
056676da | 567 | |
ac51b961 | 568 | priv->clk = devm_clk_get(&pdev->dev, NULL); |
a87d5638 | 569 | if (IS_ERR(priv->clk)) { |
a87d5638 | 570 | ret = PTR_ERR(priv->clk); |
56ae1adc | 571 | dev_err(&pdev->dev, "cannot get clock: %d\n", ret); |
010f4aa7 | 572 | goto eprobe; |
a87d5638 MD |
573 | } |
574 | ||
057a4592 WS |
575 | priv->pinctrl = devm_pinctrl_get(&pdev->dev); |
576 | if (!IS_ERR(priv->pinctrl)) { | |
577 | priv->pins_default = pinctrl_lookup_state(priv->pinctrl, | |
578 | PINCTRL_STATE_DEFAULT); | |
579 | priv->pins_uhs = pinctrl_lookup_state(priv->pinctrl, | |
580 | "state_uhs"); | |
581 | } | |
582 | ||
94b110af KM |
583 | host = tmio_mmc_host_alloc(pdev); |
584 | if (!host) { | |
585 | ret = -ENOMEM; | |
586 | goto eprobe; | |
587 | } | |
588 | ||
a72e8b17 | 589 | |
dc9f1a8d | 590 | if (of_data) { |
a72e8b17 | 591 | mmc_data->flags |= of_data->tmio_flags; |
f19417f3 | 592 | mmc_data->ocr_mask = of_data->tmio_ocr_mask; |
a72e8b17 WS |
593 | mmc_data->capabilities |= of_data->capabilities; |
594 | mmc_data->capabilities2 |= of_data->capabilities2; | |
595 | mmc_data->dma_rx_offset = of_data->dma_rx_offset; | |
596 | dma_priv->dma_buswidth = of_data->dma_buswidth; | |
597 | host->bus_shift = of_data->bus_shift; | |
598 | } | |
599 | ||
7ecc09ba | 600 | host->dma = dma_priv; |
dfe9a229 | 601 | host->write16_hook = sh_mobile_sdhi_write16_hook; |
4fe2ec57 | 602 | host->clk_enable = sh_mobile_sdhi_clk_enable; |
2fb55956 | 603 | host->clk_update = sh_mobile_sdhi_clk_update; |
00452c11 | 604 | host->clk_disable = sh_mobile_sdhi_clk_disable; |
85c02ddd | 605 | host->multi_io_quirk = sh_mobile_sdhi_multi_io_quirk; |
ff026099 WS |
606 | |
607 | /* SDR speeds are only available on Gen2+ */ | |
608 | if (mmc_data->flags & TMIO_MMC_MIN_RCAR2) { | |
609 | /* card_busy caused issues on r8a73a4 (pre-Gen2) CD-less SDHI */ | |
610 | host->card_busy = sh_mobile_sdhi_card_busy; | |
611 | host->start_signal_voltage_switch = | |
612 | sh_mobile_sdhi_start_signal_voltage_switch; | |
613 | } | |
a72e8b17 WS |
614 | |
615 | /* Orginally registers were 16 bit apart, could be 32 or 64 nowadays */ | |
616 | if (!host->bus_shift && resource_size(res) > 0x100) /* old way to determine the shift */ | |
95a7dc36 | 617 | host->bus_shift = 1; |
7ecc09ba | 618 | |
84f11d5b | 619 | if (mmd) |
f33c9d65 | 620 | *mmc_data = *mmd; |
84f11d5b | 621 | |
87ae7bbe | 622 | dma_priv->filter = shdma_chan_filter; |
0c47f6ae | 623 | dma_priv->enable = sh_mobile_sdhi_enable_dma; |
87ae7bbe | 624 | |
e471df0b | 625 | mmc_data->alignment_shift = 1; /* 2-byte alignment */ |
f33c9d65 | 626 | mmc_data->capabilities |= MMC_CAP_MMC_HIGHSPEED; |
e471df0b | 627 | |
f1334fb3 YG |
628 | /* |
629 | * All SDHI blocks support 2-byte and larger block sizes in 4-bit | |
630 | * bus width mode. | |
631 | */ | |
632 | mmc_data->flags |= TMIO_MMC_BLKSZ_2BYTES; | |
633 | ||
23b66071 AH |
634 | /* |
635 | * All SDHI blocks support SDIO IRQ signalling. | |
636 | */ | |
637 | mmc_data->flags |= TMIO_MMC_SDIO_IRQ; | |
638 | ||
b8d11962 SU |
639 | /* |
640 | * All SDHI have CMD12 controll bit | |
641 | */ | |
642 | mmc_data->flags |= TMIO_MMC_HAVE_CMD12_CTRL; | |
643 | ||
20dd0373 WS |
644 | /* All SDHI have SDIO status bits which must be 1 */ |
645 | mmc_data->flags |= TMIO_MMC_SDIO_STATUS_SETBITS; | |
6b98757e | 646 | |
94b110af | 647 | ret = tmio_mmc_host_probe(host, mmc_data); |
42051e8a | 648 | if (ret < 0) |
94b110af | 649 | goto efree; |
a87d5638 | 650 | |
e831ead3 | 651 | /* Enable tuning iff we have an SCC and a supported mode */ |
b1c95170 WS |
652 | if (of_data && of_data->scc_offset && |
653 | (host->mmc->caps & MMC_CAP_UHS_SDR104 || | |
654 | host->mmc->caps2 & MMC_CAP2_HS200_1_8V_SDR)) { | |
6ade9a2c WS |
655 | const struct sh_mobile_sdhi_scc *taps = of_data->taps; |
656 | bool hit = false; | |
657 | ||
06f438dd SH |
658 | host->mmc->caps |= MMC_CAP_HW_RESET; |
659 | ||
6ade9a2c WS |
660 | for (i = 0; i < of_data->taps_num; i++) { |
661 | if (taps[i].clk_rate == 0 || | |
662 | taps[i].clk_rate == host->mmc->f_max) { | |
663 | host->scc_tappos = taps->tap; | |
664 | hit = true; | |
665 | break; | |
06f438dd | 666 | } |
6ade9a2c | 667 | } |
06f438dd | 668 | |
6ade9a2c WS |
669 | if (!hit) |
670 | dev_warn(&host->pdev->dev, "Unknown clock rate for SDR104\n"); | |
06f438dd | 671 | |
6ade9a2c | 672 | priv->scc_ctl = host->ctl + of_data->scc_offset; |
e831ead3 WS |
673 | host->init_tuning = sh_mobile_sdhi_init_tuning; |
674 | host->prepare_tuning = sh_mobile_sdhi_prepare_tuning; | |
675 | host->select_tuning = sh_mobile_sdhi_select_tuning; | |
676 | host->check_scc_error = sh_mobile_sdhi_check_scc_error; | |
677 | host->hw_reset = sh_mobile_sdhi_hw_reset; | |
06f438dd SH |
678 | } |
679 | ||
680 | i = 0; | |
adcbc949 WS |
681 | while (1) { |
682 | irq = platform_get_irq(pdev, i); | |
683 | if (irq < 0) | |
684 | break; | |
685 | i++; | |
686 | ret = devm_request_irq(&pdev->dev, irq, tmio_mmc_irq, 0, | |
d5098cb6 SH |
687 | dev_name(&pdev->dev), host); |
688 | if (ret) | |
ac51b961 | 689 | goto eirq; |
d5098cb6 SH |
690 | } |
691 | ||
adcbc949 WS |
692 | /* There must be at least one IRQ source */ |
693 | if (!i) { | |
d5098cb6 | 694 | ret = irq; |
ac51b961 | 695 | goto eirq; |
d5098cb6 SH |
696 | } |
697 | ||
2fb55956 | 698 | dev_info(&pdev->dev, "%s base at 0x%08lx max clock rate %u MHz\n", |
1f7d6819 | 699 | mmc_hostname(host->mmc), (unsigned long) |
58126c87 | 700 | (platform_get_resource(pdev, IORESOURCE_MEM, 0)->start), |
369213bd | 701 | host->mmc->f_max / 1000000); |
a87d5638 | 702 | |
42051e8a | 703 | return ret; |
a87d5638 | 704 | |
ac51b961 | 705 | eirq: |
8e7bfdb3 | 706 | tmio_mmc_host_remove(host); |
94b110af KM |
707 | efree: |
708 | tmio_mmc_host_free(host); | |
42051e8a | 709 | eprobe: |
a87d5638 MD |
710 | return ret; |
711 | } | |
712 | ||
713 | static int sh_mobile_sdhi_remove(struct platform_device *pdev) | |
714 | { | |
42051e8a GL |
715 | struct mmc_host *mmc = platform_get_drvdata(pdev); |
716 | struct tmio_mmc_host *host = mmc_priv(mmc); | |
d6a1f863 | 717 | |
742a0c7c GL |
718 | tmio_mmc_host_remove(host); |
719 | ||
a87d5638 MD |
720 | return 0; |
721 | } | |
722 | ||
e6ee7182 | 723 | static const struct dev_pm_ops tmio_mmc_dev_pm_ops = { |
753a688c UH |
724 | SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, |
725 | pm_runtime_force_resume) | |
6ed23b80 | 726 | SET_RUNTIME_PM_OPS(tmio_mmc_host_runtime_suspend, |
4e262d7f UH |
727 | tmio_mmc_host_runtime_resume, |
728 | NULL) | |
e6ee7182 GL |
729 | }; |
730 | ||
a87d5638 MD |
731 | static struct platform_driver sh_mobile_sdhi_driver = { |
732 | .driver = { | |
733 | .name = "sh_mobile_sdhi", | |
e6ee7182 | 734 | .pm = &tmio_mmc_dev_pm_ops, |
c7bb4487 | 735 | .of_match_table = sh_mobile_sdhi_of_match, |
a87d5638 MD |
736 | }, |
737 | .probe = sh_mobile_sdhi_probe, | |
0433c143 | 738 | .remove = sh_mobile_sdhi_remove, |
a87d5638 MD |
739 | }; |
740 | ||
d1f81a64 | 741 | module_platform_driver(sh_mobile_sdhi_driver); |
a87d5638 MD |
742 | |
743 | MODULE_DESCRIPTION("SuperH Mobile SDHI driver"); | |
744 | MODULE_AUTHOR("Magnus Damm"); | |
745 | MODULE_LICENSE("GPL v2"); | |
42051e8a | 746 | MODULE_ALIAS("platform:sh_mobile_sdhi"); |