.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * Freescale eSDHC controller driver. |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (c) 2007, 2010, 2012 Freescale Semiconductor, Inc. |
---|
5 | 6 | * Copyright (c) 2009 MontaVista Software, Inc. |
---|
| 7 | + * Copyright 2020 NXP |
---|
6 | 8 | * |
---|
7 | 9 | * Authors: Xiaobo Xie <X.Xie@freescale.com> |
---|
8 | 10 | * Anton Vorontsov <avorontsov@ru.mvista.com> |
---|
9 | | - * |
---|
10 | | - * This program is free software; you can redistribute it and/or modify |
---|
11 | | - * it under the terms of the GNU General Public License as published by |
---|
12 | | - * the Free Software Foundation; either version 2 of the License, or (at |
---|
13 | | - * your option) any later version. |
---|
14 | 11 | */ |
---|
15 | 12 | |
---|
16 | 13 | #include <linux/err.h> |
---|
.. | .. |
---|
23 | 20 | #include <linux/clk.h> |
---|
24 | 21 | #include <linux/ktime.h> |
---|
25 | 22 | #include <linux/dma-mapping.h> |
---|
| 23 | +#include <linux/iopoll.h> |
---|
26 | 24 | #include <linux/mmc/host.h> |
---|
| 25 | +#include <linux/mmc/mmc.h> |
---|
27 | 26 | #include "sdhci-pltfm.h" |
---|
28 | 27 | #include "sdhci-esdhc.h" |
---|
29 | 28 | |
---|
.. | .. |
---|
78 | 77 | u8 vendor_ver; |
---|
79 | 78 | u8 spec_ver; |
---|
80 | 79 | bool quirk_incorrect_hostver; |
---|
| 80 | + bool quirk_limited_clk_division; |
---|
| 81 | + bool quirk_unreliable_pulse_detection; |
---|
| 82 | + bool quirk_tuning_erratum_type1; |
---|
| 83 | + bool quirk_tuning_erratum_type2; |
---|
| 84 | + bool quirk_ignore_data_inhibit; |
---|
| 85 | + bool quirk_delay_before_data_reset; |
---|
| 86 | + bool quirk_trans_complete_erratum; |
---|
| 87 | + bool in_sw_tuning; |
---|
81 | 88 | unsigned int peripheral_clock; |
---|
82 | 89 | const struct esdhc_clk_fixup *clk_fixup; |
---|
| 90 | + u32 div_ratio; |
---|
83 | 91 | }; |
---|
84 | 92 | |
---|
85 | 93 | /** |
---|
.. | .. |
---|
143 | 151 | return ret; |
---|
144 | 152 | } |
---|
145 | 153 | |
---|
| 154 | + /* |
---|
| 155 | + * Some controllers have unreliable Data Line Active |
---|
| 156 | + * bit for commands with busy signal. This affects |
---|
| 157 | + * Command Inhibit (data) bit. Just ignore it since |
---|
| 158 | + * MMC core driver has already polled card status |
---|
| 159 | + * with CMD13 after any command with busy siganl. |
---|
| 160 | + */ |
---|
| 161 | + if ((spec_reg == SDHCI_PRESENT_STATE) && |
---|
| 162 | + (esdhc->quirk_ignore_data_inhibit == true)) { |
---|
| 163 | + ret = value & ~SDHCI_DATA_INHIBIT; |
---|
| 164 | + return ret; |
---|
| 165 | + } |
---|
| 166 | + |
---|
146 | 167 | ret = value; |
---|
147 | 168 | return ret; |
---|
148 | 169 | } |
---|
.. | .. |
---|
154 | 175 | struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); |
---|
155 | 176 | u16 ret; |
---|
156 | 177 | int shift = (spec_reg & 0x2) * 8; |
---|
| 178 | + |
---|
| 179 | + if (spec_reg == SDHCI_TRANSFER_MODE) |
---|
| 180 | + return pltfm_host->xfer_mode_shadow; |
---|
157 | 181 | |
---|
158 | 182 | if (spec_reg == SDHCI_HOST_VERSION) |
---|
159 | 183 | ret = value & 0xffff; |
---|
.. | .. |
---|
393 | 417 | |
---|
394 | 418 | static void esdhc_be_writew(struct sdhci_host *host, u16 val, int reg) |
---|
395 | 419 | { |
---|
| 420 | + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
---|
| 421 | + struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); |
---|
396 | 422 | int base = reg & ~0x3; |
---|
397 | 423 | u32 value; |
---|
398 | 424 | u32 ret; |
---|
.. | .. |
---|
401 | 427 | ret = esdhc_writew_fixup(host, reg, val, value); |
---|
402 | 428 | if (reg != SDHCI_TRANSFER_MODE) |
---|
403 | 429 | iowrite32be(ret, host->ioaddr + base); |
---|
| 430 | + |
---|
| 431 | + /* Starting SW tuning requires ESDHC_SMPCLKSEL to be set |
---|
| 432 | + * 1us later after ESDHC_EXTN is set. |
---|
| 433 | + */ |
---|
| 434 | + if (base == ESDHC_SYSTEM_CONTROL_2) { |
---|
| 435 | + if (!(value & ESDHC_EXTN) && (ret & ESDHC_EXTN) && |
---|
| 436 | + esdhc->in_sw_tuning) { |
---|
| 437 | + udelay(1); |
---|
| 438 | + ret |= ESDHC_SMPCLKSEL; |
---|
| 439 | + iowrite32be(ret, host->ioaddr + base); |
---|
| 440 | + } |
---|
| 441 | + } |
---|
404 | 442 | } |
---|
405 | 443 | |
---|
406 | 444 | static void esdhc_le_writew(struct sdhci_host *host, u16 val, int reg) |
---|
407 | 445 | { |
---|
| 446 | + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
---|
| 447 | + struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); |
---|
408 | 448 | int base = reg & ~0x3; |
---|
409 | 449 | u32 value; |
---|
410 | 450 | u32 ret; |
---|
.. | .. |
---|
413 | 453 | ret = esdhc_writew_fixup(host, reg, val, value); |
---|
414 | 454 | if (reg != SDHCI_TRANSFER_MODE) |
---|
415 | 455 | iowrite32(ret, host->ioaddr + base); |
---|
| 456 | + |
---|
| 457 | + /* Starting SW tuning requires ESDHC_SMPCLKSEL to be set |
---|
| 458 | + * 1us later after ESDHC_EXTN is set. |
---|
| 459 | + */ |
---|
| 460 | + if (base == ESDHC_SYSTEM_CONTROL_2) { |
---|
| 461 | + if (!(value & ESDHC_EXTN) && (ret & ESDHC_EXTN) && |
---|
| 462 | + esdhc->in_sw_tuning) { |
---|
| 463 | + udelay(1); |
---|
| 464 | + ret |= ESDHC_SMPCLKSEL; |
---|
| 465 | + iowrite32(ret, host->ioaddr + base); |
---|
| 466 | + } |
---|
| 467 | + } |
---|
416 | 468 | } |
---|
417 | 469 | |
---|
418 | 470 | static void esdhc_be_writeb(struct sdhci_host *host, u8 val, int reg) |
---|
.. | .. |
---|
520 | 572 | |
---|
521 | 573 | static void esdhc_clock_enable(struct sdhci_host *host, bool enable) |
---|
522 | 574 | { |
---|
523 | | - u32 val; |
---|
| 575 | + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
---|
| 576 | + struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); |
---|
524 | 577 | ktime_t timeout; |
---|
| 578 | + u32 val, clk_en; |
---|
| 579 | + |
---|
| 580 | + clk_en = ESDHC_CLOCK_SDCLKEN; |
---|
| 581 | + |
---|
| 582 | + /* |
---|
| 583 | + * IPGEN/HCKEN/PEREN bits exist on eSDHC whose vendor version |
---|
| 584 | + * is 2.2 or lower. |
---|
| 585 | + */ |
---|
| 586 | + if (esdhc->vendor_ver <= VENDOR_V_22) |
---|
| 587 | + clk_en |= (ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | |
---|
| 588 | + ESDHC_CLOCK_PEREN); |
---|
525 | 589 | |
---|
526 | 590 | val = sdhci_readl(host, ESDHC_SYSTEM_CONTROL); |
---|
527 | 591 | |
---|
528 | 592 | if (enable) |
---|
529 | | - val |= ESDHC_CLOCK_SDCLKEN; |
---|
| 593 | + val |= clk_en; |
---|
530 | 594 | else |
---|
531 | | - val &= ~ESDHC_CLOCK_SDCLKEN; |
---|
| 595 | + val &= ~clk_en; |
---|
532 | 596 | |
---|
533 | 597 | sdhci_writel(host, val, ESDHC_SYSTEM_CONTROL); |
---|
534 | 598 | |
---|
535 | | - /* Wait max 20 ms */ |
---|
| 599 | + /* |
---|
| 600 | + * Wait max 20 ms. If vendor version is 2.2 or lower, do not |
---|
| 601 | + * wait clock stable bit which does not exist. |
---|
| 602 | + */ |
---|
536 | 603 | timeout = ktime_add_ms(ktime_get(), 20); |
---|
537 | | - val = ESDHC_CLOCK_STABLE; |
---|
538 | | - while (1) { |
---|
539 | | - bool timedout = ktime_after(ktime_get(), timeout); |
---|
540 | | - |
---|
541 | | - if (sdhci_readl(host, ESDHC_PRSSTAT) & val) |
---|
542 | | - break; |
---|
543 | | - if (timedout) { |
---|
544 | | - pr_err("%s: Internal clock never stabilised.\n", |
---|
545 | | - mmc_hostname(host->mmc)); |
---|
546 | | - break; |
---|
547 | | - } |
---|
548 | | - udelay(10); |
---|
549 | | - } |
---|
550 | | -} |
---|
551 | | - |
---|
552 | | -static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) |
---|
553 | | -{ |
---|
554 | | - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
---|
555 | | - struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); |
---|
556 | | - int pre_div = 1; |
---|
557 | | - int div = 1; |
---|
558 | | - ktime_t timeout; |
---|
559 | | - long fixup = 0; |
---|
560 | | - u32 temp; |
---|
561 | | - |
---|
562 | | - host->mmc->actual_clock = 0; |
---|
563 | | - |
---|
564 | | - if (clock == 0) { |
---|
565 | | - esdhc_clock_enable(host, false); |
---|
566 | | - return; |
---|
567 | | - } |
---|
568 | | - |
---|
569 | | - /* Workaround to start pre_div at 2 for VNN < VENDOR_V_23 */ |
---|
570 | | - if (esdhc->vendor_ver < VENDOR_V_23) |
---|
571 | | - pre_div = 2; |
---|
572 | | - |
---|
573 | | - if (host->mmc->card && mmc_card_sd(host->mmc->card) && |
---|
574 | | - esdhc->clk_fixup && host->mmc->ios.timing == MMC_TIMING_LEGACY) |
---|
575 | | - fixup = esdhc->clk_fixup->sd_dflt_max_clk; |
---|
576 | | - else if (esdhc->clk_fixup) |
---|
577 | | - fixup = esdhc->clk_fixup->max_clk[host->mmc->ios.timing]; |
---|
578 | | - |
---|
579 | | - if (fixup && clock > fixup) |
---|
580 | | - clock = fixup; |
---|
581 | | - |
---|
582 | | - temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL); |
---|
583 | | - temp &= ~(ESDHC_CLOCK_SDCLKEN | ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | |
---|
584 | | - ESDHC_CLOCK_PEREN | ESDHC_CLOCK_MASK); |
---|
585 | | - sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); |
---|
586 | | - |
---|
587 | | - while (host->max_clk / pre_div / 16 > clock && pre_div < 256) |
---|
588 | | - pre_div *= 2; |
---|
589 | | - |
---|
590 | | - while (host->max_clk / pre_div / div > clock && div < 16) |
---|
591 | | - div++; |
---|
592 | | - |
---|
593 | | - dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n", |
---|
594 | | - clock, host->max_clk / pre_div / div); |
---|
595 | | - host->mmc->actual_clock = host->max_clk / pre_div / div; |
---|
596 | | - pre_div >>= 1; |
---|
597 | | - div--; |
---|
598 | | - |
---|
599 | | - temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL); |
---|
600 | | - temp |= (ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN |
---|
601 | | - | (div << ESDHC_DIVIDER_SHIFT) |
---|
602 | | - | (pre_div << ESDHC_PREDIV_SHIFT)); |
---|
603 | | - sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); |
---|
604 | | - |
---|
605 | | - /* Wait max 20 ms */ |
---|
606 | | - timeout = ktime_add_ms(ktime_get(), 20); |
---|
607 | | - while (1) { |
---|
| 604 | + while (esdhc->vendor_ver > VENDOR_V_22) { |
---|
608 | 605 | bool timedout = ktime_after(ktime_get(), timeout); |
---|
609 | 606 | |
---|
610 | 607 | if (sdhci_readl(host, ESDHC_PRSSTAT) & ESDHC_CLOCK_STABLE) |
---|
.. | .. |
---|
612 | 609 | if (timedout) { |
---|
613 | 610 | pr_err("%s: Internal clock never stabilised.\n", |
---|
614 | 611 | mmc_hostname(host->mmc)); |
---|
615 | | - return; |
---|
| 612 | + break; |
---|
616 | 613 | } |
---|
617 | | - udelay(10); |
---|
| 614 | + usleep_range(10, 20); |
---|
| 615 | + } |
---|
| 616 | +} |
---|
| 617 | + |
---|
| 618 | +static void esdhc_flush_async_fifo(struct sdhci_host *host) |
---|
| 619 | +{ |
---|
| 620 | + ktime_t timeout; |
---|
| 621 | + u32 val; |
---|
| 622 | + |
---|
| 623 | + val = sdhci_readl(host, ESDHC_DMA_SYSCTL); |
---|
| 624 | + val |= ESDHC_FLUSH_ASYNC_FIFO; |
---|
| 625 | + sdhci_writel(host, val, ESDHC_DMA_SYSCTL); |
---|
| 626 | + |
---|
| 627 | + /* Wait max 20 ms */ |
---|
| 628 | + timeout = ktime_add_ms(ktime_get(), 20); |
---|
| 629 | + while (1) { |
---|
| 630 | + bool timedout = ktime_after(ktime_get(), timeout); |
---|
| 631 | + |
---|
| 632 | + if (!(sdhci_readl(host, ESDHC_DMA_SYSCTL) & |
---|
| 633 | + ESDHC_FLUSH_ASYNC_FIFO)) |
---|
| 634 | + break; |
---|
| 635 | + if (timedout) { |
---|
| 636 | + pr_err("%s: flushing asynchronous FIFO timeout.\n", |
---|
| 637 | + mmc_hostname(host->mmc)); |
---|
| 638 | + break; |
---|
| 639 | + } |
---|
| 640 | + usleep_range(10, 20); |
---|
| 641 | + } |
---|
| 642 | +} |
---|
| 643 | + |
---|
| 644 | +static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) |
---|
| 645 | +{ |
---|
| 646 | + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
---|
| 647 | + struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); |
---|
| 648 | + unsigned int pre_div = 1, div = 1; |
---|
| 649 | + unsigned int clock_fixup = 0; |
---|
| 650 | + ktime_t timeout; |
---|
| 651 | + u32 temp; |
---|
| 652 | + |
---|
| 653 | + if (clock == 0) { |
---|
| 654 | + host->mmc->actual_clock = 0; |
---|
| 655 | + esdhc_clock_enable(host, false); |
---|
| 656 | + return; |
---|
618 | 657 | } |
---|
619 | 658 | |
---|
620 | | - temp |= ESDHC_CLOCK_SDCLKEN; |
---|
| 659 | + /* Start pre_div at 2 for vendor version < 2.3. */ |
---|
| 660 | + if (esdhc->vendor_ver < VENDOR_V_23) |
---|
| 661 | + pre_div = 2; |
---|
| 662 | + |
---|
| 663 | + /* Fix clock value. */ |
---|
| 664 | + if (host->mmc->card && mmc_card_sd(host->mmc->card) && |
---|
| 665 | + esdhc->clk_fixup && host->mmc->ios.timing == MMC_TIMING_LEGACY) |
---|
| 666 | + clock_fixup = esdhc->clk_fixup->sd_dflt_max_clk; |
---|
| 667 | + else if (esdhc->clk_fixup) |
---|
| 668 | + clock_fixup = esdhc->clk_fixup->max_clk[host->mmc->ios.timing]; |
---|
| 669 | + |
---|
| 670 | + if (clock_fixup == 0 || clock < clock_fixup) |
---|
| 671 | + clock_fixup = clock; |
---|
| 672 | + |
---|
| 673 | + /* Calculate pre_div and div. */ |
---|
| 674 | + while (host->max_clk / pre_div / 16 > clock_fixup && pre_div < 256) |
---|
| 675 | + pre_div *= 2; |
---|
| 676 | + |
---|
| 677 | + while (host->max_clk / pre_div / div > clock_fixup && div < 16) |
---|
| 678 | + div++; |
---|
| 679 | + |
---|
| 680 | + esdhc->div_ratio = pre_div * div; |
---|
| 681 | + |
---|
| 682 | + /* Limit clock division for HS400 200MHz clock for quirk. */ |
---|
| 683 | + if (esdhc->quirk_limited_clk_division && |
---|
| 684 | + clock == MMC_HS200_MAX_DTR && |
---|
| 685 | + (host->mmc->ios.timing == MMC_TIMING_MMC_HS400 || |
---|
| 686 | + host->flags & SDHCI_HS400_TUNING)) { |
---|
| 687 | + if (esdhc->div_ratio <= 4) { |
---|
| 688 | + pre_div = 4; |
---|
| 689 | + div = 1; |
---|
| 690 | + } else if (esdhc->div_ratio <= 8) { |
---|
| 691 | + pre_div = 4; |
---|
| 692 | + div = 2; |
---|
| 693 | + } else if (esdhc->div_ratio <= 12) { |
---|
| 694 | + pre_div = 4; |
---|
| 695 | + div = 3; |
---|
| 696 | + } else { |
---|
| 697 | + pr_warn("%s: using unsupported clock division.\n", |
---|
| 698 | + mmc_hostname(host->mmc)); |
---|
| 699 | + } |
---|
| 700 | + esdhc->div_ratio = pre_div * div; |
---|
| 701 | + } |
---|
| 702 | + |
---|
| 703 | + host->mmc->actual_clock = host->max_clk / esdhc->div_ratio; |
---|
| 704 | + |
---|
| 705 | + dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n", |
---|
| 706 | + clock, host->mmc->actual_clock); |
---|
| 707 | + |
---|
| 708 | + /* Set clock division into register. */ |
---|
| 709 | + pre_div >>= 1; |
---|
| 710 | + div--; |
---|
| 711 | + |
---|
| 712 | + esdhc_clock_enable(host, false); |
---|
| 713 | + |
---|
| 714 | + temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL); |
---|
| 715 | + temp &= ~ESDHC_CLOCK_MASK; |
---|
| 716 | + temp |= ((div << ESDHC_DIVIDER_SHIFT) | |
---|
| 717 | + (pre_div << ESDHC_PREDIV_SHIFT)); |
---|
621 | 718 | sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); |
---|
| 719 | + |
---|
| 720 | + /* |
---|
| 721 | + * Wait max 20 ms. If vendor version is 2.2 or lower, do not |
---|
| 722 | + * wait clock stable bit which does not exist. |
---|
| 723 | + */ |
---|
| 724 | + timeout = ktime_add_ms(ktime_get(), 20); |
---|
| 725 | + while (esdhc->vendor_ver > VENDOR_V_22) { |
---|
| 726 | + bool timedout = ktime_after(ktime_get(), timeout); |
---|
| 727 | + |
---|
| 728 | + if (sdhci_readl(host, ESDHC_PRSSTAT) & ESDHC_CLOCK_STABLE) |
---|
| 729 | + break; |
---|
| 730 | + if (timedout) { |
---|
| 731 | + pr_err("%s: Internal clock never stabilised.\n", |
---|
| 732 | + mmc_hostname(host->mmc)); |
---|
| 733 | + break; |
---|
| 734 | + } |
---|
| 735 | + usleep_range(10, 20); |
---|
| 736 | + } |
---|
| 737 | + |
---|
| 738 | + /* Additional setting for HS400. */ |
---|
| 739 | + if (host->mmc->ios.timing == MMC_TIMING_MMC_HS400 && |
---|
| 740 | + clock == MMC_HS200_MAX_DTR) { |
---|
| 741 | + temp = sdhci_readl(host, ESDHC_TBCTL); |
---|
| 742 | + sdhci_writel(host, temp | ESDHC_HS400_MODE, ESDHC_TBCTL); |
---|
| 743 | + temp = sdhci_readl(host, ESDHC_SDCLKCTL); |
---|
| 744 | + sdhci_writel(host, temp | ESDHC_CMD_CLK_CTL, ESDHC_SDCLKCTL); |
---|
| 745 | + esdhc_clock_enable(host, true); |
---|
| 746 | + |
---|
| 747 | + temp = sdhci_readl(host, ESDHC_DLLCFG0); |
---|
| 748 | + temp |= ESDHC_DLL_ENABLE; |
---|
| 749 | + if (host->mmc->actual_clock == MMC_HS200_MAX_DTR) |
---|
| 750 | + temp |= ESDHC_DLL_FREQ_SEL; |
---|
| 751 | + sdhci_writel(host, temp, ESDHC_DLLCFG0); |
---|
| 752 | + |
---|
| 753 | + temp |= ESDHC_DLL_RESET; |
---|
| 754 | + sdhci_writel(host, temp, ESDHC_DLLCFG0); |
---|
| 755 | + udelay(1); |
---|
| 756 | + temp &= ~ESDHC_DLL_RESET; |
---|
| 757 | + sdhci_writel(host, temp, ESDHC_DLLCFG0); |
---|
| 758 | + |
---|
| 759 | + /* Wait max 20 ms */ |
---|
| 760 | + if (read_poll_timeout(sdhci_readl, temp, |
---|
| 761 | + temp & ESDHC_DLL_STS_SLV_LOCK, |
---|
| 762 | + 10, 20000, false, |
---|
| 763 | + host, ESDHC_DLLSTAT0)) |
---|
| 764 | + pr_err("%s: timeout for delay chain lock.\n", |
---|
| 765 | + mmc_hostname(host->mmc)); |
---|
| 766 | + |
---|
| 767 | + temp = sdhci_readl(host, ESDHC_TBCTL); |
---|
| 768 | + sdhci_writel(host, temp | ESDHC_HS400_WNDW_ADJUST, ESDHC_TBCTL); |
---|
| 769 | + |
---|
| 770 | + esdhc_clock_enable(host, false); |
---|
| 771 | + esdhc_flush_async_fifo(host); |
---|
| 772 | + } |
---|
| 773 | + esdhc_clock_enable(host, true); |
---|
622 | 774 | } |
---|
623 | 775 | |
---|
624 | 776 | static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width) |
---|
.. | .. |
---|
645 | 797 | |
---|
646 | 798 | static void esdhc_reset(struct sdhci_host *host, u8 mask) |
---|
647 | 799 | { |
---|
648 | | - u32 val; |
---|
| 800 | + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
---|
| 801 | + struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); |
---|
| 802 | + u32 val, bus_width = 0; |
---|
| 803 | + |
---|
| 804 | + /* |
---|
| 805 | + * Add delay to make sure all the DMA transfers are finished |
---|
| 806 | + * for quirk. |
---|
| 807 | + */ |
---|
| 808 | + if (esdhc->quirk_delay_before_data_reset && |
---|
| 809 | + (mask & SDHCI_RESET_DATA) && |
---|
| 810 | + (host->flags & SDHCI_REQ_USE_DMA)) |
---|
| 811 | + mdelay(5); |
---|
| 812 | + |
---|
| 813 | + /* |
---|
| 814 | + * Save bus-width for eSDHC whose vendor version is 2.2 |
---|
| 815 | + * or lower for data reset. |
---|
| 816 | + */ |
---|
| 817 | + if ((mask & SDHCI_RESET_DATA) && |
---|
| 818 | + (esdhc->vendor_ver <= VENDOR_V_22)) { |
---|
| 819 | + val = sdhci_readl(host, ESDHC_PROCTL); |
---|
| 820 | + bus_width = val & ESDHC_CTRL_BUSWIDTH_MASK; |
---|
| 821 | + } |
---|
649 | 822 | |
---|
650 | 823 | sdhci_reset(host, mask); |
---|
651 | 824 | |
---|
652 | | - sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); |
---|
653 | | - sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); |
---|
| 825 | + /* |
---|
| 826 | + * Restore bus-width setting and interrupt registers for eSDHC |
---|
| 827 | + * whose vendor version is 2.2 or lower for data reset. |
---|
| 828 | + */ |
---|
| 829 | + if ((mask & SDHCI_RESET_DATA) && |
---|
| 830 | + (esdhc->vendor_ver <= VENDOR_V_22)) { |
---|
| 831 | + val = sdhci_readl(host, ESDHC_PROCTL); |
---|
| 832 | + val &= ~ESDHC_CTRL_BUSWIDTH_MASK; |
---|
| 833 | + val |= bus_width; |
---|
| 834 | + sdhci_writel(host, val, ESDHC_PROCTL); |
---|
654 | 835 | |
---|
655 | | - if (mask & SDHCI_RESET_ALL) { |
---|
| 836 | + sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); |
---|
| 837 | + sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); |
---|
| 838 | + } |
---|
| 839 | + |
---|
| 840 | + /* |
---|
| 841 | + * Some bits have to be cleaned manually for eSDHC whose spec |
---|
| 842 | + * version is higher than 3.0 for all reset. |
---|
| 843 | + */ |
---|
| 844 | + if ((mask & SDHCI_RESET_ALL) && |
---|
| 845 | + (esdhc->spec_ver >= SDHCI_SPEC_300)) { |
---|
656 | 846 | val = sdhci_readl(host, ESDHC_TBCTL); |
---|
657 | 847 | val &= ~ESDHC_TB_EN; |
---|
658 | 848 | sdhci_writel(host, val, ESDHC_TBCTL); |
---|
| 849 | + |
---|
| 850 | + /* |
---|
| 851 | + * Initialize eSDHC_DLLCFG1[DLL_PD_PULSE_STRETCH_SEL] to |
---|
| 852 | + * 0 for quirk. |
---|
| 853 | + */ |
---|
| 854 | + if (esdhc->quirk_unreliable_pulse_detection) { |
---|
| 855 | + val = sdhci_readl(host, ESDHC_DLLCFG1); |
---|
| 856 | + val &= ~ESDHC_DLL_PD_PULSE_STRETCH_SEL; |
---|
| 857 | + sdhci_writel(host, val, ESDHC_DLLCFG1); |
---|
| 858 | + } |
---|
659 | 859 | } |
---|
660 | 860 | } |
---|
661 | 861 | |
---|
.. | .. |
---|
704 | 904 | scfg_node = of_find_matching_node(NULL, scfg_device_ids); |
---|
705 | 905 | if (scfg_node) |
---|
706 | 906 | scfg_base = of_iomap(scfg_node, 0); |
---|
| 907 | + of_node_put(scfg_node); |
---|
707 | 908 | if (scfg_base) { |
---|
708 | 909 | sdhciovselcr = SDHCIOVSELCR_TGLEN | |
---|
709 | 910 | SDHCIOVSELCR_VSELVAL; |
---|
.. | .. |
---|
729 | 930 | } |
---|
730 | 931 | } |
---|
731 | 932 | |
---|
| 933 | +static struct soc_device_attribute soc_tuning_erratum_type1[] = { |
---|
| 934 | + { .family = "QorIQ T1023", }, |
---|
| 935 | + { .family = "QorIQ T1040", }, |
---|
| 936 | + { .family = "QorIQ T2080", }, |
---|
| 937 | + { .family = "QorIQ LS1021A", }, |
---|
| 938 | + { }, |
---|
| 939 | +}; |
---|
| 940 | + |
---|
| 941 | +static struct soc_device_attribute soc_tuning_erratum_type2[] = { |
---|
| 942 | + { .family = "QorIQ LS1012A", }, |
---|
| 943 | + { .family = "QorIQ LS1043A", }, |
---|
| 944 | + { .family = "QorIQ LS1046A", }, |
---|
| 945 | + { .family = "QorIQ LS1080A", }, |
---|
| 946 | + { .family = "QorIQ LS2080A", }, |
---|
| 947 | + { .family = "QorIQ LA1575A", }, |
---|
| 948 | + { }, |
---|
| 949 | +}; |
---|
| 950 | + |
---|
| 951 | +static void esdhc_tuning_block_enable(struct sdhci_host *host, bool enable) |
---|
| 952 | +{ |
---|
| 953 | + u32 val; |
---|
| 954 | + |
---|
| 955 | + esdhc_clock_enable(host, false); |
---|
| 956 | + esdhc_flush_async_fifo(host); |
---|
| 957 | + |
---|
| 958 | + val = sdhci_readl(host, ESDHC_TBCTL); |
---|
| 959 | + if (enable) |
---|
| 960 | + val |= ESDHC_TB_EN; |
---|
| 961 | + else |
---|
| 962 | + val &= ~ESDHC_TB_EN; |
---|
| 963 | + sdhci_writel(host, val, ESDHC_TBCTL); |
---|
| 964 | + |
---|
| 965 | + esdhc_clock_enable(host, true); |
---|
| 966 | +} |
---|
| 967 | + |
---|
| 968 | +static void esdhc_tuning_window_ptr(struct sdhci_host *host, u8 *window_start, |
---|
| 969 | + u8 *window_end) |
---|
| 970 | +{ |
---|
| 971 | + u32 val; |
---|
| 972 | + |
---|
| 973 | + /* Write TBCTL[11:8]=4'h8 */ |
---|
| 974 | + val = sdhci_readl(host, ESDHC_TBCTL); |
---|
| 975 | + val &= ~(0xf << 8); |
---|
| 976 | + val |= 8 << 8; |
---|
| 977 | + sdhci_writel(host, val, ESDHC_TBCTL); |
---|
| 978 | + |
---|
| 979 | + mdelay(1); |
---|
| 980 | + |
---|
| 981 | + /* Read TBCTL[31:0] register and rewrite again */ |
---|
| 982 | + val = sdhci_readl(host, ESDHC_TBCTL); |
---|
| 983 | + sdhci_writel(host, val, ESDHC_TBCTL); |
---|
| 984 | + |
---|
| 985 | + mdelay(1); |
---|
| 986 | + |
---|
| 987 | + /* Read the TBSTAT[31:0] register twice */ |
---|
| 988 | + val = sdhci_readl(host, ESDHC_TBSTAT); |
---|
| 989 | + val = sdhci_readl(host, ESDHC_TBSTAT); |
---|
| 990 | + |
---|
| 991 | + *window_end = val & 0xff; |
---|
| 992 | + *window_start = (val >> 8) & 0xff; |
---|
| 993 | +} |
---|
| 994 | + |
---|
| 995 | +static void esdhc_prepare_sw_tuning(struct sdhci_host *host, u8 *window_start, |
---|
| 996 | + u8 *window_end) |
---|
| 997 | +{ |
---|
| 998 | + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
---|
| 999 | + struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); |
---|
| 1000 | + u8 start_ptr, end_ptr; |
---|
| 1001 | + |
---|
| 1002 | + if (esdhc->quirk_tuning_erratum_type1) { |
---|
| 1003 | + *window_start = 5 * esdhc->div_ratio; |
---|
| 1004 | + *window_end = 3 * esdhc->div_ratio; |
---|
| 1005 | + return; |
---|
| 1006 | + } |
---|
| 1007 | + |
---|
| 1008 | + esdhc_tuning_window_ptr(host, &start_ptr, &end_ptr); |
---|
| 1009 | + |
---|
| 1010 | + /* Reset data lines by setting ESDHCCTL[RSTD] */ |
---|
| 1011 | + sdhci_reset(host, SDHCI_RESET_DATA); |
---|
| 1012 | + /* Write 32'hFFFF_FFFF to IRQSTAT register */ |
---|
| 1013 | + sdhci_writel(host, 0xFFFFFFFF, SDHCI_INT_STATUS); |
---|
| 1014 | + |
---|
| 1015 | + /* If TBSTAT[15:8]-TBSTAT[7:0] > (4 * div_ratio) + 2 |
---|
| 1016 | + * or TBSTAT[7:0]-TBSTAT[15:8] > (4 * div_ratio) + 2, |
---|
| 1017 | + * then program TBPTR[TB_WNDW_END_PTR] = 4 * div_ratio |
---|
| 1018 | + * and program TBPTR[TB_WNDW_START_PTR] = 8 * div_ratio. |
---|
| 1019 | + */ |
---|
| 1020 | + |
---|
| 1021 | + if (abs(start_ptr - end_ptr) > (4 * esdhc->div_ratio + 2)) { |
---|
| 1022 | + *window_start = 8 * esdhc->div_ratio; |
---|
| 1023 | + *window_end = 4 * esdhc->div_ratio; |
---|
| 1024 | + } else { |
---|
| 1025 | + *window_start = 5 * esdhc->div_ratio; |
---|
| 1026 | + *window_end = 3 * esdhc->div_ratio; |
---|
| 1027 | + } |
---|
| 1028 | +} |
---|
| 1029 | + |
---|
| 1030 | +static int esdhc_execute_sw_tuning(struct mmc_host *mmc, u32 opcode, |
---|
| 1031 | + u8 window_start, u8 window_end) |
---|
| 1032 | +{ |
---|
| 1033 | + struct sdhci_host *host = mmc_priv(mmc); |
---|
| 1034 | + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
---|
| 1035 | + struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); |
---|
| 1036 | + u32 val; |
---|
| 1037 | + int ret; |
---|
| 1038 | + |
---|
| 1039 | + /* Program TBPTR[TB_WNDW_END_PTR] and TBPTR[TB_WNDW_START_PTR] */ |
---|
| 1040 | + val = ((u32)window_start << ESDHC_WNDW_STRT_PTR_SHIFT) & |
---|
| 1041 | + ESDHC_WNDW_STRT_PTR_MASK; |
---|
| 1042 | + val |= window_end & ESDHC_WNDW_END_PTR_MASK; |
---|
| 1043 | + sdhci_writel(host, val, ESDHC_TBPTR); |
---|
| 1044 | + |
---|
| 1045 | + /* Program the software tuning mode by setting TBCTL[TB_MODE]=2'h3 */ |
---|
| 1046 | + val = sdhci_readl(host, ESDHC_TBCTL); |
---|
| 1047 | + val &= ~ESDHC_TB_MODE_MASK; |
---|
| 1048 | + val |= ESDHC_TB_MODE_SW; |
---|
| 1049 | + sdhci_writel(host, val, ESDHC_TBCTL); |
---|
| 1050 | + |
---|
| 1051 | + esdhc->in_sw_tuning = true; |
---|
| 1052 | + ret = sdhci_execute_tuning(mmc, opcode); |
---|
| 1053 | + esdhc->in_sw_tuning = false; |
---|
| 1054 | + return ret; |
---|
| 1055 | +} |
---|
| 1056 | + |
---|
732 | 1057 | static int esdhc_execute_tuning(struct mmc_host *mmc, u32 opcode) |
---|
733 | 1058 | { |
---|
734 | 1059 | struct sdhci_host *host = mmc_priv(mmc); |
---|
| 1060 | + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
---|
| 1061 | + struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); |
---|
| 1062 | + u8 window_start, window_end; |
---|
| 1063 | + int ret, retries = 1; |
---|
| 1064 | + bool hs400_tuning; |
---|
| 1065 | + unsigned int clk; |
---|
735 | 1066 | u32 val; |
---|
736 | 1067 | |
---|
737 | | - /* Use tuning block for tuning procedure */ |
---|
738 | | - esdhc_clock_enable(host, false); |
---|
739 | | - val = sdhci_readl(host, ESDHC_DMA_SYSCTL); |
---|
740 | | - val |= ESDHC_FLUSH_ASYNC_FIFO; |
---|
741 | | - sdhci_writel(host, val, ESDHC_DMA_SYSCTL); |
---|
| 1068 | + /* For tuning mode, the sd clock divisor value |
---|
| 1069 | + * must be larger than 3 according to reference manual. |
---|
| 1070 | + */ |
---|
| 1071 | + clk = esdhc->peripheral_clock / 3; |
---|
| 1072 | + if (host->clock > clk) |
---|
| 1073 | + esdhc_of_set_clock(host, clk); |
---|
742 | 1074 | |
---|
| 1075 | + esdhc_tuning_block_enable(host, true); |
---|
| 1076 | + |
---|
| 1077 | + /* |
---|
| 1078 | + * The eSDHC controller takes the data timeout value into account |
---|
| 1079 | + * during tuning. If the SD card is too slow sending the response, the |
---|
| 1080 | + * timer will expire and a "Buffer Read Ready" interrupt without data |
---|
| 1081 | + * is triggered. This leads to tuning errors. |
---|
| 1082 | + * |
---|
| 1083 | + * Just set the timeout to the maximum value because the core will |
---|
| 1084 | + * already take care of it in sdhci_send_tuning(). |
---|
| 1085 | + */ |
---|
| 1086 | + sdhci_writeb(host, 0xe, SDHCI_TIMEOUT_CONTROL); |
---|
| 1087 | + |
---|
| 1088 | + hs400_tuning = host->flags & SDHCI_HS400_TUNING; |
---|
| 1089 | + |
---|
| 1090 | + do { |
---|
| 1091 | + if (esdhc->quirk_limited_clk_division && |
---|
| 1092 | + hs400_tuning) |
---|
| 1093 | + esdhc_of_set_clock(host, host->clock); |
---|
| 1094 | + |
---|
| 1095 | + /* Do HW tuning */ |
---|
| 1096 | + val = sdhci_readl(host, ESDHC_TBCTL); |
---|
| 1097 | + val &= ~ESDHC_TB_MODE_MASK; |
---|
| 1098 | + val |= ESDHC_TB_MODE_3; |
---|
| 1099 | + sdhci_writel(host, val, ESDHC_TBCTL); |
---|
| 1100 | + |
---|
| 1101 | + ret = sdhci_execute_tuning(mmc, opcode); |
---|
| 1102 | + if (ret) |
---|
| 1103 | + break; |
---|
| 1104 | + |
---|
| 1105 | + /* For type2 affected platforms of the tuning erratum, |
---|
| 1106 | + * tuning may succeed although eSDHC might not have |
---|
| 1107 | + * tuned properly. Need to check tuning window. |
---|
| 1108 | + */ |
---|
| 1109 | + if (esdhc->quirk_tuning_erratum_type2 && |
---|
| 1110 | + !host->tuning_err) { |
---|
| 1111 | + esdhc_tuning_window_ptr(host, &window_start, |
---|
| 1112 | + &window_end); |
---|
| 1113 | + if (abs(window_start - window_end) > |
---|
| 1114 | + (4 * esdhc->div_ratio + 2)) |
---|
| 1115 | + host->tuning_err = -EAGAIN; |
---|
| 1116 | + } |
---|
| 1117 | + |
---|
| 1118 | + /* If HW tuning fails and triggers erratum, |
---|
| 1119 | + * try workaround. |
---|
| 1120 | + */ |
---|
| 1121 | + ret = host->tuning_err; |
---|
| 1122 | + if (ret == -EAGAIN && |
---|
| 1123 | + (esdhc->quirk_tuning_erratum_type1 || |
---|
| 1124 | + esdhc->quirk_tuning_erratum_type2)) { |
---|
| 1125 | + /* Recover HS400 tuning flag */ |
---|
| 1126 | + if (hs400_tuning) |
---|
| 1127 | + host->flags |= SDHCI_HS400_TUNING; |
---|
| 1128 | + pr_info("%s: Hold on to use fixed sampling clock. Try SW tuning!\n", |
---|
| 1129 | + mmc_hostname(mmc)); |
---|
| 1130 | + /* Do SW tuning */ |
---|
| 1131 | + esdhc_prepare_sw_tuning(host, &window_start, |
---|
| 1132 | + &window_end); |
---|
| 1133 | + ret = esdhc_execute_sw_tuning(mmc, opcode, |
---|
| 1134 | + window_start, |
---|
| 1135 | + window_end); |
---|
| 1136 | + if (ret) |
---|
| 1137 | + break; |
---|
| 1138 | + |
---|
| 1139 | + /* Retry both HW/SW tuning with reduced clock. */ |
---|
| 1140 | + ret = host->tuning_err; |
---|
| 1141 | + if (ret == -EAGAIN && retries) { |
---|
| 1142 | + /* Recover HS400 tuning flag */ |
---|
| 1143 | + if (hs400_tuning) |
---|
| 1144 | + host->flags |= SDHCI_HS400_TUNING; |
---|
| 1145 | + |
---|
| 1146 | + clk = host->max_clk / (esdhc->div_ratio + 1); |
---|
| 1147 | + esdhc_of_set_clock(host, clk); |
---|
| 1148 | + pr_info("%s: Hold on to use fixed sampling clock. Try tuning with reduced clock!\n", |
---|
| 1149 | + mmc_hostname(mmc)); |
---|
| 1150 | + } else { |
---|
| 1151 | + break; |
---|
| 1152 | + } |
---|
| 1153 | + } else { |
---|
| 1154 | + break; |
---|
| 1155 | + } |
---|
| 1156 | + } while (retries--); |
---|
| 1157 | + |
---|
| 1158 | + if (ret) { |
---|
| 1159 | + esdhc_tuning_block_enable(host, false); |
---|
| 1160 | + } else if (hs400_tuning) { |
---|
| 1161 | + val = sdhci_readl(host, ESDHC_SDTIMNGCTL); |
---|
| 1162 | + val |= ESDHC_FLW_CTL_BG; |
---|
| 1163 | + sdhci_writel(host, val, ESDHC_SDTIMNGCTL); |
---|
| 1164 | + } |
---|
| 1165 | + |
---|
| 1166 | + return ret; |
---|
| 1167 | +} |
---|
| 1168 | + |
---|
| 1169 | +static void esdhc_set_uhs_signaling(struct sdhci_host *host, |
---|
| 1170 | + unsigned int timing) |
---|
| 1171 | +{ |
---|
| 1172 | + u32 val; |
---|
| 1173 | + |
---|
| 1174 | + /* |
---|
| 1175 | + * There are specific registers setting for HS400 mode. |
---|
| 1176 | + * Clean all of them if controller is in HS400 mode to |
---|
| 1177 | + * exit HS400 mode before re-setting any speed mode. |
---|
| 1178 | + */ |
---|
743 | 1179 | val = sdhci_readl(host, ESDHC_TBCTL); |
---|
744 | | - val |= ESDHC_TB_EN; |
---|
745 | | - sdhci_writel(host, val, ESDHC_TBCTL); |
---|
746 | | - esdhc_clock_enable(host, true); |
---|
| 1180 | + if (val & ESDHC_HS400_MODE) { |
---|
| 1181 | + val = sdhci_readl(host, ESDHC_SDTIMNGCTL); |
---|
| 1182 | + val &= ~ESDHC_FLW_CTL_BG; |
---|
| 1183 | + sdhci_writel(host, val, ESDHC_SDTIMNGCTL); |
---|
747 | 1184 | |
---|
748 | | - return sdhci_execute_tuning(mmc, opcode); |
---|
| 1185 | + val = sdhci_readl(host, ESDHC_SDCLKCTL); |
---|
| 1186 | + val &= ~ESDHC_CMD_CLK_CTL; |
---|
| 1187 | + sdhci_writel(host, val, ESDHC_SDCLKCTL); |
---|
| 1188 | + |
---|
| 1189 | + esdhc_clock_enable(host, false); |
---|
| 1190 | + val = sdhci_readl(host, ESDHC_TBCTL); |
---|
| 1191 | + val &= ~ESDHC_HS400_MODE; |
---|
| 1192 | + sdhci_writel(host, val, ESDHC_TBCTL); |
---|
| 1193 | + esdhc_clock_enable(host, true); |
---|
| 1194 | + |
---|
| 1195 | + val = sdhci_readl(host, ESDHC_DLLCFG0); |
---|
| 1196 | + val &= ~(ESDHC_DLL_ENABLE | ESDHC_DLL_FREQ_SEL); |
---|
| 1197 | + sdhci_writel(host, val, ESDHC_DLLCFG0); |
---|
| 1198 | + |
---|
| 1199 | + val = sdhci_readl(host, ESDHC_TBCTL); |
---|
| 1200 | + val &= ~ESDHC_HS400_WNDW_ADJUST; |
---|
| 1201 | + sdhci_writel(host, val, ESDHC_TBCTL); |
---|
| 1202 | + |
---|
| 1203 | + esdhc_tuning_block_enable(host, false); |
---|
| 1204 | + } |
---|
| 1205 | + |
---|
| 1206 | + if (timing == MMC_TIMING_MMC_HS400) |
---|
| 1207 | + esdhc_tuning_block_enable(host, true); |
---|
| 1208 | + else |
---|
| 1209 | + sdhci_set_uhs_signaling(host, timing); |
---|
| 1210 | +} |
---|
| 1211 | + |
---|
| 1212 | +static u32 esdhc_irq(struct sdhci_host *host, u32 intmask) |
---|
| 1213 | +{ |
---|
| 1214 | + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
---|
| 1215 | + struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); |
---|
| 1216 | + u32 command; |
---|
| 1217 | + |
---|
| 1218 | + if (esdhc->quirk_trans_complete_erratum) { |
---|
| 1219 | + command = SDHCI_GET_CMD(sdhci_readw(host, |
---|
| 1220 | + SDHCI_COMMAND)); |
---|
| 1221 | + if (command == MMC_WRITE_MULTIPLE_BLOCK && |
---|
| 1222 | + sdhci_readw(host, SDHCI_BLOCK_COUNT) && |
---|
| 1223 | + intmask & SDHCI_INT_DATA_END) { |
---|
| 1224 | + intmask &= ~SDHCI_INT_DATA_END; |
---|
| 1225 | + sdhci_writel(host, SDHCI_INT_DATA_END, |
---|
| 1226 | + SDHCI_INT_STATUS); |
---|
| 1227 | + } |
---|
| 1228 | + } |
---|
| 1229 | + return intmask; |
---|
749 | 1230 | } |
---|
750 | 1231 | |
---|
751 | 1232 | #ifdef CONFIG_PM_SLEEP |
---|
.. | .. |
---|
794 | 1275 | .adma_workaround = esdhc_of_adma_workaround, |
---|
795 | 1276 | .set_bus_width = esdhc_pltfm_set_bus_width, |
---|
796 | 1277 | .reset = esdhc_reset, |
---|
797 | | - .set_uhs_signaling = sdhci_set_uhs_signaling, |
---|
| 1278 | + .set_uhs_signaling = esdhc_set_uhs_signaling, |
---|
| 1279 | + .irq = esdhc_irq, |
---|
798 | 1280 | }; |
---|
799 | 1281 | |
---|
800 | 1282 | static const struct sdhci_ops sdhci_esdhc_le_ops = { |
---|
.. | .. |
---|
811 | 1293 | .adma_workaround = esdhc_of_adma_workaround, |
---|
812 | 1294 | .set_bus_width = esdhc_pltfm_set_bus_width, |
---|
813 | 1295 | .reset = esdhc_reset, |
---|
814 | | - .set_uhs_signaling = sdhci_set_uhs_signaling, |
---|
| 1296 | + .set_uhs_signaling = esdhc_set_uhs_signaling, |
---|
| 1297 | + .irq = esdhc_irq, |
---|
815 | 1298 | }; |
---|
816 | 1299 | |
---|
817 | 1300 | static const struct sdhci_pltfm_data sdhci_esdhc_be_pdata = { |
---|
.. | .. |
---|
837 | 1320 | { }, |
---|
838 | 1321 | }; |
---|
839 | 1322 | |
---|
| 1323 | +static struct soc_device_attribute soc_fixup_sdhc_clkdivs[] = { |
---|
| 1324 | + { .family = "QorIQ LX2160A", .revision = "1.0", }, |
---|
| 1325 | + { .family = "QorIQ LX2160A", .revision = "2.0", }, |
---|
| 1326 | + { .family = "QorIQ LS1028A", .revision = "1.0", }, |
---|
| 1327 | + { }, |
---|
| 1328 | +}; |
---|
| 1329 | + |
---|
| 1330 | +static struct soc_device_attribute soc_unreliable_pulse_detection[] = { |
---|
| 1331 | + { .family = "QorIQ LX2160A", .revision = "1.0", }, |
---|
| 1332 | + { .family = "QorIQ LX2160A", .revision = "2.0", }, |
---|
| 1333 | + { .family = "QorIQ LS1028A", .revision = "1.0", }, |
---|
| 1334 | + { }, |
---|
| 1335 | +}; |
---|
| 1336 | + |
---|
840 | 1337 | static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host) |
---|
841 | 1338 | { |
---|
842 | 1339 | const struct of_device_id *match; |
---|
.. | .. |
---|
859 | 1356 | else |
---|
860 | 1357 | esdhc->quirk_incorrect_hostver = false; |
---|
861 | 1358 | |
---|
| 1359 | + if (soc_device_match(soc_fixup_sdhc_clkdivs)) |
---|
| 1360 | + esdhc->quirk_limited_clk_division = true; |
---|
| 1361 | + else |
---|
| 1362 | + esdhc->quirk_limited_clk_division = false; |
---|
| 1363 | + |
---|
| 1364 | + if (soc_device_match(soc_unreliable_pulse_detection)) |
---|
| 1365 | + esdhc->quirk_unreliable_pulse_detection = true; |
---|
| 1366 | + else |
---|
| 1367 | + esdhc->quirk_unreliable_pulse_detection = false; |
---|
| 1368 | + |
---|
862 | 1369 | match = of_match_node(sdhci_esdhc_of_match, pdev->dev.of_node); |
---|
863 | 1370 | if (match) |
---|
864 | 1371 | esdhc->clk_fixup = match->data; |
---|
865 | 1372 | np = pdev->dev.of_node; |
---|
| 1373 | + |
---|
| 1374 | + if (of_device_is_compatible(np, "fsl,p2020-esdhc")) { |
---|
| 1375 | + esdhc->quirk_delay_before_data_reset = true; |
---|
| 1376 | + esdhc->quirk_trans_complete_erratum = true; |
---|
| 1377 | + } |
---|
| 1378 | + |
---|
866 | 1379 | clk = of_clk_get(np, 0); |
---|
867 | 1380 | if (!IS_ERR(clk)) { |
---|
868 | 1381 | /* |
---|
869 | 1382 | * esdhc->peripheral_clock would be assigned with a value |
---|
870 | 1383 | * which is eSDHC base clock when use periperal clock. |
---|
871 | | - * For ls1046a, the clock value got by common clk API is |
---|
872 | | - * peripheral clock while the eSDHC base clock is 1/2 |
---|
873 | | - * peripheral clock. |
---|
| 1384 | + * For some platforms, the clock value got by common clk |
---|
| 1385 | + * API is peripheral clock while the eSDHC base clock is |
---|
| 1386 | + * 1/2 peripheral clock. |
---|
874 | 1387 | */ |
---|
875 | | - if (of_device_is_compatible(np, "fsl,ls1046a-esdhc")) |
---|
| 1388 | + if (of_device_is_compatible(np, "fsl,ls1046a-esdhc") || |
---|
| 1389 | + of_device_is_compatible(np, "fsl,ls1028a-esdhc") || |
---|
| 1390 | + of_device_is_compatible(np, "fsl,ls1088a-esdhc")) |
---|
876 | 1391 | esdhc->peripheral_clock = clk_get_rate(clk) / 2; |
---|
877 | 1392 | else |
---|
878 | 1393 | esdhc->peripheral_clock = clk_get_rate(clk); |
---|
.. | .. |
---|
880 | 1395 | clk_put(clk); |
---|
881 | 1396 | } |
---|
882 | 1397 | |
---|
883 | | - if (esdhc->peripheral_clock) { |
---|
884 | | - esdhc_clock_enable(host, false); |
---|
885 | | - val = sdhci_readl(host, ESDHC_DMA_SYSCTL); |
---|
| 1398 | + esdhc_clock_enable(host, false); |
---|
| 1399 | + val = sdhci_readl(host, ESDHC_DMA_SYSCTL); |
---|
| 1400 | + /* |
---|
| 1401 | + * This bit is not able to be reset by SDHCI_RESET_ALL. Need to |
---|
| 1402 | + * initialize it as 1 or 0 once, to override the different value |
---|
| 1403 | + * which may be configured in bootloader. |
---|
| 1404 | + */ |
---|
| 1405 | + if (esdhc->peripheral_clock) |
---|
886 | 1406 | val |= ESDHC_PERIPHERAL_CLK_SEL; |
---|
887 | | - sdhci_writel(host, val, ESDHC_DMA_SYSCTL); |
---|
888 | | - esdhc_clock_enable(host, true); |
---|
889 | | - } |
---|
| 1407 | + else |
---|
| 1408 | + val &= ~ESDHC_PERIPHERAL_CLK_SEL; |
---|
| 1409 | + sdhci_writel(host, val, ESDHC_DMA_SYSCTL); |
---|
| 1410 | + esdhc_clock_enable(host, true); |
---|
| 1411 | +} |
---|
| 1412 | + |
---|
| 1413 | +static int esdhc_hs400_prepare_ddr(struct mmc_host *mmc) |
---|
| 1414 | +{ |
---|
| 1415 | + esdhc_tuning_block_enable(mmc_priv(mmc), false); |
---|
| 1416 | + return 0; |
---|
890 | 1417 | } |
---|
891 | 1418 | |
---|
892 | 1419 | static int sdhci_esdhc_probe(struct platform_device *pdev) |
---|
.. | .. |
---|
912 | 1439 | host->mmc_host_ops.start_signal_voltage_switch = |
---|
913 | 1440 | esdhc_signal_voltage_switch; |
---|
914 | 1441 | host->mmc_host_ops.execute_tuning = esdhc_execute_tuning; |
---|
| 1442 | + host->mmc_host_ops.hs400_prepare_ddr = esdhc_hs400_prepare_ddr; |
---|
915 | 1443 | host->tuning_delay = 1; |
---|
916 | 1444 | |
---|
917 | 1445 | esdhc_init(pdev, host); |
---|
.. | .. |
---|
920 | 1448 | |
---|
921 | 1449 | pltfm_host = sdhci_priv(host); |
---|
922 | 1450 | esdhc = sdhci_pltfm_priv(pltfm_host); |
---|
| 1451 | + if (soc_device_match(soc_tuning_erratum_type1)) |
---|
| 1452 | + esdhc->quirk_tuning_erratum_type1 = true; |
---|
| 1453 | + else |
---|
| 1454 | + esdhc->quirk_tuning_erratum_type1 = false; |
---|
| 1455 | + |
---|
| 1456 | + if (soc_device_match(soc_tuning_erratum_type2)) |
---|
| 1457 | + esdhc->quirk_tuning_erratum_type2 = true; |
---|
| 1458 | + else |
---|
| 1459 | + esdhc->quirk_tuning_erratum_type2 = false; |
---|
| 1460 | + |
---|
923 | 1461 | if (esdhc->vendor_ver == VENDOR_V_22) |
---|
924 | 1462 | host->quirks2 |= SDHCI_QUIRK2_HOST_NO_CMD23; |
---|
925 | 1463 | |
---|
.. | .. |
---|
941 | 1479 | if (of_device_is_compatible(np, "fsl,ls1021a-esdhc")) |
---|
942 | 1480 | host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; |
---|
943 | 1481 | |
---|
| 1482 | + esdhc->quirk_ignore_data_inhibit = false; |
---|
944 | 1483 | if (of_device_is_compatible(np, "fsl,p2020-esdhc")) { |
---|
945 | 1484 | /* |
---|
946 | 1485 | * Freescale messed up with P2020 as it has a non-standard |
---|
947 | 1486 | * host control register |
---|
948 | 1487 | */ |
---|
949 | 1488 | host->quirks2 |= SDHCI_QUIRK2_BROKEN_HOST_CONTROL; |
---|
| 1489 | + esdhc->quirk_ignore_data_inhibit = true; |
---|
950 | 1490 | } |
---|
951 | 1491 | |
---|
952 | 1492 | /* call to generic mmc_of_parse to support additional capabilities */ |
---|
.. | .. |
---|
969 | 1509 | static struct platform_driver sdhci_esdhc_driver = { |
---|
970 | 1510 | .driver = { |
---|
971 | 1511 | .name = "sdhci-esdhc", |
---|
| 1512 | + .probe_type = PROBE_PREFER_ASYNCHRONOUS, |
---|
972 | 1513 | .of_match_table = sdhci_esdhc_of_match, |
---|
973 | 1514 | .pm = &esdhc_of_dev_pm_ops, |
---|
974 | 1515 | }, |
---|