]>
Commit | Line | Data |
---|---|---|
75c6bbc2 GKH |
1 | From 7243e0b20729d372e97763617a7a9c89f29b33e1 Mon Sep 17 00:00:00 2001 |
2 | From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= <uwe@kleine-koenig.org> | |
3 | Date: Thu, 8 Dec 2016 17:37:08 +0100 | |
4 | Subject: spi: mvebu: fix baudrate calculation for armada variant | |
5 | MIME-Version: 1.0 | |
6 | Content-Type: text/plain; charset=UTF-8 | |
7 | Content-Transfer-Encoding: 8bit | |
8 | ||
9 | From: Uwe Kleine-König <uwe@kleine-koenig.org> | |
10 | ||
11 | commit 7243e0b20729d372e97763617a7a9c89f29b33e1 upstream. | |
12 | ||
13 | The calculation of SPR and SPPR doesn't round correctly at several | |
14 | places which might result in baud rates that are too big. For example | |
15 | with tclk_hz = 250000001 and target rate 25000000 it determined a | |
16 | divider of 10 which is wrong. | |
17 | ||
18 | Instead of fixing all the corner cases replace the calculation by an | |
19 | algorithm without a loop which should even be quicker to execute apart | |
20 | from being correct. | |
21 | ||
22 | Fixes: df59fa7f4bca ("spi: orion: support armada extended baud rates") | |
23 | Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> | |
24 | Signed-off-by: Mark Brown <broonie@kernel.org> | |
25 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
26 | ||
27 | --- | |
28 | drivers/spi/spi-orion.c | 83 +++++++++++++++++++++++++++++++----------------- | |
29 | 1 file changed, 54 insertions(+), 29 deletions(-) | |
30 | ||
31 | --- a/drivers/spi/spi-orion.c | |
32 | +++ b/drivers/spi/spi-orion.c | |
33 | @@ -138,37 +138,62 @@ static int orion_spi_baudrate_set(struct | |
34 | tclk_hz = clk_get_rate(orion_spi->clk); | |
35 | ||
36 | if (devdata->typ == ARMADA_SPI) { | |
37 | - unsigned int clk, spr, sppr, sppr2, err; | |
38 | - unsigned int best_spr, best_sppr, best_err; | |
39 | - | |
40 | - best_err = speed; | |
41 | - best_spr = 0; | |
42 | - best_sppr = 0; | |
43 | - | |
44 | - /* Iterate over the valid range looking for best fit */ | |
45 | - for (sppr = 0; sppr < 8; sppr++) { | |
46 | - sppr2 = 0x1 << sppr; | |
47 | - | |
48 | - spr = tclk_hz / sppr2; | |
49 | - spr = DIV_ROUND_UP(spr, speed); | |
50 | - if ((spr == 0) || (spr > 15)) | |
51 | - continue; | |
52 | - | |
53 | - clk = tclk_hz / (spr * sppr2); | |
54 | - err = speed - clk; | |
55 | - | |
56 | - if (err < best_err) { | |
57 | - best_spr = spr; | |
58 | - best_sppr = sppr; | |
59 | - best_err = err; | |
60 | - } | |
61 | + /* | |
62 | + * Given the core_clk (tclk_hz) and the target rate (speed) we | |
63 | + * determine the best values for SPR (in [0 .. 15]) and SPPR (in | |
64 | + * [0..7]) such that | |
65 | + * | |
66 | + * core_clk / (SPR * 2 ** SPPR) | |
67 | + * | |
68 | + * is as big as possible but not bigger than speed. | |
69 | + */ | |
70 | + | |
71 | + /* best integer divider: */ | |
72 | + unsigned divider = DIV_ROUND_UP(tclk_hz, speed); | |
73 | + unsigned spr, sppr; | |
74 | + | |
75 | + if (divider < 16) { | |
76 | + /* This is the easy case, divider is less than 16 */ | |
77 | + spr = divider; | |
78 | + sppr = 0; | |
79 | + | |
80 | + } else { | |
81 | + unsigned two_pow_sppr; | |
82 | + /* | |
83 | + * Find the highest bit set in divider. This and the | |
84 | + * three next bits define SPR (apart from rounding). | |
85 | + * SPPR is then the number of zero bits that must be | |
86 | + * appended: | |
87 | + */ | |
88 | + sppr = fls(divider) - 4; | |
89 | + | |
90 | + /* | |
91 | + * As SPR only has 4 bits, we have to round divider up | |
92 | + * to the next multiple of 2 ** sppr. | |
93 | + */ | |
94 | + two_pow_sppr = 1 << sppr; | |
95 | + divider = (divider + two_pow_sppr - 1) & -two_pow_sppr; | |
96 | + | |
97 | + /* | |
98 | + * recalculate sppr as rounding up divider might have | |
99 | + * increased it enough to change the position of the | |
100 | + * highest set bit. In this case the bit that now | |
101 | + * doesn't make it into SPR is 0, so there is no need to | |
102 | + * round again. | |
103 | + */ | |
104 | + sppr = fls(divider) - 4; | |
105 | + spr = divider >> sppr; | |
106 | + | |
107 | + /* | |
108 | + * Now do range checking. SPR is constructed to have a | |
109 | + * width of 4 bits, so this is fine for sure. So we | |
110 | + * still need to check for sppr to fit into 3 bits: | |
111 | + */ | |
112 | + if (sppr > 7) | |
113 | + return -EINVAL; | |
114 | } | |
115 | ||
116 | - if ((best_sppr == 0) && (best_spr == 0)) | |
117 | - return -EINVAL; | |
118 | - | |
119 | - prescale = ((best_sppr & 0x6) << 5) | | |
120 | - ((best_sppr & 0x1) << 4) | best_spr; | |
121 | + prescale = ((sppr & 0x6) << 5) | ((sppr & 0x1) << 4) | spr; | |
122 | } else { | |
123 | /* | |
124 | * the supported rates are: 4,6,8...30 |