From 754ec43c0184aae48f5a8c917d8282449ab564a9 Mon Sep 17 00:00:00 2001 From: Julius Werner Date: Thu, 26 Mar 2015 16:30:24 -0700 Subject: spi/rockchip: Round up clock rate divisor to err on the safe side The Rockchip SPI driver currently calculates its clock rate divisor by integer dividing the parent rate by the target rate, and then rounding the result up to the next even number (since the divisor must be even). Clock rate divisors should always be rounded up, so that the resulting frequency is lower or equal to the target. This is correctly done in the second step here but not in the first, so we still have a risk of exceeding the desired target frequency (e.g. setting spi-max-frequency to 40000000 with a parent clock of 99000000 could lead to a divisor of 99000000 / 40000000 == 2 (which is even) that then results in an effective frequency of 99000000 / 2 == 49500000 (potentially exceeding the flash chip's specifications). This patch changes the division to round up to fix this problem. Signed-off-by: Julius Werner Signed-off-by: Mark Brown --- drivers/spi/spi-rockchip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c index 1a777dc261d6..5e4e52cbe053 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -519,7 +519,7 @@ static void rockchip_spi_config(struct rockchip_spi *rs) } /* div doesn't support odd number */ - div = max_t(u32, rs->max_freq / rs->speed, 1); + div = DIV_ROUND_UP(rs->max_freq, rs->speed); div = (div + 1) & 0xfffe; writel_relaxed(cr0, rs->regs + ROCKCHIP_SPI_CTRLR0); -- cgit v1.2.3 From f511ab09dfb0fe7b2335eccac51ff9f001a32e4a Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Wed, 1 Apr 2015 10:46:15 +0200 Subject: spi: imx: read back the RX/TX watermark levels earlier They are used to decide if the controller can do DMA on a buffer of a specific length and thus are needed before any transfer is attempted. This fixes a memory leak where the SPI core uses the drivers can_dma() callback to determine if a buffer needs to be mapped. As the watermark levels aren't correct at that point the driver falsely claims to be able to DMA the buffer when it fact it isn't. After the transfer has been done the core uses the same callback to determine if it needs to unmap the buffers. As the driver now correctly claims to not being able to DMA the buffer the core doesn't attempt to unmap the buffer which leaves the SGT leaking. Fixes: f62caccd12c17e4 (spi: spi-imx: add DMA support) Signed-off-by: Lucas Stach Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- drivers/spi/spi-imx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index 6fea4af51c41..aea3a67e5ce1 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -370,8 +370,6 @@ static int __maybe_unused mx51_ecspi_config(struct spi_imx_data *spi_imx, if (spi_imx->dma_is_inited) { dma = readl(spi_imx->base + MX51_ECSPI_DMA); - spi_imx->tx_wml = spi_imx_get_fifosize(spi_imx) / 2; - spi_imx->rx_wml = spi_imx_get_fifosize(spi_imx) / 2; spi_imx->rxt_wml = spi_imx_get_fifosize(spi_imx) / 2; rx_wml_cfg = spi_imx->rx_wml << MX51_ECSPI_DMA_RX_WML_OFFSET; tx_wml_cfg = spi_imx->tx_wml << MX51_ECSPI_DMA_TX_WML_OFFSET; @@ -868,6 +866,8 @@ static int spi_imx_sdma_init(struct device *dev, struct spi_imx_data *spi_imx, master->max_dma_len = MAX_SDMA_BD_BYTES; spi_imx->bitbang.master->flags = SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX; + spi_imx->tx_wml = spi_imx_get_fifosize(spi_imx) / 2; + spi_imx->rx_wml = spi_imx_get_fifosize(spi_imx) / 2; spi_imx->dma_is_inited = 1; return 0; -- cgit v1.2.3 From e689d6df8257f92abf59e93736632b79c9b2aa66 Mon Sep 17 00:00:00 2001 From: Aaron Brice Date: Fri, 3 Apr 2015 13:39:29 -0700 Subject: spi: fsl-dspi: Fix clock rate scale values Previous algorithm had an outer loop with the values {2,3,5,7} and an inner loop with {2,4,6,8,16,32,...,32768}, and would pick the first value over the required scaling value (where the total scale was the two numbers multiplied). Since the inner loop went up to 32768 it would always pick a value of 2 for PBR and a much higher than necessary value for BR. The desired scale factor was being divided by two I believe to compensate for the much higher scale factors (the divide by two not specified in the reference manual). Updated to check all values and find the smallest scale factor possible without going over the desired clock rate. Signed-off-by: Aaron Brice Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-dspi.c | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c index d1a39249704a..82133584c0ea 100644 --- a/drivers/spi/spi-fsl-dspi.c +++ b/drivers/spi/spi-fsl-dspi.c @@ -148,23 +148,32 @@ static void hz_to_spi_baud(char *pbr, char *br, int speed_hz, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768 }; - int temp, i = 0, j = 0; - - temp = clkrate / 2 / speed_hz; - - for (i = 0; i < ARRAY_SIZE(pbr_tbl); i++) - for (j = 0; j < ARRAY_SIZE(brs); j++) { - if (pbr_tbl[i] * brs[j] >= temp) { - *pbr = i; - *br = j; - return; + int scale_needed, scale, minscale = INT_MAX; + int i, j; + + scale_needed = clkrate / speed_hz; + if (clkrate % speed_hz) + scale_needed++; + + for (i = 0; i < ARRAY_SIZE(brs); i++) + for (j = 0; j < ARRAY_SIZE(pbr_tbl); j++) { + scale = brs[i] * pbr_tbl[j]; + if (scale >= scale_needed) { + if (scale < minscale) { + minscale = scale; + *br = i; + *pbr = j; + } + break; } } - pr_warn("Can not find valid baud rate,speed_hz is %d,clkrate is %ld\ - ,we use the max prescaler value.\n", speed_hz, clkrate); - *pbr = ARRAY_SIZE(pbr_tbl) - 1; - *br = ARRAY_SIZE(brs) - 1; + if (minscale == INT_MAX) { + pr_warn("Can not find valid baud rate,speed_hz is %d,clkrate is %ld, we use the max prescaler value.\n", + speed_hz, clkrate); + *pbr = ARRAY_SIZE(pbr_tbl) - 1; + *br = ARRAY_SIZE(brs) - 1; + } } static int dspi_transfer_write(struct fsl_dspi *dspi) -- cgit v1.2.3