Patch "spi: mvebu: fix baudrate calculation for armada variant" has been added to the 4.9-stable tree
Subsystems (2)
This is a note to let you know that I've just added the patch titled
spi: mvebu: fix baudrate calculation for armada variant
to the 4.9-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
spi-mvebu-fix-baudrate-calculation-for-armada-variant.patch
and it can be found in the queue-4.9 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From
7243e0b20729d372e97763617a7a9c89f29b33e1Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= <[email protected]>
Date: Thu, 8 Dec 2016 17:37:08 +0100
Subject: spi: mvebu: fix baudrate calculation for armada variant
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
From: Uwe Kleine-König <[email protected]>
commit 7243e0b20729d372e97763617a7a9c89f29b33e1 upstream.
The calculation of SPR and SPPR doesn't round correctly at several places which might result in baud rates that are too big. For example with tclk_hz = 250000001 and target rate 25000000 it determined a divider of 10 which is wrong.
Instead of fixing all the corner cases replace the calculation by an algorithm without a loop which should even be quicker to execute apart from being correct.
--- drivers/spi/spi-orion.c | 83 +++++++++++++++++++++++++++++++----------------- 1 file changed, 54 insertions(+), 29 deletions(-)
drivers/spi/spi-orion.c +54 -29
@@ -138,37 +138,62 @@ static int orion_spi_baudrate_set(struct tclk_hz =clk_get_rate (orion_spi->clk);if (devdata->typ ==ARMADA_SPI ) { -unsigned int clk, spr, sppr, sppr2, err; -unsigned int best_spr, best_sppr, best_err; - - best_err = speed; - best_spr =0 ; - best_sppr =0 ; - -/* Iterate over the valid range looking for best fit */ -for (sppr =0 ; sppr <8 ; sppr++) { - sppr2 =0x1 << sppr; - - spr = tclk_hz / sppr2; - spr =DIV_ROUND_UP (spr, speed); -if ((spr ==0 ) || (spr >15 )) -continue ; - - clk = tclk_hz / (spr * sppr2); - err = speed - clk; - -if (err < best_err) { - best_spr = spr; - best_sppr = sppr; - best_err = err; - } +/* +* Given the core_clk (tclk_hz) and the target rate (speed) we +* determine the best values for SPR (in [0 .. 15]) and SPPR (in +* [0..7]) such that +* +* core_clk / (SPR * 2 ** SPPR) +* +* is as big as possible but not bigger than speed. +*/ + +/* best integer divider: */ +unsigned divider =DIV_ROUND_UP (tclk_hz, speed); +unsigned spr, sppr; + +if (divider <16 ) { +/* This is the easy case, divider is less than 16 */ + spr = divider; + sppr =0 ; + + }else { +unsigned two_pow_sppr; +/* +* Find the highest bit set in divider. This and the +* three next bits define SPR (apart from rounding). +* SPPR is then the number of zero bits that must be +* appended: +*/ + sppr =fls (divider) -4 ; + +/* +* As SPR only has 4 bits, we have to round divider up +* to the next multiple of 2 ** sppr. +*/ + two_pow_sppr =1 << sppr; + divider = (divider + two_pow_sppr -1 ) & -two_pow_sppr; + +/* +* recalculate sppr as rounding up divider might have +* increased it enough to change the position of the +* highest set bit. In this case the bit that now +* doesn't make it into SPR is 0, so there is no need to +* round again. +*/ + sppr =fls (divider) -4 ; + spr = divider >> sppr; + +/* +* Now do range checking. SPR is constructed to have a +* width of 4 bits, so this is fine for sure. So we +* still need to check for sppr to fit into 3 bits: +*/ +if (sppr >7 ) +return -EINVAL ; } -if ((best_sppr ==0 ) && (best_spr ==0 )) -return -EINVAL ; - - prescale = ((best_sppr &0x6 ) <<5 ) | - ((best_sppr &0x1 ) <<4 ) | best_spr; + prescale = ((sppr &0x6 ) <<5 ) | ((sppr &0x1 ) <<4 ) | spr; }else {/* * the supported rates are: 4,6,8...30
Patches currently in stable-queue which might be from [email protected] are
queue-4.9/spi-mvebu-fix-baudrate-calculation-for-armada-variant.patch