Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mmc: sh_mobile_sdhi: Add tuning support

Add tuning support for use with SDR104 mode
This includes adding support for the sampling clock controller (SCC).

Based on work by Ai Kyuse.

Cc: Ai Kyuse <ai.kyuse.uw@renesas.com>
Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
Acked-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Tested-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

authored by

Simon Horman and committed by
Ulf Hansson
06f438dd 4f119977

+264 -1
+264 -1
drivers/mmc/host/sh_mobile_sdhi.c
··· 47 47 48 48 #define host_to_priv(host) container_of((host)->pdata, struct sh_mobile_sdhi, mmc_data) 49 49 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 + 50 55 struct sh_mobile_sdhi_of_data { 51 56 unsigned long tmio_flags; 52 57 u32 tmio_ocr_mask; ··· 60 55 enum dma_slave_buswidth dma_buswidth; 61 56 dma_addr_t dma_rx_offset; 62 57 unsigned bus_shift; 58 + int scc_offset; 59 + struct sh_mobile_sdhi_scc *taps; 60 + int taps_num; 63 61 }; 64 62 65 63 static const struct sh_mobile_sdhi_of_data of_default_cfg = { ··· 81 73 .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ, 82 74 }; 83 75 76 + /* Definitions for sampling clocks */ 77 + static struct sh_mobile_sdhi_scc rcar_gen2_scc_taps[] = { 78 + { 79 + .clk_rate = 156000000, 80 + .tap = 0x00000703, 81 + }, 82 + { 83 + .clk_rate = 0, 84 + .tap = 0x00000300, 85 + }, 86 + }; 87 + 84 88 static const struct sh_mobile_sdhi_of_data of_rcar_gen2_compatible = { 85 89 .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE | 86 90 TMIO_MMC_CLK_ACTUAL | TMIO_MMC_MIN_RCAR2, 87 91 .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ, 88 92 .dma_buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES, 89 93 .dma_rx_offset = 0x2000, 94 + .scc_offset = 0x0300, 95 + .taps = rcar_gen2_scc_taps, 96 + .taps_num = ARRAY_SIZE(rcar_gen2_scc_taps), 97 + }; 98 + 99 + /* Definitions for sampling clocks */ 100 + static struct sh_mobile_sdhi_scc rcar_gen3_scc_taps[] = { 101 + { 102 + .clk_rate = 0, 103 + .tap = 0x00000300, 104 + }, 90 105 }; 91 106 92 107 static const struct sh_mobile_sdhi_of_data of_rcar_gen3_compatible = { ··· 117 86 TMIO_MMC_CLK_ACTUAL | TMIO_MMC_MIN_RCAR2, 118 87 .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ, 119 88 .bus_shift = 2, 89 + .scc_offset = 0x1000, 90 + .taps = rcar_gen3_scc_taps, 91 + .taps_num = ARRAY_SIZE(rcar_gen3_scc_taps), 120 92 }; 121 93 122 94 static const struct of_device_id sh_mobile_sdhi_of_match[] = { ··· 147 113 struct tmio_mmc_dma dma_priv; 148 114 struct pinctrl *pinctrl; 149 115 struct pinctrl_state *pins_default, *pins_uhs; 116 + void __iomem *scc_ctl; 150 117 }; 151 118 152 119 static void sh_mobile_sdhi_sdbuf_width(struct tmio_mmc_host *host, int width) ··· 298 263 return pinctrl_select_state(priv->pinctrl, pin_state); 299 264 } 300 265 266 + /* SCC registers */ 267 + #define SH_MOBILE_SDHI_SCC_DTCNTL 0x000 268 + #define SH_MOBILE_SDHI_SCC_TAPSET 0x002 269 + #define SH_MOBILE_SDHI_SCC_DT2FF 0x004 270 + #define SH_MOBILE_SDHI_SCC_CKSEL 0x006 271 + #define SH_MOBILE_SDHI_SCC_RVSCNTL 0x008 272 + #define SH_MOBILE_SDHI_SCC_RVSREQ 0x00A 273 + 274 + /* Definitions for values the SH_MOBILE_SDHI_SCC_DTCNTL register */ 275 + #define SH_MOBILE_SDHI_SCC_DTCNTL_TAPEN BIT(0) 276 + #define SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_SHIFT 16 277 + #define SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_MASK 0xff 278 + 279 + /* Definitions for values the SH_MOBILE_SDHI_SCC_CKSEL register */ 280 + #define SH_MOBILE_SDHI_SCC_CKSEL_DTSEL BIT(0) 281 + /* Definitions for values the SH_MOBILE_SDHI_SCC_RVSCNTL register */ 282 + #define SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN BIT(0) 283 + /* Definitions for values the SH_MOBILE_SDHI_SCC_RVSREQ register */ 284 + #define SH_MOBILE_SDHI_SCC_RVSREQ_RVSERR BIT(2) 285 + 286 + static inline u32 sd_scc_read32(struct tmio_mmc_host *host, 287 + struct sh_mobile_sdhi *priv, int addr) 288 + { 289 + return readl(priv->scc_ctl + (addr << host->bus_shift)); 290 + } 291 + 292 + static inline void sd_scc_write32(struct tmio_mmc_host *host, 293 + struct sh_mobile_sdhi *priv, 294 + int addr, u32 val) 295 + { 296 + writel(val, priv->scc_ctl + (addr << host->bus_shift)); 297 + } 298 + 299 + static unsigned int sh_mobile_sdhi_init_tuning(struct tmio_mmc_host *host) 300 + { 301 + struct sh_mobile_sdhi *priv; 302 + 303 + if (!(host->mmc->caps & MMC_CAP_UHS_SDR104)) 304 + return 0; 305 + 306 + priv = host_to_priv(host); 307 + 308 + /* set sampling clock selection range */ 309 + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DTCNTL, 310 + 0x8 << SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_SHIFT); 311 + 312 + /* Initialize SCC */ 313 + sd_ctrl_write32_as_16_and_16(host, CTL_STATUS, 0x0); 314 + 315 + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DTCNTL, 316 + SH_MOBILE_SDHI_SCC_DTCNTL_TAPEN | 317 + sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_DTCNTL)); 318 + 319 + sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN & 320 + sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); 321 + 322 + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_CKSEL, 323 + SH_MOBILE_SDHI_SCC_CKSEL_DTSEL | 324 + sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_CKSEL)); 325 + 326 + sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN | 327 + sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); 328 + 329 + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL, 330 + ~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN & 331 + sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL)); 332 + 333 + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DT2FF, host->scc_tappos); 334 + 335 + /* Read TAPNUM */ 336 + return (sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_DTCNTL) >> 337 + SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_SHIFT) & 338 + SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_MASK; 339 + } 340 + 341 + static void sh_mobile_sdhi_prepare_tuning(struct tmio_mmc_host *host, 342 + unsigned long tap) 343 + { 344 + struct sh_mobile_sdhi *priv = host_to_priv(host); 345 + 346 + /* Set sampling clock position */ 347 + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TAPSET, tap); 348 + } 349 + 350 + #define SH_MOBILE_SDHI_MAX_TAP 3 351 + 352 + static int sh_mobile_sdhi_select_tuning(struct tmio_mmc_host *host) 353 + { 354 + struct sh_mobile_sdhi *priv = host_to_priv(host); 355 + unsigned long tap_cnt; /* counter of tuning success */ 356 + unsigned long tap_set; /* tap position */ 357 + unsigned long tap_start;/* start position of tuning success */ 358 + unsigned long tap_end; /* end position of tuning success */ 359 + unsigned long ntap; /* temporary counter of tuning success */ 360 + unsigned long i; 361 + 362 + /* Clear SCC_RVSREQ */ 363 + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ, 0); 364 + 365 + /* 366 + * Find the longest consecutive run of successful probes. If that 367 + * is more than SH_MOBILE_SDHI_MAX_TAP probes long then use the 368 + * center index as the tap. 369 + */ 370 + tap_cnt = 0; 371 + ntap = 0; 372 + tap_start = 0; 373 + tap_end = 0; 374 + for (i = 0; i < host->tap_num * 2; i++) { 375 + if (test_bit(i, host->taps)) 376 + ntap++; 377 + else { 378 + if (ntap > tap_cnt) { 379 + tap_start = i - ntap; 380 + tap_end = i - 1; 381 + tap_cnt = ntap; 382 + } 383 + ntap = 0; 384 + } 385 + } 386 + 387 + if (ntap > tap_cnt) { 388 + tap_start = i - ntap; 389 + tap_end = i - 1; 390 + tap_cnt = ntap; 391 + } 392 + 393 + if (tap_cnt >= SH_MOBILE_SDHI_MAX_TAP) 394 + tap_set = (tap_start + tap_end) / 2 % host->tap_num; 395 + else 396 + return -EIO; 397 + 398 + /* Set SCC */ 399 + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TAPSET, tap_set); 400 + 401 + /* Enable auto re-tuning */ 402 + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL, 403 + SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN | 404 + sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL)); 405 + 406 + return 0; 407 + } 408 + 409 + 410 + static bool sh_mobile_sdhi_check_scc_error(struct tmio_mmc_host *host) 411 + { 412 + struct sh_mobile_sdhi *priv; 413 + 414 + if (!(host->mmc->caps & MMC_CAP_UHS_SDR104)) 415 + return 0; 416 + 417 + priv = host_to_priv(host); 418 + 419 + /* Check SCC error */ 420 + if (sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL) & 421 + SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN && 422 + sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ) & 423 + SH_MOBILE_SDHI_SCC_RVSREQ_RVSERR) { 424 + /* Clear SCC error */ 425 + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ, 0); 426 + return true; 427 + } 428 + 429 + return false; 430 + } 431 + 432 + static void sh_mobile_sdhi_hw_reset(struct tmio_mmc_host *host) 433 + { 434 + struct sh_mobile_sdhi *priv; 435 + 436 + if (!(host->mmc->caps & MMC_CAP_UHS_SDR104)) 437 + return; 438 + 439 + priv = host_to_priv(host); 440 + 441 + /* Reset SCC */ 442 + sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN & 443 + sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); 444 + 445 + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_CKSEL, 446 + ~SH_MOBILE_SDHI_SCC_CKSEL_DTSEL & 447 + sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_CKSEL)); 448 + 449 + sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN | 450 + sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); 451 + 452 + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL, 453 + ~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN & 454 + sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL)); 455 + 456 + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL, 457 + ~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN & 458 + sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL)); 459 + } 460 + 301 461 static int sh_mobile_sdhi_wait_idle(struct tmio_mmc_host *host) 302 462 { 303 463 int timeout = 1000; ··· 563 333 struct tmio_mmc_data *mmd = pdev->dev.platform_data; 564 334 struct tmio_mmc_host *host; 565 335 struct resource *res; 566 - int irq, ret, i = 0; 336 + int irq, ret, i; 567 337 struct tmio_mmc_dma *dma_priv; 568 338 569 339 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ··· 623 393 host->card_busy = sh_mobile_sdhi_card_busy; 624 394 host->start_signal_voltage_switch = 625 395 sh_mobile_sdhi_start_signal_voltage_switch; 396 + host->init_tuning = sh_mobile_sdhi_init_tuning; 397 + host->prepare_tuning = sh_mobile_sdhi_prepare_tuning; 398 + host->select_tuning = sh_mobile_sdhi_select_tuning; 399 + host->check_scc_error = sh_mobile_sdhi_check_scc_error; 400 + host->hw_reset = sh_mobile_sdhi_hw_reset; 626 401 } 627 402 628 403 /* Orginally registers were 16 bit apart, could be 32 or 64 nowadays */ ··· 668 433 if (ret < 0) 669 434 goto efree; 670 435 436 + if (host->mmc->caps & MMC_CAP_UHS_SDR104) { 437 + host->mmc->caps |= MMC_CAP_HW_RESET; 438 + 439 + if (of_id && of_id->data) { 440 + const struct sh_mobile_sdhi_of_data *of_data; 441 + const struct sh_mobile_sdhi_scc *taps; 442 + bool hit = false; 443 + 444 + of_data = of_id->data; 445 + taps = of_data->taps; 446 + 447 + for (i = 0; i < of_data->taps_num; i++) { 448 + if (taps[i].clk_rate == 0 || 449 + taps[i].clk_rate == host->mmc->f_max) { 450 + host->scc_tappos = taps->tap; 451 + hit = true; 452 + break; 453 + } 454 + } 455 + 456 + if (!hit) 457 + dev_warn(&host->pdev->dev, "Unknown clock rate for SDR104\n"); 458 + 459 + priv->scc_ctl = host->ctl + of_data->scc_offset; 460 + } 461 + } 462 + 463 + i = 0; 671 464 while (1) { 672 465 irq = platform_get_irq(pdev, i); 673 466 if (irq < 0)