.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
---|
1 | 2 | /* |
---|
2 | 3 | * Renesas SDHI |
---|
3 | 4 | * |
---|
4 | | - * Copyright (C) 2015-17 Renesas Electronics Corporation |
---|
5 | | - * Copyright (C) 2016-17 Sang Engineering, Wolfram Sang |
---|
| 5 | + * Copyright (C) 2015-19 Renesas Electronics Corporation |
---|
| 6 | + * Copyright (C) 2016-19 Sang Engineering, Wolfram Sang |
---|
6 | 7 | * Copyright (C) 2016-17 Horms Solutions, Simon Horman |
---|
7 | 8 | * 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 | 9 | * |
---|
13 | 10 | * Based on "Compaq ASIC3 support": |
---|
14 | 11 | * |
---|
.. | .. |
---|
27 | 24 | #include <linux/module.h> |
---|
28 | 25 | #include <linux/of_device.h> |
---|
29 | 26 | #include <linux/platform_device.h> |
---|
| 27 | +#include <linux/pm_domain.h> |
---|
30 | 28 | #include <linux/mmc/host.h> |
---|
| 29 | +#include <linux/mmc/mmc.h> |
---|
31 | 30 | #include <linux/mmc/slot-gpio.h> |
---|
32 | 31 | #include <linux/mfd/tmio.h> |
---|
33 | 32 | #include <linux/sh_dma.h> |
---|
.. | .. |
---|
35 | 34 | #include <linux/pinctrl/consumer.h> |
---|
36 | 35 | #include <linux/pinctrl/pinctrl-state.h> |
---|
37 | 36 | #include <linux/regulator/consumer.h> |
---|
| 37 | +#include <linux/sys_soc.h> |
---|
38 | 38 | |
---|
39 | 39 | #include "renesas_sdhi.h" |
---|
40 | 40 | #include "tmio_mmc.h" |
---|
.. | .. |
---|
47 | 47 | #define SDHI_VER_GEN2_SDR104 0xcb0d |
---|
48 | 48 | #define SDHI_VER_GEN3_SD 0xcc10 |
---|
49 | 49 | #define SDHI_VER_GEN3_SDMMC 0xcd10 |
---|
| 50 | + |
---|
| 51 | +#define SDHI_GEN3_MMC0_ADDR 0xee140000 |
---|
50 | 52 | |
---|
51 | 53 | static void renesas_sdhi_sdbuf_width(struct tmio_mmc_host *host, int width) |
---|
52 | 54 | { |
---|
.. | .. |
---|
84 | 86 | { |
---|
85 | 87 | struct mmc_host *mmc = host->mmc; |
---|
86 | 88 | struct renesas_sdhi *priv = host_to_priv(host); |
---|
87 | | - int ret = clk_prepare_enable(priv->clk); |
---|
88 | | - |
---|
89 | | - if (ret < 0) |
---|
90 | | - return ret; |
---|
| 89 | + int ret; |
---|
91 | 90 | |
---|
92 | 91 | ret = clk_prepare_enable(priv->clk_cd); |
---|
93 | | - if (ret < 0) { |
---|
94 | | - clk_disable_unprepare(priv->clk); |
---|
| 92 | + if (ret < 0) |
---|
95 | 93 | return ret; |
---|
96 | | - } |
---|
97 | 94 | |
---|
98 | 95 | /* |
---|
99 | 96 | * The clock driver may not know what maximum frequency |
---|
.. | .. |
---|
121 | 118 | { |
---|
122 | 119 | struct renesas_sdhi *priv = host_to_priv(host); |
---|
123 | 120 | unsigned int freq, diff, best_freq = 0, diff_min = ~0; |
---|
124 | | - int i, ret; |
---|
| 121 | + int i; |
---|
125 | 122 | |
---|
126 | | - /* tested only on R-Car Gen2+ currently; may work for others */ |
---|
127 | | - if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2)) |
---|
| 123 | + /* |
---|
| 124 | + * We simply return the current rate if a) we are not on a R-Car Gen2+ |
---|
| 125 | + * SoC (may work for others, but untested) or b) if the SCC needs its |
---|
| 126 | + * clock during tuning, so we don't change the external clock setup. |
---|
| 127 | + */ |
---|
| 128 | + if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2) || mmc_doing_tune(host->mmc)) |
---|
128 | 129 | return clk_get_rate(priv->clk); |
---|
129 | 130 | |
---|
130 | 131 | /* |
---|
.. | .. |
---|
150 | 151 | } |
---|
151 | 152 | } |
---|
152 | 153 | |
---|
153 | | - ret = clk_set_rate(priv->clk, best_freq); |
---|
| 154 | + clk_set_rate(priv->clk, best_freq); |
---|
154 | 155 | |
---|
155 | | - return ret == 0 ? best_freq : clk_get_rate(priv->clk); |
---|
| 156 | + return clk_get_rate(priv->clk); |
---|
| 157 | +} |
---|
| 158 | + |
---|
| 159 | +static void renesas_sdhi_set_clock(struct tmio_mmc_host *host, |
---|
| 160 | + unsigned int new_clock) |
---|
| 161 | +{ |
---|
| 162 | + u32 clk = 0, clock; |
---|
| 163 | + |
---|
| 164 | + sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN & |
---|
| 165 | + sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); |
---|
| 166 | + |
---|
| 167 | + if (new_clock == 0) { |
---|
| 168 | + host->mmc->actual_clock = 0; |
---|
| 169 | + goto out; |
---|
| 170 | + } |
---|
| 171 | + |
---|
| 172 | + host->mmc->actual_clock = renesas_sdhi_clk_update(host, new_clock); |
---|
| 173 | + clock = host->mmc->actual_clock / 512; |
---|
| 174 | + |
---|
| 175 | + for (clk = 0x80000080; new_clock >= (clock << 1); clk >>= 1) |
---|
| 176 | + clock <<= 1; |
---|
| 177 | + |
---|
| 178 | + /* 1/1 clock is option */ |
---|
| 179 | + if ((host->pdata->flags & TMIO_MMC_CLK_ACTUAL) && ((clk >> 22) & 0x1)) { |
---|
| 180 | + if (!(host->mmc->ios.timing == MMC_TIMING_MMC_HS400)) |
---|
| 181 | + clk |= 0xff; |
---|
| 182 | + else |
---|
| 183 | + clk &= ~0xff; |
---|
| 184 | + } |
---|
| 185 | + |
---|
| 186 | + sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk & CLK_CTL_DIV_MASK); |
---|
| 187 | + if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2)) |
---|
| 188 | + usleep_range(10000, 11000); |
---|
| 189 | + |
---|
| 190 | + sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN | |
---|
| 191 | + sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); |
---|
| 192 | + |
---|
| 193 | +out: |
---|
| 194 | + /* HW engineers overrode docs: no sleep needed on R-Car2+ */ |
---|
| 195 | + if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2)) |
---|
| 196 | + usleep_range(10000, 11000); |
---|
156 | 197 | } |
---|
157 | 198 | |
---|
158 | 199 | static void renesas_sdhi_clk_disable(struct tmio_mmc_host *host) |
---|
159 | 200 | { |
---|
160 | 201 | struct renesas_sdhi *priv = host_to_priv(host); |
---|
161 | 202 | |
---|
162 | | - clk_disable_unprepare(priv->clk); |
---|
163 | 203 | clk_disable_unprepare(priv->clk_cd); |
---|
164 | 204 | } |
---|
165 | 205 | |
---|
.. | .. |
---|
199 | 239 | MMC_SIGNAL_VOLTAGE_330 ? 0 : -EINVAL; |
---|
200 | 240 | |
---|
201 | 241 | ret = mmc_regulator_set_vqmmc(host->mmc, ios); |
---|
202 | | - if (ret) |
---|
| 242 | + if (ret < 0) |
---|
203 | 243 | return ret; |
---|
204 | 244 | |
---|
205 | 245 | return pinctrl_select_state(priv->pinctrl, pin_state); |
---|
.. | .. |
---|
212 | 252 | #define SH_MOBILE_SDHI_SCC_CKSEL 0x006 |
---|
213 | 253 | #define SH_MOBILE_SDHI_SCC_RVSCNTL 0x008 |
---|
214 | 254 | #define SH_MOBILE_SDHI_SCC_RVSREQ 0x00A |
---|
| 255 | +#define SH_MOBILE_SDHI_SCC_SMPCMP 0x00C |
---|
215 | 256 | #define SH_MOBILE_SDHI_SCC_TMPPORT2 0x00E |
---|
| 257 | +#define SH_MOBILE_SDHI_SCC_TMPPORT3 0x014 |
---|
| 258 | +#define SH_MOBILE_SDHI_SCC_TMPPORT4 0x016 |
---|
| 259 | +#define SH_MOBILE_SDHI_SCC_TMPPORT5 0x018 |
---|
| 260 | +#define SH_MOBILE_SDHI_SCC_TMPPORT6 0x01A |
---|
| 261 | +#define SH_MOBILE_SDHI_SCC_TMPPORT7 0x01C |
---|
216 | 262 | |
---|
217 | | -/* Definitions for values the SH_MOBILE_SDHI_SCC_DTCNTL register */ |
---|
218 | 263 | #define SH_MOBILE_SDHI_SCC_DTCNTL_TAPEN BIT(0) |
---|
219 | 264 | #define SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_SHIFT 16 |
---|
220 | 265 | #define SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_MASK 0xff |
---|
221 | 266 | |
---|
222 | | -/* Definitions for values the SH_MOBILE_SDHI_SCC_CKSEL register */ |
---|
223 | 267 | #define SH_MOBILE_SDHI_SCC_CKSEL_DTSEL BIT(0) |
---|
224 | | -/* Definitions for values the SH_MOBILE_SDHI_SCC_RVSCNTL register */ |
---|
| 268 | + |
---|
225 | 269 | #define SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN BIT(0) |
---|
226 | | -/* Definitions for values the SH_MOBILE_SDHI_SCC_RVSREQ register */ |
---|
| 270 | + |
---|
| 271 | +#define SH_MOBILE_SDHI_SCC_RVSREQ_REQTAPDOWN BIT(0) |
---|
| 272 | +#define SH_MOBILE_SDHI_SCC_RVSREQ_REQTAPUP BIT(1) |
---|
227 | 273 | #define SH_MOBILE_SDHI_SCC_RVSREQ_RVSERR BIT(2) |
---|
228 | | -/* Definitions for values the SH_MOBILE_SDHI_SCC_TMPPORT2 register */ |
---|
| 274 | + |
---|
| 275 | +#define SH_MOBILE_SDHI_SCC_SMPCMP_CMD_REQDOWN BIT(8) |
---|
| 276 | +#define SH_MOBILE_SDHI_SCC_SMPCMP_CMD_REQUP BIT(24) |
---|
| 277 | +#define SH_MOBILE_SDHI_SCC_SMPCMP_CMD_ERR (BIT(8) | BIT(24)) |
---|
| 278 | + |
---|
229 | 279 | #define SH_MOBILE_SDHI_SCC_TMPPORT2_HS400OSEL BIT(4) |
---|
230 | 280 | #define SH_MOBILE_SDHI_SCC_TMPPORT2_HS400EN BIT(31) |
---|
| 281 | + |
---|
| 282 | +/* Definitions for values the SH_MOBILE_SDHI_SCC_TMPPORT4 register */ |
---|
| 283 | +#define SH_MOBILE_SDHI_SCC_TMPPORT4_DLL_ACC_START BIT(0) |
---|
| 284 | + |
---|
| 285 | +/* Definitions for values the SH_MOBILE_SDHI_SCC_TMPPORT5 register */ |
---|
| 286 | +#define SH_MOBILE_SDHI_SCC_TMPPORT5_DLL_RW_SEL_R BIT(8) |
---|
| 287 | +#define SH_MOBILE_SDHI_SCC_TMPPORT5_DLL_RW_SEL_W (0 << 8) |
---|
| 288 | +#define SH_MOBILE_SDHI_SCC_TMPPORT5_DLL_ADR_MASK 0x3F |
---|
| 289 | + |
---|
| 290 | +/* Definitions for values the SH_MOBILE_SDHI_SCC register */ |
---|
| 291 | +#define SH_MOBILE_SDHI_SCC_TMPPORT_DISABLE_WP_CODE 0xa5000000 |
---|
| 292 | +#define SH_MOBILE_SDHI_SCC_TMPPORT_CALIB_CODE_MASK 0x1f |
---|
| 293 | +#define SH_MOBILE_SDHI_SCC_TMPPORT_MANUAL_MODE BIT(7) |
---|
| 294 | + |
---|
| 295 | +static const u8 r8a7796_es13_calib_table[2][SDHI_CALIB_TABLE_MAX] = { |
---|
| 296 | + { 3, 3, 3, 3, 3, 3, 3, 4, 4, 5, 6, 7, 8, 9, 10, 15, |
---|
| 297 | + 16, 16, 16, 16, 16, 16, 17, 18, 18, 19, 20, 21, 22, 23, 24, 25 }, |
---|
| 298 | + { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 7, 8, 11, |
---|
| 299 | + 12, 17, 18, 18, 18, 18, 18, 18, 18, 19, 20, 21, 22, 23, 25, 25 } |
---|
| 300 | +}; |
---|
| 301 | + |
---|
| 302 | +static const u8 r8a77965_calib_table[2][SDHI_CALIB_TABLE_MAX] = { |
---|
| 303 | + { 1, 2, 6, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15, 15, 16, |
---|
| 304 | + 17, 18, 19, 20, 21, 22, 23, 24, 25, 25, 26, 27, 28, 29, 30, 31 }, |
---|
| 305 | + { 2, 3, 4, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 16, 17, |
---|
| 306 | + 17, 17, 20, 21, 22, 23, 24, 25, 27, 28, 29, 30, 31, 31, 31, 31 } |
---|
| 307 | +}; |
---|
| 308 | + |
---|
| 309 | +static const u8 r8a77990_calib_table[2][SDHI_CALIB_TABLE_MAX] = { |
---|
| 310 | + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
---|
| 311 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, |
---|
| 312 | + { 0, 0, 0, 1, 2, 3, 3, 4, 4, 4, 5, 5, 6, 8, 9, 10, |
---|
| 313 | + 11, 12, 13, 15, 16, 17, 17, 18, 18, 19, 20, 22, 24, 25, 26, 26 } |
---|
| 314 | +}; |
---|
231 | 315 | |
---|
232 | 316 | static inline u32 sd_scc_read32(struct tmio_mmc_host *host, |
---|
233 | 317 | struct renesas_sdhi *priv, int addr) |
---|
.. | .. |
---|
278 | 362 | SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_MASK; |
---|
279 | 363 | } |
---|
280 | 364 | |
---|
281 | | -static void renesas_sdhi_prepare_tuning(struct tmio_mmc_host *host, |
---|
282 | | - unsigned long tap) |
---|
| 365 | +static void renesas_sdhi_hs400_complete(struct mmc_host *mmc) |
---|
283 | 366 | { |
---|
| 367 | + struct tmio_mmc_host *host = mmc_priv(mmc); |
---|
284 | 368 | struct renesas_sdhi *priv = host_to_priv(host); |
---|
285 | | - |
---|
286 | | - /* Set sampling clock position */ |
---|
287 | | - sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TAPSET, tap); |
---|
288 | | -} |
---|
289 | | - |
---|
290 | | -static void renesas_sdhi_hs400_complete(struct tmio_mmc_host *host) |
---|
291 | | -{ |
---|
292 | | - struct renesas_sdhi *priv = host_to_priv(host); |
---|
| 369 | + u32 bad_taps = priv->quirks ? priv->quirks->hs400_bad_taps : 0; |
---|
| 370 | + bool use_4tap = priv->quirks && priv->quirks->hs400_4taps; |
---|
293 | 371 | |
---|
294 | 372 | sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN & |
---|
295 | 373 | sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); |
---|
.. | .. |
---|
297 | 375 | /* Set HS400 mode */ |
---|
298 | 376 | sd_ctrl_write16(host, CTL_SDIF_MODE, 0x0001 | |
---|
299 | 377 | sd_ctrl_read16(host, CTL_SDIF_MODE)); |
---|
| 378 | + |
---|
| 379 | + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DT2FF, |
---|
| 380 | + priv->scc_tappos_hs400); |
---|
| 381 | + |
---|
| 382 | + /* Gen3 can't do automatic tap correction with HS400, so disable it */ |
---|
| 383 | + if (sd_ctrl_read16(host, CTL_VERSION) == SDHI_VER_GEN3_SDMMC) |
---|
| 384 | + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL, |
---|
| 385 | + ~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN & |
---|
| 386 | + sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL)); |
---|
| 387 | + |
---|
300 | 388 | sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT2, |
---|
301 | 389 | (SH_MOBILE_SDHI_SCC_TMPPORT2_HS400EN | |
---|
302 | 390 | SH_MOBILE_SDHI_SCC_TMPPORT2_HS400OSEL) | |
---|
303 | 391 | sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT2)); |
---|
304 | 392 | |
---|
305 | | - /* Set the sampling clock selection range of HS400 mode */ |
---|
306 | 393 | sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DTCNTL, |
---|
307 | 394 | SH_MOBILE_SDHI_SCC_DTCNTL_TAPEN | |
---|
308 | | - 0x4 << SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_SHIFT); |
---|
| 395 | + sd_scc_read32(host, priv, |
---|
| 396 | + SH_MOBILE_SDHI_SCC_DTCNTL)); |
---|
309 | 397 | |
---|
| 398 | + /* Avoid bad TAP */ |
---|
| 399 | + if (bad_taps & BIT(priv->tap_set)) { |
---|
| 400 | + u32 new_tap = (priv->tap_set + 1) % priv->tap_num; |
---|
310 | 401 | |
---|
311 | | - if (host->pdata->flags & TMIO_MMC_HAVE_4TAP_HS400) |
---|
312 | | - sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TAPSET, |
---|
313 | | - host->tap_set / 2); |
---|
| 402 | + if (bad_taps & BIT(new_tap)) |
---|
| 403 | + new_tap = (priv->tap_set - 1) % priv->tap_num; |
---|
| 404 | + |
---|
| 405 | + if (bad_taps & BIT(new_tap)) { |
---|
| 406 | + new_tap = priv->tap_set; |
---|
| 407 | + dev_dbg(&host->pdev->dev, "Can't handle three bad tap in a row\n"); |
---|
| 408 | + } |
---|
| 409 | + |
---|
| 410 | + priv->tap_set = new_tap; |
---|
| 411 | + } |
---|
| 412 | + |
---|
| 413 | + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TAPSET, |
---|
| 414 | + priv->tap_set / (use_4tap ? 2 : 1)); |
---|
314 | 415 | |
---|
315 | 416 | sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_CKSEL, |
---|
316 | 417 | SH_MOBILE_SDHI_SCC_CKSEL_DTSEL | |
---|
.. | .. |
---|
318 | 419 | |
---|
319 | 420 | sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN | |
---|
320 | 421 | sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); |
---|
| 422 | + |
---|
| 423 | + if (priv->adjust_hs400_calib_table) |
---|
| 424 | + priv->needs_adjust_hs400 = true; |
---|
321 | 425 | } |
---|
322 | 426 | |
---|
323 | 427 | static void renesas_sdhi_reset_scc(struct tmio_mmc_host *host, |
---|
.. | .. |
---|
332 | 436 | SH_MOBILE_SDHI_SCC_CKSEL)); |
---|
333 | 437 | } |
---|
334 | 438 | |
---|
335 | | -static void renesas_sdhi_disable_scc(struct tmio_mmc_host *host) |
---|
| 439 | +static void renesas_sdhi_disable_scc(struct mmc_host *mmc) |
---|
336 | 440 | { |
---|
| 441 | + struct tmio_mmc_host *host = mmc_priv(mmc); |
---|
337 | 442 | struct renesas_sdhi *priv = host_to_priv(host); |
---|
338 | 443 | |
---|
339 | 444 | renesas_sdhi_reset_scc(host, priv); |
---|
.. | .. |
---|
347 | 452 | sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); |
---|
348 | 453 | } |
---|
349 | 454 | |
---|
| 455 | +static u32 sd_scc_tmpport_read32(struct tmio_mmc_host *host, |
---|
| 456 | + struct renesas_sdhi *priv, u32 addr) |
---|
| 457 | +{ |
---|
| 458 | + /* read mode */ |
---|
| 459 | + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT5, |
---|
| 460 | + SH_MOBILE_SDHI_SCC_TMPPORT5_DLL_RW_SEL_R | |
---|
| 461 | + (SH_MOBILE_SDHI_SCC_TMPPORT5_DLL_ADR_MASK & addr)); |
---|
| 462 | + |
---|
| 463 | + /* access start and stop */ |
---|
| 464 | + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT4, |
---|
| 465 | + SH_MOBILE_SDHI_SCC_TMPPORT4_DLL_ACC_START); |
---|
| 466 | + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT4, 0); |
---|
| 467 | + |
---|
| 468 | + return sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT7); |
---|
| 469 | +} |
---|
| 470 | + |
---|
| 471 | +static void sd_scc_tmpport_write32(struct tmio_mmc_host *host, |
---|
| 472 | + struct renesas_sdhi *priv, u32 addr, u32 val) |
---|
| 473 | +{ |
---|
| 474 | + /* write mode */ |
---|
| 475 | + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT5, |
---|
| 476 | + SH_MOBILE_SDHI_SCC_TMPPORT5_DLL_RW_SEL_W | |
---|
| 477 | + (SH_MOBILE_SDHI_SCC_TMPPORT5_DLL_ADR_MASK & addr)); |
---|
| 478 | + |
---|
| 479 | + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT6, val); |
---|
| 480 | + |
---|
| 481 | + /* access start and stop */ |
---|
| 482 | + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT4, |
---|
| 483 | + SH_MOBILE_SDHI_SCC_TMPPORT4_DLL_ACC_START); |
---|
| 484 | + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT4, 0); |
---|
| 485 | +} |
---|
| 486 | + |
---|
| 487 | +static void renesas_sdhi_adjust_hs400_mode_enable(struct tmio_mmc_host *host) |
---|
| 488 | +{ |
---|
| 489 | + struct renesas_sdhi *priv = host_to_priv(host); |
---|
| 490 | + u32 calib_code; |
---|
| 491 | + |
---|
| 492 | + /* disable write protect */ |
---|
| 493 | + sd_scc_tmpport_write32(host, priv, 0x00, |
---|
| 494 | + SH_MOBILE_SDHI_SCC_TMPPORT_DISABLE_WP_CODE); |
---|
| 495 | + /* read calibration code and adjust */ |
---|
| 496 | + calib_code = sd_scc_tmpport_read32(host, priv, 0x26); |
---|
| 497 | + calib_code &= SH_MOBILE_SDHI_SCC_TMPPORT_CALIB_CODE_MASK; |
---|
| 498 | + |
---|
| 499 | + sd_scc_tmpport_write32(host, priv, 0x22, |
---|
| 500 | + SH_MOBILE_SDHI_SCC_TMPPORT_MANUAL_MODE | |
---|
| 501 | + priv->adjust_hs400_calib_table[calib_code]); |
---|
| 502 | + |
---|
| 503 | + /* set offset value to TMPPORT3, hardcoded to OFFSET0 (= 0x3) for now */ |
---|
| 504 | + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT3, 0x3); |
---|
| 505 | + |
---|
| 506 | + /* adjustment done, clear flag */ |
---|
| 507 | + priv->needs_adjust_hs400 = false; |
---|
| 508 | +} |
---|
| 509 | + |
---|
| 510 | +static void renesas_sdhi_adjust_hs400_mode_disable(struct tmio_mmc_host *host) |
---|
| 511 | +{ |
---|
| 512 | + struct renesas_sdhi *priv = host_to_priv(host); |
---|
| 513 | + |
---|
| 514 | + /* disable write protect */ |
---|
| 515 | + sd_scc_tmpport_write32(host, priv, 0x00, |
---|
| 516 | + SH_MOBILE_SDHI_SCC_TMPPORT_DISABLE_WP_CODE); |
---|
| 517 | + /* disable manual calibration */ |
---|
| 518 | + sd_scc_tmpport_write32(host, priv, 0x22, 0); |
---|
| 519 | + /* clear offset value of TMPPORT3 */ |
---|
| 520 | + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT3, 0); |
---|
| 521 | +} |
---|
| 522 | + |
---|
350 | 523 | static void renesas_sdhi_reset_hs400_mode(struct tmio_mmc_host *host, |
---|
351 | 524 | struct renesas_sdhi *priv) |
---|
352 | 525 | { |
---|
.. | .. |
---|
356 | 529 | /* Reset HS400 mode */ |
---|
357 | 530 | sd_ctrl_write16(host, CTL_SDIF_MODE, ~0x0001 & |
---|
358 | 531 | sd_ctrl_read16(host, CTL_SDIF_MODE)); |
---|
| 532 | + |
---|
| 533 | + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DT2FF, priv->scc_tappos); |
---|
| 534 | + |
---|
359 | 535 | sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT2, |
---|
360 | 536 | ~(SH_MOBILE_SDHI_SCC_TMPPORT2_HS400EN | |
---|
361 | 537 | SH_MOBILE_SDHI_SCC_TMPPORT2_HS400OSEL) & |
---|
362 | 538 | sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT2)); |
---|
363 | 539 | |
---|
| 540 | + if (priv->adjust_hs400_calib_table) |
---|
| 541 | + renesas_sdhi_adjust_hs400_mode_disable(host); |
---|
| 542 | + |
---|
364 | 543 | sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN | |
---|
365 | 544 | sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); |
---|
366 | 545 | } |
---|
367 | 546 | |
---|
368 | | -static void renesas_sdhi_prepare_hs400_tuning(struct tmio_mmc_host *host) |
---|
| 547 | +static int renesas_sdhi_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios) |
---|
369 | 548 | { |
---|
| 549 | + struct tmio_mmc_host *host = mmc_priv(mmc); |
---|
| 550 | + |
---|
370 | 551 | renesas_sdhi_reset_hs400_mode(host, host_to_priv(host)); |
---|
| 552 | + return 0; |
---|
371 | 553 | } |
---|
372 | 554 | |
---|
373 | | -#define SH_MOBILE_SDHI_MAX_TAP 3 |
---|
| 555 | +static void renesas_sdhi_reset(struct tmio_mmc_host *host) |
---|
| 556 | +{ |
---|
| 557 | + struct renesas_sdhi *priv = host_to_priv(host); |
---|
| 558 | + |
---|
| 559 | + renesas_sdhi_reset_scc(host, priv); |
---|
| 560 | + renesas_sdhi_reset_hs400_mode(host, priv); |
---|
| 561 | + priv->needs_adjust_hs400 = false; |
---|
| 562 | + |
---|
| 563 | + sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN | |
---|
| 564 | + sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); |
---|
| 565 | + |
---|
| 566 | + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL, |
---|
| 567 | + ~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN & |
---|
| 568 | + sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL)); |
---|
| 569 | + |
---|
| 570 | + if (host->pdata->flags & TMIO_MMC_MIN_RCAR2) |
---|
| 571 | + sd_ctrl_write32_as_16_and_16(host, CTL_IRQ_MASK, |
---|
| 572 | + TMIO_MASK_INIT_RCAR2); |
---|
| 573 | +} |
---|
| 574 | + |
---|
| 575 | +#define SH_MOBILE_SDHI_MIN_TAP_ROW 3 |
---|
374 | 576 | |
---|
375 | 577 | static int renesas_sdhi_select_tuning(struct tmio_mmc_host *host) |
---|
376 | 578 | { |
---|
377 | 579 | struct renesas_sdhi *priv = host_to_priv(host); |
---|
378 | | - unsigned long tap_cnt; /* counter of tuning success */ |
---|
379 | | - unsigned long tap_start;/* start position of tuning success */ |
---|
380 | | - unsigned long tap_end; /* end position of tuning success */ |
---|
381 | | - unsigned long ntap; /* temporary counter of tuning success */ |
---|
382 | | - unsigned long i; |
---|
| 580 | + unsigned int tap_start = 0, tap_end = 0, tap_cnt = 0, rs, re, i; |
---|
| 581 | + unsigned int taps_size = priv->tap_num * 2, min_tap_row; |
---|
| 582 | + unsigned long *bitmap; |
---|
383 | 583 | |
---|
384 | | - /* Clear SCC_RVSREQ */ |
---|
385 | 584 | sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ, 0); |
---|
386 | 585 | |
---|
387 | 586 | /* |
---|
.. | .. |
---|
389 | 588 | * result requiring the tap to be good in both runs before |
---|
390 | 589 | * considering it for tuning selection. |
---|
391 | 590 | */ |
---|
392 | | - for (i = 0; i < host->tap_num * 2; i++) { |
---|
393 | | - int offset = host->tap_num * (i < host->tap_num ? 1 : -1); |
---|
| 591 | + for (i = 0; i < taps_size; i++) { |
---|
| 592 | + int offset = priv->tap_num * (i < priv->tap_num ? 1 : -1); |
---|
394 | 593 | |
---|
395 | | - if (!test_bit(i, host->taps)) |
---|
396 | | - clear_bit(i + offset, host->taps); |
---|
| 594 | + if (!test_bit(i, priv->taps)) |
---|
| 595 | + clear_bit(i + offset, priv->taps); |
---|
| 596 | + |
---|
| 597 | + if (!test_bit(i, priv->smpcmp)) |
---|
| 598 | + clear_bit(i + offset, priv->smpcmp); |
---|
397 | 599 | } |
---|
398 | 600 | |
---|
399 | 601 | /* |
---|
400 | | - * Find the longest consecutive run of successful probes. If that |
---|
401 | | - * is more than SH_MOBILE_SDHI_MAX_TAP probes long then use the |
---|
402 | | - * center index as the tap. |
---|
| 602 | + * If all TAP are OK, the sampling clock position is selected by |
---|
| 603 | + * identifying the change point of data. |
---|
403 | 604 | */ |
---|
404 | | - tap_cnt = 0; |
---|
405 | | - ntap = 0; |
---|
406 | | - tap_start = 0; |
---|
407 | | - tap_end = 0; |
---|
408 | | - for (i = 0; i < host->tap_num * 2; i++) { |
---|
409 | | - if (test_bit(i, host->taps)) { |
---|
410 | | - ntap++; |
---|
411 | | - } else { |
---|
412 | | - if (ntap > tap_cnt) { |
---|
413 | | - tap_start = i - ntap; |
---|
414 | | - tap_end = i - 1; |
---|
415 | | - tap_cnt = ntap; |
---|
416 | | - } |
---|
417 | | - ntap = 0; |
---|
| 605 | + if (bitmap_full(priv->taps, taps_size)) { |
---|
| 606 | + bitmap = priv->smpcmp; |
---|
| 607 | + min_tap_row = 1; |
---|
| 608 | + } else { |
---|
| 609 | + bitmap = priv->taps; |
---|
| 610 | + min_tap_row = SH_MOBILE_SDHI_MIN_TAP_ROW; |
---|
| 611 | + } |
---|
| 612 | + |
---|
| 613 | + /* |
---|
| 614 | + * Find the longest consecutive run of successful probes. If that |
---|
| 615 | + * is at least SH_MOBILE_SDHI_MIN_TAP_ROW probes long then use the |
---|
| 616 | + * center index as the tap, otherwise bail out. |
---|
| 617 | + */ |
---|
| 618 | + bitmap_for_each_set_region(bitmap, rs, re, 0, taps_size) { |
---|
| 619 | + if (re - rs > tap_cnt) { |
---|
| 620 | + tap_end = re; |
---|
| 621 | + tap_start = rs; |
---|
| 622 | + tap_cnt = tap_end - tap_start; |
---|
418 | 623 | } |
---|
419 | 624 | } |
---|
420 | 625 | |
---|
421 | | - if (ntap > tap_cnt) { |
---|
422 | | - tap_start = i - ntap; |
---|
423 | | - tap_end = i - 1; |
---|
424 | | - tap_cnt = ntap; |
---|
425 | | - } |
---|
426 | | - |
---|
427 | | - if (tap_cnt >= SH_MOBILE_SDHI_MAX_TAP) |
---|
428 | | - host->tap_set = (tap_start + tap_end) / 2 % host->tap_num; |
---|
| 626 | + if (tap_cnt >= min_tap_row) |
---|
| 627 | + priv->tap_set = (tap_start + tap_end) / 2 % priv->tap_num; |
---|
429 | 628 | else |
---|
430 | 629 | return -EIO; |
---|
431 | 630 | |
---|
432 | 631 | /* Set SCC */ |
---|
433 | | - sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TAPSET, host->tap_set); |
---|
| 632 | + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TAPSET, priv->tap_set); |
---|
434 | 633 | |
---|
435 | 634 | /* Enable auto re-tuning */ |
---|
436 | 635 | sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL, |
---|
.. | .. |
---|
440 | 639 | return 0; |
---|
441 | 640 | } |
---|
442 | 641 | |
---|
443 | | -static bool renesas_sdhi_check_scc_error(struct tmio_mmc_host *host) |
---|
| 642 | +static int renesas_sdhi_execute_tuning(struct mmc_host *mmc, u32 opcode) |
---|
| 643 | +{ |
---|
| 644 | + struct tmio_mmc_host *host = mmc_priv(mmc); |
---|
| 645 | + struct renesas_sdhi *priv = host_to_priv(host); |
---|
| 646 | + int i, ret; |
---|
| 647 | + |
---|
| 648 | + priv->tap_num = renesas_sdhi_init_tuning(host); |
---|
| 649 | + if (!priv->tap_num) |
---|
| 650 | + return 0; /* Tuning is not supported */ |
---|
| 651 | + |
---|
| 652 | + if (priv->tap_num * 2 >= sizeof(priv->taps) * BITS_PER_BYTE) { |
---|
| 653 | + dev_err(&host->pdev->dev, |
---|
| 654 | + "Too many taps, please update 'taps' in tmio_mmc_host!\n"); |
---|
| 655 | + return -EINVAL; |
---|
| 656 | + } |
---|
| 657 | + |
---|
| 658 | + bitmap_zero(priv->taps, priv->tap_num * 2); |
---|
| 659 | + bitmap_zero(priv->smpcmp, priv->tap_num * 2); |
---|
| 660 | + |
---|
| 661 | + /* Issue CMD19 twice for each tap */ |
---|
| 662 | + for (i = 0; i < 2 * priv->tap_num; i++) { |
---|
| 663 | + int cmd_error = 0; |
---|
| 664 | + |
---|
| 665 | + /* Set sampling clock position */ |
---|
| 666 | + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TAPSET, i % priv->tap_num); |
---|
| 667 | + |
---|
| 668 | + if (mmc_send_tuning(mmc, opcode, &cmd_error) == 0) |
---|
| 669 | + set_bit(i, priv->taps); |
---|
| 670 | + |
---|
| 671 | + if (sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_SMPCMP) == 0) |
---|
| 672 | + set_bit(i, priv->smpcmp); |
---|
| 673 | + |
---|
| 674 | + if (cmd_error) |
---|
| 675 | + mmc_abort_tuning(mmc, opcode); |
---|
| 676 | + } |
---|
| 677 | + |
---|
| 678 | + ret = renesas_sdhi_select_tuning(host); |
---|
| 679 | + if (ret < 0) |
---|
| 680 | + renesas_sdhi_reset(host); |
---|
| 681 | + return ret; |
---|
| 682 | +} |
---|
| 683 | + |
---|
| 684 | +static bool renesas_sdhi_manual_correction(struct tmio_mmc_host *host, bool use_4tap) |
---|
| 685 | +{ |
---|
| 686 | + struct renesas_sdhi *priv = host_to_priv(host); |
---|
| 687 | + unsigned int new_tap = priv->tap_set, error_tap = priv->tap_set; |
---|
| 688 | + u32 val; |
---|
| 689 | + |
---|
| 690 | + val = sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ); |
---|
| 691 | + if (!val) |
---|
| 692 | + return false; |
---|
| 693 | + |
---|
| 694 | + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ, 0); |
---|
| 695 | + |
---|
| 696 | + /* Change TAP position according to correction status */ |
---|
| 697 | + if (sd_ctrl_read16(host, CTL_VERSION) == SDHI_VER_GEN3_SDMMC && |
---|
| 698 | + host->mmc->ios.timing == MMC_TIMING_MMC_HS400) { |
---|
| 699 | + u32 bad_taps = priv->quirks ? priv->quirks->hs400_bad_taps : 0; |
---|
| 700 | + /* |
---|
| 701 | + * With HS400, the DAT signal is based on DS, not CLK. |
---|
| 702 | + * Therefore, use only CMD status. |
---|
| 703 | + */ |
---|
| 704 | + u32 smpcmp = sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_SMPCMP) & |
---|
| 705 | + SH_MOBILE_SDHI_SCC_SMPCMP_CMD_ERR; |
---|
| 706 | + if (!smpcmp) { |
---|
| 707 | + return false; /* no error in CMD signal */ |
---|
| 708 | + } else if (smpcmp == SH_MOBILE_SDHI_SCC_SMPCMP_CMD_REQUP) { |
---|
| 709 | + new_tap++; |
---|
| 710 | + error_tap--; |
---|
| 711 | + } else if (smpcmp == SH_MOBILE_SDHI_SCC_SMPCMP_CMD_REQDOWN) { |
---|
| 712 | + new_tap--; |
---|
| 713 | + error_tap++; |
---|
| 714 | + } else { |
---|
| 715 | + return true; /* need retune */ |
---|
| 716 | + } |
---|
| 717 | + |
---|
| 718 | + /* |
---|
| 719 | + * When new_tap is a bad tap, we cannot change. Then, we compare |
---|
| 720 | + * with the HS200 tuning result. When smpcmp[error_tap] is OK, |
---|
| 721 | + * we can at least retune. |
---|
| 722 | + */ |
---|
| 723 | + if (bad_taps & BIT(new_tap % priv->tap_num)) |
---|
| 724 | + return test_bit(error_tap % priv->tap_num, priv->smpcmp); |
---|
| 725 | + } else { |
---|
| 726 | + if (val & SH_MOBILE_SDHI_SCC_RVSREQ_RVSERR) |
---|
| 727 | + return true; /* need retune */ |
---|
| 728 | + else if (val & SH_MOBILE_SDHI_SCC_RVSREQ_REQTAPUP) |
---|
| 729 | + new_tap++; |
---|
| 730 | + else if (val & SH_MOBILE_SDHI_SCC_RVSREQ_REQTAPDOWN) |
---|
| 731 | + new_tap--; |
---|
| 732 | + else |
---|
| 733 | + return false; |
---|
| 734 | + } |
---|
| 735 | + |
---|
| 736 | + priv->tap_set = (new_tap % priv->tap_num); |
---|
| 737 | + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TAPSET, |
---|
| 738 | + priv->tap_set / (use_4tap ? 2 : 1)); |
---|
| 739 | + |
---|
| 740 | + return false; |
---|
| 741 | +} |
---|
| 742 | + |
---|
| 743 | +static bool renesas_sdhi_auto_correction(struct tmio_mmc_host *host) |
---|
444 | 744 | { |
---|
445 | 745 | struct renesas_sdhi *priv = host_to_priv(host); |
---|
446 | 746 | |
---|
447 | 747 | /* Check SCC error */ |
---|
448 | | - if (sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL) & |
---|
449 | | - SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN && |
---|
450 | | - sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ) & |
---|
| 748 | + if (sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ) & |
---|
451 | 749 | SH_MOBILE_SDHI_SCC_RVSREQ_RVSERR) { |
---|
452 | | - /* Clear SCC error */ |
---|
453 | 750 | sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ, 0); |
---|
454 | 751 | return true; |
---|
455 | 752 | } |
---|
.. | .. |
---|
457 | 754 | return false; |
---|
458 | 755 | } |
---|
459 | 756 | |
---|
460 | | -static void renesas_sdhi_hw_reset(struct tmio_mmc_host *host) |
---|
| 757 | +static bool renesas_sdhi_check_scc_error(struct tmio_mmc_host *host) |
---|
461 | 758 | { |
---|
462 | | - struct renesas_sdhi *priv; |
---|
| 759 | + struct renesas_sdhi *priv = host_to_priv(host); |
---|
| 760 | + bool use_4tap = priv->quirks && priv->quirks->hs400_4taps; |
---|
463 | 761 | |
---|
464 | | - priv = host_to_priv(host); |
---|
| 762 | + /* |
---|
| 763 | + * Skip checking SCC errors when running on 4 taps in HS400 mode as |
---|
| 764 | + * any retuning would still result in the same 4 taps being used. |
---|
| 765 | + */ |
---|
| 766 | + if (!(host->mmc->ios.timing == MMC_TIMING_UHS_SDR104) && |
---|
| 767 | + !(host->mmc->ios.timing == MMC_TIMING_MMC_HS200) && |
---|
| 768 | + !(host->mmc->ios.timing == MMC_TIMING_MMC_HS400 && !use_4tap)) |
---|
| 769 | + return false; |
---|
465 | 770 | |
---|
466 | | - renesas_sdhi_reset_scc(host, priv); |
---|
467 | | - renesas_sdhi_reset_hs400_mode(host, priv); |
---|
| 771 | + if (mmc_doing_tune(host->mmc)) |
---|
| 772 | + return false; |
---|
468 | 773 | |
---|
469 | | - sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN | |
---|
470 | | - sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); |
---|
| 774 | + if (sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL) & |
---|
| 775 | + SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN) |
---|
| 776 | + return renesas_sdhi_auto_correction(host); |
---|
471 | 777 | |
---|
472 | | - sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL, |
---|
473 | | - ~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN & |
---|
474 | | - sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL)); |
---|
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)); |
---|
| 778 | + return renesas_sdhi_manual_correction(host, use_4tap); |
---|
479 | 779 | } |
---|
480 | 780 | |
---|
481 | 781 | static int renesas_sdhi_wait_idle(struct tmio_mmc_host *host, u32 bit) |
---|
.. | .. |
---|
511 | 811 | case HOST_MODE: |
---|
512 | 812 | if (host->pdata->flags & TMIO_MMC_HAVE_CBSY) |
---|
513 | 813 | bit = TMIO_STAT_CMD_BUSY; |
---|
514 | | - /* fallthrough */ |
---|
| 814 | + fallthrough; |
---|
515 | 815 | case CTL_SD_CARD_CLK_CTL: |
---|
516 | 816 | return renesas_sdhi_wait_idle(host, bit); |
---|
517 | 817 | } |
---|
.. | .. |
---|
537 | 837 | return blk_size; |
---|
538 | 838 | } |
---|
539 | 839 | |
---|
| 840 | +static void renesas_sdhi_fixup_request(struct tmio_mmc_host *host, struct mmc_request *mrq) |
---|
| 841 | +{ |
---|
| 842 | + struct renesas_sdhi *priv = host_to_priv(host); |
---|
| 843 | + |
---|
| 844 | + if (priv->needs_adjust_hs400 && mrq->cmd->opcode == MMC_SEND_STATUS) |
---|
| 845 | + renesas_sdhi_adjust_hs400_mode_enable(host); |
---|
| 846 | +} |
---|
540 | 847 | static void renesas_sdhi_enable_dma(struct tmio_mmc_host *host, bool enable) |
---|
541 | 848 | { |
---|
542 | 849 | /* Iff regs are 8 byte apart, sdbuf is 64 bit. Otherwise always 32. */ |
---|
.. | .. |
---|
546 | 853 | renesas_sdhi_sdbuf_width(host, enable ? width : 16); |
---|
547 | 854 | } |
---|
548 | 855 | |
---|
| 856 | +static const struct renesas_sdhi_quirks sdhi_quirks_4tap_nohs400 = { |
---|
| 857 | + .hs400_disabled = true, |
---|
| 858 | + .hs400_4taps = true, |
---|
| 859 | +}; |
---|
| 860 | + |
---|
| 861 | +static const struct renesas_sdhi_quirks sdhi_quirks_4tap = { |
---|
| 862 | + .hs400_4taps = true, |
---|
| 863 | + .hs400_bad_taps = BIT(2) | BIT(3) | BIT(6) | BIT(7), |
---|
| 864 | +}; |
---|
| 865 | + |
---|
| 866 | +static const struct renesas_sdhi_quirks sdhi_quirks_nohs400 = { |
---|
| 867 | + .hs400_disabled = true, |
---|
| 868 | +}; |
---|
| 869 | + |
---|
| 870 | +static const struct renesas_sdhi_quirks sdhi_quirks_bad_taps1357 = { |
---|
| 871 | + .hs400_bad_taps = BIT(1) | BIT(3) | BIT(5) | BIT(7), |
---|
| 872 | +}; |
---|
| 873 | + |
---|
| 874 | +static const struct renesas_sdhi_quirks sdhi_quirks_bad_taps2367 = { |
---|
| 875 | + .hs400_bad_taps = BIT(2) | BIT(3) | BIT(6) | BIT(7), |
---|
| 876 | +}; |
---|
| 877 | + |
---|
| 878 | +static const struct renesas_sdhi_quirks sdhi_quirks_r8a7796_es13 = { |
---|
| 879 | + .hs400_4taps = true, |
---|
| 880 | + .hs400_bad_taps = BIT(2) | BIT(3) | BIT(6) | BIT(7), |
---|
| 881 | + .hs400_calib_table = r8a7796_es13_calib_table, |
---|
| 882 | +}; |
---|
| 883 | + |
---|
| 884 | +static const struct renesas_sdhi_quirks sdhi_quirks_r8a77965 = { |
---|
| 885 | + .hs400_bad_taps = BIT(2) | BIT(3) | BIT(6) | BIT(7), |
---|
| 886 | + .hs400_calib_table = r8a77965_calib_table, |
---|
| 887 | +}; |
---|
| 888 | + |
---|
| 889 | +static const struct renesas_sdhi_quirks sdhi_quirks_r8a77990 = { |
---|
| 890 | + .hs400_calib_table = r8a77990_calib_table, |
---|
| 891 | +}; |
---|
| 892 | + |
---|
| 893 | +/* |
---|
| 894 | + * Note for r8a7796 / r8a774a1: we can't distinguish ES1.1 and 1.2 as of now. |
---|
| 895 | + * So, we want to treat them equally and only have a match for ES1.2 to enforce |
---|
| 896 | + * this if there ever will be a way to distinguish ES1.2. |
---|
| 897 | + */ |
---|
| 898 | +static const struct soc_device_attribute sdhi_quirks_match[] = { |
---|
| 899 | + { .soc_id = "r8a774a1", .revision = "ES1.[012]", .data = &sdhi_quirks_4tap_nohs400 }, |
---|
| 900 | + { .soc_id = "r8a7795", .revision = "ES1.*", .data = &sdhi_quirks_4tap_nohs400 }, |
---|
| 901 | + { .soc_id = "r8a7795", .revision = "ES2.0", .data = &sdhi_quirks_4tap }, |
---|
| 902 | + { .soc_id = "r8a7795", .revision = "ES3.*", .data = &sdhi_quirks_bad_taps2367 }, |
---|
| 903 | + { .soc_id = "r8a7796", .revision = "ES1.[012]", .data = &sdhi_quirks_4tap_nohs400 }, |
---|
| 904 | + { .soc_id = "r8a7796", .revision = "ES1.*", .data = &sdhi_quirks_r8a7796_es13 }, |
---|
| 905 | + { .soc_id = "r8a77961", .data = &sdhi_quirks_bad_taps1357 }, |
---|
| 906 | + { .soc_id = "r8a77965", .data = &sdhi_quirks_r8a77965 }, |
---|
| 907 | + { .soc_id = "r8a77980", .data = &sdhi_quirks_nohs400 }, |
---|
| 908 | + { .soc_id = "r8a77990", .data = &sdhi_quirks_r8a77990 }, |
---|
| 909 | + { /* Sentinel. */ }, |
---|
| 910 | +}; |
---|
| 911 | + |
---|
549 | 912 | int renesas_sdhi_probe(struct platform_device *pdev, |
---|
550 | 913 | const struct tmio_mmc_dma_ops *dma_ops) |
---|
551 | 914 | { |
---|
552 | 915 | struct tmio_mmc_data *mmd = pdev->dev.platform_data; |
---|
| 916 | + const struct renesas_sdhi_quirks *quirks = NULL; |
---|
553 | 917 | const struct renesas_sdhi_of_data *of_data; |
---|
| 918 | + const struct soc_device_attribute *attr; |
---|
554 | 919 | struct tmio_mmc_data *mmc_data; |
---|
555 | 920 | struct tmio_mmc_dma *dma_priv; |
---|
556 | 921 | struct tmio_mmc_host *host; |
---|
557 | 922 | struct renesas_sdhi *priv; |
---|
| 923 | + int num_irqs, irq, ret, i; |
---|
558 | 924 | struct resource *res; |
---|
559 | | - int irq, ret, i; |
---|
560 | 925 | u16 ver; |
---|
561 | 926 | |
---|
562 | 927 | of_data = of_device_get_match_data(&pdev->dev); |
---|
| 928 | + |
---|
| 929 | + attr = soc_device_match(sdhi_quirks_match); |
---|
| 930 | + if (attr) |
---|
| 931 | + quirks = attr->data; |
---|
563 | 932 | |
---|
564 | 933 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
---|
565 | 934 | if (!res) |
---|
.. | .. |
---|
570 | 939 | if (!priv) |
---|
571 | 940 | return -ENOMEM; |
---|
572 | 941 | |
---|
| 942 | + priv->quirks = quirks; |
---|
573 | 943 | mmc_data = &priv->mmc_data; |
---|
574 | 944 | dma_priv = &priv->dma_priv; |
---|
575 | 945 | |
---|
.. | .. |
---|
621 | 991 | |
---|
622 | 992 | host->write16_hook = renesas_sdhi_write16_hook; |
---|
623 | 993 | host->clk_enable = renesas_sdhi_clk_enable; |
---|
624 | | - host->clk_update = renesas_sdhi_clk_update; |
---|
625 | 994 | host->clk_disable = renesas_sdhi_clk_disable; |
---|
| 995 | + host->set_clock = renesas_sdhi_set_clock; |
---|
626 | 996 | host->multi_io_quirk = renesas_sdhi_multi_io_quirk; |
---|
627 | 997 | host->dma_ops = dma_ops; |
---|
| 998 | + |
---|
| 999 | + if (quirks && quirks->hs400_disabled) |
---|
| 1000 | + host->mmc->caps2 &= ~(MMC_CAP2_HS400 | MMC_CAP2_HS400_ES); |
---|
628 | 1001 | |
---|
629 | 1002 | /* For some SoC, we disable internal WP. GPIO may override this */ |
---|
630 | 1003 | if (mmc_can_gpio_ro(host->mmc)) |
---|
.. | .. |
---|
636 | 1009 | host->ops.card_busy = renesas_sdhi_card_busy; |
---|
637 | 1010 | host->ops.start_signal_voltage_switch = |
---|
638 | 1011 | renesas_sdhi_start_signal_voltage_switch; |
---|
| 1012 | + host->sdcard_irq_setbit_mask = TMIO_STAT_ALWAYS_SET_27; |
---|
639 | 1013 | |
---|
640 | | - /* SDR and HS200/400 registers requires HW reset */ |
---|
641 | 1014 | if (of_data && of_data->scc_offset) { |
---|
642 | 1015 | priv->scc_ctl = host->ctl + of_data->scc_offset; |
---|
643 | | - host->mmc->caps |= MMC_CAP_HW_RESET; |
---|
644 | | - host->hw_reset = renesas_sdhi_hw_reset; |
---|
| 1016 | + host->reset = renesas_sdhi_reset; |
---|
645 | 1017 | } |
---|
646 | 1018 | } |
---|
647 | 1019 | |
---|
.. | .. |
---|
675 | 1047 | /* All SDHI have SDIO status bits which must be 1 */ |
---|
676 | 1048 | mmc_data->flags |= TMIO_MMC_SDIO_STATUS_SETBITS; |
---|
677 | 1049 | |
---|
| 1050 | + dev_pm_domain_start(&pdev->dev); |
---|
| 1051 | + |
---|
678 | 1052 | ret = renesas_sdhi_clk_enable(host); |
---|
679 | 1053 | if (ret) |
---|
680 | 1054 | goto efree; |
---|
.. | .. |
---|
684 | 1058 | if (ver < SDHI_VER_GEN2_SDR104 && mmc_data->max_blk_count > U16_MAX) |
---|
685 | 1059 | mmc_data->max_blk_count = U16_MAX; |
---|
686 | 1060 | |
---|
687 | | - ret = tmio_mmc_host_probe(host); |
---|
688 | | - if (ret < 0) |
---|
689 | | - goto edisclk; |
---|
690 | | - |
---|
691 | 1061 | /* One Gen2 SDHI incarnation does NOT have a CBSY bit */ |
---|
692 | 1062 | if (ver == SDHI_VER_GEN2_SDR50) |
---|
693 | 1063 | mmc_data->flags &= ~TMIO_MMC_HAVE_CBSY; |
---|
| 1064 | + |
---|
| 1065 | + if (ver == SDHI_VER_GEN3_SDMMC && quirks && quirks->hs400_calib_table) { |
---|
| 1066 | + host->fixup_request = renesas_sdhi_fixup_request; |
---|
| 1067 | + priv->adjust_hs400_calib_table = *( |
---|
| 1068 | + res->start == SDHI_GEN3_MMC0_ADDR ? |
---|
| 1069 | + quirks->hs400_calib_table : |
---|
| 1070 | + quirks->hs400_calib_table + 1); |
---|
| 1071 | + } |
---|
| 1072 | + |
---|
| 1073 | + ret = tmio_mmc_host_probe(host); |
---|
| 1074 | + if (ret < 0) |
---|
| 1075 | + goto edisclk; |
---|
694 | 1076 | |
---|
695 | 1077 | /* Enable tuning iff we have an SCC and a supported mode */ |
---|
696 | 1078 | if (of_data && of_data->scc_offset && |
---|
.. | .. |
---|
698 | 1080 | host->mmc->caps2 & (MMC_CAP2_HS200_1_8V_SDR | |
---|
699 | 1081 | MMC_CAP2_HS400_1_8V))) { |
---|
700 | 1082 | const struct renesas_sdhi_scc *taps = of_data->taps; |
---|
| 1083 | + bool use_4tap = priv->quirks && priv->quirks->hs400_4taps; |
---|
701 | 1084 | bool hit = false; |
---|
702 | 1085 | |
---|
703 | 1086 | for (i = 0; i < of_data->taps_num; i++) { |
---|
704 | 1087 | if (taps[i].clk_rate == 0 || |
---|
705 | 1088 | taps[i].clk_rate == host->mmc->f_max) { |
---|
706 | 1089 | priv->scc_tappos = taps->tap; |
---|
| 1090 | + priv->scc_tappos_hs400 = use_4tap ? |
---|
| 1091 | + taps->tap_hs400_4tap : |
---|
| 1092 | + taps->tap; |
---|
707 | 1093 | hit = true; |
---|
708 | 1094 | break; |
---|
709 | 1095 | } |
---|
710 | 1096 | } |
---|
711 | 1097 | |
---|
712 | 1098 | if (!hit) |
---|
713 | | - dev_warn(&host->pdev->dev, "Unknown clock rate for SDR104\n"); |
---|
| 1099 | + dev_warn(&host->pdev->dev, "Unknown clock rate for tuning\n"); |
---|
714 | 1100 | |
---|
715 | | - host->init_tuning = renesas_sdhi_init_tuning; |
---|
716 | | - host->prepare_tuning = renesas_sdhi_prepare_tuning; |
---|
717 | | - host->select_tuning = renesas_sdhi_select_tuning; |
---|
718 | | - host->check_scc_error = renesas_sdhi_check_scc_error; |
---|
719 | | - host->prepare_hs400_tuning = |
---|
720 | | - renesas_sdhi_prepare_hs400_tuning; |
---|
721 | | - host->hs400_downgrade = renesas_sdhi_disable_scc; |
---|
722 | | - host->hs400_complete = renesas_sdhi_hs400_complete; |
---|
| 1101 | + host->check_retune = renesas_sdhi_check_scc_error; |
---|
| 1102 | + host->ops.execute_tuning = renesas_sdhi_execute_tuning; |
---|
| 1103 | + host->ops.prepare_hs400_tuning = renesas_sdhi_prepare_hs400_tuning; |
---|
| 1104 | + host->ops.hs400_downgrade = renesas_sdhi_disable_scc; |
---|
| 1105 | + host->ops.hs400_complete = renesas_sdhi_hs400_complete; |
---|
723 | 1106 | } |
---|
724 | 1107 | |
---|
725 | | - i = 0; |
---|
726 | | - while (1) { |
---|
| 1108 | + num_irqs = platform_irq_count(pdev); |
---|
| 1109 | + if (num_irqs < 0) { |
---|
| 1110 | + ret = num_irqs; |
---|
| 1111 | + goto eirq; |
---|
| 1112 | + } |
---|
| 1113 | + |
---|
| 1114 | + /* There must be at least one IRQ source */ |
---|
| 1115 | + if (!num_irqs) { |
---|
| 1116 | + ret = -ENXIO; |
---|
| 1117 | + goto eirq; |
---|
| 1118 | + } |
---|
| 1119 | + |
---|
| 1120 | + for (i = 0; i < num_irqs; i++) { |
---|
727 | 1121 | irq = platform_get_irq(pdev, i); |
---|
728 | | - if (irq < 0) |
---|
729 | | - break; |
---|
730 | | - i++; |
---|
| 1122 | + if (irq < 0) { |
---|
| 1123 | + ret = irq; |
---|
| 1124 | + goto eirq; |
---|
| 1125 | + } |
---|
| 1126 | + |
---|
731 | 1127 | ret = devm_request_irq(&pdev->dev, irq, tmio_mmc_irq, 0, |
---|
732 | 1128 | dev_name(&pdev->dev), host); |
---|
733 | 1129 | if (ret) |
---|
734 | 1130 | goto eirq; |
---|
735 | 1131 | } |
---|
736 | 1132 | |
---|
737 | | - /* There must be at least one IRQ source */ |
---|
738 | | - if (!i) { |
---|
739 | | - ret = irq; |
---|
740 | | - goto eirq; |
---|
741 | | - } |
---|
742 | | - |
---|
743 | | - dev_info(&pdev->dev, "%s base at 0x%08lx max clock rate %u MHz\n", |
---|
744 | | - mmc_hostname(host->mmc), (unsigned long) |
---|
745 | | - (platform_get_resource(pdev, IORESOURCE_MEM, 0)->start), |
---|
746 | | - host->mmc->f_max / 1000000); |
---|
| 1133 | + dev_info(&pdev->dev, "%s base at %pa, max clock rate %u MHz\n", |
---|
| 1134 | + mmc_hostname(host->mmc), &res->start, host->mmc->f_max / 1000000); |
---|
747 | 1135 | |
---|
748 | 1136 | return ret; |
---|
749 | 1137 | |
---|