brcm2708: update patches to latest version
[openwrt/svn-archive/archive.git] / target / linux / brcm2708 / patches-4.4 / 0176-bcm2835-mmc-Only-claim-one-DMA-channel.patch
diff --git a/target/linux/brcm2708/patches-4.4/0176-bcm2835-mmc-Only-claim-one-DMA-channel.patch b/target/linux/brcm2708/patches-4.4/0176-bcm2835-mmc-Only-claim-one-DMA-channel.patch
new file mode 100644 (file)
index 0000000..8f224fa
--- /dev/null
@@ -0,0 +1,170 @@
+From af80d75abc7604cd9eb1788b0171148d000db09d Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Tue, 8 Mar 2016 09:49:16 +0000
+Subject: [PATCH 176/180] bcm2835-mmc: Only claim one DMA channel
+
+With both MMC controllers enabled there are few DMA channels left. The
+bcm2835-mmc driver only uses DMA in one direction at a time, so it
+doesn't need to claim two channels.
+
+See: https://github.com/raspberrypi/linux/issues/1327
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/bcm2708_common.dtsi |  5 +--
+ drivers/mmc/host/bcm2835-mmc.c        | 69 +++++++++++++++++++++++++----------
+ 2 files changed, 51 insertions(+), 23 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm2708_common.dtsi
++++ b/arch/arm/boot/dts/bcm2708_common.dtsi
+@@ -232,9 +232,8 @@
+                       reg = <0x7e300000 0x100>;
+                       interrupts = <2 30>;
+                       clocks = <&clk_mmc>;
+-                      dmas = <&dma 11>,
+-                             <&dma 11>;
+-                      dma-names = "tx", "rx";
++                      dmas = <&dma 11>;
++                      dma-names = "rx-tx";
+                       brcm,overclock-50 = <0>;
+                       status = "disabled";
+               };
+--- a/drivers/mmc/host/bcm2835-mmc.c
++++ b/drivers/mmc/host/bcm2835-mmc.c
+@@ -108,8 +108,9 @@ struct bcm2835_host {
+       u32                                             shadow;
+       /*DMA part*/
+-      struct dma_chan                 *dma_chan_rx;           /* DMA channel for reads */
+-      struct dma_chan                 *dma_chan_tx;           /* DMA channel for writes */
++      struct dma_chan                 *dma_chan_rxtx;         /* DMA channel for reads and writes */
++      struct dma_slave_config         dma_cfg_rx;
++      struct dma_slave_config         dma_cfg_tx;
+       struct dma_async_tx_descriptor  *tx_desc;       /* descriptor */
+       bool                                    have_dma;
+@@ -342,7 +343,7 @@ static void bcm2835_mmc_dma_complete(voi
+       if (host->data && !(host->data->flags & MMC_DATA_WRITE)) {
+               /* otherwise handled in SDHCI IRQ */
+-              dma_chan = host->dma_chan_rx;
++              dma_chan = host->dma_chan_rxtx;
+               dir_data = DMA_FROM_DEVICE;
+               dma_unmap_sg(dma_chan->device->dev,
+@@ -493,16 +494,21 @@ static void bcm2835_mmc_transfer_dma(str
+       if (host->blocks == 0)
+               return;
++      dma_chan = host->dma_chan_rxtx;
+       if (host->data->flags & MMC_DATA_READ) {
+-              dma_chan = host->dma_chan_rx;
+               dir_data = DMA_FROM_DEVICE;
+               dir_slave = DMA_DEV_TO_MEM;
+       } else {
+-              dma_chan = host->dma_chan_tx;
+               dir_data = DMA_TO_DEVICE;
+               dir_slave = DMA_MEM_TO_DEV;
+       }
++      /* The parameters have already been validated, so this will not fail */
++      (void)dmaengine_slave_config(dma_chan,
++                                   (dir_data == DMA_FROM_DEVICE) ?
++                                   &host->dma_cfg_rx :
++                                   &host->dma_cfg_tx);
++
+       BUG_ON(!dma_chan->device);
+       BUG_ON(!dma_chan->device->dev);
+       BUG_ON(!host->data->sg);
+@@ -936,7 +942,7 @@ static void bcm2835_mmc_data_irq(struct
+               if  (host->data->flags & MMC_DATA_WRITE) {
+                       /* IRQ handled here */
+-                      dma_chan = host->dma_chan_tx;
++                      dma_chan = host->dma_chan_rxtx;
+                       dir_data = DMA_TO_DEVICE;
+                       dma_unmap_sg(dma_chan->device->dev,
+                                host->data->sg, host->data->sg_len,
+@@ -1316,28 +1322,47 @@ static int bcm2835_mmc_add_host(struct b
+       dev_info(dev, "Forcing PIO mode\n");
+       host->have_dma = false;
+ #else
+-      if (IS_ERR_OR_NULL(host->dma_chan_tx) ||
+-          IS_ERR_OR_NULL(host->dma_chan_rx)) {
+-              dev_err(dev, "%s: Unable to initialise DMA channels. Falling back to PIO\n",
++      if (IS_ERR_OR_NULL(host->dma_chan_rxtx)) {
++              dev_err(dev, "%s: Unable to initialise DMA channel. Falling back to PIO\n",
+                       DRIVER_NAME);
+               host->have_dma = false;
+       } else {
+-              dev_info(dev, "DMA channels allocated");
+-              host->have_dma = true;
++              dev_info(dev, "DMA channel allocated");
+               cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+               cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+               cfg.slave_id = 11;              /* DREQ channel */
++              /* Validate the slave configurations */
++
+               cfg.direction = DMA_MEM_TO_DEV;
+               cfg.src_addr = 0;
+               cfg.dst_addr = host->bus_addr + SDHCI_BUFFER;
+-              ret = dmaengine_slave_config(host->dma_chan_tx, &cfg);
+-              cfg.direction = DMA_DEV_TO_MEM;
+-              cfg.src_addr = host->bus_addr + SDHCI_BUFFER;
+-              cfg.dst_addr = 0;
+-              ret = dmaengine_slave_config(host->dma_chan_rx, &cfg);
++              ret = dmaengine_slave_config(host->dma_chan_rxtx, &cfg);
++
++              if (ret == 0) {
++                      host->dma_cfg_tx = cfg;
++
++                      cfg.direction = DMA_DEV_TO_MEM;
++                      cfg.src_addr = host->bus_addr + SDHCI_BUFFER;
++                      cfg.dst_addr = 0;
++
++                      ret = dmaengine_slave_config(host->dma_chan_rxtx, &cfg);
++              }
++
++              if (ret == 0) {
++                      host->dma_cfg_rx = cfg;
++
++                      host->use_dma = true;
++              } else {
++                      pr_err("%s: unable to configure DMA channel. "
++                             "Faling back to PIO\n",
++                             mmc_hostname(mmc));
++                      dma_release_channel(host->dma_chan_rxtx);
++                      host->dma_chan_rxtx = NULL;
++                      host->use_dma = false;
++              }
+       }
+ #endif
+       mmc->max_segs = 128;
+@@ -1416,16 +1441,20 @@ static int bcm2835_mmc_probe(struct plat
+ #ifndef FORCE_PIO
+       if (node) {
+-              host->dma_chan_tx = dma_request_slave_channel(dev, "tx");
+-              host->dma_chan_rx = dma_request_slave_channel(dev, "rx");
++              host->dma_chan_rxtx = dma_request_slave_channel(dev, "rx-tx");
++              if (!host->dma_chan_rxtx)
++                      host->dma_chan_rxtx =
++                              dma_request_slave_channel(dev, "tx");
++              if (!host->dma_chan_rxtx)
++                      host->dma_chan_rxtx =
++                              dma_request_slave_channel(dev, "rx");
+       } else {
+               dma_cap_mask_t mask;
+               dma_cap_zero(mask);
+               /* we don't care about the channel, any would work */
+               dma_cap_set(DMA_SLAVE, mask);
+-              host->dma_chan_tx = dma_request_channel(mask, NULL, NULL);
+-              host->dma_chan_rx = dma_request_channel(mask, NULL, NULL);
++              host->dma_chan_rxtx = dma_request_channel(mask, NULL, NULL);
+       }
+ #endif
+       clk = devm_clk_get(dev, NULL);