* [PATCH 1/5] spi/mxs: Fix extra CS pulses and read mode in multi-transfer messages @ 2013-03-29 15:19 Trent Piepho [not found] ` <1364570381-17605-1-git-send-email-tpiepho-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 0 siblings, 1 reply; 24+ messages in thread From: Trent Piepho @ 2013-03-29 15:19 UTC (permalink / raw) To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f Cc: Marek Vasut, Fabio Estevam, Trent Piepho, Shawn Guo There are two bits which control the CS line in the CTRL0 register: LOCK_CS and IGNORE_CRC. The latter would be better named DEASSERT_CS in SPI mode. LOCK_CS keeps CS asserted though the entire transfer. This should always be set. The DMA code will always set it, explicitly on the first segment of the first transfer, and then implicitly on all the rest by never clearing the bit from the value read from the ctrl0 register. The only reason to not set LOCK_CS would be to attempt an altered protocol where CS pulses between each word. Though don't get your hopes up, as the hardware doesn't appear to do this in any sane manner. Setting DEASSERT_CS causes CS to be de-asserted at the end of the transfer. It would normally be set on the final segment of the final transfer. The DMA code explicitly sets it in this case, but because it never clears the bit from the ctrl0 register is will remain set for all transfers in subsequent messages. This results in a CS pulse between transfers. There is a similar problem with the read mode bit never being cleared in DMA mode. The spi transfer "cs_change" flag is ignored by the driver. The driver passes a "first" and "last" flag to the transfer functions for a message, so they can know how to set these bits. It does this by passing them as pointers. There is no reason to do this, as the flags are not modified in the transfer function. And since LOCK_CS can be set and left that way, there is no need for a "first" flag at all. This patch fixes DEASSERT_CS and READ being left on in DMA mode, eliminates the flags being passed as separate pointers, and adds support for the cs_change flag. Note that while using the cs_change flag to leave CS asserted after the final transfer works, getting the CS to automatically turn off when a different slave is addressed might not work. Signed-off-by: Trent Piepho <tpiepho-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> Cc: Marek Vasut <marex-ynQEQJNshbs@public.gmane.org> Cc: Fabio Estevam <fabio.estevam-KZfg59tc24xl57MIdRCFDg@public.gmane.org> Cc: Shawn Guo <shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> --- drivers/spi/spi-mxs.c | 86 +++++++++++++++++++++---------------------------- 1 file changed, 36 insertions(+), 50 deletions(-) diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c index 22a0af0..aa77d96b9 100644 --- a/drivers/spi/spi-mxs.c +++ b/drivers/spi/spi-mxs.c @@ -58,6 +58,11 @@ #define SG_MAXLEN 0xff00 +/* Flags for txrx functions. More efficient that using an argument register for + * each one. */ +#define TXRX_WRITE 1 /* This is a write */ +#define TXRX_DEASSERT_CS 2 /* De-assert CS at end of txrx */ + struct mxs_spi { struct mxs_ssp ssp; struct completion c; @@ -91,6 +96,8 @@ static int mxs_spi_setup_transfer(struct spi_device *dev, mxs_ssp_set_clk_rate(ssp, hz); + writel(BM_SSP_CTRL0_LOCK_CS, + ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET); writel(BF_SSP_CTRL1_SSP_MODE(BV_SSP_CTRL1_SSP_MODE__SPI) | BF_SSP_CTRL1_WORD_LENGTH (BV_SSP_CTRL1_WORD_LENGTH__EIGHT_BITS) | @@ -155,26 +162,6 @@ static void mxs_spi_set_cs(struct mxs_spi *spi, unsigned cs) writel(select, ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET); } -static inline void mxs_spi_enable(struct mxs_spi *spi) -{ - struct mxs_ssp *ssp = &spi->ssp; - - writel(BM_SSP_CTRL0_LOCK_CS, - ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET); - writel(BM_SSP_CTRL0_IGNORE_CRC, - ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_CLR); -} - -static inline void mxs_spi_disable(struct mxs_spi *spi) -{ - struct mxs_ssp *ssp = &spi->ssp; - - writel(BM_SSP_CTRL0_LOCK_CS, - ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_CLR); - writel(BM_SSP_CTRL0_IGNORE_CRC, - ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET); -} - static int mxs_ssp_wait(struct mxs_spi *spi, int offset, int mask, bool set) { const unsigned long timeout = jiffies + msecs_to_jiffies(SSP_TIMEOUT); @@ -214,7 +201,7 @@ static irqreturn_t mxs_ssp_irq_handler(int irq, void *dev_id) static int mxs_spi_txrx_dma(struct mxs_spi *spi, int cs, unsigned char *buf, int len, - int *first, int *last, int write) + unsigned int flags) { struct mxs_ssp *ssp = &spi->ssp; struct dma_async_tx_descriptor *desc = NULL; @@ -241,20 +228,21 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi, int cs, INIT_COMPLETION(spi->c); ctrl0 = readl(ssp->base + HW_SSP_CTRL0); - ctrl0 &= ~BM_SSP_CTRL0_XFER_COUNT; + ctrl0 &= ~BM_SSP_CTRL0_XFER_COUNT & ~BM_SSP_CTRL0_IGNORE_CRC & + ~BM_SSP_CTRL0_READ; ctrl0 |= BM_SSP_CTRL0_DATA_XFER | mxs_spi_cs_to_reg(cs); - if (*first) - ctrl0 |= BM_SSP_CTRL0_LOCK_CS; - if (!write) + if (!(flags & TXRX_WRITE)) ctrl0 |= BM_SSP_CTRL0_READ; /* Queue the DMA data transfer. */ for (sg_count = 0; sg_count < sgs; sg_count++) { + /* Prepare the transfer descriptor. */ min = min(len, desc_len); - /* Prepare the transfer descriptor. */ - if ((sg_count + 1 == sgs) && *last) + /* De-assert CS on last segment if flag is set (i.e., no more + * transfers will follow) */ + if ((sg_count + 1 == sgs) && (flags & TXRX_DEASSERT_CS)) ctrl0 |= BM_SSP_CTRL0_IGNORE_CRC; if (ssp->devid == IMX23_SSP) { @@ -279,7 +267,7 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi, int cs, sg_init_one(&dma_xfer[sg_count].sg, sg_buf, min); ret = dma_map_sg(ssp->dev, &dma_xfer[sg_count].sg, 1, - write ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + (flags & TXRX_WRITE) ? DMA_TO_DEVICE : DMA_FROM_DEVICE); len -= min; buf += min; @@ -299,7 +287,7 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi, int cs, desc = dmaengine_prep_slave_sg(ssp->dmach, &dma_xfer[sg_count].sg, 1, - write ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM, + (flags & TXRX_WRITE) ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc) { @@ -336,7 +324,7 @@ err_vmalloc: while (--sg_count >= 0) { err_mapped: dma_unmap_sg(ssp->dev, &dma_xfer[sg_count].sg, 1, - write ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + (flags & TXRX_WRITE) ? DMA_TO_DEVICE : DMA_FROM_DEVICE); } kfree(dma_xfer); @@ -346,18 +334,20 @@ err_mapped: static int mxs_spi_txrx_pio(struct mxs_spi *spi, int cs, unsigned char *buf, int len, - int *first, int *last, int write) + unsigned int flags) { struct mxs_ssp *ssp = &spi->ssp; - if (*first) - mxs_spi_enable(spi); + /* Clear this now, set it on last transfer if needed */ + writel(BM_SSP_CTRL0_IGNORE_CRC, + ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_CLR); mxs_spi_set_cs(spi, cs); while (len--) { - if (*last && len == 0) - mxs_spi_disable(spi); + if (len == 0 && (flags & TXRX_DEASSERT_CS)) + writel(BM_SSP_CTRL0_IGNORE_CRC, + ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET); if (ssp->devid == IMX23_SSP) { writel(BM_SSP_CTRL0_XFER_COUNT, @@ -368,7 +358,7 @@ static int mxs_spi_txrx_pio(struct mxs_spi *spi, int cs, writel(1, ssp->base + HW_SSP_XFER_SIZE); } - if (write) + if (flags & TXRX_WRITE) writel(BM_SSP_CTRL0_READ, ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_CLR); else @@ -381,13 +371,13 @@ static int mxs_spi_txrx_pio(struct mxs_spi *spi, int cs, if (mxs_ssp_wait(spi, HW_SSP_CTRL0, BM_SSP_CTRL0_RUN, 1)) return -ETIMEDOUT; - if (write) + if (flags & TXRX_WRITE) writel(*buf, ssp->base + HW_SSP_DATA(ssp)); writel(BM_SSP_CTRL0_DATA_XFER, ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET); - if (!write) { + if (!(flags & TXRX_WRITE)) { if (mxs_ssp_wait(spi, HW_SSP_STATUS(ssp), BM_SSP_STATUS_FIFO_EMPTY, 0)) return -ETIMEDOUT; @@ -412,13 +402,11 @@ static int mxs_spi_transfer_one(struct spi_master *master, { struct mxs_spi *spi = spi_master_get_devdata(master); struct mxs_ssp *ssp = &spi->ssp; - int first, last; struct spi_transfer *t, *tmp_t; + unsigned int flag; int status = 0; int cs; - first = last = 0; - cs = m->spi->chip_select; list_for_each_entry_safe(t, tmp_t, &m->transfers, transfer_list) { @@ -427,10 +415,9 @@ static int mxs_spi_transfer_one(struct spi_master *master, if (status) break; - if (&t->transfer_list == m->transfers.next) - first = 1; - if (&t->transfer_list == m->transfers.prev) - last = 1; + /* De-assert on last transfer, inverted by cs_change flag */ + flag = (&t->transfer_list == m->transfers.prev) ^ t->cs_change ? + TXRX_DEASSERT_CS : 0; if ((t->rx_buf && t->tx_buf) || (t->rx_dma && t->tx_dma)) { dev_err(ssp->dev, "Cannot send and receive simultaneously\n"); @@ -455,11 +442,11 @@ static int mxs_spi_transfer_one(struct spi_master *master, if (t->tx_buf) status = mxs_spi_txrx_pio(spi, cs, (void *)t->tx_buf, - t->len, &first, &last, 1); + t->len, flag | TXRX_WRITE); if (t->rx_buf) status = mxs_spi_txrx_pio(spi, cs, t->rx_buf, t->len, - &first, &last, 0); + flag); } else { writel(BM_SSP_CTRL1_DMA_ENABLE, ssp->base + HW_SSP_CTRL1(ssp) + @@ -468,11 +455,11 @@ static int mxs_spi_transfer_one(struct spi_master *master, if (t->tx_buf) status = mxs_spi_txrx_dma(spi, cs, (void *)t->tx_buf, t->len, - &first, &last, 1); + flag | TXRX_WRITE); if (t->rx_buf) status = mxs_spi_txrx_dma(spi, cs, t->rx_buf, t->len, - &first, &last, 0); + flag); } if (status) { @@ -481,7 +468,6 @@ static int mxs_spi_transfer_one(struct spi_master *master, } m->actual_length += t->len; - first = last = 0; } m->status = status; -- 1.7.10.4 ------------------------------------------------------------------------------ Own the Future-Intel(R) Level Up Game Demo Contest 2013 Rise to greatness in Intel's independent game demo contest. Compete for recognition, cash, and the chance to get your game on Steam. $5K grand prize plus 10 genre and skill prizes. Submit your demo by 6/6/13. http://altfarm.mediaplex.com/ad/ck/12124-176961-30367-2 ^ permalink raw reply related [flat|nested] 24+ messages in thread
[parent not found: <1364570381-17605-1-git-send-email-tpiepho-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>]
* [PATCH 2/5] spi/mxs: Fix chip select control bits in DMA mode [not found] ` <1364570381-17605-1-git-send-email-tpiepho-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> @ 2013-03-29 15:19 ` Trent Piepho [not found] ` <1364570381-17605-2-git-send-email-tpiepho-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 2013-03-29 15:19 ` [PATCH 3/5] spi/mxs: Remove full duplex check, spi core already does it Trent Piepho ` (3 subsequent siblings) 4 siblings, 1 reply; 24+ messages in thread From: Trent Piepho @ 2013-03-29 15:19 UTC (permalink / raw) To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f Cc: Marek Vasut, Fabio Estevam, Trent Piepho, Shawn Guo In DMA mode the chip select control bits would be ORed into the CTRL0 register without first clearing the bits. This means that after addressing slave 1 the bit would be still be set when addressing slave 0, resulting in slave 1 continuing to be addressed. The message handing function would pass the cs value to the txrx function, which would re-program the bits on each transfer in the message. The selected cs does not change during a message so this is inefficient. It also means there are two different sets of code for selecting the CS, one for PIO that worked and one for DMA that didn't. Change the code to set the CS bits in the message transfer function once. Now the DMA and PIO txrx functions don't need to care about CS at all. Signed-off-by: Trent Piepho <tpiepho-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> Cc: Marek Vasut <marex-ynQEQJNshbs@public.gmane.org> Cc: Fabio Estevam <fabio.estevam-KZfg59tc24xl57MIdRCFDg@public.gmane.org> Cc: Shawn Guo <shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> --- drivers/spi/spi-mxs.c | 40 +++++++++++++++------------------------- 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c index aa77d96b9..5d63b21 100644 --- a/drivers/spi/spi-mxs.c +++ b/drivers/spi/spi-mxs.c @@ -130,9 +130,9 @@ static int mxs_spi_setup(struct spi_device *dev) return err; } -static uint32_t mxs_spi_cs_to_reg(unsigned cs) +static u32 mxs_spi_cs_to_reg(unsigned cs) { - uint32_t select = 0; + u32 select = 0; /* * i.MX28 Datasheet: 17.10.1: HW_SSP_CTRL0 @@ -150,18 +150,6 @@ static uint32_t mxs_spi_cs_to_reg(unsigned cs) return select; } -static void mxs_spi_set_cs(struct mxs_spi *spi, unsigned cs) -{ - const uint32_t mask = - BM_SSP_CTRL0_WAIT_FOR_CMD | BM_SSP_CTRL0_WAIT_FOR_IRQ; - uint32_t select; - struct mxs_ssp *ssp = &spi->ssp; - - writel(mask, ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_CLR); - select = mxs_spi_cs_to_reg(cs); - writel(select, ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET); -} - static int mxs_ssp_wait(struct mxs_spi *spi, int offset, int mask, bool set) { const unsigned long timeout = jiffies + msecs_to_jiffies(SSP_TIMEOUT); @@ -199,7 +187,7 @@ static irqreturn_t mxs_ssp_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } -static int mxs_spi_txrx_dma(struct mxs_spi *spi, int cs, +static int mxs_spi_txrx_dma(struct mxs_spi *spi, unsigned char *buf, int len, unsigned int flags) { @@ -227,10 +215,11 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi, int cs, INIT_COMPLETION(spi->c); + /* Chip select was already programmed into CTRL0 */ ctrl0 = readl(ssp->base + HW_SSP_CTRL0); ctrl0 &= ~BM_SSP_CTRL0_XFER_COUNT & ~BM_SSP_CTRL0_IGNORE_CRC & ~BM_SSP_CTRL0_READ; - ctrl0 |= BM_SSP_CTRL0_DATA_XFER | mxs_spi_cs_to_reg(cs); + ctrl0 |= BM_SSP_CTRL0_DATA_XFER; if (!(flags & TXRX_WRITE)) ctrl0 |= BM_SSP_CTRL0_READ; @@ -332,7 +321,7 @@ err_mapped: return ret; } -static int mxs_spi_txrx_pio(struct mxs_spi *spi, int cs, +static int mxs_spi_txrx_pio(struct mxs_spi *spi, unsigned char *buf, int len, unsigned int flags) { @@ -342,8 +331,6 @@ static int mxs_spi_txrx_pio(struct mxs_spi *spi, int cs, writel(BM_SSP_CTRL0_IGNORE_CRC, ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_CLR); - mxs_spi_set_cs(spi, cs); - while (len--) { if (len == 0 && (flags & TXRX_DEASSERT_CS)) writel(BM_SSP_CTRL0_IGNORE_CRC, @@ -405,9 +392,12 @@ static int mxs_spi_transfer_one(struct spi_master *master, struct spi_transfer *t, *tmp_t; unsigned int flag; int status = 0; - int cs; - cs = m->spi->chip_select; + /* Program CS register bits here, it will be used for all transfers. */ + writel(BM_SSP_CTRL0_WAIT_FOR_CMD | BM_SSP_CTRL0_WAIT_FOR_IRQ, + ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_CLR); + writel(mxs_spi_cs_to_reg(m->spi->chip_select), + ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET); list_for_each_entry_safe(t, tmp_t, &m->transfers, transfer_list) { @@ -440,11 +430,11 @@ static int mxs_spi_transfer_one(struct spi_master *master, STMP_OFFSET_REG_CLR); if (t->tx_buf) - status = mxs_spi_txrx_pio(spi, cs, + status = mxs_spi_txrx_pio(spi, (void *)t->tx_buf, t->len, flag | TXRX_WRITE); if (t->rx_buf) - status = mxs_spi_txrx_pio(spi, cs, + status = mxs_spi_txrx_pio(spi, t->rx_buf, t->len, flag); } else { @@ -453,11 +443,11 @@ static int mxs_spi_transfer_one(struct spi_master *master, STMP_OFFSET_REG_SET); if (t->tx_buf) - status = mxs_spi_txrx_dma(spi, cs, + status = mxs_spi_txrx_dma(spi, (void *)t->tx_buf, t->len, flag | TXRX_WRITE); if (t->rx_buf) - status = mxs_spi_txrx_dma(spi, cs, + status = mxs_spi_txrx_dma(spi, t->rx_buf, t->len, flag); } -- 1.7.10.4 ------------------------------------------------------------------------------ Own the Future-Intel(R) Level Up Game Demo Contest 2013 Rise to greatness in Intel's independent game demo contest. Compete for recognition, cash, and the chance to get your game on Steam. $5K grand prize plus 10 genre and skill prizes. Submit your demo by 6/6/13. http://altfarm.mediaplex.com/ad/ck/12124-176961-30367-2 ^ permalink raw reply related [flat|nested] 24+ messages in thread
[parent not found: <1364570381-17605-2-git-send-email-tpiepho-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>]
* Re: [PATCH 2/5] spi/mxs: Fix chip select control bits in DMA mode [not found] ` <1364570381-17605-2-git-send-email-tpiepho-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> @ 2013-04-01 23:13 ` Marek Vasut [not found] ` <201304020113.42124.marex-ynQEQJNshbs@public.gmane.org> 0 siblings, 1 reply; 24+ messages in thread From: Marek Vasut @ 2013-04-01 23:13 UTC (permalink / raw) To: Trent Piepho Cc: Fabio Estevam, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Shawn Guo, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r Dear Trent Piepho, > In DMA mode the chip select control bits would be ORed into the CTRL0 > register without first clearing the bits. This means that after > addressing slave 1 the bit would be still be set when addressing slave > 0, resulting in slave 1 continuing to be addressed. > > The message handing function would pass the cs value to the txrx > function, which would re-program the bits on each transfer in the > message. The selected cs does not change during a message so this is > inefficient. It also means there are two different sets of code for > selecting the CS, one for PIO that worked and one for DMA that didn't. > > Change the code to set the CS bits in the message transfer function > once. Now the DMA and PIO txrx functions don't need to care about CS > at all. Ok, lemme ask this one more time -- will the DMA work with long transfers where the CTRL0 will be overwritten on each turn? Did you actually test this? > Signed-off-by: Trent Piepho <tpiepho-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> > Cc: Marek Vasut <marex-ynQEQJNshbs@public.gmane.org> > Cc: Fabio Estevam <fabio.estevam-KZfg59tc24xl57MIdRCFDg@public.gmane.org> > Cc: Shawn Guo <shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> > --- > drivers/spi/spi-mxs.c | 40 +++++++++++++++------------------------- > 1 file changed, 15 insertions(+), 25 deletions(-) > > diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c > index aa77d96b9..5d63b21 100644 > --- a/drivers/spi/spi-mxs.c > +++ b/drivers/spi/spi-mxs.c > @@ -130,9 +130,9 @@ static int mxs_spi_setup(struct spi_device *dev) > return err; > } > > -static uint32_t mxs_spi_cs_to_reg(unsigned cs) > +static u32 mxs_spi_cs_to_reg(unsigned cs) > { > - uint32_t select = 0; > + u32 select = 0; This change is unneeded, remove it. > /* > * i.MX28 Datasheet: 17.10.1: HW_SSP_CTRL0 > @@ -150,18 +150,6 @@ static uint32_t mxs_spi_cs_to_reg(unsigned cs) > return select; > } > > -static void mxs_spi_set_cs(struct mxs_spi *spi, unsigned cs) > -{ > - const uint32_t mask = > - BM_SSP_CTRL0_WAIT_FOR_CMD | BM_SSP_CTRL0_WAIT_FOR_IRQ; > - uint32_t select; > - struct mxs_ssp *ssp = &spi->ssp; > - > - writel(mask, ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_CLR); > - select = mxs_spi_cs_to_reg(cs); > - writel(select, ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET); > -} > - > static int mxs_ssp_wait(struct mxs_spi *spi, int offset, int mask, bool > set) { > const unsigned long timeout = jiffies + msecs_to_jiffies(SSP_TIMEOUT); > @@ -199,7 +187,7 @@ static irqreturn_t mxs_ssp_irq_handler(int irq, void > *dev_id) return IRQ_HANDLED; > } > > -static int mxs_spi_txrx_dma(struct mxs_spi *spi, int cs, > +static int mxs_spi_txrx_dma(struct mxs_spi *spi, > unsigned char *buf, int len, > unsigned int flags) > { > @@ -227,10 +215,11 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi, int > cs, > > INIT_COMPLETION(spi->c); > > + /* Chip select was already programmed into CTRL0 */ > ctrl0 = readl(ssp->base + HW_SSP_CTRL0); > ctrl0 &= ~BM_SSP_CTRL0_XFER_COUNT & ~BM_SSP_CTRL0_IGNORE_CRC & > ~BM_SSP_CTRL0_READ; > - ctrl0 |= BM_SSP_CTRL0_DATA_XFER | mxs_spi_cs_to_reg(cs); > + ctrl0 |= BM_SSP_CTRL0_DATA_XFER; > > if (!(flags & TXRX_WRITE)) > ctrl0 |= BM_SSP_CTRL0_READ; > @@ -332,7 +321,7 @@ err_mapped: > return ret; > } > > -static int mxs_spi_txrx_pio(struct mxs_spi *spi, int cs, > +static int mxs_spi_txrx_pio(struct mxs_spi *spi, > unsigned char *buf, int len, > unsigned int flags) > { > @@ -342,8 +331,6 @@ static int mxs_spi_txrx_pio(struct mxs_spi *spi, int > cs, writel(BM_SSP_CTRL0_IGNORE_CRC, > ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_CLR); > > - mxs_spi_set_cs(spi, cs); > - > while (len--) { > if (len == 0 && (flags & TXRX_DEASSERT_CS)) > writel(BM_SSP_CTRL0_IGNORE_CRC, > @@ -405,9 +392,12 @@ static int mxs_spi_transfer_one(struct spi_master > *master, struct spi_transfer *t, *tmp_t; > unsigned int flag; > int status = 0; > - int cs; > > - cs = m->spi->chip_select; > + /* Program CS register bits here, it will be used for all transfers. */ > + writel(BM_SSP_CTRL0_WAIT_FOR_CMD | BM_SSP_CTRL0_WAIT_FOR_IRQ, > + ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_CLR); > + writel(mxs_spi_cs_to_reg(m->spi->chip_select), > + ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET); > > list_for_each_entry_safe(t, tmp_t, &m->transfers, transfer_list) { > > @@ -440,11 +430,11 @@ static int mxs_spi_transfer_one(struct spi_master > *master, STMP_OFFSET_REG_CLR); > > if (t->tx_buf) > - status = mxs_spi_txrx_pio(spi, cs, > + status = mxs_spi_txrx_pio(spi, > (void *)t->tx_buf, > t->len, flag | TXRX_WRITE); > if (t->rx_buf) > - status = mxs_spi_txrx_pio(spi, cs, > + status = mxs_spi_txrx_pio(spi, > t->rx_buf, t->len, > flag); > } else { > @@ -453,11 +443,11 @@ static int mxs_spi_transfer_one(struct spi_master > *master, STMP_OFFSET_REG_SET); > > if (t->tx_buf) > - status = mxs_spi_txrx_dma(spi, cs, > + status = mxs_spi_txrx_dma(spi, > (void *)t->tx_buf, t->len, > flag | TXRX_WRITE); > if (t->rx_buf) > - status = mxs_spi_txrx_dma(spi, cs, > + status = mxs_spi_txrx_dma(spi, > t->rx_buf, t->len, > flag); > } Best regards, Marek Vasut ------------------------------------------------------------------------------ Own the Future-Intel® Level Up Game Demo Contest 2013 Rise to greatness in Intel's independent game demo contest. Compete for recognition, cash, and the chance to get your game on Steam. $5K grand prize plus 10 genre and skill prizes. Submit your demo by 6/6/13. http://p.sf.net/sfu/intel_levelupd2d ^ permalink raw reply [flat|nested] 24+ messages in thread
[parent not found: <201304020113.42124.marex-ynQEQJNshbs@public.gmane.org>]
* Re: [PATCH 2/5] spi/mxs: Fix chip select control bits in DMA mode [not found] ` <201304020113.42124.marex-ynQEQJNshbs@public.gmane.org> @ 2013-04-01 23:27 ` Trent Piepho [not found] ` <CA+7tXih2wAVeLpVoYkt4Tmo3h0YtLoZY3vCcv5s8sUD1u8_BVQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 0 siblings, 1 reply; 24+ messages in thread From: Trent Piepho @ 2013-04-01 23:27 UTC (permalink / raw) To: Marek Vasut Cc: Fabio Estevam, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Shawn Guo, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org On Mon, Apr 1, 2013 at 4:13 PM, Marek Vasut <marex-ynQEQJNshbs@public.gmane.org> wrote: >> >> Change the code to set the CS bits in the message transfer function >> once. Now the DMA and PIO txrx functions don't need to care about CS >> at all. > > Ok, lemme ask this one more time -- will the DMA work with long transfers where > the CTRL0 will be overwritten on each turn? Did you actually test this? I don't have SPI flash, so I can't test SPI flash. I can test other spi devices and by capturing the pins with a logic analyzer. It does work after the patch, and does not work before the patch. The error should be obvious from looking at the code. ctrl0 is not overwritten, from scratch, each on transfer. The ctrl0 value in the PIO part of the DMA is based on the current value of ctrl0 with additional bits ORed in. The flaw here is that bits that should not be set are not masked out. >> >> -static uint32_t mxs_spi_cs_to_reg(unsigned cs) >> +static u32 mxs_spi_cs_to_reg(unsigned cs) >> { >> - uint32_t select = 0; >> + u32 select = 0; I'll make it a separate patch. ------------------------------------------------------------------------------ Own the Future-Intel® Level Up Game Demo Contest 2013 Rise to greatness in Intel's independent game demo contest. Compete for recognition, cash, and the chance to get your game on Steam. $5K grand prize plus 10 genre and skill prizes. Submit your demo by 6/6/13. http://p.sf.net/sfu/intel_levelupd2d ^ permalink raw reply [flat|nested] 24+ messages in thread
[parent not found: <CA+7tXih2wAVeLpVoYkt4Tmo3h0YtLoZY3vCcv5s8sUD1u8_BVQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>]
* Re: [PATCH 2/5] spi/mxs: Fix chip select control bits in DMA mode [not found] ` <CA+7tXih2wAVeLpVoYkt4Tmo3h0YtLoZY3vCcv5s8sUD1u8_BVQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> @ 2013-04-01 23:30 ` Marek Vasut [not found] ` <201304020130.51951.marex-ynQEQJNshbs@public.gmane.org> 0 siblings, 1 reply; 24+ messages in thread From: Marek Vasut @ 2013-04-01 23:30 UTC (permalink / raw) To: Trent Piepho Cc: Fabio Estevam, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Shawn Guo, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org Dear Trent Piepho, > On Mon, Apr 1, 2013 at 4:13 PM, Marek Vasut <marex-ynQEQJNshbs@public.gmane.org> wrote: > >> Change the code to set the CS bits in the message transfer function > >> once. Now the DMA and PIO txrx functions don't need to care about CS > >> at all. > > > > Ok, lemme ask this one more time -- will the DMA work with long transfers > > where the CTRL0 will be overwritten on each turn? Did you actually test > > this? > > I don't have SPI flash, so I can't test SPI flash. I can test other > spi devices and by capturing the pins with a logic analyzer. It does > work after the patch, and does not work before the patch. The error > should be obvious from looking at the code. > > ctrl0 is not overwritten, from scratch, each on transfer. The ctrl0 > value in the PIO part of the DMA is based on the current value of > ctrl0 with additional bits ORed in. The flaw here is that bits that > should not be set are not masked out. > > >> -static uint32_t mxs_spi_cs_to_reg(unsigned cs) > >> +static u32 mxs_spi_cs_to_reg(unsigned cs) > >> > >> { > >> > >> - uint32_t select = 0; > >> + u32 select = 0; > > I'll make it a separate patch. This is completely irrelevant change, please just submit the relevant patches. Best regards, Marek Vasut ------------------------------------------------------------------------------ Own the Future-Intel® Level Up Game Demo Contest 2013 Rise to greatness in Intel's independent game demo contest. Compete for recognition, cash, and the chance to get your game on Steam. $5K grand prize plus 10 genre and skill prizes. Submit your demo by 6/6/13. http://p.sf.net/sfu/intel_levelupd2d ^ permalink raw reply [flat|nested] 24+ messages in thread
[parent not found: <201304020130.51951.marex-ynQEQJNshbs@public.gmane.org>]
* Re: [PATCH 2/5] spi/mxs: Fix chip select control bits in DMA mode [not found] ` <201304020130.51951.marex-ynQEQJNshbs@public.gmane.org> @ 2013-04-01 23:40 ` Trent Piepho [not found] ` <CA+7tXij_V1iAdPuPoTQ6CK6U5Y-iJprCPsTj=_LHAV1-=CL7gA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 0 siblings, 1 reply; 24+ messages in thread From: Trent Piepho @ 2013-04-01 23:40 UTC (permalink / raw) To: Marek Vasut Cc: Fabio Estevam, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Shawn Guo, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org On Mon, Apr 1, 2013 at 4:30 PM, Marek Vasut <marex-ynQEQJNshbs@public.gmane.org> wrote: >> >> -static uint32_t mxs_spi_cs_to_reg(unsigned cs) >> >> +static u32 mxs_spi_cs_to_reg(unsigned cs) >> >> >> >> { >> >> >> >> - uint32_t select = 0; >> >> + u32 select = 0; >> >> I'll make it a separate patch. > > This is completely irrelevant change, please just submit the relevant patches. Kernel code should use u16, u32, etc. instead of the uint16_t, uint32_t types. The rest of the driver uses them. Why should this one function use a different type than the rest? It's ugly and inconsistent. And really, it's just as relevant as insisting that multiline patches use some exact format, which checkpatch.pl doesn't complain about. ------------------------------------------------------------------------------ Own the Future-Intel® Level Up Game Demo Contest 2013 Rise to greatness in Intel's independent game demo contest. Compete for recognition, cash, and the chance to get your game on Steam. $5K grand prize plus 10 genre and skill prizes. Submit your demo by 6/6/13. http://p.sf.net/sfu/intel_levelupd2d ^ permalink raw reply [flat|nested] 24+ messages in thread
[parent not found: <CA+7tXij_V1iAdPuPoTQ6CK6U5Y-iJprCPsTj=_LHAV1-=CL7gA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>]
* Re: [PATCH 2/5] spi/mxs: Fix chip select control bits in DMA mode [not found] ` <CA+7tXij_V1iAdPuPoTQ6CK6U5Y-iJprCPsTj=_LHAV1-=CL7gA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> @ 2013-04-02 0:02 ` Marek Vasut [not found] ` <201304020202.43501.marex-ynQEQJNshbs@public.gmane.org> 0 siblings, 1 reply; 24+ messages in thread From: Marek Vasut @ 2013-04-02 0:02 UTC (permalink / raw) To: Trent Piepho Cc: Fabio Estevam, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Shawn Guo, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org Dear Trent Piepho, > On Mon, Apr 1, 2013 at 4:30 PM, Marek Vasut <marex-ynQEQJNshbs@public.gmane.org> wrote: > >> >> -static uint32_t mxs_spi_cs_to_reg(unsigned cs) > >> >> +static u32 mxs_spi_cs_to_reg(unsigned cs) > >> >> > >> >> { > >> >> > >> >> - uint32_t select = 0; > >> >> + u32 select = 0; > >> > >> I'll make it a separate patch. > > > > This is completely irrelevant change, please just submit the relevant > > patches. > > Kernel code should use u16, u32, etc. instead of the uint16_t, > uint32_t types. The rest of the driver uses them. Why should this > one function use a different type than the rest? It's ugly and > inconsistent. Is this documented somewhere please? I see only a mention about this in chapter 5 of Documentation/CodingStyle , section (d) . Either way, separate such cosmetic change into another series so they're not in the way of relevant stuff. > And really, it's just as relevant as insisting that multiline patches > use some exact format, which checkpatch.pl doesn't complain about. The checkpatch is not almighty tool, Documentation/CodingStyle describes how code should be written/annotated/documented. Best regards, Marek Vasut ------------------------------------------------------------------------------ Own the Future-Intel(R) Level Up Game Demo Contest 2013 Rise to greatness in Intel's independent game demo contest. Compete for recognition, cash, and the chance to get your game on Steam. $5K grand prize plus 10 genre and skill prizes. Submit your demo by 6/6/13. http://altfarm.mediaplex.com/ad/ck/12124-176961-30367-2 ^ permalink raw reply [flat|nested] 24+ messages in thread
[parent not found: <201304020202.43501.marex-ynQEQJNshbs@public.gmane.org>]
* Re: [PATCH 2/5] spi/mxs: Fix chip select control bits in DMA mode [not found] ` <201304020202.43501.marex-ynQEQJNshbs@public.gmane.org> @ 2013-04-02 1:58 ` Trent Piepho 0 siblings, 0 replies; 24+ messages in thread From: Trent Piepho @ 2013-04-02 1:58 UTC (permalink / raw) To: Marek Vasut Cc: Fabio Estevam, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Shawn Guo, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org On Mon, Apr 1, 2013 at 5:02 PM, Marek Vasut <marex-ynQEQJNshbs@public.gmane.org> wrote: >> On Mon, Apr 1, 2013 at 4:30 PM, Marek Vasut <marex-ynQEQJNshbs@public.gmane.org> wrote: >> >> >> -static uint32_t mxs_spi_cs_to_reg(unsigned cs) >> >> >> +static u32 mxs_spi_cs_to_reg(unsigned cs) >> >> >> >> >> >> { >> >> >> >> >> >> - uint32_t select = 0; >> >> >> + u32 select = 0; >> >> >> >> I'll make it a separate patch. >> > >> > This is completely irrelevant change, please just submit the relevant >> > patches. >> >> Kernel code should use u16, u32, etc. instead of the uint16_t, >> uint32_t types. The rest of the driver uses them. Why should this >> one function use a different type than the rest? It's ugly and >> inconsistent. > > Is this documented somewhere please? I see only a mention about this in chapter > 5 of Documentation/CodingStyle , section (d) . Either way, separate such > cosmetic change into another series so they're not in the way of relevant stuff. It's pretty clearly existing practice: $ perl -ne '@x=/\buint32_t\b/g;$x+=$#x+1;END{print "$x\n";}' drivers/spi/*.[ch] 9 $ perl -ne '@x=/\bu32\b/g;$x+=$#x+1;END{print "$x\n";}' drivers/spi/*.[ch] 501 ------------------------------------------------------------------------------ Own the Future-Intel(R) Level Up Game Demo Contest 2013 Rise to greatness in Intel's independent game demo contest. Compete for recognition, cash, and the chance to get your game on Steam. $5K grand prize plus 10 genre and skill prizes. Submit your demo by 6/6/13. http://altfarm.mediaplex.com/ad/ck/12124-176961-30367-2 ^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH 3/5] spi/mxs: Remove full duplex check, spi core already does it [not found] ` <1364570381-17605-1-git-send-email-tpiepho-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 2013-03-29 15:19 ` [PATCH 2/5] spi/mxs: Fix chip select control bits in DMA mode Trent Piepho @ 2013-03-29 15:19 ` Trent Piepho 2013-03-29 15:19 ` [PATCH 4/5] spi/mxs: Remove bogus setting of ssp clk rate field Trent Piepho ` (2 subsequent siblings) 4 siblings, 0 replies; 24+ messages in thread From: Trent Piepho @ 2013-03-29 15:19 UTC (permalink / raw) To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f Cc: Marek Vasut, Fabio Estevam, Trent Piepho, Shawn Guo Because the driver sets the SPI_MASTER_HALF_DUPLEX flag, the spi core will check transfers to insure they are not full duplex. It's not necessary to check that in the mxs driver as well. Signed-off-by: Trent Piepho <tpiepho-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> Cc: Marek Vasut <marex-ynQEQJNshbs@public.gmane.org> Cc: Fabio Estevam <fabio.estevam-KZfg59tc24xl57MIdRCFDg@public.gmane.org> Cc: Shawn Guo <shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> --- drivers/spi/spi-mxs.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c index 5d63b21..7218006 100644 --- a/drivers/spi/spi-mxs.c +++ b/drivers/spi/spi-mxs.c @@ -408,12 +408,6 @@ static int mxs_spi_transfer_one(struct spi_master *master, /* De-assert on last transfer, inverted by cs_change flag */ flag = (&t->transfer_list == m->transfers.prev) ^ t->cs_change ? TXRX_DEASSERT_CS : 0; - if ((t->rx_buf && t->tx_buf) || (t->rx_dma && t->tx_dma)) { - dev_err(ssp->dev, - "Cannot send and receive simultaneously\n"); - status = -EINVAL; - break; - } /* * Small blocks can be transfered via PIO. -- 1.7.10.4 ------------------------------------------------------------------------------ Own the Future-Intel(R) Level Up Game Demo Contest 2013 Rise to greatness in Intel's independent game demo contest. Compete for recognition, cash, and the chance to get your game on Steam. $5K grand prize plus 10 genre and skill prizes. Submit your demo by 6/6/13. http://altfarm.mediaplex.com/ad/ck/12124-176961-30367-2 ^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 4/5] spi/mxs: Remove bogus setting of ssp clk rate field [not found] ` <1364570381-17605-1-git-send-email-tpiepho-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 2013-03-29 15:19 ` [PATCH 2/5] spi/mxs: Fix chip select control bits in DMA mode Trent Piepho 2013-03-29 15:19 ` [PATCH 3/5] spi/mxs: Remove full duplex check, spi core already does it Trent Piepho @ 2013-03-29 15:19 ` Trent Piepho [not found] ` <1364570381-17605-4-git-send-email-tpiepho-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 2013-03-29 15:19 ` [PATCH 5/5] spi/mxs: Fix multiple slave bug and don't set clock for each xfer Trent Piepho 2013-04-01 23:11 ` [PATCH 1/5] spi/mxs: Fix extra CS pulses and read mode in multi-transfer messages Marek Vasut 4 siblings, 1 reply; 24+ messages in thread From: Trent Piepho @ 2013-03-29 15:19 UTC (permalink / raw) To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f Cc: Marek Vasut, Fabio Estevam, Trent Piepho, Shawn Guo The ssp struct has a clock rate field, to provide the actual value, in Hz, of the SSP output clock (the rate of SSP_SCK) after mxs_ssp_set_clk_rate() is called. It should be read-only, except for mxs_ssp_set_clk_rate(). For some reason the spi-mxs driver decides to write to this field on init, and sets it to the value of the SSP input clock (clk_sspN, from the MXS clocking block) in kHz. It shouldn't be setting the value, and certainly shouldn't be setting it with the wrong clock in the wrong units. Signed-off-by: Trent Piepho <tpiepho-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> Cc: Marek Vasut <marex-ynQEQJNshbs@public.gmane.org> Cc: Fabio Estevam <fabio.estevam-KZfg59tc24xl57MIdRCFDg@public.gmane.org> Cc: Shawn Guo <shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> --- drivers/spi/spi-mxs.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c index 7218006..fc52f78 100644 --- a/drivers/spi/spi-mxs.c +++ b/drivers/spi/spi-mxs.c @@ -587,7 +587,6 @@ static int mxs_spi_probe(struct platform_device *pdev) clk_prepare_enable(ssp->clk); clk_set_rate(ssp->clk, clk_freq); - ssp->clk_rate = clk_get_rate(ssp->clk) / 1000; stmp_reset_block(ssp->base); -- 1.7.10.4 ------------------------------------------------------------------------------ Own the Future-Intel(R) Level Up Game Demo Contest 2013 Rise to greatness in Intel's independent game demo contest. Compete for recognition, cash, and the chance to get your game on Steam. $5K grand prize plus 10 genre and skill prizes. Submit your demo by 6/6/13. http://altfarm.mediaplex.com/ad/ck/12124-176961-30367-2 ^ permalink raw reply related [flat|nested] 24+ messages in thread
[parent not found: <1364570381-17605-4-git-send-email-tpiepho-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>]
* Re: [PATCH 4/5] spi/mxs: Remove bogus setting of ssp clk rate field [not found] ` <1364570381-17605-4-git-send-email-tpiepho-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> @ 2013-04-01 23:16 ` Marek Vasut [not found] ` <201304020116.04781.marex-ynQEQJNshbs@public.gmane.org> 0 siblings, 1 reply; 24+ messages in thread From: Marek Vasut @ 2013-04-01 23:16 UTC (permalink / raw) To: Trent Piepho Cc: Fabio Estevam, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Shawn Guo, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r Dear Trent Piepho, > The ssp struct has a clock rate field, to provide the actual value, in Hz, > of the SSP output clock (the rate of SSP_SCK) after mxs_ssp_set_clk_rate() > is called. It should be read-only, except for mxs_ssp_set_clk_rate(). > > For some reason the spi-mxs driver decides to write to this field on init, > and sets it to the value of the SSP input clock (clk_sspN, from the MXS > clocking block) in kHz. It shouldn't be setting the value, and certainly > shouldn't be setting it with the wrong clock in the wrong units. I suspect this patch should also fix drivers/clk/mxs/clk-ssp.c then? > Signed-off-by: Trent Piepho <tpiepho-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> > Cc: Marek Vasut <marex-ynQEQJNshbs@public.gmane.org> > Cc: Fabio Estevam <fabio.estevam-KZfg59tc24xl57MIdRCFDg@public.gmane.org> > Cc: Shawn Guo <shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> > --- > drivers/spi/spi-mxs.c | 1 - > 1 file changed, 1 deletion(-) > > diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c > index 7218006..fc52f78 100644 > --- a/drivers/spi/spi-mxs.c > +++ b/drivers/spi/spi-mxs.c > @@ -587,7 +587,6 @@ static int mxs_spi_probe(struct platform_device *pdev) > > clk_prepare_enable(ssp->clk); > clk_set_rate(ssp->clk, clk_freq); > - ssp->clk_rate = clk_get_rate(ssp->clk) / 1000; > > stmp_reset_block(ssp->base); Best regards, Marek Vasut ------------------------------------------------------------------------------ Own the Future-Intel® Level Up Game Demo Contest 2013 Rise to greatness in Intel's independent game demo contest. Compete for recognition, cash, and the chance to get your game on Steam. $5K grand prize plus 10 genre and skill prizes. Submit your demo by 6/6/13. http://p.sf.net/sfu/intel_levelupd2d ^ permalink raw reply [flat|nested] 24+ messages in thread
[parent not found: <201304020116.04781.marex-ynQEQJNshbs@public.gmane.org>]
* Re: [PATCH 4/5] spi/mxs: Remove bogus setting of ssp clk rate field [not found] ` <201304020116.04781.marex-ynQEQJNshbs@public.gmane.org> @ 2013-04-01 23:32 ` Trent Piepho [not found] ` <CA+7tXihhL2ETT+AgvX5KASZOOgi6bucModE88ztY9Q8U1gDbOQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 0 siblings, 1 reply; 24+ messages in thread From: Trent Piepho @ 2013-04-01 23:32 UTC (permalink / raw) To: Marek Vasut Cc: Fabio Estevam, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Shawn Guo, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org On Mon, Apr 1, 2013 at 4:16 PM, Marek Vasut <marex-ynQEQJNshbs@public.gmane.org> wrote: >> The ssp struct has a clock rate field, to provide the actual value, in Hz, >> of the SSP output clock (the rate of SSP_SCK) after mxs_ssp_set_clk_rate() >> is called. It should be read-only, except for mxs_ssp_set_clk_rate(). >> >> For some reason the spi-mxs driver decides to write to this field on init, >> and sets it to the value of the SSP input clock (clk_sspN, from the MXS >> clocking block) in kHz. It shouldn't be setting the value, and certainly >> shouldn't be setting it with the wrong clock in the wrong units. > > I suspect this patch should also fix drivers/clk/mxs/clk-ssp.c then? Why do you say that? I see no problem with clk-ssp.c, as setting the clk_rate field in the ssp struct to the actual programmed rate makes sense. The code in spi-mxs.c just makes no sense. I suspect it was added by mistake when porting the driver. ------------------------------------------------------------------------------ Own the Future-Intel® Level Up Game Demo Contest 2013 Rise to greatness in Intel's independent game demo contest. Compete for recognition, cash, and the chance to get your game on Steam. $5K grand prize plus 10 genre and skill prizes. Submit your demo by 6/6/13. http://p.sf.net/sfu/intel_levelupd2d ^ permalink raw reply [flat|nested] 24+ messages in thread
[parent not found: <CA+7tXihhL2ETT+AgvX5KASZOOgi6bucModE88ztY9Q8U1gDbOQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>]
* Re: [PATCH 4/5] spi/mxs: Remove bogus setting of ssp clk rate field [not found] ` <CA+7tXihhL2ETT+AgvX5KASZOOgi6bucModE88ztY9Q8U1gDbOQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> @ 2013-04-01 23:37 ` Marek Vasut 2013-04-02 0:07 ` Trent Piepho 0 siblings, 1 reply; 24+ messages in thread From: Marek Vasut @ 2013-04-01 23:37 UTC (permalink / raw) To: Trent Piepho Cc: Fabio Estevam, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Shawn Guo, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org Dear Trent Piepho, > On Mon, Apr 1, 2013 at 4:16 PM, Marek Vasut <marex-ynQEQJNshbs@public.gmane.org> wrote: > >> The ssp struct has a clock rate field, to provide the actual value, in > >> Hz, of the SSP output clock (the rate of SSP_SCK) after > >> mxs_ssp_set_clk_rate() is called. It should be read-only, except for > >> mxs_ssp_set_clk_rate(). > >> > >> For some reason the spi-mxs driver decides to write to this field on > >> init, and sets it to the value of the SSP input clock (clk_sspN, from > >> the MXS clocking block) in kHz. It shouldn't be setting the value, and > >> certainly shouldn't be setting it with the wrong clock in the wrong > >> units. > > > > I suspect this patch should also fix drivers/clk/mxs/clk-ssp.c then? > > Why do you say that? I see no problem with clk-ssp.c, as setting the > clk_rate field in the ssp struct to the actual programmed rate makes > sense. The code in spi-mxs.c just makes no sense. I suspect it was > added by mistake when porting the driver. Either remove it altogether if it's unused OR make sure it's inited to some sane value from the start. Best regards, Marek Vasut ------------------------------------------------------------------------------ Own the Future-Intel® Level Up Game Demo Contest 2013 Rise to greatness in Intel's independent game demo contest. Compete for recognition, cash, and the chance to get your game on Steam. $5K grand prize plus 10 genre and skill prizes. Submit your demo by 6/6/13. http://p.sf.net/sfu/intel_levelupd2d ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 4/5] spi/mxs: Remove bogus setting of ssp clk rate field 2013-04-01 23:37 ` Marek Vasut @ 2013-04-02 0:07 ` Trent Piepho [not found] ` <CA+7tXihfDnmkTJGzk_yvRKYwb5mJzzLJVV+XupCEGnmpQdKDLQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 0 siblings, 1 reply; 24+ messages in thread From: Trent Piepho @ 2013-04-02 0:07 UTC (permalink / raw) To: Marek Vasut Cc: Fabio Estevam, spi-devel-general, Shawn Guo, linux-arm-kernel@lists.infradead.org On Mon, Apr 1, 2013 at 4:37 PM, Marek Vasut <marex@denx.de> wrote: >> On Mon, Apr 1, 2013 at 4:16 PM, Marek Vasut <marex@denx.de> wrote: >> >> The ssp struct has a clock rate field, to provide the actual value, in >> >> Hz, of the SSP output clock (the rate of SSP_SCK) after >> >> mxs_ssp_set_clk_rate() is called. It should be read-only, except for >> >> mxs_ssp_set_clk_rate(). >> >> >> >> For some reason the spi-mxs driver decides to write to this field on >> >> init, and sets it to the value of the SSP input clock (clk_sspN, from >> >> the MXS clocking block) in kHz. It shouldn't be setting the value, and >> >> certainly shouldn't be setting it with the wrong clock in the wrong >> >> units. >> > >> > I suspect this patch should also fix drivers/clk/mxs/clk-ssp.c then? >> >> Why do you say that? I see no problem with clk-ssp.c, as setting the >> clk_rate field in the ssp struct to the actual programmed rate makes >> sense. The code in spi-mxs.c just makes no sense. I suspect it was >> added by mistake when porting the driver. > > Either remove it altogether if it's unused OR make sure it's inited to some sane > value from the start. This field doesn't need to be initted by a user of the common SSP clock code, as it is not an input to that code. It is set by the SSP clock code. After the SSP clock is programmed, it can be read to find the true SSP rate. There is no need for any user of the SSP code to set the clk_rate field, and other than this one incorrect line, no user does so. It's not used currently in the SPI driver at all, but it certainly could be. The SSP code is shared with the MMC driver that can drive an SSP port in SD/MMC mode. The mxs-mmc code does need the actual SSP clock and does use the field. That code does not write to ssp->clk_rate, because as I have said, it is in output from the SSP clock code. Since the ssp struct is part of the spi master device data, it would be initialized to zero when allocated by spi_master_alloc(). The SPI clock isn't part of the spi master, but of a spi slave and a spi transfer. Thus there is no sensible value to initialize the spi clock to at the time the spi master is created. Which is fine. The code doesn't try to and other spi drivers don't either. At the time a spi slave is created the spi clock could be programmed. But that would introduce a race. The proper thing to do, and what the driver does, is to program the spi clock with the requested clock for a spi transfer. ^ permalink raw reply [flat|nested] 24+ messages in thread
[parent not found: <CA+7tXihfDnmkTJGzk_yvRKYwb5mJzzLJVV+XupCEGnmpQdKDLQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>]
* Re: [PATCH 4/5] spi/mxs: Remove bogus setting of ssp clk rate field [not found] ` <CA+7tXihfDnmkTJGzk_yvRKYwb5mJzzLJVV+XupCEGnmpQdKDLQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> @ 2013-04-02 0:29 ` Marek Vasut 0 siblings, 0 replies; 24+ messages in thread From: Marek Vasut @ 2013-04-02 0:29 UTC (permalink / raw) To: Trent Piepho Cc: Fabio Estevam, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Shawn Guo, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org Dear Trent Piepho, > On Mon, Apr 1, 2013 at 4:37 PM, Marek Vasut <marex-ynQEQJNshbs@public.gmane.org> wrote: > >> On Mon, Apr 1, 2013 at 4:16 PM, Marek Vasut <marex-ynQEQJNshbs@public.gmane.org> wrote: > >> >> The ssp struct has a clock rate field, to provide the actual value, > >> >> in Hz, of the SSP output clock (the rate of SSP_SCK) after > >> >> mxs_ssp_set_clk_rate() is called. It should be read-only, except for > >> >> mxs_ssp_set_clk_rate(). > >> >> > >> >> For some reason the spi-mxs driver decides to write to this field on > >> >> init, and sets it to the value of the SSP input clock (clk_sspN, from > >> >> the MXS clocking block) in kHz. It shouldn't be setting the value, > >> >> and certainly shouldn't be setting it with the wrong clock in the > >> >> wrong units. > >> > > >> > I suspect this patch should also fix drivers/clk/mxs/clk-ssp.c then? > >> > >> Why do you say that? I see no problem with clk-ssp.c, as setting the > >> clk_rate field in the ssp struct to the actual programmed rate makes > >> sense. The code in spi-mxs.c just makes no sense. I suspect it was > >> added by mistake when porting the driver. > > > > Either remove it altogether if it's unused OR make sure it's inited to > > some sane value from the start. > > This field doesn't need to be initted by a user of the common SSP > clock code, as it is not an input to that code. It is set by the SSP > clock code. After the SSP clock is programmed, it can be read to find > the true SSP rate. There is no need for any user of the SSP code to > set the clk_rate field, and other than this one incorrect line, no > user does so. It's not used currently in the SPI driver at all, but > it certainly could be. The SSP code is shared with the MMC driver > that can drive an SSP port in SD/MMC mode. The mxs-mmc code does need > the actual SSP clock and does use the field. That code does not write > to ssp->clk_rate, because as I have said, it is in output from the SSP > clock code. If the clk_rate is at least inited to zero, then this patch does makes sense. [...] Best regards, Marek Vasut ------------------------------------------------------------------------------ Own the Future-Intel(R) Level Up Game Demo Contest 2013 Rise to greatness in Intel's independent game demo contest. Compete for recognition, cash, and the chance to get your game on Steam. $5K grand prize plus 10 genre and skill prizes. Submit your demo by 6/6/13. http://altfarm.mediaplex.com/ad/ck/12124-176961-30367-2 ^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH 5/5] spi/mxs: Fix multiple slave bug and don't set clock for each xfer [not found] ` <1364570381-17605-1-git-send-email-tpiepho-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> ` (2 preceding siblings ...) 2013-03-29 15:19 ` [PATCH 4/5] spi/mxs: Remove bogus setting of ssp clk rate field Trent Piepho @ 2013-03-29 15:19 ` Trent Piepho [not found] ` <1364570381-17605-5-git-send-email-tpiepho-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 2013-04-01 23:11 ` [PATCH 1/5] spi/mxs: Fix extra CS pulses and read mode in multi-transfer messages Marek Vasut 4 siblings, 1 reply; 24+ messages in thread From: Trent Piepho @ 2013-03-29 15:19 UTC (permalink / raw) To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f Cc: Marek Vasut, Fabio Estevam, Trent Piepho, Shawn Guo Despite many warnings in the SPI documentation and code, the spi-mxs driver sets shared chip registers in the ->setup method. This method can be called when transfers are in progress on other slaves controlled by the master. Setting registers or any other shared state will corrupt those transfers. So fix mxs_spi_setup() to not call mxs_spi_setup_transfer(). Now that mxs_spi_setup_transfer() won't be called with a NULL transfer, since it's only purpose is to setup a transfer, the code can be simplified. mxs_spi_setup_transfer() would set the SSP SCK rate every time it was called, which is before each transfer. It is uncommon for the SCK rate to change between transfers and this causes unnecessary reprogramming of the clock registers. Changed to only set the rate when it has changed. This significantly speeds up short SPI messages, especially messages made up of many transfers. On an iMX287, using spidev with messages that consist of 511 transfers of 4 bytes each at an SCK of 48 MHz, the effective transfer rate more than doubles from about 290 KB/sec to 600 KB/sec. Signed-off-by: Trent Piepho <tpiepho-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> Cc: Marek Vasut <marex-ynQEQJNshbs@public.gmane.org> Cc: Fabio Estevam <fabio.estevam-KZfg59tc24xl57MIdRCFDg@public.gmane.org> Cc: Shawn Guo <shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> --- drivers/spi/spi-mxs.c | 54 ++++++++++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c index fc52f78..b60baab 100644 --- a/drivers/spi/spi-mxs.c +++ b/drivers/spi/spi-mxs.c @@ -66,44 +66,47 @@ struct mxs_spi { struct mxs_ssp ssp; struct completion c; + unsigned int sck; /* Rate requested (vs actual) */ }; static int mxs_spi_setup_transfer(struct spi_device *dev, - struct spi_transfer *t) + const struct spi_transfer *t) { struct mxs_spi *spi = spi_master_get_devdata(dev->master); struct mxs_ssp *ssp = &spi->ssp; - uint8_t bits_per_word; - uint32_t hz = 0; - - bits_per_word = dev->bits_per_word; - if (t && t->bits_per_word) - bits_per_word = t->bits_per_word; + const unsigned int bits_per_word = t->bits_per_word ? : dev->bits_per_word; + const unsigned int hz = t->speed_hz ? min(dev->max_speed_hz, t->speed_hz) : + dev->max_speed_hz; if (bits_per_word != 8) { - dev_err(&dev->dev, "%s, unsupported bits_per_word=%d\n", - __func__, bits_per_word); + dev_err(&dev->dev, "Unsupported bits per word of %d\n", + bits_per_word); return -EINVAL; } - hz = dev->max_speed_hz; - if (t && t->speed_hz) - hz = min(hz, t->speed_hz); if (hz == 0) { - dev_err(&dev->dev, "Cannot continue with zero clock\n"); + dev_err(&dev->dev, "SPI clock rate of zero not possible\n"); return -EINVAL; } - mxs_ssp_set_clk_rate(ssp, hz); + if (hz != spi->sck) { + mxs_ssp_set_clk_rate(ssp, hz); + /* Save requested value, not actual value from ssp->clk_rate. + * Otherwise we would set the rate again each trasfer when + * actual is not quite the same as requested. */ + spi->sck = hz; + /* Perhaps we should return an error if the actual clock is + * nowhere close? */ + } writel(BM_SSP_CTRL0_LOCK_CS, ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET); + writel(BF_SSP_CTRL1_SSP_MODE(BV_SSP_CTRL1_SSP_MODE__SPI) | - BF_SSP_CTRL1_WORD_LENGTH - (BV_SSP_CTRL1_WORD_LENGTH__EIGHT_BITS) | - ((dev->mode & SPI_CPOL) ? BM_SSP_CTRL1_POLARITY : 0) | - ((dev->mode & SPI_CPHA) ? BM_SSP_CTRL1_PHASE : 0), - ssp->base + HW_SSP_CTRL1(ssp)); + BF_SSP_CTRL1_WORD_LENGTH(BV_SSP_CTRL1_WORD_LENGTH__EIGHT_BITS) | + ((dev->mode & SPI_CPOL) ? BM_SSP_CTRL1_POLARITY : 0) | + ((dev->mode & SPI_CPHA) ? BM_SSP_CTRL1_PHASE : 0), + ssp->base + HW_SSP_CTRL1(ssp)); writel(0x0, ssp->base + HW_SSP_CMD0); writel(0x0, ssp->base + HW_SSP_CMD1); @@ -113,21 +116,16 @@ static int mxs_spi_setup_transfer(struct spi_device *dev, static int mxs_spi_setup(struct spi_device *dev) { - int err = 0; - if (!dev->bits_per_word) dev->bits_per_word = 8; - if (dev->mode & ~(SPI_CPOL | SPI_CPHA)) + if (dev->bits_per_word != 8) return -EINVAL; - err = mxs_spi_setup_transfer(dev, NULL); - if (err) { - dev_err(&dev->dev, - "Failed to setup transfer, error = %d\n", err); - } + if (dev->mode & ~(SPI_CPOL | SPI_CPHA)) + return -EINVAL; - return err; + return 0; } static u32 mxs_spi_cs_to_reg(unsigned cs) -- 1.7.10.4 ------------------------------------------------------------------------------ Own the Future-Intel(R) Level Up Game Demo Contest 2013 Rise to greatness in Intel's independent game demo contest. Compete for recognition, cash, and the chance to get your game on Steam. $5K grand prize plus 10 genre and skill prizes. Submit your demo by 6/6/13. http://altfarm.mediaplex.com/ad/ck/12124-176961-30367-2 ^ permalink raw reply related [flat|nested] 24+ messages in thread
[parent not found: <1364570381-17605-5-git-send-email-tpiepho-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>]
* Re: [PATCH 5/5] spi/mxs: Fix multiple slave bug and don't set clock for each xfer [not found] ` <1364570381-17605-5-git-send-email-tpiepho-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> @ 2013-04-01 23:18 ` Marek Vasut 0 siblings, 0 replies; 24+ messages in thread From: Marek Vasut @ 2013-04-01 23:18 UTC (permalink / raw) To: Trent Piepho Cc: Fabio Estevam, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Shawn Guo, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r Dear Trent Piepho, > Despite many warnings in the SPI documentation and code, the spi-mxs > driver sets shared chip registers in the ->setup method. This method can > be called when transfers are in progress on other slaves controlled by the > master. Setting registers or any other shared state will corrupt those > transfers. > > So fix mxs_spi_setup() to not call mxs_spi_setup_transfer(). > > Now that mxs_spi_setup_transfer() won't be called with a NULL transfer, > since it's only purpose is to setup a transfer, the code can be > simplified. > > mxs_spi_setup_transfer() would set the SSP SCK rate every time it was > called, which is before each transfer. It is uncommon for the SCK rate to > change between transfers and this causes unnecessary reprogramming of the > clock registers. Changed to only set the rate when it has changed. > > This significantly speeds up short SPI messages, especially messages made > up of many transfers. On an iMX287, using spidev with messages that > consist of 511 transfers of 4 bytes each at an SCK of 48 MHz, the > effective transfer rate more than doubles from about 290 KB/sec to 600 > KB/sec. This patch is full of unrelated changes, the relevant parts are not clear. Please clean up and resubmit with only the relevant changes. > Signed-off-by: Trent Piepho <tpiepho-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> > Cc: Marek Vasut <marex-ynQEQJNshbs@public.gmane.org> > Cc: Fabio Estevam <fabio.estevam-KZfg59tc24xl57MIdRCFDg@public.gmane.org> > Cc: Shawn Guo <shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> > --- > drivers/spi/spi-mxs.c | 54 > ++++++++++++++++++++++++------------------------- 1 file changed, 26 > insertions(+), 28 deletions(-) > > diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c > index fc52f78..b60baab 100644 > --- a/drivers/spi/spi-mxs.c > +++ b/drivers/spi/spi-mxs.c > @@ -66,44 +66,47 @@ > struct mxs_spi { > struct mxs_ssp ssp; > struct completion c; > + unsigned int sck; /* Rate requested (vs actual) */ > }; > > static int mxs_spi_setup_transfer(struct spi_device *dev, > - struct spi_transfer *t) > + const struct spi_transfer *t) > { > struct mxs_spi *spi = spi_master_get_devdata(dev->master); > struct mxs_ssp *ssp = &spi->ssp; > - uint8_t bits_per_word; > - uint32_t hz = 0; > - > - bits_per_word = dev->bits_per_word; > - if (t && t->bits_per_word) > - bits_per_word = t->bits_per_word; > + const unsigned int bits_per_word = t->bits_per_word ? : > dev->bits_per_word; + const unsigned int hz = t->speed_hz ? > min(dev->max_speed_hz, t->speed_hz) : + dev->max_speed_hz; > > if (bits_per_word != 8) { > - dev_err(&dev->dev, "%s, unsupported bits_per_word=%d\n", > - __func__, bits_per_word); > + dev_err(&dev->dev, "Unsupported bits per word of %d\n", > + bits_per_word); > return -EINVAL; > } > > - hz = dev->max_speed_hz; > - if (t && t->speed_hz) > - hz = min(hz, t->speed_hz); > if (hz == 0) { > - dev_err(&dev->dev, "Cannot continue with zero clock\n"); > + dev_err(&dev->dev, "SPI clock rate of zero not possible\n"); > return -EINVAL; > } > > - mxs_ssp_set_clk_rate(ssp, hz); > + if (hz != spi->sck) { > + mxs_ssp_set_clk_rate(ssp, hz); > + /* Save requested value, not actual value from ssp->clk_rate. > + * Otherwise we would set the rate again each trasfer when > + * actual is not quite the same as requested. */ > + spi->sck = hz; > + /* Perhaps we should return an error if the actual clock is > + * nowhere close? */ > + } > > writel(BM_SSP_CTRL0_LOCK_CS, > ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET); > + > writel(BF_SSP_CTRL1_SSP_MODE(BV_SSP_CTRL1_SSP_MODE__SPI) | > - BF_SSP_CTRL1_WORD_LENGTH > - (BV_SSP_CTRL1_WORD_LENGTH__EIGHT_BITS) | > - ((dev->mode & SPI_CPOL) ? BM_SSP_CTRL1_POLARITY : 0) | > - ((dev->mode & SPI_CPHA) ? BM_SSP_CTRL1_PHASE : 0), > - ssp->base + HW_SSP_CTRL1(ssp)); > + BF_SSP_CTRL1_WORD_LENGTH(BV_SSP_CTRL1_WORD_LENGTH__EIGHT_BITS) | > + ((dev->mode & SPI_CPOL) ? BM_SSP_CTRL1_POLARITY : 0) | > + ((dev->mode & SPI_CPHA) ? BM_SSP_CTRL1_PHASE : 0), > + ssp->base + HW_SSP_CTRL1(ssp)); > > writel(0x0, ssp->base + HW_SSP_CMD0); > writel(0x0, ssp->base + HW_SSP_CMD1); > @@ -113,21 +116,16 @@ static int mxs_spi_setup_transfer(struct spi_device > *dev, > > static int mxs_spi_setup(struct spi_device *dev) > { > - int err = 0; > - > if (!dev->bits_per_word) > dev->bits_per_word = 8; > > - if (dev->mode & ~(SPI_CPOL | SPI_CPHA)) > + if (dev->bits_per_word != 8) > return -EINVAL; > > - err = mxs_spi_setup_transfer(dev, NULL); > - if (err) { > - dev_err(&dev->dev, > - "Failed to setup transfer, error = %d\n", err); > - } > + if (dev->mode & ~(SPI_CPOL | SPI_CPHA)) > + return -EINVAL; > > - return err; > + return 0; > } > > static u32 mxs_spi_cs_to_reg(unsigned cs) Best regards, Marek Vasut ------------------------------------------------------------------------------ Own the Future-Intel® Level Up Game Demo Contest 2013 Rise to greatness in Intel's independent game demo contest. Compete for recognition, cash, and the chance to get your game on Steam. $5K grand prize plus 10 genre and skill prizes. Submit your demo by 6/6/13. http://p.sf.net/sfu/intel_levelupd2d ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 1/5] spi/mxs: Fix extra CS pulses and read mode in multi-transfer messages [not found] ` <1364570381-17605-1-git-send-email-tpiepho-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> ` (3 preceding siblings ...) 2013-03-29 15:19 ` [PATCH 5/5] spi/mxs: Fix multiple slave bug and don't set clock for each xfer Trent Piepho @ 2013-04-01 23:11 ` Marek Vasut [not found] ` <201304020111.13969.marex-ynQEQJNshbs@public.gmane.org> 4 siblings, 1 reply; 24+ messages in thread From: Marek Vasut @ 2013-04-01 23:11 UTC (permalink / raw) To: Trent Piepho Cc: Fabio Estevam, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Shawn Guo, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r Dear Trent Piepho, > There are two bits which control the CS line in the CTRL0 register: > LOCK_CS and IGNORE_CRC. The latter would be better named DEASSERT_CS > in SPI mode. > > LOCK_CS keeps CS asserted though the entire transfer. This should > always be set. The DMA code will always set it, explicitly on the > first segment of the first transfer, and then implicitly on all the > rest by never clearing the bit from the value read from the ctrl0 > register. > > The only reason to not set LOCK_CS would be to attempt an altered > protocol where CS pulses between each word. Though don't get your > hopes up, as the hardware doesn't appear to do this in any sane > manner. > > Setting DEASSERT_CS causes CS to be de-asserted at the end of the > transfer. It would normally be set on the final segment of the final > transfer. The DMA code explicitly sets it in this case, but because > it never clears the bit from the ctrl0 register is will remain set for > all transfers in subsequent messages. This results in a CS pulse > between transfers. > > There is a similar problem with the read mode bit never being cleared > in DMA mode. > > The spi transfer "cs_change" flag is ignored by the driver. > > The driver passes a "first" and "last" flag to the transfer functions > for a message, so they can know how to set these bits. It does this > by passing them as pointers. There is no reason to do this, as the > flags are not modified in the transfer function. And since LOCK_CS > can be set and left that way, there is no need for a "first" flag at > all. > > This patch fixes DEASSERT_CS and READ being left on in DMA mode, > eliminates the flags being passed as separate pointers, and adds > support for the cs_change flag. > > Note that while using the cs_change flag to leave CS asserted after > the final transfer works, getting the CS to automatically turn off > when a different slave is addressed might not work. > > Signed-off-by: Trent Piepho <tpiepho-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> > Cc: Marek Vasut <marex-ynQEQJNshbs@public.gmane.org> > Cc: Fabio Estevam <fabio.estevam-KZfg59tc24xl57MIdRCFDg@public.gmane.org> > Cc: Shawn Guo <shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> > --- > drivers/spi/spi-mxs.c | 86 > +++++++++++++++++++++---------------------------- 1 file changed, 36 > insertions(+), 50 deletions(-) > > diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c > index 22a0af0..aa77d96b9 100644 > --- a/drivers/spi/spi-mxs.c > +++ b/drivers/spi/spi-mxs.c > @@ -58,6 +58,11 @@ > > #define SG_MAXLEN 0xff00 > > +/* Flags for txrx functions. More efficient that using an argument > register for + * each one. */ Fix the comment please. /* * Multiline comment should really * be like this. */ > +#define TXRX_WRITE 1 /* This is a write */ > +#define TXRX_DEASSERT_CS 2 /* De-assert CS at end of txrx */ New flags? I'm sure the GCC can optimize function parameters pretty well, esp. if you make the bool. > struct mxs_spi { > struct mxs_ssp ssp; > struct completion c; > @@ -91,6 +96,8 @@ static int mxs_spi_setup_transfer(struct spi_device *dev, > > mxs_ssp_set_clk_rate(ssp, hz); > > + writel(BM_SSP_CTRL0_LOCK_CS, > + ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET); > writel(BF_SSP_CTRL1_SSP_MODE(BV_SSP_CTRL1_SSP_MODE__SPI) | > BF_SSP_CTRL1_WORD_LENGTH > (BV_SSP_CTRL1_WORD_LENGTH__EIGHT_BITS) | > @@ -155,26 +162,6 @@ static void mxs_spi_set_cs(struct mxs_spi *spi, > unsigned cs) writel(select, ssp->base + HW_SSP_CTRL0 + > STMP_OFFSET_REG_SET); > } > > -static inline void mxs_spi_enable(struct mxs_spi *spi) > -{ > - struct mxs_ssp *ssp = &spi->ssp; > - > - writel(BM_SSP_CTRL0_LOCK_CS, > - ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET); > - writel(BM_SSP_CTRL0_IGNORE_CRC, > - ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_CLR); > -} > - > -static inline void mxs_spi_disable(struct mxs_spi *spi) > -{ > - struct mxs_ssp *ssp = &spi->ssp; > - > - writel(BM_SSP_CTRL0_LOCK_CS, > - ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_CLR); > - writel(BM_SSP_CTRL0_IGNORE_CRC, > - ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET); > -} > - > static int mxs_ssp_wait(struct mxs_spi *spi, int offset, int mask, bool > set) { > const unsigned long timeout = jiffies + msecs_to_jiffies(SSP_TIMEOUT); > @@ -214,7 +201,7 @@ static irqreturn_t mxs_ssp_irq_handler(int irq, void > *dev_id) > > static int mxs_spi_txrx_dma(struct mxs_spi *spi, int cs, > unsigned char *buf, int len, > - int *first, int *last, int write) > + unsigned int flags) > { > struct mxs_ssp *ssp = &spi->ssp; > struct dma_async_tx_descriptor *desc = NULL; > @@ -241,20 +228,21 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi, int > cs, INIT_COMPLETION(spi->c); > > ctrl0 = readl(ssp->base + HW_SSP_CTRL0); > - ctrl0 &= ~BM_SSP_CTRL0_XFER_COUNT; > + ctrl0 &= ~BM_SSP_CTRL0_XFER_COUNT & ~BM_SSP_CTRL0_IGNORE_CRC & > + ~BM_SSP_CTRL0_READ; Well ... ctrl0 &= ~(FOO | BAR | BAZ); ... won't cut it? > ctrl0 |= BM_SSP_CTRL0_DATA_XFER | mxs_spi_cs_to_reg(cs); > > - if (*first) > - ctrl0 |= BM_SSP_CTRL0_LOCK_CS; The DMA will overwrite ctrl0 in each turn, did you try very long (>64kB long) transfers with your adjustments? To test this, you can try $ dd if=/dev/mtdN of=/dev/null bs=1M on sufficiently large SPI flash supporting the FAST_READ opcode. > - if (!write) > + if (!(flags & TXRX_WRITE)) > ctrl0 |= BM_SSP_CTRL0_READ; > > /* Queue the DMA data transfer. */ > for (sg_count = 0; sg_count < sgs; sg_count++) { > + /* Prepare the transfer descriptor. */ > min = min(len, desc_len); > > - /* Prepare the transfer descriptor. */ > - if ((sg_count + 1 == sgs) && *last) > + /* De-assert CS on last segment if flag is set (i.e., no more > + * transfers will follow) */ Wrong multi-line comment. See Documentation/CodingStyle chapter 8. > + if ((sg_count + 1 == sgs) && (flags & TXRX_DEASSERT_CS)) > ctrl0 |= BM_SSP_CTRL0_IGNORE_CRC; > > if (ssp->devid == IMX23_SSP) { > @@ -279,7 +267,7 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi, int > cs, > > sg_init_one(&dma_xfer[sg_count].sg, sg_buf, min); > ret = dma_map_sg(ssp->dev, &dma_xfer[sg_count].sg, 1, > - write ? DMA_TO_DEVICE : DMA_FROM_DEVICE); > + (flags & TXRX_WRITE) ? DMA_TO_DEVICE : DMA_FROM_DEVICE); I think this is unneeded. > len -= min; > buf += min; > @@ -299,7 +287,7 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi, int > cs, > > desc = dmaengine_prep_slave_sg(ssp->dmach, > &dma_xfer[sg_count].sg, 1, > - write ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM, > + (flags & TXRX_WRITE) ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM, > DMA_PREP_INTERRUPT | DMA_CTRL_ACK); > > if (!desc) { > @@ -336,7 +324,7 @@ err_vmalloc: > while (--sg_count >= 0) { > err_mapped: > dma_unmap_sg(ssp->dev, &dma_xfer[sg_count].sg, 1, > - write ? DMA_TO_DEVICE : DMA_FROM_DEVICE); > + (flags & TXRX_WRITE) ? DMA_TO_DEVICE : DMA_FROM_DEVICE); > } > > kfree(dma_xfer); > @@ -346,18 +334,20 @@ err_mapped: > > static int mxs_spi_txrx_pio(struct mxs_spi *spi, int cs, > unsigned char *buf, int len, > - int *first, int *last, int write) > + unsigned int flags) > { > struct mxs_ssp *ssp = &spi->ssp; > > - if (*first) > - mxs_spi_enable(spi); > + /* Clear this now, set it on last transfer if needed */ > + writel(BM_SSP_CTRL0_IGNORE_CRC, > + ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_CLR); > > mxs_spi_set_cs(spi, cs); > > while (len--) { > - if (*last && len == 0) > - mxs_spi_disable(spi); > + if (len == 0 && (flags & TXRX_DEASSERT_CS)) > + writel(BM_SSP_CTRL0_IGNORE_CRC, > + ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET); Ok, I'll stop here. You mixed two kinds of changes here: 1) The "fixup" of the flags 2) The adjustments to handling the IGNORE_CRC and LOCK_CS Split the patch please. ------------------------------------------------------------------------------ Own the Future-Intel® Level Up Game Demo Contest 2013 Rise to greatness in Intel's independent game demo contest. Compete for recognition, cash, and the chance to get your game on Steam. $5K grand prize plus 10 genre and skill prizes. Submit your demo by 6/6/13. http://p.sf.net/sfu/intel_levelupd2d ^ permalink raw reply [flat|nested] 24+ messages in thread
[parent not found: <201304020111.13969.marex-ynQEQJNshbs@public.gmane.org>]
* Re: [PATCH 1/5] spi/mxs: Fix extra CS pulses and read mode in multi-transfer messages [not found] ` <201304020111.13969.marex-ynQEQJNshbs@public.gmane.org> @ 2013-04-02 1:24 ` Trent Piepho [not found] ` <CA+7tXigx=qcDDJZGAx7JEX+Y-CDG-B0xyYgs6fHbUZofH7gnKw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 0 siblings, 1 reply; 24+ messages in thread From: Trent Piepho @ 2013-04-02 1:24 UTC (permalink / raw) To: Marek Vasut Cc: Fabio Estevam, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Shawn Guo, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org On Mon, Apr 1, 2013 at 4:11 PM, Marek Vasut <marex-ynQEQJNshbs@public.gmane.org> wrote: >> +#define TXRX_WRITE 1 /* This is a write */ >> +#define TXRX_DEASSERT_CS 2 /* De-assert CS at end of txrx */ > > New flags? I'm sure the GCC can optimize function parameters pretty well, esp. > if you make the bool. Nope. I checked the actual compiled code. Each bool takes another parameter. Since the txrx functions are large and called from multiple sites, they are not inlined. Gcc is not able to combine all the bool arguments into one single bitfield argument. On arm, to check if an argument on the stack is true requires two instructions. First an ldr to move the argument into a register and then a cmp to check it for zero. Checking for a bit is the basically the same, first an ldr and then a tst. So there is no performance advantage of "if(x)" vs "if(x&32)". But, if one uses bit flags then the same flag word can be used for every flag, avoiding the need to load a different word for each flag. So using the flags avoids extra instructions in the caller for each call to place each flag in its own boolean on the stack or in an argument register (depending on the # of function arguments), and then avoids extra code in the callee to load any arguments on the stack into a register. It can make code in loops faster and smaller by using fewer register and avoiding a register load inside the loop. BTW, after converting the code to bool arguments instead of flags: add/remove: 0/0 grow/shrink: 4/0 up/down: 130/0 (130) function old new delta mxs_spi_transfer_one 808 900 +92 mxs_spi_txrx_pio 492 508 +16 mxs_spi_txrx_dma 1188 1204 +16 __UNIQUE_ID_vermagic0 73 79 +6 Bool arguments for each flag is larger than using one argument and bit flags. And there are more flags needed to support things like GPIO CS lines. >> ctrl0 = readl(ssp->base + HW_SSP_CTRL0); >> - ctrl0 &= ~BM_SSP_CTRL0_XFER_COUNT; >> + ctrl0 &= ~BM_SSP_CTRL0_XFER_COUNT & ~BM_SSP_CTRL0_IGNORE_CRC & >> + ~BM_SSP_CTRL0_READ; > > Well ... ctrl0 &= ~(FOO | BAR | BAZ); ... won't cut it? Well, by De Morgan's law the two expressions are the same. And they are the same number of characters. And both will produce a compile time constant and thus the same code. However, I like the ~FOO & ~BAR & ~BAR form better as there is greater parallelism between each term of the expression. >> ctrl0 |= BM_SSP_CTRL0_DATA_XFER | mxs_spi_cs_to_reg(cs); >> >> - if (*first) >> - ctrl0 |= BM_SSP_CTRL0_LOCK_CS; > > The DMA will overwrite ctrl0 in each turn, did you try very long (>64kB long) > transfers with your adjustments? To test this, you can try > > $ dd if=/dev/mtdN of=/dev/null bs=1M > > on sufficiently large SPI flash supporting the FAST_READ opcode. Don't have SPI flash. I did test with logic analyzer and the current code is clearly broken and my changes clearly fix it. It should be obvious from looking a the code that it is wrong. The DMA does write ctrl0 on each segment of each transfer, but look at the previous paragraph to see where it comes from. Once READ or IGNORE_CRC are set, nothing will clear them until PIO mode is used. It's the same with the bug fix for 3.9 that clears the XFER_COUNT bits in DMA mode. Strangely, I didn't notice that bug since all my xfers are the same length! But I do switch between slaves, between read and write, and use messages with multiple transfers, in DMA mode, all of which are broken in the current driver. >> + if ((sg_count + 1 == sgs) && (flags & TXRX_DEASSERT_CS)) >> ctrl0 |= BM_SSP_CTRL0_IGNORE_CRC; >> >> if (ssp->devid == IMX23_SSP) { >> @@ -279,7 +267,7 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi, int >> cs, >> >> sg_init_one(&dma_xfer[sg_count].sg, sg_buf, min); >> ret = dma_map_sg(ssp->dev, &dma_xfer[sg_count].sg, 1, >> - write ? DMA_TO_DEVICE : DMA_FROM_DEVICE); >> + (flags & TXRX_WRITE) ? DMA_TO_DEVICE : DMA_FROM_DEVICE); > > I think this is unneeded. Whatis ? Setting the DMA direction or using flags? Look at it this way: Existing code that uses the first/last flags is wrong and needs to be changed. Therefor code using 'first' and 'last' will be changed. Passing the flags as pointers is bad practice and makes no sense to do. Does it make any sense to re-write code fix the way it uses first and last, then re-write those same lines a second time to not use pointers? If the way the flags are passed should change, then why not do it the most efficient way. It isn't any more complicated and produces better code. One flag per parameter becomes cumbersome when more flags are added for additional features. I'm all for splitting my patches up. I sent five patches when I bet 9 out 10 developers would have just done one. But I don't think it makes any sense to re-write the same line of code over and over again in successive patches in a series before getting to the final version. It just makes more churn to review. I hate it when I get a series of patches and spot a flaw, take the time to write up the flaw and how it should be fixed, only to discover that the flaw is fixed later on in the series and I wasted my time. ------------------------------------------------------------------------------ Own the Future-Intel(R) Level Up Game Demo Contest 2013 Rise to greatness in Intel's independent game demo contest. Compete for recognition, cash, and the chance to get your game on Steam. $5K grand prize plus 10 genre and skill prizes. Submit your demo by 6/6/13. http://altfarm.mediaplex.com/ad/ck/12124-176961-30367-2 ^ permalink raw reply [flat|nested] 24+ messages in thread
[parent not found: <CA+7tXigx=qcDDJZGAx7JEX+Y-CDG-B0xyYgs6fHbUZofH7gnKw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>]
* Re: [PATCH 1/5] spi/mxs: Fix extra CS pulses and read mode in multi-transfer messages [not found] ` <CA+7tXigx=qcDDJZGAx7JEX+Y-CDG-B0xyYgs6fHbUZofH7gnKw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> @ 2013-04-02 4:22 ` Marek Vasut [not found] ` <201304020622.52429.marex-ynQEQJNshbs@public.gmane.org> 0 siblings, 1 reply; 24+ messages in thread From: Marek Vasut @ 2013-04-02 4:22 UTC (permalink / raw) To: Trent Piepho Cc: Fabio Estevam, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Shawn Guo, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org Dear Trent Piepho, > On Mon, Apr 1, 2013 at 4:11 PM, Marek Vasut <marex-ynQEQJNshbs@public.gmane.org> wrote: > >> +#define TXRX_WRITE 1 /* This is a write */ > >> +#define TXRX_DEASSERT_CS 2 /* De-assert CS at end of txrx */ > > > > New flags? I'm sure the GCC can optimize function parameters pretty well, > > esp. if you make the bool. > > Nope. I checked the actual compiled code. Each bool takes another > parameter. Since the txrx functions are large and called from > multiple sites, they are not inlined. Gcc is not able to combine all > the bool arguments into one single bitfield argument. That's pretty poor, oh well. btw. is it necessary to define new flags or is it possible to reuse some? [...] > >> ctrl0 = readl(ssp->base + HW_SSP_CTRL0); > >> > >> - ctrl0 &= ~BM_SSP_CTRL0_XFER_COUNT; > >> + ctrl0 &= ~BM_SSP_CTRL0_XFER_COUNT & ~BM_SSP_CTRL0_IGNORE_CRC & > >> + ~BM_SSP_CTRL0_READ; > > > > Well ... ctrl0 &= ~(FOO | BAR | BAZ); ... won't cut it? > > Well, by De Morgan's law the two expressions are the same. And they > are the same number of characters. And both will produce a compile > time constant and thus the same code. However, I like the ~FOO & ~BAR > & ~BAR form better as there is greater parallelism between each term > of the expression. What about the law of readability of code ? ;-) > >> ctrl0 |= BM_SSP_CTRL0_DATA_XFER | mxs_spi_cs_to_reg(cs); > >> > >> - if (*first) > >> - ctrl0 |= BM_SSP_CTRL0_LOCK_CS; > > > > The DMA will overwrite ctrl0 in each turn, did you try very long (>64kB > > long) transfers with your adjustments? To test this, you can try > > > > $ dd if=/dev/mtdN of=/dev/null bs=1M > > > > on sufficiently large SPI flash supporting the FAST_READ opcode. > > Don't have SPI flash. I did test with logic analyzer and the current > code is clearly broken and my changes clearly fix it. Good, but you clearly didn't test it in the most used case. This will clearly piss off a lot of people if you break something. And this will clearly not be good ;-) I'm clearly planning to test the code, but only once it's clearly possible to tell apart churn from the actual fix (see my other rambling, just reminding you). So I'll wait for V2 and give it a go on a large flash. > It should be obvious from looking a the code that it is wrong. Sorry, it is not obvious. > The DMA does write > ctrl0 on each segment of each transfer, but look at the previous > paragraph to see where it comes from. Once READ or IGNORE_CRC are > set, nothing will clear them until PIO mode is used. When using a flash, the DMA and PIO mode usage is intermixed. Usually, the PIO is used to program the command and then DMA to transmit the payload. It's hardly ever PIO only orr DMA only for the whole transfer. > It's the same > with the bug fix for 3.9 that clears the XFER_COUNT bits in DMA mode. > Strangely, I didn't notice that bug since all my xfers are the same > length! But I do switch between slaves, between read and write, and > use messages with multiple transfers, in DMA mode, all of which are > broken in the current driver. btw. are you using MX23 or MX28 to test this? > >> + if ((sg_count + 1 == sgs) && (flags & TXRX_DEASSERT_CS)) > >> > >> ctrl0 |= BM_SSP_CTRL0_IGNORE_CRC; > >> > >> if (ssp->devid == IMX23_SSP) { > >> > >> @@ -279,7 +267,7 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi, int > >> cs, > >> > >> sg_init_one(&dma_xfer[sg_count].sg, sg_buf, min); > >> ret = dma_map_sg(ssp->dev, &dma_xfer[sg_count].sg, 1, > >> > >> - write ? DMA_TO_DEVICE : DMA_FROM_DEVICE); > >> + (flags & TXRX_WRITE) ? DMA_TO_DEVICE : > >> DMA_FROM_DEVICE); > > > > I think this is unneeded. > > Whatis ? Setting the DMA direction or using flags? > > Look at it this way: > > Existing code that uses the first/last flags is wrong and needs to be > changed. Therefor code using 'first' and 'last' will be changed. > > Passing the flags as pointers is bad practice and makes no sense to > do. Does it make any sense to re-write code fix the way it uses first > and last, then re-write those same lines a second time to not use > pointers? You can always flip it the other way -- first rework the use of flags, then apply the fix. It'd make the patch much easier to understand, don't you think? > If the way the flags are passed should change, then why not do it the > most efficient way. It isn't any more complicated and produces better > code. One flag per parameter becomes cumbersome when more flags are > added for additional features. > > I'm all for splitting my patches up. I sent five patches when I bet 9 > out 10 developers would have just done one. But I don't think it > makes any sense to re-write the same line of code over and over again > in successive patches in a series before getting to the final version. > It just makes more churn to review. Splitting the patchset to make it more understandable is OK though. And I'm really getting lost in this patch. > I hate it when I get a series of patches and spot a flaw, take the > time to write up the flaw and how it should be fixed, only to discover > that the flaw is fixed later on in the series and I wasted my time. Best regards, Marek Vasut ------------------------------------------------------------------------------ Own the Future-Intel(R) Level Up Game Demo Contest 2013 Rise to greatness in Intel's independent game demo contest. Compete for recognition, cash, and the chance to get your game on Steam. $5K grand prize plus 10 genre and skill prizes. Submit your demo by 6/6/13. http://altfarm.mediaplex.com/ad/ck/12124-176961-30367-2 ^ permalink raw reply [flat|nested] 24+ messages in thread
[parent not found: <201304020622.52429.marex-ynQEQJNshbs@public.gmane.org>]
* Re: [PATCH 1/5] spi/mxs: Fix extra CS pulses and read mode in multi-transfer messages [not found] ` <201304020622.52429.marex-ynQEQJNshbs@public.gmane.org> @ 2013-04-02 7:11 ` Trent Piepho [not found] ` <CA+7tXigvg+5k0Baa12CVwP5Ar7HUsJ8ihB19xrav4CNA6ZMFiA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 0 siblings, 1 reply; 24+ messages in thread From: Trent Piepho @ 2013-04-02 7:11 UTC (permalink / raw) To: Marek Vasut Cc: Fabio Estevam, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Shawn Guo, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org On Mon, Apr 1, 2013 at 9:22 PM, Marek Vasut <marex-ynQEQJNshbs@public.gmane.org> wrote: >> On Mon, Apr 1, 2013 at 4:11 PM, Marek Vasut <marex-ynQEQJNshbs@public.gmane.org> wrote: >> >> +#define TXRX_WRITE 1 /* This is a write */ >> >> +#define TXRX_DEASSERT_CS 2 /* De-assert CS at end of txrx */ > > btw. is it necessary to define new flags or is it possible to reuse some? I don't see any others that would make sense. The driver doesn't define any flags at all. The spi layer doesn't have ones that match. And this is for a private static interface inside the driver. It wouldn't be right to co-opt flags defined for some other purpose. >> >> ctrl0 = readl(ssp->base + HW_SSP_CTRL0); >> >> >> >> - ctrl0 &= ~BM_SSP_CTRL0_XFER_COUNT; >> >> + ctrl0 &= ~BM_SSP_CTRL0_XFER_COUNT & ~BM_SSP_CTRL0_IGNORE_CRC & >> >> + ~BM_SSP_CTRL0_READ; >> > >> > Well ... ctrl0 &= ~(FOO | BAR | BAZ); ... won't cut it? >> >> Well, by De Morgan's law the two expressions are the same. And they >> are the same number of characters. And both will produce a compile >> time constant and thus the same code. However, I like the ~FOO & ~BAR >> & ~BAR form better as there is greater parallelism between each term >> of the expression. > > What about the law of readability of code ? ;-) Don't see anything in CodingStyle that one should be preferred over the other. I think this way is more readable than the other. Generally you can think of masking off bits via bitwise-and and setting bits with bitwise-or. So if you want to do a sequence of masks, then using a sequence of bitwise-ands is the most readable and straightforward code IMHO. Combing bits to mask with bitwise-or, then inverting the set and masking with that seems like a less clear way of doing the same thing. And this way the existing tokens aren't modified, so there is less churn! >> The DMA does write >> ctrl0 on each segment of each transfer, but look at the previous >> paragraph to see where it comes from. Once READ or IGNORE_CRC are >> set, nothing will clear them until PIO mode is used. > > When using a flash, the DMA and PIO mode usage is intermixed. Usually, the PIO > is used to program the command and then DMA to transmit the payload. It's hardly > ever PIO only orr DMA only for the whole transfer. Probably why the problem hasn't been noticed. It's obvious from a cursory examination of the driver that bits in ctrl0 are only SET in the DMA code, never cleared. The PIO code does clear them. >> It's the same >> with the bug fix for 3.9 that clears the XFER_COUNT bits in DMA mode. >> Strangely, I didn't notice that bug since all my xfers are the same >> length! But I do switch between slaves, between read and write, and >> use messages with multiple transfers, in DMA mode, all of which are >> broken in the current driver. > > btw. are you using MX23 or MX28 to test this? IMX28. >> Existing code that uses the first/last flags is wrong and needs to be >> changed. Therefor code using 'first' and 'last' will be changed. >> >> Passing the flags as pointers is bad practice and makes no sense to >> do. Does it make any sense to re-write code fix the way it uses first >> and last, then re-write those same lines a second time to not use >> pointers? > > You can always flip it the other way -- first rework the use of flags, then > apply the fix. It'd make the patch much easier to understand, don't you think? So I should change 'first' to not be a pointer to an integer in one patch, then delete the flag entirely in another patch? What's the point of changing code just to delete it immediately afterward? I'd call that useless churn. It also makes a patch series a PITA to deal with, as a change to intermediate patch 1 creates a conflict when trying to apply intermediate patch 2, 3, 4 and so on. Instead of spending 5 mins creating V2 of one patch that needs a change, you have to speed an hour fixing V2 of an entire series. And that problem is only caused by trying to create the extra intermediate stages, that no one actually cares about and will never use, with various known flaws that are already fixed. ------------------------------------------------------------------------------ Own the Future-Intel(R) Level Up Game Demo Contest 2013 Rise to greatness in Intel's independent game demo contest. Compete for recognition, cash, and the chance to get your game on Steam. $5K grand prize plus 10 genre and skill prizes. Submit your demo by 6/6/13. http://altfarm.mediaplex.com/ad/ck/12124-176961-30367-2 ^ permalink raw reply [flat|nested] 24+ messages in thread
[parent not found: <CA+7tXigvg+5k0Baa12CVwP5Ar7HUsJ8ihB19xrav4CNA6ZMFiA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>]
* Re: [PATCH 1/5] spi/mxs: Fix extra CS pulses and read mode in multi-transfer messages [not found] ` <CA+7tXigvg+5k0Baa12CVwP5Ar7HUsJ8ihB19xrav4CNA6ZMFiA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> @ 2013-04-02 10:32 ` Marek Vasut [not found] ` <201304021232.12736.marex-ynQEQJNshbs@public.gmane.org> 0 siblings, 1 reply; 24+ messages in thread From: Marek Vasut @ 2013-04-02 10:32 UTC (permalink / raw) To: Trent Piepho Cc: Fabio Estevam, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Shawn Guo, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org Dear Trent Piepho, > On Mon, Apr 1, 2013 at 9:22 PM, Marek Vasut <marex-ynQEQJNshbs@public.gmane.org> wrote: > >> On Mon, Apr 1, 2013 at 4:11 PM, Marek Vasut <marex-ynQEQJNshbs@public.gmane.org> wrote: > >> >> +#define TXRX_WRITE 1 /* This is a write */ > >> >> +#define TXRX_DEASSERT_CS 2 /* De-assert CS at end of txrx > >> >> */ > > > > btw. is it necessary to define new flags or is it possible to reuse some? > > I don't see any others that would make sense. The driver doesn't > define any flags at all. The spi layer doesn't have ones that match. > And this is for a private static interface inside the driver. It > wouldn't be right to co-opt flags defined for some other purpose. Ok, makes sense then. btw. if defining bitfield flags, it makes more sense to use (1 << n) notation to make it more readable and also less prone to people using the actual flag value as a bitshift argument. > >> >> ctrl0 = readl(ssp->base + HW_SSP_CTRL0); > >> >> > >> >> - ctrl0 &= ~BM_SSP_CTRL0_XFER_COUNT; > >> >> + ctrl0 &= ~BM_SSP_CTRL0_XFER_COUNT & ~BM_SSP_CTRL0_IGNORE_CRC & > >> >> + ~BM_SSP_CTRL0_READ; > >> > > >> > Well ... ctrl0 &= ~(FOO | BAR | BAZ); ... won't cut it? > >> > >> Well, by De Morgan's law the two expressions are the same. And they > >> are the same number of characters. And both will produce a compile > >> time constant and thus the same code. However, I like the ~FOO & ~BAR > >> & ~BAR form better as there is greater parallelism between each term > >> of the expression. > > > > What about the law of readability of code ? ;-) > > Don't see anything in CodingStyle that one should be preferred over > the other. There ain't any I'm aware of, but to paraphrase you, let's keep the format that's already used in the driver ;-) : 114 if (dev->mode & ~(SPI_CPOL | SPI_CPHA)) > I think this way is more readable than the other. > Generally you can think of masking off bits via bitwise-and and > setting bits with bitwise-or. So if you want to do a sequence of > masks, then using a sequence of bitwise-ands is the most readable and > straightforward code IMHO. Combing bits to mask with bitwise-or, then > inverting the set and masking with that seems like a less clear way of > doing the same thing. And this way the existing tokens aren't > modified, so there is less churn! > > >> The DMA does write > >> ctrl0 on each segment of each transfer, but look at the previous > >> paragraph to see where it comes from. Once READ or IGNORE_CRC are > >> set, nothing will clear them until PIO mode is used. > > > > When using a flash, the DMA and PIO mode usage is intermixed. Usually, > > the PIO is used to program the command and then DMA to transmit the > > payload. It's hardly ever PIO only orr DMA only for the whole transfer. > > Probably why the problem hasn't been noticed. It's obvious from a > cursory examination of the driver that bits in ctrl0 are only SET in > the DMA code, never cleared. The PIO code does clear them. > > >> It's the same > >> with the bug fix for 3.9 that clears the XFER_COUNT bits in DMA mode. > >> Strangely, I didn't notice that bug since all my xfers are the same > >> length! But I do switch between slaves, between read and write, and > >> use messages with multiple transfers, in DMA mode, all of which are > >> broken in the current driver. > > > > btw. are you using MX23 or MX28 to test this? > > IMX28. Is that any mainline board? > >> Existing code that uses the first/last flags is wrong and needs to be > >> changed. Therefor code using 'first' and 'last' will be changed. > >> > >> Passing the flags as pointers is bad practice and makes no sense to > >> do. Does it make any sense to re-write code fix the way it uses first > >> and last, then re-write those same lines a second time to not use > >> pointers? > > > > You can always flip it the other way -- first rework the use of flags, > > then apply the fix. It'd make the patch much easier to understand, don't > > you think? > > So I should change 'first' to not be a pointer to an integer in one > patch, then delete the flag entirely in another patch? I'd say make a patch (0001) that implements the transition to using your newly defined flags and then make a patch (0002) that "Fix extra CS pulses and read mode in multi-transfer messages". One patch shall do one thing, that's the usual rule of the thumb. Obviously keep them in a series if these patches shall go in together. And why doesn't squashing them all together work you might ask -- because reviewing the result is hard. [...] Best regards, Marek Vasut ------------------------------------------------------------------------------ Own the Future-Intel(R) Level Up Game Demo Contest 2013 Rise to greatness in Intel's independent game demo contest. Compete for recognition, cash, and the chance to get your game on Steam. $5K grand prize plus 10 genre and skill prizes. Submit your demo by 6/6/13. http://altfarm.mediaplex.com/ad/ck/12124-176961-30367-2 ^ permalink raw reply [flat|nested] 24+ messages in thread
[parent not found: <201304021232.12736.marex-ynQEQJNshbs@public.gmane.org>]
* Re: [PATCH 1/5] spi/mxs: Fix extra CS pulses and read mode in multi-transfer messages [not found] ` <201304021232.12736.marex-ynQEQJNshbs@public.gmane.org> @ 2013-04-02 12:40 ` Trent Piepho [not found] ` <CA+7tXii8xhZQeKU2dTN26LxySNXhJT9NgRXcJ21cOX64qYj1NA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 0 siblings, 1 reply; 24+ messages in thread From: Trent Piepho @ 2013-04-02 12:40 UTC (permalink / raw) To: Marek Vasut Cc: Fabio Estevam, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Shawn Guo, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org On Tue, Apr 2, 2013 at 3:32 AM, Marek Vasut <marex-ynQEQJNshbs@public.gmane.org> wrote: >> >> Don't see anything in CodingStyle that one should be preferred over >> the other. > > There ain't any I'm aware of, but to paraphrase you, let's keep the format > that's already used in the driver ;-) : > > 114 if (dev->mode & ~(SPI_CPOL | SPI_CPHA)) Thanks for pointing that out, as that code can be deleted. Which means I don't need to be consistent with it anymore and can create a new standard, to be followed henceforth, now and forever. But it looks like the or method is more common in the kernel code. So I'll change it in V2. >> > btw. are you using MX23 or MX28 to test this? >> >> IMX28. > > Is that any mainline board? Nope, custom hardware. >> >> Existing code that uses the first/last flags is wrong and needs to be >> >> changed. Therefor code using 'first' and 'last' will be changed. >> >> >> >> Passing the flags as pointers is bad practice and makes no sense to >> >> do. Does it make any sense to re-write code fix the way it uses first >> >> and last, then re-write those same lines a second time to not use >> >> pointers? >> > >> > You can always flip it the other way -- first rework the use of flags, >> > then apply the fix. It'd make the patch much easier to understand, don't >> > you think? >> >> So I should change 'first' to not be a pointer to an integer in one >> patch, then delete the flag entirely in another patch? > > I'd say make a patch (0001) that implements the transition to using your newly > defined flags and then make a patch (0002) that "Fix extra CS pulses and read > mode in multi-transfer messages". One patch shall do one thing, that's the usual > rule of the thumb. Obviously keep them in a series if these patches shall go in > together. And why doesn't squashing them all together work you might ask -- > because reviewing the result is hard. 5 patches have now been split into 12. ------------------------------------------------------------------------------ Own the Future-Intel(R) Level Up Game Demo Contest 2013 Rise to greatness in Intel's independent game demo contest. Compete for recognition, cash, and the chance to get your game on Steam. $5K grand prize plus 10 genre and skill prizes. Submit your demo by 6/6/13. http://altfarm.mediaplex.com/ad/ck/12124-176961-30367-2 ^ permalink raw reply [flat|nested] 24+ messages in thread
[parent not found: <CA+7tXii8xhZQeKU2dTN26LxySNXhJT9NgRXcJ21cOX64qYj1NA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>]
* Re: [PATCH 1/5] spi/mxs: Fix extra CS pulses and read mode in multi-transfer messages [not found] ` <CA+7tXii8xhZQeKU2dTN26LxySNXhJT9NgRXcJ21cOX64qYj1NA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> @ 2013-04-02 23:39 ` Marek Vasut 0 siblings, 0 replies; 24+ messages in thread From: Marek Vasut @ 2013-04-02 23:39 UTC (permalink / raw) To: Trent Piepho Cc: Fabio Estevam, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Shawn Guo, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org Dear Trent Piepho, > On Tue, Apr 2, 2013 at 3:32 AM, Marek Vasut <marex-ynQEQJNshbs@public.gmane.org> wrote: > >> Don't see anything in CodingStyle that one should be preferred over > >> the other. > > > > There ain't any I'm aware of, but to paraphrase you, let's keep the > > format that's already used in the driver ;-) : > > > > 114 if (dev->mode & ~(SPI_CPOL | SPI_CPHA)) > > Thanks for pointing that out, as that code can be deleted. Which > means I don't need to be consistent with it anymore and can create a > new standard, to be followed henceforth, now and forever. > > But it looks like the or method is more common in the kernel code. So > I'll change it in V2. > > >> > btw. are you using MX23 or MX28 to test this? > >> > >> IMX28. > > > > Is that any mainline board? > > Nope, custom hardware. > > >> >> Existing code that uses the first/last flags is wrong and needs to be > >> >> changed. Therefor code using 'first' and 'last' will be changed. > >> >> > >> >> Passing the flags as pointers is bad practice and makes no sense to > >> >> do. Does it make any sense to re-write code fix the way it uses > >> >> first and last, then re-write those same lines a second time to not > >> >> use pointers? > >> > > >> > You can always flip it the other way -- first rework the use of flags, > >> > then apply the fix. It'd make the patch much easier to understand, > >> > don't you think? > >> > >> So I should change 'first' to not be a pointer to an integer in one > >> patch, then delete the flag entirely in another patch? > > > > I'd say make a patch (0001) that implements the transition to using your > > newly defined flags and then make a patch (0002) that "Fix extra CS > > pulses and read mode in multi-transfer messages". One patch shall do one > > thing, that's the usual rule of the thumb. Obviously keep them in a > > series if these patches shall go in together. And why doesn't squashing > > them all together work you might ask -- because reviewing the result is > > hard. > > 5 patches have now been split into 12. Much better, yes. Best regards, Marek Vasut ------------------------------------------------------------------------------ Minimize network downtime and maximize team effectiveness. Reduce network management and security costs.Learn how to hire the most talented Cisco Certified professionals. Visit the Employer Resources Portal http://www.cisco.com/web/learning/employer_resources/index.html ^ permalink raw reply [flat|nested] 24+ messages in thread
end of thread, other threads:[~2013-04-02 23:39 UTC | newest] Thread overview: 24+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2013-03-29 15:19 [PATCH 1/5] spi/mxs: Fix extra CS pulses and read mode in multi-transfer messages Trent Piepho [not found] ` <1364570381-17605-1-git-send-email-tpiepho-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 2013-03-29 15:19 ` [PATCH 2/5] spi/mxs: Fix chip select control bits in DMA mode Trent Piepho [not found] ` <1364570381-17605-2-git-send-email-tpiepho-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 2013-04-01 23:13 ` Marek Vasut [not found] ` <201304020113.42124.marex-ynQEQJNshbs@public.gmane.org> 2013-04-01 23:27 ` Trent Piepho [not found] ` <CA+7tXih2wAVeLpVoYkt4Tmo3h0YtLoZY3vCcv5s8sUD1u8_BVQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 2013-04-01 23:30 ` Marek Vasut [not found] ` <201304020130.51951.marex-ynQEQJNshbs@public.gmane.org> 2013-04-01 23:40 ` Trent Piepho [not found] ` <CA+7tXij_V1iAdPuPoTQ6CK6U5Y-iJprCPsTj=_LHAV1-=CL7gA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 2013-04-02 0:02 ` Marek Vasut [not found] ` <201304020202.43501.marex-ynQEQJNshbs@public.gmane.org> 2013-04-02 1:58 ` Trent Piepho 2013-03-29 15:19 ` [PATCH 3/5] spi/mxs: Remove full duplex check, spi core already does it Trent Piepho 2013-03-29 15:19 ` [PATCH 4/5] spi/mxs: Remove bogus setting of ssp clk rate field Trent Piepho [not found] ` <1364570381-17605-4-git-send-email-tpiepho-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 2013-04-01 23:16 ` Marek Vasut [not found] ` <201304020116.04781.marex-ynQEQJNshbs@public.gmane.org> 2013-04-01 23:32 ` Trent Piepho [not found] ` <CA+7tXihhL2ETT+AgvX5KASZOOgi6bucModE88ztY9Q8U1gDbOQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 2013-04-01 23:37 ` Marek Vasut 2013-04-02 0:07 ` Trent Piepho [not found] ` <CA+7tXihfDnmkTJGzk_yvRKYwb5mJzzLJVV+XupCEGnmpQdKDLQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 2013-04-02 0:29 ` Marek Vasut 2013-03-29 15:19 ` [PATCH 5/5] spi/mxs: Fix multiple slave bug and don't set clock for each xfer Trent Piepho [not found] ` <1364570381-17605-5-git-send-email-tpiepho-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 2013-04-01 23:18 ` Marek Vasut 2013-04-01 23:11 ` [PATCH 1/5] spi/mxs: Fix extra CS pulses and read mode in multi-transfer messages Marek Vasut [not found] ` <201304020111.13969.marex-ynQEQJNshbs@public.gmane.org> 2013-04-02 1:24 ` Trent Piepho [not found] ` <CA+7tXigx=qcDDJZGAx7JEX+Y-CDG-B0xyYgs6fHbUZofH7gnKw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 2013-04-02 4:22 ` Marek Vasut [not found] ` <201304020622.52429.marex-ynQEQJNshbs@public.gmane.org> 2013-04-02 7:11 ` Trent Piepho [not found] ` <CA+7tXigvg+5k0Baa12CVwP5Ar7HUsJ8ihB19xrav4CNA6ZMFiA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 2013-04-02 10:32 ` Marek Vasut [not found] ` <201304021232.12736.marex-ynQEQJNshbs@public.gmane.org> 2013-04-02 12:40 ` Trent Piepho [not found] ` <CA+7tXii8xhZQeKU2dTN26LxySNXhJT9NgRXcJ21cOX64qYj1NA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 2013-04-02 23:39 ` Marek Vasut
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).