aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/host/sdhci.c
diff options
context:
space:
mode:
authorArindam Nath <arindam.nath@amd.com>2011-05-05 02:49:04 -0400
committerChris Ball <cjb@laptop.org>2011-05-24 23:53:46 -0400
commitb513ea250eb7c36a8afb3df938d632ca6b4df7cd (patch)
tree41b597f488ffa21c675f49bd8c8ea00d177125e2 /drivers/mmc/host/sdhci.c
parent3a3035114307cd55e024662bb295a87b849f0bd4 (diff)
mmc: sd: add support for tuning during uhs initialization
Host Controller needs tuning during initialization to operate SDR50 and SDR104 UHS-I cards. Whether SDR50 mode actually needs tuning is indicated by bit 45 of the Host Controller Capabilities register. A new command CMD19 has been defined in the Physical Layer spec v3.01 to request the card to send tuning pattern. We enable Buffer Read Ready interrupt at the very begining of tuning procedure, because that is the only interrupt generated by the Host Controller during tuning. We program the block size to 64 in the Block Size register. We make sure that DMA Enable and Multi Block Select in the Transfer Mode register are set to 0 before actually sending CMD19. The tuning block is sent by the card to the Host Controller using DAT lines, so we set Data Present Select (bit 5) in the Command register. The Host Controller is responsible for doing the verfication of tuning block sent by the card at the hardware level. After sending CMD19, we wait for Buffer Read Ready interrupt. In case we don't receive an interrupt after the specified timeout value, we fall back on fixed sampling clock by setting Execute Tuning (bit 6) and Sampling Clock Select (bit 7) of Host Control2 register to 0. Before exiting the tuning procedure, we disable Buffer Read Ready interrupt and re-enable other interrupts. Tested by Zhangfei Gao with a Toshiba uhs card and general hs card, on mmp2 in SDMA mode. Signed-off-by: Arindam Nath <arindam.nath@amd.com> Reviewed-by: Philip Rakity <prakity@marvell.com> Tested-by: Philip Rakity <prakity@marvell.com> Acked-by: Zhangfei Gao <zhangfei.gao@marvell.com> Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc/host/sdhci.c')
-rw-r--r--drivers/mmc/host/sdhci.c168
1 files changed, 167 insertions, 1 deletions
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 2a15aad2eba5..8a56eacea34d 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
41static unsigned int debug_quirks = 0; 43static unsigned int debug_quirks = 0;
42 44
43static void sdhci_finish_data(struct sdhci_host *); 45static 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
1508static 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
1644out:
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
1504static const struct mmc_host_ops sdhci_ops = { 1652static 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)