[PATCH 7/8] intel_mid_ssp_spi: Bounce data through the Langwell SRAMwhen needed

From: Alan Cox
Date: Wed Feb 09 2011 - 05:38:18 EST


From: Alan Cox <alan@xxxxxxxxxxxxxxx>

This is required for Moorestown slave mode operation

Based on earlier generic driver work by Mathieu SOULARD
<mathieux.soulard@xxxxxxxxx>

Signed-off-by: Alan Cox <alan@xxxxxxxxxxxxxxx>
---

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)

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/