brcm2708: update against latest rpi-3.10.y branch
[15.05/openwrt.git] / target / linux / brcm2708 / patches-3.10 / 0026-Add-low-latency-mode-to-sdcard-driver.-Disable-with-.patch
diff --git a/target/linux/brcm2708/patches-3.10/0026-Add-low-latency-mode-to-sdcard-driver.-Disable-with-.patch b/target/linux/brcm2708/patches-3.10/0026-Add-low-latency-mode-to-sdcard-driver.-Disable-with-.patch
new file mode 100644 (file)
index 0000000..dfb61a6
--- /dev/null
@@ -0,0 +1,514 @@
+From fc153c5cb49f20f5e9644d92b8be064ed9159a16 Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Sun, 12 May 2013 12:27:48 +0100
+Subject: [PATCH 026/174] Add low-latency mode to sdcard driver. Disable with
+ sdhci-bcm2708.enable_llm=0. Thanks ddv2005.
+
+---
+ drivers/mmc/host/sdhci-bcm2708.c |  17 ++--
+ drivers/mmc/host/sdhci.c         | 165 ++++++++++++++++++++++++++++++---------
+ drivers/mmc/host/sdhci.h         |   6 ++
+ include/linux/mmc/sdhci.h        |   1 +
+ 4 files changed, 145 insertions(+), 44 deletions(-)
+
+--- a/drivers/mmc/host/sdhci-bcm2708.c
++++ b/drivers/mmc/host/sdhci-bcm2708.c
+@@ -135,6 +135,7 @@ static bool allow_highspeed = 1;
+ static int emmc_clock_freq = BCM2708_EMMC_CLOCK_FREQ;
+ static bool sync_after_dma = 1;
+ static bool missing_status = 1;
++bool enable_llm = 1;
+ #if 0
+ static void hptime_test(void)
+@@ -871,12 +872,11 @@ static irqreturn_t sdhci_bcm2708_dma_irq
+       struct sdhci_host *host = dev_id;
+       struct sdhci_bcm2708_priv *host_priv = SDHCI_HOST_PRIV(host);
+       u32 dma_cs; /* control and status register */
+-      unsigned long flags;
+       BUG_ON(NULL == dev_id);
+       BUG_ON(NULL == host_priv->dma_chan_base);
+-      spin_lock_irqsave(&host->lock, flags);
++      sdhci_spin_lock(host);
+       dma_cs = readl(host_priv->dma_chan_base + BCM2708_DMA_CS);
+@@ -917,8 +917,7 @@ static irqreturn_t sdhci_bcm2708_dma_irq
+               result = IRQ_HANDLED;
+       }
+-
+-      spin_unlock_irqrestore(&host->lock, flags);
++      sdhci_spin_unlock(host);
+       return result;
+ }
+@@ -1193,9 +1192,12 @@ static int sdhci_bcm2708_probe(struct pl
+               sdhci_bcm2708_ops.missing_status = sdhci_bcm2708_missing_status;
+       }
++      printk("sdhci: %s low-latency mode\n",enable_llm?"Enable":"Disable");
++
+       host->hw_name = "BCM2708_Arasan";
+       host->ops = &sdhci_bcm2708_ops;
+       host->irq = platform_get_irq(pdev, 0);
++      host->second_irq = 0;
+       host->quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION |
+                      SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
+@@ -1256,12 +1258,13 @@ static int sdhci_bcm2708_probe(struct pl
+       }
+       host_priv->dma_chan = ret;
+-      ret = request_irq(host_priv->dma_irq, sdhci_bcm2708_dma_irq,
+-                        IRQF_SHARED, DRIVER_NAME " (dma)", host);
++      ret = request_irq(host_priv->dma_irq, sdhci_bcm2708_dma_irq,0,//IRQF_SHARED,
++                        DRIVER_NAME " (dma)", host);
+       if (ret) {
+               dev_err(&pdev->dev, "cannot set DMA IRQ\n");
+               goto err_add_dma_irq;
+       }
++      host->second_irq = host_priv->dma_irq;
+       DBG("DMA CBs %p handle %08X DMA%d %p DMA IRQ %d\n",
+           host_priv->cb_base, (unsigned)host_priv->cb_handle,
+           host_priv->dma_chan, host_priv->dma_chan_base,
+@@ -1384,6 +1387,7 @@ module_param(allow_highspeed, bool, 0444
+ module_param(emmc_clock_freq, int, 0444);
+ module_param(sync_after_dma, bool, 0444);
+ module_param(missing_status, bool, 0444);
++module_param(enable_llm, bool, 0444);
+ MODULE_DESCRIPTION("Secure Digital Host Controller Interface platform driver");
+ MODULE_AUTHOR("Broadcom <info@broadcom.com>");
+@@ -1394,5 +1398,6 @@ MODULE_PARM_DESC(allow_highspeed, "Allow
+ MODULE_PARM_DESC(emmc_clock_freq, "Specify the speed of emmc clock");
+ MODULE_PARM_DESC(sync_after_dma, "Block in driver until dma complete");
+ MODULE_PARM_DESC(missing_status, "Use the missing status quirk");
++MODULE_PARM_DESC(enable_llm, "Enable low-latency mode");
+--- a/drivers/mmc/host/sdhci.c
++++ b/drivers/mmc/host/sdhci.c
+@@ -124,6 +124,91 @@ static void sdhci_dumpregs(struct sdhci_
+  * Low level functions                                                       *
+  *                                                                           *
+ \*****************************************************************************/
++extern bool enable_llm;
++static int sdhci_locked=0;
++void sdhci_spin_lock(struct sdhci_host *host)
++{
++      spin_lock(&host->lock);
++#ifdef CONFIG_PREEMPT
++      if(enable_llm)
++      {
++              disable_irq_nosync(host->irq);
++              if(host->second_irq)
++                      disable_irq_nosync(host->second_irq);
++              local_irq_enable();
++      }
++#endif
++}
++
++void sdhci_spin_unlock(struct sdhci_host *host)
++{
++#ifdef CONFIG_PREEMPT
++      if(enable_llm)
++      {
++              local_irq_disable();
++              if(host->second_irq)
++                      enable_irq(host->second_irq);
++              enable_irq(host->irq);
++      }
++#endif
++      spin_unlock(&host->lock);
++}
++
++void sdhci_spin_lock_irqsave(struct sdhci_host *host,unsigned long *flags)
++{
++#ifdef CONFIG_PREEMPT
++      if(enable_llm)
++      {
++              while(sdhci_locked)
++              {
++                      preempt_schedule();
++              }
++              spin_lock_irqsave(&host->lock,*flags);
++              disable_irq(host->irq);
++              if(host->second_irq)
++                      disable_irq(host->second_irq);
++              local_irq_enable();
++      }
++      else
++#endif
++              spin_lock_irqsave(&host->lock,*flags);
++}
++
++void sdhci_spin_unlock_irqrestore(struct sdhci_host *host,unsigned long flags)
++{
++#ifdef CONFIG_PREEMPT
++      if(enable_llm)
++      {
++              local_irq_disable();
++              if(host->second_irq)
++                      enable_irq(host->second_irq);
++              enable_irq(host->irq);
++      }
++#endif
++      spin_unlock_irqrestore(&host->lock,flags);
++}
++
++static void sdhci_spin_enable_schedule(struct sdhci_host *host)
++{
++#ifdef CONFIG_PREEMPT
++      if(enable_llm)
++      {
++              sdhci_locked = 1;
++              preempt_enable();
++      }
++#endif
++}
++
++static void sdhci_spin_disable_schedule(struct sdhci_host *host)
++{
++#ifdef CONFIG_PREEMPT
++      if(enable_llm)
++      {
++              preempt_disable();
++              sdhci_locked = 0;
++      }
++#endif
++}
+ static void sdhci_clear_set_irqs(struct sdhci_host *host, u32 clear, u32 set)
+ {
+@@ -289,7 +374,7 @@ static void sdhci_led_control(struct led
+       struct sdhci_host *host = container_of(led, struct sdhci_host, led);
+       unsigned long flags;
+-      spin_lock_irqsave(&host->lock, flags);
++      sdhci_spin_lock_irqsave(host, &flags);
+       if (host->runtime_suspended)
+               goto out;
+@@ -299,7 +384,7 @@ static void sdhci_led_control(struct led
+       else
+               sdhci_activate_led(host);
+ out:
+-      spin_unlock_irqrestore(&host->lock, flags);
++      sdhci_spin_unlock_irqrestore(host, flags);
+ }
+ #endif
+@@ -1007,7 +1092,9 @@ static void sdhci_send_command(struct sd
+                       return;
+               }
+               timeout--;
++              sdhci_spin_enable_schedule(host);
+               mdelay(1);
++              sdhci_spin_disable_schedule(host);
+       }
+       DBG("send cmd %d - wait 0x%X irq 0x%x\n", cmd->opcode, mask,
+           sdhci_readl(host, SDHCI_INT_STATUS));
+@@ -1234,7 +1321,9 @@ clock_set:
+                       return;
+               }
+               timeout--;
++              sdhci_spin_enable_schedule(host);
+               mdelay(1);
++              sdhci_spin_disable_schedule(host);
+       }
+       clk |= SDHCI_CLOCK_CARD_EN;
+@@ -1330,7 +1419,7 @@ static void sdhci_request(struct mmc_hos
+       sdhci_runtime_pm_get(host);
+-      spin_lock_irqsave(&host->lock, flags);
++      sdhci_spin_lock_irqsave(host, &flags);
+       WARN_ON(host->mrq != NULL);
+@@ -1388,9 +1477,9 @@ static void sdhci_request(struct mmc_hos
+                                       mmc->card->type == MMC_TYPE_MMC ?
+                                       MMC_SEND_TUNING_BLOCK_HS200 :
+                                       MMC_SEND_TUNING_BLOCK;
+-                              spin_unlock_irqrestore(&host->lock, flags);
++                              sdhci_spin_unlock_irqrestore(host, flags);
+                               sdhci_execute_tuning(mmc, tuning_opcode);
+-                              spin_lock_irqsave(&host->lock, flags);
++                              sdhci_spin_lock_irqsave(host, &flags);
+                               /* Restore original mmc_request structure */
+                               host->mrq = mrq;
+@@ -1404,7 +1493,7 @@ static void sdhci_request(struct mmc_hos
+       }
+       mmiowb();
+-      spin_unlock_irqrestore(&host->lock, flags);
++      sdhci_spin_unlock_irqrestore(host, flags);
+ }
+ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
+@@ -1413,10 +1502,10 @@ static void sdhci_do_set_ios(struct sdhc
+       int vdd_bit = -1;
+       u8 ctrl;
+-      spin_lock_irqsave(&host->lock, flags);
++      sdhci_spin_lock_irqsave(host, &flags);
+       if (host->flags & SDHCI_DEVICE_DEAD) {
+-              spin_unlock_irqrestore(&host->lock, flags);
++              sdhci_spin_unlock_irqrestore(host, flags);
+               if (host->vmmc && ios->power_mode == MMC_POWER_OFF)
+                       mmc_regulator_set_ocr(host->mmc, host->vmmc, 0);
+               return;
+@@ -1443,9 +1532,9 @@ static void sdhci_do_set_ios(struct sdhc
+               vdd_bit = sdhci_set_power(host, ios->vdd);
+       if (host->vmmc && vdd_bit != -1) {
+-              spin_unlock_irqrestore(&host->lock, flags);
++              sdhci_spin_unlock_irqrestore(host, flags);
+               mmc_regulator_set_ocr(host->mmc, host->vmmc, vdd_bit);
+-              spin_lock_irqsave(&host->lock, flags);
++              sdhci_spin_lock_irqsave(host, &flags);
+       }
+       if (host->ops->platform_send_init_74_clocks)
+@@ -1583,7 +1672,7 @@ static void sdhci_do_set_ios(struct sdhc
+               sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
+       mmiowb();
+-      spin_unlock_irqrestore(&host->lock, flags);
++      sdhci_spin_unlock_irqrestore(host, flags);
+ }
+ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+@@ -1631,7 +1720,7 @@ static int sdhci_check_ro(struct sdhci_h
+       unsigned long flags;
+       int is_readonly;
+-      spin_lock_irqsave(&host->lock, flags);
++      sdhci_spin_lock_irqsave(host, &flags);
+       if (host->flags & SDHCI_DEVICE_DEAD)
+               is_readonly = 0;
+@@ -1641,7 +1730,7 @@ static int sdhci_check_ro(struct sdhci_h
+               is_readonly = !(sdhci_readl(host, SDHCI_PRESENT_STATE)
+                               & SDHCI_WRITE_PROTECT);
+-      spin_unlock_irqrestore(&host->lock, flags);
++      sdhci_spin_unlock_irqrestore(host, flags);
+       /* This quirk needs to be replaced by a callback-function later */
+       return host->quirks & SDHCI_QUIRK_INVERTED_WRITE_PROTECT ?
+@@ -1714,9 +1803,9 @@ static void sdhci_enable_sdio_irq(struct
+       struct sdhci_host *host = mmc_priv(mmc);
+       unsigned long flags;
+-      spin_lock_irqsave(&host->lock, flags);
++      sdhci_spin_lock_irqsave(host, &flags);
+       sdhci_enable_sdio_irq_nolock(host, enable);
+-      spin_unlock_irqrestore(&host->lock, flags);
++      sdhci_spin_unlock_irqrestore(host, flags);
+ }
+ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
+@@ -2060,7 +2149,7 @@ static void sdhci_card_event(struct mmc_
+       struct sdhci_host *host = mmc_priv(mmc);
+       unsigned long flags;
+-      spin_lock_irqsave(&host->lock, flags);
++      sdhci_spin_lock_irqsave(host, &flags);
+       /* Check host->mrq first in case we are runtime suspended */
+       if (host->mrq &&
+@@ -2077,7 +2166,7 @@ static void sdhci_card_event(struct mmc_
+               tasklet_schedule(&host->finish_tasklet);
+       }
+-      spin_unlock_irqrestore(&host->lock, flags);
++      sdhci_spin_unlock_irqrestore(host, flags);
+ }
+ static const struct mmc_host_ops sdhci_ops = {
+@@ -2116,14 +2205,14 @@ static void sdhci_tasklet_finish(unsigne
+       host = (struct sdhci_host*)param;
+-      spin_lock_irqsave(&host->lock, flags);
++      sdhci_spin_lock_irqsave(host, &flags);
+         /*
+          * If this tasklet gets rescheduled while running, it will
+          * be run again afterwards but without any active request.
+          */
+       if (!host->mrq) {
+-              spin_unlock_irqrestore(&host->lock, flags);
++              sdhci_spin_unlock_irqrestore(host, flags);
+               return;
+       }
+@@ -2161,7 +2250,7 @@ static void sdhci_tasklet_finish(unsigne
+ #endif
+       mmiowb();
+-      spin_unlock_irqrestore(&host->lock, flags);
++      sdhci_spin_unlock_irqrestore(host, flags);
+       mmc_request_done(host->mmc, mrq);
+       sdhci_runtime_pm_put(host);
+@@ -2174,7 +2263,7 @@ static void sdhci_timeout_timer(unsigned
+       host = (struct sdhci_host*)data;
+-      spin_lock_irqsave(&host->lock, flags);
++      sdhci_spin_lock_irqsave(host, &flags);
+       if (host->mrq) {
+               pr_err("%s: Timeout waiting for hardware "
+@@ -2195,7 +2284,7 @@ static void sdhci_timeout_timer(unsigned
+       }
+       mmiowb();
+-      spin_unlock_irqrestore(&host->lock, flags);
++      sdhci_spin_unlock_irqrestore(host, flags);
+ }
+ static void sdhci_tuning_timer(unsigned long data)
+@@ -2205,11 +2294,11 @@ static void sdhci_tuning_timer(unsigned
+       host = (struct sdhci_host *)data;
+-      spin_lock_irqsave(&host->lock, flags);
++      sdhci_spin_lock_irqsave(host, &flags);
+       host->flags |= SDHCI_NEEDS_RETUNING;
+-      spin_unlock_irqrestore(&host->lock, flags);
++      sdhci_spin_unlock_irqrestore(host, flags);
+ }
+ /*****************************************************************************\
+@@ -2433,10 +2522,10 @@ static irqreturn_t sdhci_irq(int irq, vo
+       u32 intmask, unexpected = 0;
+       int cardint = 0, max_loops = 16;
+-      spin_lock(&host->lock);
++      sdhci_spin_lock(host);
+       if (host->runtime_suspended) {
+-              spin_unlock(&host->lock);
++              sdhci_spin_unlock(host);
+               pr_warning("%s: got irq while runtime suspended\n",
+                      mmc_hostname(host->mmc));
+               return IRQ_HANDLED;
+@@ -2540,7 +2629,7 @@ again:
+       if (intmask && --max_loops)
+               goto again;
+ out:
+-      spin_unlock(&host->lock);
++      sdhci_spin_unlock(host);
+       if (unexpected) {
+               pr_err("%s: Unexpected interrupt 0x%08x.\n",
+@@ -2702,15 +2791,15 @@ int sdhci_runtime_suspend_host(struct sd
+               host->flags &= ~SDHCI_NEEDS_RETUNING;
+       }
+-      spin_lock_irqsave(&host->lock, flags);
++      sdhci_spin_lock_irqsave(host, &flags);
+       sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
+-      spin_unlock_irqrestore(&host->lock, flags);
++      sdhci_spin_unlock_irqrestore(host, flags);
+       synchronize_irq(host->irq);
+-      spin_lock_irqsave(&host->lock, flags);
++      sdhci_spin_lock_irqsave(host, &flags);
+       host->runtime_suspended = true;
+-      spin_unlock_irqrestore(&host->lock, flags);
++      sdhci_spin_unlock_irqrestore(host, flags);
+       return ret;
+ }
+@@ -2736,16 +2825,16 @@ int sdhci_runtime_resume_host(struct sdh
+       sdhci_do_start_signal_voltage_switch(host, &host->mmc->ios);
+       if ((host_flags & SDHCI_PV_ENABLED) &&
+               !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN)) {
+-              spin_lock_irqsave(&host->lock, flags);
++              sdhci_spin_lock_irqsave(host, &flags);
+               sdhci_enable_preset_value(host, true);
+-              spin_unlock_irqrestore(&host->lock, flags);
++              sdhci_spin_unlock_irqrestore(host, flags);
+       }
+       /* Set the re-tuning expiration flag */
+       if (host->flags & SDHCI_USING_RETUNING_TIMER)
+               host->flags |= SDHCI_NEEDS_RETUNING;
+-      spin_lock_irqsave(&host->lock, flags);
++      sdhci_spin_lock_irqsave(host, &flags);
+       host->runtime_suspended = false;
+@@ -2756,7 +2845,7 @@ int sdhci_runtime_resume_host(struct sdh
+       /* Enable Card Detection */
+       sdhci_enable_card_detection(host);
+-      spin_unlock_irqrestore(&host->lock, flags);
++      sdhci_spin_unlock_irqrestore(host, flags);
+       return ret;
+ }
+@@ -3248,7 +3337,7 @@ int sdhci_add_host(struct sdhci_host *ho
+               host->tuning_timer.function = sdhci_tuning_timer;
+       }
+-      ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,
++      ret = request_irq(host->irq, sdhci_irq, 0,//IRQF_SHARED,
+               mmc_hostname(mmc), host);
+       if (ret) {
+               pr_err("%s: Failed to request IRQ %d: %d\n",
+@@ -3312,7 +3401,7 @@ void sdhci_remove_host(struct sdhci_host
+       unsigned long flags;
+       if (dead) {
+-              spin_lock_irqsave(&host->lock, flags);
++              sdhci_spin_lock_irqsave(host, &flags);
+               host->flags |= SDHCI_DEVICE_DEAD;
+@@ -3324,7 +3413,7 @@ void sdhci_remove_host(struct sdhci_host
+                       tasklet_schedule(&host->finish_tasklet);
+               }
+-              spin_unlock_irqrestore(&host->lock, flags);
++              sdhci_spin_unlock_irqrestore(host, flags);
+       }
+       sdhci_disable_card_detection(host);
+--- a/drivers/mmc/host/sdhci.h
++++ b/drivers/mmc/host/sdhci.h
+@@ -441,4 +441,10 @@ extern int sdhci_runtime_suspend_host(st
+ extern int sdhci_runtime_resume_host(struct sdhci_host *host);
+ #endif
++extern void sdhci_spin_lock_irqsave(struct sdhci_host *host,unsigned long *flags);
++extern void sdhci_spin_unlock_irqrestore(struct sdhci_host *host,unsigned long flags);
++extern void sdhci_spin_lock(struct sdhci_host *host);
++extern void sdhci_spin_unlock(struct sdhci_host *host);
++
++
+ #endif /* __SDHCI_HW_H */
+--- a/include/linux/mmc/sdhci.h
++++ b/include/linux/mmc/sdhci.h
+@@ -97,6 +97,7 @@ struct sdhci_host {
+ #define SDHCI_QUIRK2_PRESET_VALUE_BROKEN              (1<<3)
+       int irq;                /* Device IRQ */
++      int second_irq;         /* Additional IRQ to disable/enable in low-latency mode */
+       void __iomem *ioaddr;   /* Mapped address */
+       const struct sdhci_ops *ops;    /* Low level hw interface */