aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
authorArindam Nath <arindam.nath@amd.com>2011-05-05 02:49:07 -0400
committerChris Ball <cjb@laptop.org>2011-05-24 23:53:48 -0400
commitcf2b5eea1ea0ff9b3184bc6771bcb93a9fdcd1d9 (patch)
tree36288f760fb7556952f8365c3c0cad6b445b04f6 /drivers/mmc
parentc3ed3877625f10d600b0eca2ca48a68c46aed660 (diff)
mmc: sdhci: add support for retuning mode 1
Host Controller v3.00 can support retuning modes 1,2 or 3 depending on the bits 46-47 of the Capabilities register. Also, the timer count for retuning is indicated by bits 40-43 of the same register. We initialize timer_list for retuning the first time we execute tuning procedure. This condition is indicated by SDHCI_NEEDS_RETUNING not being set. Since retuning mode 1 sets a limit of 4MB on the maximum data length, we set max_blk_count appropriately. Once the tuning timer expires, we set SDHCI_NEEDS_RETUNING flag, and if the flag is set, we execute tuning procedure before sending the next command. We need to restore mmc_request structure after executing retuning procedure since host->mrq is used inside the procedure to send CMD19. We also disable and re-enable this flag during suspend and resume respectively, as per the spec v3.00. 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')
-rw-r--r--drivers/mmc/host/sdhci.c109
-rw-r--r--drivers/mmc/host/sdhci.h6
2 files changed, 112 insertions, 3 deletions
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 07cca557c4b5..fa3301644b15 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -46,6 +46,8 @@ static void sdhci_finish_data(struct sdhci_host *);
46 46
47static void sdhci_send_command(struct sdhci_host *, struct mmc_command *); 47static void sdhci_send_command(struct sdhci_host *, struct mmc_command *);
48static void sdhci_finish_command(struct sdhci_host *); 48static void sdhci_finish_command(struct sdhci_host *);
49static int sdhci_execute_tuning(struct mmc_host *mmc);
50static void sdhci_tuning_timer(unsigned long data);
49 51
50static void sdhci_dumpregs(struct sdhci_host *host) 52static void sdhci_dumpregs(struct sdhci_host *host)
51{ 53{
@@ -1206,8 +1208,27 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
1206 if (!present || host->flags & SDHCI_DEVICE_DEAD) { 1208 if (!present || host->flags & SDHCI_DEVICE_DEAD) {
1207 host->mrq->cmd->error = -ENOMEDIUM; 1209 host->mrq->cmd->error = -ENOMEDIUM;
1208 tasklet_schedule(&host->finish_tasklet); 1210 tasklet_schedule(&host->finish_tasklet);
1209 } else 1211 } else {
1212 u32 present_state;
1213
1214 present_state = sdhci_readl(host, SDHCI_PRESENT_STATE);
1215 /*
1216 * Check if the re-tuning timer has already expired and there
1217 * is no on-going data transfer. If so, we need to execute
1218 * tuning procedure before sending command.
1219 */
1220 if ((host->flags & SDHCI_NEEDS_RETUNING) &&
1221 !(present_state & (SDHCI_DOING_WRITE | SDHCI_DOING_READ))) {
1222 spin_unlock_irqrestore(&host->lock, flags);
1223 sdhci_execute_tuning(mmc);
1224 spin_lock_irqsave(&host->lock, flags);
1225
1226 /* Restore original mmc_request structure */
1227 host->mrq = mrq;
1228 }
1229
1210 sdhci_send_command(host, mrq->cmd); 1230 sdhci_send_command(host, mrq->cmd);
1231 }
1211 1232
1212 mmiowb(); 1233 mmiowb();
1213 spin_unlock_irqrestore(&host->lock, flags); 1234 spin_unlock_irqrestore(&host->lock, flags);
@@ -1673,6 +1694,37 @@ static int sdhci_execute_tuning(struct mmc_host *mmc)
1673 } 1694 }
1674 1695
1675out: 1696out:
1697 /*
1698 * If this is the very first time we are here, we start the retuning
1699 * timer. Since only during the first time, SDHCI_NEEDS_RETUNING
1700 * flag won't be set, we check this condition before actually starting
1701 * the timer.
1702 */
1703 if (!(host->flags & SDHCI_NEEDS_RETUNING) && host->tuning_count &&
1704 (host->tuning_mode == SDHCI_TUNING_MODE_1)) {
1705 mod_timer(&host->tuning_timer, jiffies +
1706 host->tuning_count * HZ);
1707 /* Tuning mode 1 limits the maximum data length to 4MB */
1708 mmc->max_blk_count = (4 * 1024 * 1024) / mmc->max_blk_size;
1709 } else {
1710 host->flags &= ~SDHCI_NEEDS_RETUNING;
1711 /* Reload the new initial value for timer */
1712 if (host->tuning_mode == SDHCI_TUNING_MODE_1)
1713 mod_timer(&host->tuning_timer, jiffies +
1714 host->tuning_count * HZ);
1715 }
1716
1717 /*
1718 * In case tuning fails, host controllers which support re-tuning can
1719 * try tuning again at a later time, when the re-tuning timer expires.
1720 * So for these controllers, we return 0. Since there might be other
1721 * controllers who do not have this capability, we return error for
1722 * them.
1723 */
1724 if (err && host->tuning_count &&
1725 host->tuning_mode == SDHCI_TUNING_MODE_1)
1726 err = 0;
1727
1676 sdhci_clear_set_irqs(host, SDHCI_INT_DATA_AVAIL, ier); 1728 sdhci_clear_set_irqs(host, SDHCI_INT_DATA_AVAIL, ier);
1677 spin_unlock(&host->lock); 1729 spin_unlock(&host->lock);
1678 enable_irq(host->irq); 1730 enable_irq(host->irq);
@@ -1775,6 +1827,9 @@ static void sdhci_tasklet_finish(unsigned long param)
1775 1827
1776 del_timer(&host->timer); 1828 del_timer(&host->timer);
1777 1829
1830 if (host->version >= SDHCI_SPEC_300)
1831 del_timer(&host->tuning_timer);
1832
1778 mrq = host->mrq; 1833 mrq = host->mrq;
1779 1834
1780 /* 1835 /*
@@ -1848,6 +1903,20 @@ static void sdhci_timeout_timer(unsigned long data)
1848 spin_unlock_irqrestore(&host->lock, flags); 1903 spin_unlock_irqrestore(&host->lock, flags);
1849} 1904}
1850 1905
1906static void sdhci_tuning_timer(unsigned long data)
1907{
1908 struct sdhci_host *host;
1909 unsigned long flags;
1910
1911 host = (struct sdhci_host *)data;
1912
1913 spin_lock_irqsave(&host->lock, flags);
1914
1915 host->flags |= SDHCI_NEEDS_RETUNING;
1916
1917 spin_unlock_irqrestore(&host->lock, flags);
1918}
1919
1851/*****************************************************************************\ 1920/*****************************************************************************\
1852 * * 1921 * *
1853 * Interrupt handling * 1922 * Interrupt handling *
@@ -2122,6 +2191,14 @@ int sdhci_suspend_host(struct sdhci_host *host, pm_message_t state)
2122 2191
2123 sdhci_disable_card_detection(host); 2192 sdhci_disable_card_detection(host);
2124 2193
2194 /* Disable tuning since we are suspending */
2195 if (host->version >= SDHCI_SPEC_300 && host->tuning_count &&
2196 host->tuning_mode == SDHCI_TUNING_MODE_1) {
2197 host->flags &= ~SDHCI_NEEDS_RETUNING;
2198 mod_timer(&host->tuning_timer, jiffies +
2199 host->tuning_count * HZ);
2200 }
2201
2125 ret = mmc_suspend_host(host->mmc); 2202 ret = mmc_suspend_host(host->mmc);
2126 if (ret) 2203 if (ret)
2127 return ret; 2204 return ret;
@@ -2163,6 +2240,11 @@ int sdhci_resume_host(struct sdhci_host *host)
2163 ret = mmc_resume_host(host->mmc); 2240 ret = mmc_resume_host(host->mmc);
2164 sdhci_enable_card_detection(host); 2241 sdhci_enable_card_detection(host);
2165 2242
2243 /* Set the re-tuning expiration flag */
2244 if ((host->version >= SDHCI_SPEC_300) && host->tuning_count &&
2245 (host->tuning_mode == SDHCI_TUNING_MODE_1))
2246 host->flags |= SDHCI_NEEDS_RETUNING;
2247
2166 return ret; 2248 return ret;
2167} 2249}
2168 2250
@@ -2414,6 +2496,21 @@ int sdhci_add_host(struct sdhci_host *host)
2414 if (caps[1] & SDHCI_DRIVER_TYPE_D) 2496 if (caps[1] & SDHCI_DRIVER_TYPE_D)
2415 mmc->caps |= MMC_CAP_DRIVER_TYPE_D; 2497 mmc->caps |= MMC_CAP_DRIVER_TYPE_D;
2416 2498
2499 /* Initial value for re-tuning timer count */
2500 host->tuning_count = (caps[1] & SDHCI_RETUNING_TIMER_COUNT_MASK) >>
2501 SDHCI_RETUNING_TIMER_COUNT_SHIFT;
2502
2503 /*
2504 * In case Re-tuning Timer is not disabled, the actual value of
2505 * re-tuning timer will be 2 ^ (n - 1).
2506 */
2507 if (host->tuning_count)
2508 host->tuning_count = 1 << (host->tuning_count - 1);
2509
2510 /* Re-tuning mode supported by the Host Controller */
2511 host->tuning_mode = (caps[1] & SDHCI_RETUNING_MODE_MASK) >>
2512 SDHCI_RETUNING_MODE_SHIFT;
2513
2417 ocr_avail = 0; 2514 ocr_avail = 0;
2418 /* 2515 /*
2419 * According to SD Host Controller spec v3.00, if the Host System 2516 * According to SD Host Controller spec v3.00, if the Host System
@@ -2559,9 +2656,15 @@ int sdhci_add_host(struct sdhci_host *host)
2559 2656
2560 setup_timer(&host->timer, sdhci_timeout_timer, (unsigned long)host); 2657 setup_timer(&host->timer, sdhci_timeout_timer, (unsigned long)host);
2561 2658
2562 if (host->version >= SDHCI_SPEC_300) 2659 if (host->version >= SDHCI_SPEC_300) {
2563 init_waitqueue_head(&host->buf_ready_int); 2660 init_waitqueue_head(&host->buf_ready_int);
2564 2661
2662 /* Initialize re-tuning timer */
2663 init_timer(&host->tuning_timer);
2664 host->tuning_timer.data = (unsigned long)host;
2665 host->tuning_timer.function = sdhci_tuning_timer;
2666 }
2667
2565 ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED, 2668 ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,
2566 mmc_hostname(mmc), host); 2669 mmc_hostname(mmc), host);
2567 if (ret) 2670 if (ret)
@@ -2655,6 +2758,8 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
2655 free_irq(host->irq, host); 2758 free_irq(host->irq, host);
2656 2759
2657 del_timer_sync(&host->timer); 2760 del_timer_sync(&host->timer);
2761 if (host->version >= SDHCI_SPEC_300)
2762 del_timer_sync(&host->tuning_timer);
2658 2763
2659 tasklet_kill(&host->card_tasklet); 2764 tasklet_kill(&host->card_tasklet);
2660 tasklet_kill(&host->finish_tasklet); 2765 tasklet_kill(&host->finish_tasklet);
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 6b0a0ee9ac6e..8ea11b7cf89a 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -191,7 +191,11 @@
191#define SDHCI_DRIVER_TYPE_A 0x00000010 191#define SDHCI_DRIVER_TYPE_A 0x00000010
192#define SDHCI_DRIVER_TYPE_C 0x00000020 192#define SDHCI_DRIVER_TYPE_C 0x00000020
193#define SDHCI_DRIVER_TYPE_D 0x00000040 193#define SDHCI_DRIVER_TYPE_D 0x00000040
194#define SDHCI_USE_SDR50_TUNING 0x00002000 194#define SDHCI_RETUNING_TIMER_COUNT_MASK 0x00000F00
195#define SDHCI_RETUNING_TIMER_COUNT_SHIFT 8
196#define SDHCI_USE_SDR50_TUNING 0x00002000
197#define SDHCI_RETUNING_MODE_MASK 0x0000C000
198#define SDHCI_RETUNING_MODE_SHIFT 14
195#define SDHCI_CLOCK_MUL_MASK 0x00FF0000 199#define SDHCI_CLOCK_MUL_MASK 0x00FF0000
196#define SDHCI_CLOCK_MUL_SHIFT 16 200#define SDHCI_CLOCK_MUL_SHIFT 16
197 201