From: Grant Likely <grant.likely-s3s/WqlpOiPyB63q8FvJNQ@public.gmane.org>
To: Feng Tang <feng.tang-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
Cc: "Williams,
Dan J" <dan.j.williams-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>,
Alan Cox <alan-qBU/x9rampVanCEyBjwyrvXRex20P6io@public.gmane.org>,
spi mailing list
<spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
Subject: Re: [PATCH] dw_spi: add DMA support
Date: Thu, 23 Dec 2010 16:31:39 -0700 [thread overview]
Message-ID: <20101223233139.GQ20384@angua.secretlab.ca> (raw)
In-Reply-To: <20101123175331.3d7ed427@feng-i7>
On Tue, Nov 23, 2010 at 05:53:31PM +0800, Feng Tang wrote:
>
>
> On Tue, 23 Nov 2010 14:48:39 +0800
> Linus Walleij <linus.ml.walleij-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
>
> > This is much better than last time but I still have questions...
> >
> > 2010/11/18 Alan Cox <alan-qBU/x9rampVanCEyBjwyrvXRex20P6io@public.gmane.org>:
> >
> > > + /* 1. Init rx channel */
> > > + rxs = &dw_dma->dmas_rx;
> > > + ds = &rxs->dma_slave;
> > > + ds->direction = DMA_FROM_DEVICE;
> > > + rxs->hs_mode = LNW_DMA_HW_HS;
> > > + rxs->cfg_mode = LNW_DMA_PER_TO_MEM;
> > > + ds->src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
> > > + ds->dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
> > > + ds->src_maxburst = 16;
> > > + ds->dst_maxburst = 16;
> >
> > This is great stuff! That is exactly how ds is to be set up.
> > I would prefer that you don't dereference the this rxs thing here
> > but whatever.
> >
> > > + dma_cap_zero(mask);
> > > + dma_cap_set(DMA_MEMCPY, mask);
> > > + dma_cap_set(DMA_SLAVE, mask);
> >
> > This is not elegant. Are you going to do memcpy() or slave
> > transfers? What you want to do is fix your DMA engine so that
> > just asking for DMA_SLAVE works.
> >
> > > + dma_cap_set(DMA_SLAVE, mask);
> > > + dma_cap_set(DMA_MEMCPY, mask);
> >
> > Here again...
> >
> > > +static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change)
> > > +{
> > (...)
> > > + flag = DMA_PREP_INTERRUPT | DMA_CTRL_ACK;
> > > + if (dws->tx_dma) {
> > > + txdesc =
> > > txchan->device->device_prep_dma_memcpy(txchan,
> > > + dws->dma_addr, dws->tx_dma,
> > > + dws->len, flag);
> > > + txdesc->callback = dw_spi_dma_done;
> > > + txdesc->callback_param = &dws->tx_param;
> > > + }
> > > +
> > > + /* 3. start the RX dma transfer */
> > > + if (dws->rx_dma) {
> > > + rxdesc =
> > > rxchan->device->device_prep_dma_memcpy(rxchan,
> > > + dws->rx_dma, dws->dma_addr,
> > > + dws->len, flag);
> > > + rxdesc->callback = dw_spi_dma_done;
> > > + rxdesc->callback_param = &dws->rx_param;
> > > + }
> >
> > Using device_prep_dma_memcpy() for this is still nonsense, it should
> > be device_prep_slave_sg().
> >
> > I know the DMA driver needs fixing in order for this to work properly,
> > so why not fix it?
> >
> > These are the most important concerns I raised last iteration, so
> > I challenge you to fix drivers/dma/dw_dmac.c or wherever the real
> > problem sits.
> >
> > Can you describe where the problem with fixing this to use real
> > slave sglists is?
> >
> > Yours,
> > Linus Walleij
>
> Hi Linus,
>
> Thanks for the reviews, I made some dma change as you suggested, pls
> help to review.
>
> Thanks,
> Feng
>
> >From b77efc5945e31442b53b285d6a3f77def376ebb3 Mon Sep 17 00:00:00 2001
> From: Feng Tang <feng.tang-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
> Date: Tue, 23 Nov 2010 17:34:28 +0800
> Subject: [PATCH] spi/dw_spi: add DMA support
>
> dw_spi driver in upstream only supports PIO mode, and this patch
> will support it to cowork with the Designware DMA controller used
> on Intel Moorestown platform
>
> It has been tested with a Option GTM501L 3G modem, to use DMA mode,
> DMA controller 2 of Moorestown has to be enabled
>
> Signed-off-by: Feng Tang <feng.tang-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
> [Typo fix and renames to match intel_mid_dma renaming]
> Signed-off-by: Vinod Koul <vinod.koul-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
> [Clean up, change dma interface suggested by Linus Walleij]
> Signed-off-by: Feng Tang <feng.tang-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
> [Fix timing delay, add cpu_relax]
> Signed-off-by: Arjan van de Ven <arjan-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> Signed-off-by: Alan Cox <alan-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
Hi Feng, Alan.
Some relatively minor comments below, but they should be addressed
before merging. Particularly the EXPORT_SYMBOL --> EXPORT_SYMBOL_GPL
change. Once done, feel free to add my acked-by line and merge this
via the same tree as the dma controller changes to avoid merge
ordering issues. I don't think I need to rereview the next version if
it doesn't materially change.
Acked-by: Grant Likely <grant.likely-s3s/WqlpOiPyB63q8FvJNQ@public.gmane.org> (after addressing
comments)
> ---
> drivers/spi/Kconfig | 4 +
> drivers/spi/Makefile | 3 +-
> drivers/spi/dw_spi.c | 48 ++++++----
> drivers/spi/dw_spi_mid.c | 225 ++++++++++++++++++++++++++++++++++++++++++++
> drivers/spi/dw_spi_pci.c | 14 ++-
> include/linux/spi/dw_spi.h | 24 ++++-
> 6 files changed, 288 insertions(+), 30 deletions(-)
> create mode 100644 drivers/spi/dw_spi_mid.c
>
> diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
> index 78f9fd0..d53c830 100644
> --- a/drivers/spi/Kconfig
> +++ b/drivers/spi/Kconfig
> @@ -396,6 +396,10 @@ config SPI_DW_PCI
> tristate "PCI interface driver for DW SPI core"
> depends on SPI_DESIGNWARE && PCI
>
> +config SPI_DW_MID_DMA
> + bool "DMA support for DW SPI controller on Intel Moorestown platform"
> + depends on SPI_DW_PCI && INTEL_MID_DMAC
> +
> config SPI_DW_MMIO
> tristate "Memory-mapped io interface driver for DW SPI core"
> depends on SPI_DESIGNWARE && HAVE_CLK
> diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
> index 8bc1a5a..5e6e812 100644
> --- a/drivers/spi/Makefile
> +++ b/drivers/spi/Makefile
> @@ -17,7 +17,8 @@ obj-$(CONFIG_SPI_BUTTERFLY) += spi_butterfly.o
> obj-$(CONFIG_SPI_COLDFIRE_QSPI) += coldfire_qspi.o
> obj-$(CONFIG_SPI_DAVINCI) += davinci_spi.o
> obj-$(CONFIG_SPI_DESIGNWARE) += dw_spi.o
> -obj-$(CONFIG_SPI_DW_PCI) += dw_spi_pci.o
> +obj-$(CONFIG_SPI_DW_PCI) += dw_spi_midpci.o
> +dw_spi_midpci-objs := dw_spi_pci.o dw_spi_mid.o
> obj-$(CONFIG_SPI_DW_MMIO) += dw_spi_mmio.o
> obj-$(CONFIG_SPI_EP93XX) += ep93xx_spi.o
> obj-$(CONFIG_SPI_GPIO) += spi_gpio.o
> diff --git a/drivers/spi/dw_spi.c b/drivers/spi/dw_spi.c
> index 9043931..69cc223 100644
> --- a/drivers/spi/dw_spi.c
> +++ b/drivers/spi/dw_spi.c
> @@ -164,20 +164,23 @@ static inline void mrst_spi_debugfs_remove(struct dw_spi *dws)
>
> static void wait_till_not_busy(struct dw_spi *dws)
> {
> - unsigned long end = jiffies + 1 + usecs_to_jiffies(1000);
> + unsigned long end = jiffies + 1 + usecs_to_jiffies(5000);
>
> while (time_before(jiffies, end)) {
> if (!(dw_readw(dws, sr) & SR_BUSY))
> return;
> + cpu_relax();
> }
> dev_err(&dws->master->dev,
> - "DW SPI: Status keeps busy for 1000us after a read/write!\n");
> + "DW SPI: Status keeps busy for 5000us after a read/write!\n");
> }
>
> static void flush(struct dw_spi *dws)
> {
> - while (dw_readw(dws, sr) & SR_RF_NOT_EMPT)
> + while (dw_readw(dws, sr) & SR_RF_NOT_EMPT) {
> dw_readw(dws, dr);
> + cpu_relax();
> + }
>
> wait_till_not_busy(dws);
> }
> @@ -285,8 +288,10 @@ static void *next_transfer(struct dw_spi *dws)
> */
> static int map_dma_buffers(struct dw_spi *dws)
> {
> - if (!dws->cur_msg->is_dma_mapped || !dws->dma_inited
> - || !dws->cur_chip->enable_dma)
> + if (!dws->cur_msg->is_dma_mapped
> + || !dws->dma_inited
> + || !dws->cur_chip->enable_dma
> + || !dws->dma_ops)
> return 0;
>
> if (dws->cur_transfer->tx_dma)
> @@ -338,7 +343,7 @@ static void int_error_stop(struct dw_spi *dws, const char *msg)
> tasklet_schedule(&dws->pump_transfers);
> }
>
> -static void transfer_complete(struct dw_spi *dws)
> +void dw_spi_xfer_done(struct dw_spi *dws)
> {
> /* Update total byte transfered return count actual bytes read */
> dws->cur_msg->actual_length += dws->len;
> @@ -353,6 +358,7 @@ static void transfer_complete(struct dw_spi *dws)
> } else
> tasklet_schedule(&dws->pump_transfers);
> }
> +EXPORT_SYMBOL_GPL(dw_spi_xfer_done);
>
> static irqreturn_t interrupt_transfer(struct dw_spi *dws)
> {
> @@ -384,7 +390,7 @@ static irqreturn_t interrupt_transfer(struct dw_spi *dws)
> if (dws->tx_end > dws->tx)
> spi_umask_intr(dws, SPI_INT_TXEI);
> else
> - transfer_complete(dws);
> + dw_spi_xfer_done(dws);
> }
>
> return IRQ_HANDLED;
> @@ -414,11 +420,7 @@ static void poll_transfer(struct dw_spi *dws)
> while (dws->write(dws))
> dws->read(dws);
>
> - transfer_complete(dws);
> -}
> -
> -static void dma_transfer(struct dw_spi *dws, int cs_change)
> -{
> + dw_spi_xfer_done(dws);
> }
>
> static void pump_transfers(unsigned long data)
> @@ -600,7 +602,7 @@ static void pump_transfers(unsigned long data)
> }
>
> if (dws->dma_mapped)
> - dma_transfer(dws, cs_change);
> + dws->dma_ops->dma_transfer(dws, cs_change);
>
> if (chip->poll_mode)
> poll_transfer(dws);
> @@ -896,11 +898,15 @@ int __devinit dw_spi_add_host(struct dw_spi *dws)
> master->setup = dw_spi_setup;
> master->transfer = dw_spi_transfer;
>
> - dws->dma_inited = 0;
> -
> /* Basic HW init */
> spi_hw_init(dws);
>
> + if (dws->dma_ops && dws->dma_ops->dma_init) {
> + ret = dws->dma_ops->dma_init(dws);
> + if (ret)
> + goto err_diable_hw;
> + }
> +
> /* Initial and start queue */
> ret = init_queue(dws);
> if (ret) {
> @@ -925,6 +931,8 @@ int __devinit dw_spi_add_host(struct dw_spi *dws)
>
> err_queue_alloc:
> destroy_queue(dws);
> + if (dws->dma_ops && dws->dma_ops->dma_exit)
> + dws->dma_ops->dma_exit(dws);
> err_diable_hw:
> spi_enable_chip(dws, 0);
> free_irq(dws->irq, dws);
> @@ -933,7 +941,7 @@ err_free_master:
> exit:
> return ret;
> }
> -EXPORT_SYMBOL(dw_spi_add_host);
> +EXPORT_SYMBOL_GPL(dw_spi_add_host);
These EXPORT_SYMBOL->EXPORT_SYMBOL_GPL changes really belong in a
separate patch. Particularly because this isn't even remotely related
to adding DMA support to the driver, and is instead a statement of
policy on the use of this driver. Please split.
>
> void __devexit dw_spi_remove_host(struct dw_spi *dws)
> {
> @@ -949,6 +957,8 @@ void __devexit dw_spi_remove_host(struct dw_spi *dws)
> dev_err(&dws->master->dev, "dw_spi_remove: workqueue will not "
> "complete, message memory not freed\n");
>
> + if (dws->dma_ops && dws->dma_ops->dma_exit)
> + dws->dma_ops->dma_exit(dws);
> spi_enable_chip(dws, 0);
> /* Disable clk */
> spi_set_clk(dws, 0);
> @@ -957,7 +967,7 @@ void __devexit dw_spi_remove_host(struct dw_spi *dws)
> /* Disconnect from the SPI framework */
> spi_unregister_master(dws->master);
> }
> -EXPORT_SYMBOL(dw_spi_remove_host);
> +EXPORT_SYMBOL_GPL(dw_spi_remove_host);
>
> int dw_spi_suspend_host(struct dw_spi *dws)
> {
> @@ -970,7 +980,7 @@ int dw_spi_suspend_host(struct dw_spi *dws)
> spi_set_clk(dws, 0);
> return ret;
> }
> -EXPORT_SYMBOL(dw_spi_suspend_host);
> +EXPORT_SYMBOL_GPL(dw_spi_suspend_host);
>
> int dw_spi_resume_host(struct dw_spi *dws)
> {
> @@ -982,7 +992,7 @@ int dw_spi_resume_host(struct dw_spi *dws)
> dev_err(&dws->master->dev, "fail to start queue (%d)\n", ret);
> return ret;
> }
> -EXPORT_SYMBOL(dw_spi_resume_host);
> +EXPORT_SYMBOL_GPL(dw_spi_resume_host);
>
> MODULE_AUTHOR("Feng Tang <feng.tang-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>");
> MODULE_DESCRIPTION("Driver for DesignWare SPI controller core");
> diff --git a/drivers/spi/dw_spi_mid.c b/drivers/spi/dw_spi_mid.c
> new file mode 100644
> index 0000000..e60a8a5
> --- /dev/null
> +++ b/drivers/spi/dw_spi_mid.c
> @@ -0,0 +1,225 @@
> +/*
> + * dw_spi_mid.c - special handling for DW core on Intel MID platform
> + *
> + * Copyright (c) 2009, Intel Corporation.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, write to the Free Software Foundation,
> + * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
> + */
> +
> +#include <linux/dma-mapping.h>
> +#include <linux/dmaengine.h>
> +#include <linux/interrupt.h>
> +#include <linux/slab.h>
> +#include <linux/spi/spi.h>
> +#include <linux/spi/dw_spi.h>
> +
> +#ifdef CONFIG_SPI_DW_MID_DMA
> +#include <linux/intel_mid_dma.h>
> +#include <linux/pci.h>
> +
> +struct mid_dma {
> + struct intel_mid_dma_slave dmas_tx;
> + struct intel_mid_dma_slave dmas_rx;
> +};
> +
> +static bool mid_spi_dma_chan_filter(struct dma_chan *chan, void *param)
> +{
> + struct dw_spi *dws = param;
> +
> + if (dws->dmac && &dws->dmac->dev == chan->device->dev)
> + return true;
> + else
> + return false;
Heh. A little verbose. How about simply:
reutrn dws->dmac && (&dws->dmac->dev == chan->device->dev);
> +}
> +
> +static int mid_spi_dma_init(struct dw_spi *dws)
> +{
> + struct mid_dma *dw_dma = dws->dma_priv;
> + struct intel_mid_dma_slave *rxs, *txs;
> + dma_cap_mask_t mask;
> +
> + /* Get pci device for DMA */
> + dws->dmac = pci_get_device(PCI_VENDOR_ID_INTEL, 0x813, NULL);
> +
> + dma_cap_zero(mask);
> + dma_cap_set(DMA_SLAVE, mask);
> +
> + /* 1. Init rx channel */
> + dws->rxchan = dma_request_channel(mask, mid_spi_dma_chan_filter, dws);
> + if (!dws->rxchan)
> + goto err_exit;
> + rxs = &dw_dma->dmas_rx;
> + rxs->hs_mode = LNW_DMA_HW_HS;
> + rxs->cfg_mode = LNW_DMA_PER_TO_MEM;
> + dws->rxchan->private = rxs;
> +
> + /* 2. Init tx channel */
> + dws->txchan = dma_request_channel(mask, mid_spi_dma_chan_filter, dws);
> + if (!dws->txchan)
> + goto free_rxchan;
> + txs = &dw_dma->dmas_tx;
> + txs->hs_mode = LNW_DMA_HW_HS;
> + txs->cfg_mode = LNW_DMA_MEM_TO_PER;
> + dws->txchan->private = txs;
> +
> + dws->dma_inited = 1;
> + return 0;
> +
> +free_rxchan:
> + dma_release_channel(dws->rxchan);
> +err_exit:
> + return -1;
> +
> +}
> +
> +static void mid_spi_dma_exit(struct dw_spi *dws)
> +{
> + dma_release_channel(dws->txchan);
> + dma_release_channel(dws->rxchan);
> +}
> +
> +/*
> + * dws->dma_chan_done is cleared before the dma transfer starts,
> + * callback for rx/tx channel will each increment it by 1.
> + * Reaching 2 means the whole spi transaction is done.
> + */
> +static void dw_spi_dma_done(void *arg)
> +{
> + struct dw_spi *dws = arg;
> +
> + if (++dws->dma_chan_done != 2)
> + return;
> + dw_spi_xfer_done(dws);
> +}
> +
> +static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change)
> +{
> + struct dma_async_tx_descriptor *txdesc = NULL, *rxdesc = NULL;
> + struct dma_chan *txchan, *rxchan;
> + struct dma_slave_config txconf, rxconf;
> + u16 dma_ctrl = 0;
> +
> + /* 1. setup DMA related registers */
> + if (cs_change) {
> + spi_enable_chip(dws, 0);
> + dw_writew(dws, dmardlr, 0xf);
> + dw_writew(dws, dmatdlr, 0x10);
> + if (dws->tx_dma)
> + dma_ctrl |= 0x2;
> + if (dws->rx_dma)
> + dma_ctrl |= 0x1;
> + dw_writew(dws, dmacr, dma_ctrl);
> + spi_enable_chip(dws, 1);
> + }
> +
> + dws->dma_chan_done = 0;
> + txchan = dws->txchan;
> + rxchan = dws->rxchan;
> +
> + /* 2. Prepare the TX dma transfer */
> + txconf.direction = DMA_TO_DEVICE;
> + txconf.dst_addr = dws->dma_addr;
> + txconf.dst_maxburst = LNW_DMA_MSIZE_16;
> + txconf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
> + txconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
> +
> + txchan->device->device_control(txchan, DMA_SLAVE_CONFIG,
> + (unsigned long) &txconf);
> +
> + memset(&dws->tx_sgl, 0, sizeof(dws->tx_sgl));
> + dws->tx_sgl.dma_address = dws->tx_dma;
> + dws->tx_sgl.length = dws->len;
> +
> + txdesc = txchan->device->device_prep_slave_sg(txchan,
> + &dws->tx_sgl,
> + 1,
> + DMA_TO_DEVICE,
> + DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_DEST_UNMAP);
> + txdesc->callback = dw_spi_dma_done;
> + txdesc->callback_param = dws;
> +
> + /* 3. Prepare the RX dma transfer */
> + rxconf.direction = DMA_FROM_DEVICE;
> + rxconf.src_addr = dws->dma_addr;
> + rxconf.src_maxburst = LNW_DMA_MSIZE_16;
> + rxconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
> + rxconf.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
> +
> + rxchan->device->device_control(rxchan, DMA_SLAVE_CONFIG,
> + (unsigned long) &rxconf);
> +
> + memset(&dws->rx_sgl, 0, sizeof(dws->rx_sgl));
> + dws->rx_sgl.dma_address = dws->rx_dma;
> + dws->rx_sgl.length = dws->len;
> +
> + rxdesc = rxchan->device->device_prep_slave_sg(rxchan,
> + &dws->rx_sgl,
> + 1,
> + DMA_FROM_DEVICE,
> + DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_DEST_UNMAP);
> + rxdesc->callback = dw_spi_dma_done;
> + rxdesc->callback_param = dws;
> +
> + /* rx must be started before tx due to spi instinct */
> + rxdesc->tx_submit(rxdesc);
> + txdesc->tx_submit(txdesc);
> + return 0;
> +}
> +
> +static struct dw_spi_dma_ops mid_dma_ops = {
> + .dma_init = mid_spi_dma_init,
> + .dma_exit = mid_spi_dma_exit,
> + .dma_transfer = mid_spi_dma_transfer,
> +};
> +#endif
> +
> +/* Some specific info for SPI0 controller on Moorestown */
> +/* HW info for MRST CLk Control Unit, one 32b reg */
> +#define MRST_SPI_CLK_BASE 100000000 /* 100m */
> +#define MRST_CLK_SPI0_REG 0xff11d86c
> +#define CLK_SPI_BDIV_OFFSET 0
> +#define CLK_SPI_BDIV_MASK 0x00000007
> +#define CLK_SPI_CDIV_OFFSET 9
> +#define CLK_SPI_CDIV_MASK 0x00000e00
> +#define CLK_SPI_CDIV_100M 0x0
> +#define CLK_SPI_CDIV_50M 0x1
> +#define CLK_SPI_CDIV_33M 0x2
> +#define CLK_SPI_CDIV_25M 0x3
> +#define CLK_SPI_DISABLE_OFFSET 8
> +
> +int dw_spi_mid_init(struct dw_spi *dws)
> +{
> + u32 *clk_reg, clk_cdiv;
> +
> + clk_reg = ioremap_nocache(MRST_CLK_SPI0_REG, 16);
> + if (!clk_reg)
> + return -ENOMEM;
> +
> + /* get SPI controller operating freq info */
> + clk_cdiv = ((*clk_reg) & CLK_SPI_CDIV_MASK) >> CLK_SPI_CDIV_OFFSET;
Don't directly dereference register pointers with *clk_reg. use the io
assessor macros instead.
> + dws->max_freq = MRST_SPI_CLK_BASE / (clk_cdiv + 1);
> + iounmap(clk_reg);
> +
> + dws->num_cs = 16;
> + dws->fifo_len = 40; /* FIFO has 40 words buffer */
> +
> +#ifdef CONFIG_SPI_DW_MID_DMA
> + dws->dma_priv = kzalloc(sizeof(struct mid_dma), GFP_KERNEL);
> + if (!dws->dma_priv)
> + return -ENOMEM;
> + dws->dma_ops = &mid_dma_ops;
> +#endif
> + return 0;
> +}
> +
> diff --git a/drivers/spi/dw_spi_pci.c b/drivers/spi/dw_spi_pci.c
> index 1f52755..076d1f8 100644
> --- a/drivers/spi/dw_spi_pci.c
> +++ b/drivers/spi/dw_spi_pci.c
> @@ -1,5 +1,5 @@
> /*
> - * mrst_spi_pci.c - PCI interface driver for DW SPI Core
> + * dw_spi_pci.c - PCI interface driver for DW SPI Core
> *
> * Copyright (c) 2009, Intel Corporation.
> *
> @@ -26,8 +26,8 @@
> #define DRIVER_NAME "dw_spi_pci"
>
> struct dw_spi_pci {
> - struct pci_dev *pdev;
> - struct dw_spi dws;
> + struct pci_dev *pdev;
> + struct dw_spi dws;
Nitpick: unrelated whitespace change.
> };
>
> static int __devinit spi_pci_probe(struct pci_dev *pdev,
> @@ -72,9 +72,13 @@ static int __devinit spi_pci_probe(struct pci_dev *pdev,
> dws->parent_dev = &pdev->dev;
> dws->bus_num = 0;
> dws->num_cs = 4;
> - dws->max_freq = 25000000; /* for Moorestwon */
> dws->irq = pdev->irq;
> - dws->fifo_len = 40; /* FIFO has 40 words buffer */
> +
> + if (pdev->device == 0x0800) {
A comment would go well here explaining why 0x0800 is special.
> + ret = dw_spi_mid_init(dws);
> + if (ret)
> + goto err_unmap;
> + }
>
> ret = dw_spi_add_host(dws);
> if (ret)
> diff --git a/include/linux/spi/dw_spi.h b/include/linux/spi/dw_spi.h
> index c91302f..95a9653 100644
> --- a/include/linux/spi/dw_spi.h
> +++ b/include/linux/spi/dw_spi.h
> @@ -1,5 +1,6 @@
> #ifndef DW_SPI_HEADER_H
> #define DW_SPI_HEADER_H
> +
> #include <linux/io.h>
>
> /* Bit fields in CTRLR0 */
> @@ -82,6 +83,13 @@ struct dw_spi_reg {
> though only low 16 bits matters */
> } __packed;
>
> +struct dw_spi;
> +struct dw_spi_dma_ops {
> + int (*dma_init)(struct dw_spi *dws);
> + void (*dma_exit)(struct dw_spi *dws);
> + int (*dma_transfer)(struct dw_spi *dws, int cs_change);
> +};
> +
> struct dw_spi {
> struct spi_master *master;
> struct spi_device *cur_dev;
> @@ -136,13 +144,15 @@ struct dw_spi {
> /* Dma info */
> int dma_inited;
> struct dma_chan *txchan;
> + struct scatterlist tx_sgl;
> struct dma_chan *rxchan;
> - int txdma_done;
> - int rxdma_done;
> - u64 tx_param;
> - u64 rx_param;
> + struct scatterlist rx_sgl;
> + int dma_chan_done;
> struct device *dma_dev;
> - dma_addr_t dma_addr;
> + dma_addr_t dma_addr; /* phy addr of the Data register */
> + struct dw_spi_dma_ops *dma_ops;
> + void *dma_priv; /* platform relate info */
> + struct pci_dev *dmac;
>
> /* Bus interface info */
> void *priv;
> @@ -216,4 +226,8 @@ extern int dw_spi_add_host(struct dw_spi *dws);
> extern void dw_spi_remove_host(struct dw_spi *dws);
> extern int dw_spi_suspend_host(struct dw_spi *dws);
> extern int dw_spi_resume_host(struct dw_spi *dws);
> +extern void dw_spi_xfer_done(struct dw_spi *dws);
> +
> +/* platform related setup */
> +extern int dw_spi_mid_init(struct dw_spi *dws); /* Intel MID platforms */
> #endif /* DW_SPI_HEADER_H */
> --
> 1.7.0.4
>
>
> ------------------------------------------------------------------------------
> Increase Visibility of Your 3D Game App & Earn a Chance To Win $500!
> Tap into the largest installed PC base & get more eyes on your game by
> optimizing for Intel(R) Graphics Technology. Get started today with the
> Intel(R) Software Partner Program. Five $500 cash prizes are up for grabs.
> http://p.sf.net/sfu/intelisp-dev2dev
> _______________________________________________
> spi-devel-general mailing list
> spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
> https://lists.sourceforge.net/lists/listinfo/spi-devel-general
------------------------------------------------------------------------------
Learn how Oracle Real Application Clusters (RAC) One Node allows customers
to consolidate database storage, standardize their database environment, and,
should the need arise, upgrade to a full multi-node Oracle RAC database
without downtime or disruption
http://p.sf.net/sfu/oracle-sfdevnl
next prev parent reply other threads:[~2010-12-23 23:31 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <20101118200935.26334.53708.stgit@localhost.localdomain>
[not found] ` <20101118200935.26334.53708.stgit-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org>
2010-11-23 6:48 ` [PATCH] dw_spi: add DMA support Linus Walleij
[not found] ` <AANLkTik8v=H=exeOO93Q_oOxVU=snck_SGWDXuy+-db7-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2010-11-23 9:53 ` Feng Tang
2010-11-30 15:13 ` Linus Walleij
[not found] ` <AANLkTim_XfK2nL4pmw=Xrak+=+cpSg9hv89qnio9YR8k-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2010-12-02 7:36 ` Feng Tang
2010-12-23 23:31 ` Grant Likely [this message]
2010-11-18 20:31 Alan Cox
-- strict thread matches above, loose matches on Subject: below --
2010-10-22 19:11 Alan Cox
[not found] ` <20101022191049.8830.51496.stgit-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org>
2010-10-23 16:10 ` Linus Walleij
2010-10-24 8:47 ` 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=20101223233139.GQ20384@angua.secretlab.ca \
--to=grant.likely-s3s/wqlpoipyb63q8fvjnq@public.gmane.org \
--cc=alan-qBU/x9rampVanCEyBjwyrvXRex20P6io@public.gmane.org \
--cc=dan.j.williams-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org \
--cc=feng.tang-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org \
--cc=spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org \
/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).