diff mbox

[7/8] intel_mid_ssp_spi: Bounce data through the Langwell SRAM when needed

Message ID 20110209100918.555.28252.stgit@bob.linux.org.uk (mailing list archive)
State Superseded, archived
Headers show

Commit Message

Alan Cox Feb. 9, 2011, 10:09 a.m. UTC
None
diff mbox

Patch

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)