diff options
| -rw-r--r-- | drivers/mmc/core/sd.c | 6 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci.c | 168 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci.h | 3 | ||||
| -rw-r--r-- | include/linux/mmc/host.h | 1 | ||||
| -rw-r--r-- | include/linux/mmc/mmc.h | 1 | ||||
| -rw-r--r-- | include/linux/mmc/sdhci.h | 4 |
6 files changed, 182 insertions, 1 deletions
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 732c3171cec..fc65475a26e 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c | |||
| @@ -618,6 +618,12 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card) | |||
| 618 | 618 | ||
| 619 | /* Set current limit for the card */ | 619 | /* Set current limit for the card */ |
| 620 | err = sd_set_current_limit(card, status); | 620 | err = sd_set_current_limit(card, status); |
| 621 | if (err) | ||
| 622 | goto out; | ||
| 623 | |||
| 624 | /* SPI mode doesn't define CMD19 */ | ||
| 625 | if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning) | ||
| 626 | err = card->host->ops->execute_tuning(card->host); | ||
| 621 | 627 | ||
| 622 | out: | 628 | out: |
| 623 | kfree(status); | 629 | kfree(status); |
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 2a15aad2eba..8a56eacea34 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c | |||
| @@ -38,6 +38,8 @@ | |||
| 38 | #define SDHCI_USE_LEDS_CLASS | 38 | #define SDHCI_USE_LEDS_CLASS |
| 39 | #endif | 39 | #endif |
| 40 | 40 | ||
| 41 | #define MAX_TUNING_LOOP 40 | ||
| 42 | |||
| 41 | static unsigned int debug_quirks = 0; | 43 | static unsigned int debug_quirks = 0; |
| 42 | 44 | ||
| 43 | static void sdhci_finish_data(struct sdhci_host *); | 45 | static void sdhci_finish_data(struct sdhci_host *); |
| @@ -968,7 +970,9 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) | |||
| 968 | flags |= SDHCI_CMD_CRC; | 970 | flags |= SDHCI_CMD_CRC; |
| 969 | if (cmd->flags & MMC_RSP_OPCODE) | 971 | if (cmd->flags & MMC_RSP_OPCODE) |
| 970 | flags |= SDHCI_CMD_INDEX; | 972 | flags |= SDHCI_CMD_INDEX; |
| 971 | if (cmd->data) | 973 | |
| 974 | /* CMD19 is special in that the Data Present Select should be set */ | ||
| 975 | if (cmd->data || (cmd->opcode == MMC_SEND_TUNING_BLOCK)) | ||
| 972 | flags |= SDHCI_CMD_DATA; | 976 | flags |= SDHCI_CMD_DATA; |
| 973 | 977 | ||
| 974 | sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND); | 978 | sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND); |
| @@ -1501,12 +1505,157 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, | |||
| 1501 | return 0; | 1505 | return 0; |
| 1502 | } | 1506 | } |
| 1503 | 1507 | ||
| 1508 | static int sdhci_execute_tuning(struct mmc_host *mmc) | ||
| 1509 | { | ||
| 1510 | struct sdhci_host *host; | ||
| 1511 | u16 ctrl; | ||
| 1512 | u32 ier; | ||
| 1513 | int tuning_loop_counter = MAX_TUNING_LOOP; | ||
| 1514 | unsigned long timeout; | ||
| 1515 | int err = 0; | ||
| 1516 | |||
| 1517 | host = mmc_priv(mmc); | ||
| 1518 | |||
| 1519 | disable_irq(host->irq); | ||
| 1520 | spin_lock(&host->lock); | ||
| 1521 | |||
| 1522 | ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); | ||
| 1523 | |||
| 1524 | /* | ||
| 1525 | * Host Controller needs tuning only in case of SDR104 mode | ||
| 1526 | * and for SDR50 mode when Use Tuning for SDR50 is set in | ||
| 1527 | * Capabilities register. | ||
| 1528 | */ | ||
| 1529 | if (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR104) || | ||
| 1530 | (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR50) && | ||
| 1531 | (host->flags & SDHCI_SDR50_NEEDS_TUNING))) | ||
| 1532 | ctrl |= SDHCI_CTRL_EXEC_TUNING; | ||
| 1533 | else { | ||
| 1534 | spin_unlock(&host->lock); | ||
| 1535 | enable_irq(host->irq); | ||
| 1536 | return 0; | ||
| 1537 | } | ||
| 1538 | |||
| 1539 | sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); | ||
| 1540 | |||
| 1541 | /* | ||
| 1542 | * As per the Host Controller spec v3.00, tuning command | ||
| 1543 | * generates Buffer Read Ready interrupt, so enable that. | ||
| 1544 | * | ||
| 1545 | * Note: The spec clearly says that when tuning sequence | ||
| 1546 | * is being performed, the controller does not generate | ||
| 1547 | * interrupts other than Buffer Read Ready interrupt. But | ||
| 1548 | * to make sure we don't hit a controller bug, we _only_ | ||
| 1549 | * enable Buffer Read Ready interrupt here. | ||
| 1550 | */ | ||
| 1551 | ier = sdhci_readl(host, SDHCI_INT_ENABLE); | ||
| 1552 | sdhci_clear_set_irqs(host, ier, SDHCI_INT_DATA_AVAIL); | ||
| 1553 | |||
| 1554 | /* | ||
| 1555 | * Issue CMD19 repeatedly till Execute Tuning is set to 0 or the number | ||
| 1556 | * of loops reaches 40 times or a timeout of 150ms occurs. | ||
| 1557 | */ | ||
| 1558 | timeout = 150; | ||
| 1559 | do { | ||
| 1560 | struct mmc_command cmd = {0}; | ||
| 1561 | struct mmc_request mrq = {0}; | ||
| 1562 | |||
| 1563 | if (!tuning_loop_counter && !timeout) | ||
| 1564 | break; | ||
| 1565 | |||
| 1566 | cmd.opcode = MMC_SEND_TUNING_BLOCK; | ||
| 1567 | cmd.arg = 0; | ||
| 1568 | cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; | ||
| 1569 | cmd.retries = 0; | ||
| 1570 | cmd.data = NULL; | ||
| 1571 | cmd.error = 0; | ||
| 1572 | |||
| 1573 | mrq.cmd = &cmd; | ||
| 1574 | host->mrq = &mrq; | ||
| 1575 | |||
| 1576 | /* | ||
| 1577 | * In response to CMD19, the card sends 64 bytes of tuning | ||
| 1578 | * block to the Host Controller. So we set the block size | ||
| 1579 | * to 64 here. | ||
| 1580 | */ | ||
| 1581 | sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64), SDHCI_BLOCK_SIZE); | ||
| 1582 | |||
| 1583 | /* | ||
| 1584 | * The tuning block is sent by the card to the host controller. | ||
| 1585 | * So we set the TRNS_READ bit in the Transfer Mode register. | ||
| 1586 | * This also takes care of setting DMA Enable and Multi Block | ||
| 1587 | * Select in the same register to 0. | ||
| 1588 | */ | ||
| 1589 | sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE); | ||
| 1590 | |||
| 1591 | sdhci_send_command(host, &cmd); | ||
| 1592 | |||
| 1593 | host->cmd = NULL; | ||
| 1594 | host->mrq = NULL; | ||
| 1595 | |||
| 1596 | spin_unlock(&host->lock); | ||
| 1597 | enable_irq(host->irq); | ||
| 1598 | |||
| 1599 | /* Wait for Buffer Read Ready interrupt */ | ||
| 1600 | wait_event_interruptible_timeout(host->buf_ready_int, | ||
| 1601 | (host->tuning_done == 1), | ||
| 1602 | msecs_to_jiffies(50)); | ||
| 1603 | disable_irq(host->irq); | ||
| 1604 | spin_lock(&host->lock); | ||
| 1605 | |||
| 1606 | if (!host->tuning_done) { | ||
| 1607 | printk(KERN_INFO DRIVER_NAME ": Timeout waiting for " | ||
| 1608 | "Buffer Read Ready interrupt during tuning " | ||
| 1609 | "procedure, falling back to fixed sampling " | ||
| 1610 | "clock\n"); | ||
| 1611 | ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); | ||
| 1612 | ctrl &= ~SDHCI_CTRL_TUNED_CLK; | ||
| 1613 | ctrl &= ~SDHCI_CTRL_EXEC_TUNING; | ||
| 1614 | sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); | ||
| 1615 | |||
| 1616 | err = -EIO; | ||
| 1617 | goto out; | ||
| 1618 | } | ||
| 1619 | |||
| 1620 | host->tuning_done = 0; | ||
| 1621 | |||
| 1622 | ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); | ||
| 1623 | tuning_loop_counter--; | ||
| 1624 | timeout--; | ||
| 1625 | mdelay(1); | ||
| 1626 | } while (ctrl & SDHCI_CTRL_EXEC_TUNING); | ||
| 1627 | |||
| 1628 | /* | ||
| 1629 | * The Host Driver has exhausted the maximum number of loops allowed, | ||
| 1630 | * so use fixed sampling frequency. | ||
| 1631 | */ | ||
| 1632 | if (!tuning_loop_counter || !timeout) { | ||
| 1633 | ctrl &= ~SDHCI_CTRL_TUNED_CLK; | ||
| 1634 | sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); | ||
| 1635 | } else { | ||
| 1636 | if (!(ctrl & SDHCI_CTRL_TUNED_CLK)) { | ||
| 1637 | printk(KERN_INFO DRIVER_NAME ": Tuning procedure" | ||
| 1638 | " failed, falling back to fixed sampling" | ||
| 1639 | " clock\n"); | ||
| 1640 | err = -EIO; | ||
| 1641 | } | ||
| 1642 | } | ||
| 1643 | |||
| 1644 | out: | ||
| 1645 | sdhci_clear_set_irqs(host, SDHCI_INT_DATA_AVAIL, ier); | ||
| 1646 | spin_unlock(&host->lock); | ||
| 1647 | enable_irq(host->irq); | ||
| 1648 | |||
| 1649 | return err; | ||
| 1650 | } | ||
| 1651 | |||
| 1504 | static const struct mmc_host_ops sdhci_ops = { | 1652 | static const struct mmc_host_ops sdhci_ops = { |
| 1505 | .request = sdhci_request, | 1653 | .request = sdhci_request, |
| 1506 | .set_ios = sdhci_set_ios, | 1654 | .set_ios = sdhci_set_ios, |
| 1507 | .get_ro = sdhci_get_ro, | 1655 | .get_ro = sdhci_get_ro, |
| 1508 | .enable_sdio_irq = sdhci_enable_sdio_irq, | 1656 | .enable_sdio_irq = sdhci_enable_sdio_irq, |
| 1509 | .start_signal_voltage_switch = sdhci_start_signal_voltage_switch, | 1657 | .start_signal_voltage_switch = sdhci_start_signal_voltage_switch, |
| 1658 | .execute_tuning = sdhci_execute_tuning, | ||
| 1510 | }; | 1659 | }; |
| 1511 | 1660 | ||
| 1512 | /*****************************************************************************\ | 1661 | /*****************************************************************************\ |
| @@ -1724,6 +1873,16 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) | |||
| 1724 | { | 1873 | { |
| 1725 | BUG_ON(intmask == 0); | 1874 | BUG_ON(intmask == 0); |
| 1726 | 1875 | ||
| 1876 | /* CMD19 generates _only_ Buffer Read Ready interrupt */ | ||
| 1877 | if (intmask & SDHCI_INT_DATA_AVAIL) { | ||
| 1878 | if (SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND)) == | ||
| 1879 | MMC_SEND_TUNING_BLOCK) { | ||
| 1880 | host->tuning_done = 1; | ||
| 1881 | wake_up(&host->buf_ready_int); | ||
| 1882 | return; | ||
| 1883 | } | ||
| 1884 | } | ||
| 1885 | |||
| 1727 | if (!host->data) { | 1886 | if (!host->data) { |
| 1728 | /* | 1887 | /* |
| 1729 | * The "data complete" interrupt is also used to | 1888 | * The "data complete" interrupt is also used to |
| @@ -2160,6 +2319,10 @@ int sdhci_add_host(struct sdhci_host *host) | |||
| 2160 | if (caps[1] & SDHCI_SUPPORT_DDR50) | 2319 | if (caps[1] & SDHCI_SUPPORT_DDR50) |
| 2161 | mmc->caps |= MMC_CAP_UHS_DDR50; | 2320 | mmc->caps |= MMC_CAP_UHS_DDR50; |
| 2162 | 2321 | ||
| 2322 | /* Does the host needs tuning for SDR50? */ | ||
| 2323 | if (caps[1] & SDHCI_USE_SDR50_TUNING) | ||
| 2324 | host->flags |= SDHCI_SDR50_NEEDS_TUNING; | ||
| 2325 | |||
| 2163 | /* Driver Type(s) (A, C, D) supported by the host */ | 2326 | /* Driver Type(s) (A, C, D) supported by the host */ |
| 2164 | if (caps[1] & SDHCI_DRIVER_TYPE_A) | 2327 | if (caps[1] & SDHCI_DRIVER_TYPE_A) |
| 2165 | mmc->caps |= MMC_CAP_DRIVER_TYPE_A; | 2328 | mmc->caps |= MMC_CAP_DRIVER_TYPE_A; |
| @@ -2313,6 +2476,9 @@ int sdhci_add_host(struct sdhci_host *host) | |||
| 2313 | 2476 | ||
| 2314 | setup_timer(&host->timer, sdhci_timeout_timer, (unsigned long)host); | 2477 | setup_timer(&host->timer, sdhci_timeout_timer, (unsigned long)host); |
| 2315 | 2478 | ||
| 2479 | if (host->version >= SDHCI_SPEC_300) | ||
| 2480 | init_waitqueue_head(&host->buf_ready_int); | ||
| 2481 | |||
| 2316 | ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED, | 2482 | ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED, |
| 2317 | mmc_hostname(mmc), host); | 2483 | mmc_hostname(mmc), host); |
| 2318 | if (ret) | 2484 | if (ret) |
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index d96f6afcca1..e62367491ee 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h | |||
| @@ -161,6 +161,8 @@ | |||
| 161 | #define SDHCI_CTRL_DRV_TYPE_A 0x0010 | 161 | #define SDHCI_CTRL_DRV_TYPE_A 0x0010 |
| 162 | #define SDHCI_CTRL_DRV_TYPE_C 0x0020 | 162 | #define SDHCI_CTRL_DRV_TYPE_C 0x0020 |
| 163 | #define SDHCI_CTRL_DRV_TYPE_D 0x0030 | 163 | #define SDHCI_CTRL_DRV_TYPE_D 0x0030 |
| 164 | #define SDHCI_CTRL_EXEC_TUNING 0x0040 | ||
| 165 | #define SDHCI_CTRL_TUNED_CLK 0x0080 | ||
| 164 | #define SDHCI_CTRL_PRESET_VAL_ENABLE 0x8000 | 166 | #define SDHCI_CTRL_PRESET_VAL_ENABLE 0x8000 |
| 165 | 167 | ||
| 166 | #define SDHCI_CAPABILITIES 0x40 | 168 | #define SDHCI_CAPABILITIES 0x40 |
| @@ -188,6 +190,7 @@ | |||
| 188 | #define SDHCI_DRIVER_TYPE_A 0x00000010 | 190 | #define SDHCI_DRIVER_TYPE_A 0x00000010 |
| 189 | #define SDHCI_DRIVER_TYPE_C 0x00000020 | 191 | #define SDHCI_DRIVER_TYPE_C 0x00000020 |
| 190 | #define SDHCI_DRIVER_TYPE_D 0x00000040 | 192 | #define SDHCI_DRIVER_TYPE_D 0x00000040 |
| 193 | #define SDHCI_USE_SDR50_TUNING 0x00002000 | ||
| 191 | 194 | ||
| 192 | #define SDHCI_CAPABILITIES_1 0x44 | 195 | #define SDHCI_CAPABILITIES_1 0x44 |
| 193 | 196 | ||
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 52b5dc914a8..ca7007fdb39 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h | |||
| @@ -136,6 +136,7 @@ struct mmc_host_ops { | |||
| 136 | void (*init_card)(struct mmc_host *host, struct mmc_card *card); | 136 | void (*init_card)(struct mmc_host *host, struct mmc_card *card); |
| 137 | 137 | ||
| 138 | int (*start_signal_voltage_switch)(struct mmc_host *host, struct mmc_ios *ios); | 138 | int (*start_signal_voltage_switch)(struct mmc_host *host, struct mmc_ios *ios); |
| 139 | int (*execute_tuning)(struct mmc_host *host); | ||
| 139 | }; | 140 | }; |
| 140 | 141 | ||
| 141 | struct mmc_card; | 142 | struct mmc_card; |
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h index 373b2bf5e5b..9fa5a73f393 100644 --- a/include/linux/mmc/mmc.h +++ b/include/linux/mmc/mmc.h | |||
| @@ -50,6 +50,7 @@ | |||
| 50 | #define MMC_SET_BLOCKLEN 16 /* ac [31:0] block len R1 */ | 50 | #define MMC_SET_BLOCKLEN 16 /* ac [31:0] block len R1 */ |
| 51 | #define MMC_READ_SINGLE_BLOCK 17 /* adtc [31:0] data addr R1 */ | 51 | #define MMC_READ_SINGLE_BLOCK 17 /* adtc [31:0] data addr R1 */ |
| 52 | #define MMC_READ_MULTIPLE_BLOCK 18 /* adtc [31:0] data addr R1 */ | 52 | #define MMC_READ_MULTIPLE_BLOCK 18 /* adtc [31:0] data addr R1 */ |
| 53 | #define MMC_SEND_TUNING_BLOCK 19 /* adtc R1 */ | ||
| 53 | 54 | ||
| 54 | /* class 3 */ | 55 | /* class 3 */ |
| 55 | #define MMC_WRITE_DAT_UNTIL_STOP 20 /* adtc [31:0] data addr R1 */ | 56 | #define MMC_WRITE_DAT_UNTIL_STOP 20 /* adtc [31:0] data addr R1 */ |
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h index 92e1c9ad126..b74c8530e95 100644 --- a/include/linux/mmc/sdhci.h +++ b/include/linux/mmc/sdhci.h | |||
| @@ -111,6 +111,7 @@ struct sdhci_host { | |||
| 111 | #define SDHCI_USE_ADMA (1<<1) /* Host is ADMA capable */ | 111 | #define SDHCI_USE_ADMA (1<<1) /* Host is ADMA capable */ |
| 112 | #define SDHCI_REQ_USE_DMA (1<<2) /* Use DMA for this req. */ | 112 | #define SDHCI_REQ_USE_DMA (1<<2) /* Use DMA for this req. */ |
| 113 | #define SDHCI_DEVICE_DEAD (1<<3) /* Device unresponsive */ | 113 | #define SDHCI_DEVICE_DEAD (1<<3) /* Device unresponsive */ |
| 114 | #define SDHCI_SDR50_NEEDS_TUNING (1<<4) /* SDR50 needs tuning */ | ||
| 114 | 115 | ||
| 115 | unsigned int version; /* SDHCI spec. version */ | 116 | unsigned int version; /* SDHCI spec. version */ |
| 116 | 117 | ||
| @@ -147,6 +148,9 @@ struct sdhci_host { | |||
| 147 | unsigned int ocr_avail_sd; | 148 | unsigned int ocr_avail_sd; |
| 148 | unsigned int ocr_avail_mmc; | 149 | unsigned int ocr_avail_mmc; |
| 149 | 150 | ||
| 151 | wait_queue_head_t buf_ready_int; /* Waitqueue for Buffer Read Ready interrupt */ | ||
| 152 | unsigned int tuning_done; /* Condition flag set when CMD19 succeeds */ | ||
| 153 | |||
| 150 | unsigned long private[0] ____cacheline_aligned; | 154 | unsigned long private[0] ____cacheline_aligned; |
| 151 | }; | 155 | }; |
| 152 | #endif /* __SDHCI_H */ | 156 | #endif /* __SDHCI_H */ |
