From: Alan Cox <a...@linux.intel.com>

This is required for Moorestown slave mode operation

Based on earlier generic driver work by Mathieu SOULARD
<mathieux.soul...@intel.com>

Signed-off-by: Alan Cox <a...@linux.intel.com>
---

 drivers/spi/intel_mid_ssp_spi.c     |  123 ++++++++++++++++++++++++++++++++++-
 drivers/spi/intel_mid_ssp_spi_def.h |    7 ++
 2 files changed, 125 insertions(+), 5 deletions(-)


diff --git a/drivers/spi/intel_mid_ssp_spi.c b/drivers/spi/intel_mid_ssp_spi.c
index 26e41c2..8d7a157 100644
--- a/drivers/spi/intel_mid_ssp_spi.c
+++ b/drivers/spi/intel_mid_ssp_spi.c
@@ -186,8 +186,11 @@ struct driver_data {
        int rxdma_done;
        struct callback_param tx_param;
        struct callback_param rx_param;
-       /* PM_QOS request (for Moorestown) */
+       /* PM_QOS request (for Moorestown slave) */
        struct pm_qos_request_list pm_qos_req;
+       /* Bounce buffers for DMA (Moorestown slave) */
+       u8 __iomem *virt_addr_sram_tx;
+       u8 __iomem *virt_addr_sram_rx;
 };
 
 struct chip_data {
@@ -414,6 +417,29 @@ static void unmap_dma_buffers(struct driver_data *drv_data,
        drv_data->dma_mapped = 0;
 }
 
+/**
+ * unmapcopy_dma_buffers() - Unmap the DMA buffers used during the last 
transfer.
+ * @drv_data:          Pointer to the private driver data
+ *
+ * Handle the buffer unmap when the data is being bounced through Langwell
+ * (Moorestown in slave mode)
+ */
+static void unmapcopy_dma_buffers(struct driver_data *drv_data,
+                             struct spi_message *msg)
+{
+       struct device *dev = &drv_data->pdev->dev;
+
+       if (unlikely(!drv_data->dma_mapped)) {
+               dev_err(dev, "ERROR : DMA buffers not mapped");
+               return;
+       }
+       if (unlikely(msg->is_dma_mapped))
+               return;
+
+       memcpy_fromio(drv_data->rx, drv_data->virt_addr_sram_rx, drv_data->len);
+       drv_data->dma_mapped = 0;
+}
+
 
 static void dma_transfer_complete(void *arg)
 {
@@ -450,7 +476,10 @@ static void dma_transfer_complete(void *arg)
                                                PM_QOS_DEFAULT_VALUE);
 
        /* release DMA mappings */
-       unmap_dma_buffers(drv_data, drv_data->cur_msg);
+       if (drv_data->quirks & QUIRKS_SRAM_ADDITIONAL_CPY)
+               unmapcopy_dma_buffers(drv_data, drv_data->cur_msg);
+       else
+               unmap_dma_buffers(drv_data, drv_data->cur_msg);
 
        /* Update total byte transfered return count actual bytes read */
        drv_data->cur_msg->actual_length = drv_data->len;
@@ -461,6 +490,40 @@ static void dma_transfer_complete(void *arg)
 }
 
 /**
+ * intel_mid_ssp_spi_map_sram() - Map SRAM
+ * @drv_data:          Pointer to the private driver data
+ *
+ * Map the Langwell SRAM used for bouncing on the Moorestown platform in
+ * slave mode.
+ */
+static int intel_mid_ssp_spi_map_sram(struct driver_data *drv_data)
+{
+       struct device *dev = &drv_data->pdev->dev;
+
+       drv_data->virt_addr_sram_rx = ioremap_nocache(SRAM_BASE_ADDR,
+                                               2 * MAX_SPI_TRANSFER_SIZE);
+       if (drv_data->virt_addr_sram_rx == NULL) {
+               dev_err(dev, "Virt_addr_sram_rx is null\n");
+               return -ENOMEM;
+       }
+       drv_data->virt_addr_sram_tx =
+               drv_data->virt_addr_sram_rx + MAX_SPI_TRANSFER_SIZE;
+       return 0;
+}
+
+/**
+ * intel_mid_ssp_spi_unmap_sram() - Map SRAM
+ * @drv_data:          Pointer to the private driver data
+ *
+ * Unmap the Langwell SRAM used for bouncing on the Moorestown platform in
+ * slave mode.
+ */
+static void intel_mid_ssp_spi_unmap_sram(struct driver_data *drv_data)
+{
+       iounmap(drv_data->virt_addr_sram_rx);
+}
+
+/**
  * intel_mid_ssp_spi_dma_init() - Initialize DMA
  * @drv_data:          Pointer to the private driver data
  *
@@ -486,6 +549,10 @@ static void intel_mid_ssp_spi_dma_init(struct driver_data 
*drv_data)
                return;
        }
 
+       if (drv_data->quirks & QUIRKS_SRAM_ADDITIONAL_CPY)
+               if (intel_mid_ssp_spi_map_sram(drv_data) < 0)
+                       return;
+
        /* 1. init rx channel */
        rxs = &drv_data->dmas_rx;
        rxs->hs_mode = LNW_DMA_HW_HS;
@@ -534,6 +601,9 @@ static void intel_mid_ssp_spi_dma_init(struct driver_data 
*drv_data)
 free_rxchan:
        dev_err(&drv_data->pdev->dev, "DMA TX Channel Not available");
        dma_release_channel(drv_data->rxchan);
+       if (drv_data->quirks & QUIRKS_SRAM_ADDITIONAL_CPY)
+               intel_mid_ssp_spi_unmap_sram(drv_data);
+               
 err_exit:
        dev_err(&drv_data->pdev->dev, "DMA RX Channel Not available");
        pci_dev_put(drv_data->dmac1);
@@ -549,6 +619,8 @@ static void intel_mid_ssp_spi_dma_exit(struct driver_data 
*drv_data)
                return;
        dma_release_channel(drv_data->txchan);
        dma_release_channel(drv_data->rxchan);
+       if (drv_data->quirks & QUIRKS_SRAM_ADDITIONAL_CPY)
+               intel_mid_ssp_spi_unmap_sram(drv_data);
        pci_dev_put(drv_data->dmac1);
        drv_data->dma_inited = 0;
 }
@@ -667,6 +739,42 @@ static int map_dma_buffers(struct driver_data *drv_data,
        return 1;
 }
 
+/**
+ * mapcopy_dma_buffers() - Map DMA buffer before a transfer
+ * @drv_data:          Pointer to the private driver data
+ *
+ * Copy the data buffer into SRAM and then set that for DMA
+ */
+static int mapcopy_dma_buffers(struct driver_data *drv_data,
+                          struct spi_message *msg,
+                          struct spi_transfer *transfer)
+{
+       struct device *dev = &drv_data->pdev->dev;
+
+       if (unlikely(drv_data->dma_mapped)) {
+               dev_err(dev, "ERROR : DMA buffers already mapped");
+               return 0;
+       }
+       if (unlikely(msg->is_dma_mapped)) {
+               drv_data->rx_dma = transfer->rx_dma;
+               drv_data->tx_dma = transfer->tx_dma;
+               return 1;
+       }
+       if (drv_data->len > PCI_DMAC_MAXDI * drv_data->n_bytes) {
+               /* if length is too long we revert to programmed I/O */
+               return 0;
+       }
+
+       if (likely(drv_data->rx))
+               drv_data->rx_dma = SRAM_RX_ADDR;
+       if (likely(drv_data->tx)) {
+               memcpy_toio(drv_data->virt_addr_sram_tx, drv_data->tx,
+                       drv_data->len);
+               drv_data->tx_dma = SRAM_TX_ADDR;
+       }
+       return 1;
+}
+
 static void set_dma_width(struct driver_data *drv_data, int bits)
 {
        struct dma_slave_config *rxconf, *txconf;
@@ -1017,9 +1125,14 @@ static int transfer(struct spi_device *spi, struct 
spi_message *msg)
        }
 
        /* try to map dma buffer and do a dma transfer if successful */
-       if (likely(chip->enable_dma))
-               drv_data->dma_mapped = map_dma_buffers(drv_data, msg, transfer);
-       else {
+       if (likely(chip->enable_dma)) {
+               if (drv_data->quirks & QUIRKS_SRAM_ADDITIONAL_CPY)
+                       drv_data->dma_mapped = mapcopy_dma_buffers(drv_data,
+                                                               msg, transfer);
+               else
+                       drv_data->dma_mapped = map_dma_buffers(drv_data,
+                                                               msg, transfer);
+       } else {
                WARN_ON(drv_data->dma_mapped != 0);
                drv_data->dma_mapped = 0;
        }
diff --git a/drivers/spi/intel_mid_ssp_spi_def.h 
b/drivers/spi/intel_mid_ssp_spi_def.h
index 88d872b..8c4d6e7 100644
--- a/drivers/spi/intel_mid_ssp_spi_def.h
+++ b/drivers/spi/intel_mid_ssp_spi_def.h
@@ -117,6 +117,13 @@
 #define SSPSP  0x2c
 #define SYSCFG 0x20bc0
 
+/* Needed for slave mode on Moorestown. There is no neat architectural way to
+   get these values but they won't change */
+#define SRAM_BASE_ADDR 0xfffdc000
+#define MAX_SPI_TRANSFER_SIZE 8192
+#define SRAM_RX_ADDR   SRAM_BASE_ADDR
+#define SRAM_TX_ADDR  (SRAM_BASE_ADDR + MAX_SPI_TRANSFER_SIZE)
+
 /* SSP assignement configuration from PCI config */
 #define SSP_CFG_GET_MODE(ssp_cfg)      ((ssp_cfg) & 0x07)
 #define SSP_CFG_GET_SPI_BUS_NB(ssp_cfg)        (((ssp_cfg) >> 3) & 0x07)


------------------------------------------------------------------------------
The ultimate all-in-one performance toolkit: Intel(R) Parallel Studio XE:
Pinpoint memory and threading errors before they happen.
Find and fix more than 250 security defects in the development cycle.
Locate bottlenecks in serial and parallel code that limit performance.
http://p.sf.net/sfu/intel-dev2devfeb
_______________________________________________
spi-devel-general mailing list
spi-devel-general@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/spi-devel-general

Reply via email to