linux-spi.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Alan Cox <alan@lxorguk.ukuu.org.uk>
To: spi-devel-general@lists.sourceforge.net, russ.gorby@intel.com,
	grant.likely@secretlab.ca, linux-kernel@vger.kernel.org
Subject: [PATCH 7/8] intel_mid_ssp_spi: Bounce data through the Langwell SRAM when needed
Date: Wed, 09 Feb 2011 10:09:22 +0000	[thread overview]
Message-ID: <20110209100918.555.28252.stgit@bob.linux.org.uk> (raw)
In-Reply-To: <20110209100231.555.90520.stgit@bob.linux.org.uk>

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

This is required for Moorestown slave mode operation

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

Signed-off-by: Alan Cox <alan@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)

  parent reply	other threads:[~2011-02-09 10:09 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-02-09 10:06 [PATCH 0/8] Intel MID SSP SPI merged driver Alan Cox
2011-02-09 10:07 ` [PATCH 1/8] Intel SPI master controller driver for the Medfield platform Alan Cox
2011-02-15  5:19   ` Grant Likely
2011-02-09 10:07 ` [PATCH 2/8] intel_mid_ssp_spi: Re-introduce quirks fields Alan Cox
2011-02-15  5:21   ` Grant Likely
2011-02-09 10:08 ` [PATCH 3/8] intel_mid_ssp_spi: Implement the MRST quirk Alan Cox
2011-02-09 10:08 ` [PATCH 4/8] intel_mid_ssp_spi: Add the uglies needed for Moorestown master mode Alan Cox
2011-02-09 10:08 ` [PATCH 5/8] intel_mid_ssp_spi: Add chip definitions Alan Cox
2011-02-09 10:09 ` [PATCH 6/8] intel_mid_ssp_spi: Add the QoS quirk for slave mode Alan Cox
2011-02-09 10:09 ` Alan Cox [this message]
2011-02-09 10:09 ` [PATCH 8/8] intel_mid_ssp_spi: Implement slave side quirk Alan Cox

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20110209100918.555.28252.stgit@bob.linux.org.uk \
    --to=alan@lxorguk.ukuu.org.uk \
    --cc=grant.likely@secretlab.ca \
    --cc=linux-kernel@vger.kernel.org \
    --cc=russ.gorby@intel.com \
    --cc=spi-devel-general@lists.sourceforge.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).