diff options
author | Ken Ma <make@marvell.com> | 2021-04-30 15:26:29 +0200 |
---|---|---|
committer | Stefan Roese <sr@denx.de> | 2021-05-16 06:48:45 +0200 |
commit | 037818c544c44b31dd532409e3abc3747e24a60d (patch) | |
tree | b09273e05b6a8918be77507c4af4d3d5b03cbc73 /drivers/spi | |
parent | 76a516452b38c4f1542db382ebaf05054797100c (diff) | |
download | u-boot-037818c544c44b31dd532409e3abc3747e24a60d.tar.gz u-boot-037818c544c44b31dd532409e3abc3747e24a60d.tar.bz2 u-boot-037818c544c44b31dd532409e3abc3747e24a60d.zip |
spi: kirkwood: support extended baud rates
The Armada SoC family implementation of this SPI hardware module has
extended the configuration register to allow for a wider range of SPI
clock rates. Specifically the Serial Baud Rate Pre-selection bits in the
SPI Interface Configuration Register now also use bits 6 and 7 as well.
Modify the baud rate calculation to handle these differences for the
Armada case. Potentially a baud rate can be setup using a number of
different pre-scalar and scalar combinations. This code tries all
possible pre-scalar divisors (8 in total) to try and find the most
accurate set.
Signed-off-by: Ken Ma <make@marvell.com>
Signed-off-by: Stefan Roese <sr@denx.de>
Diffstat (limited to 'drivers/spi')
-rw-r--r-- | drivers/spi/kirkwood_spi.c | 60 |
1 files changed, 55 insertions, 5 deletions
diff --git a/drivers/spi/kirkwood_spi.c b/drivers/spi/kirkwood_spi.c index 43812da0eb..3dc62f351a 100644 --- a/drivers/spi/kirkwood_spi.c +++ b/drivers/spi/kirkwood_spi.c @@ -111,12 +111,62 @@ static int mvebu_spi_set_speed(struct udevice *bus, uint hz) { struct mvebu_spi_plat *plat = dev_get_plat(bus); struct kwspi_registers *reg = plat->spireg; - u32 data; + u32 data, divider; + unsigned int spr, sppr; + + /* + * Calculate spi clock prescaller using max_hz. + * SPPR is SPI Baud Rate Pre-selection, it holds bits 5 and 7:6 in + * SPI Interface Configuration Register; + * SPR is SPI Baud Rate Selection, it holds bits 3:0 in SPI Interface + * Configuration Register. + * The SPR together with the SPPR define the SPI CLK frequency as + * follows: + * SPI actual frequency = core_clk / (SPR * (2 ^ SPPR)) + */ + divider = DIV_ROUND_UP(CONFIG_SYS_TCLK, hz); + if (divider < 16) { + /* This is the easy case, divider is less than 16 */ + spr = divider; + sppr = 0; + + } else { + unsigned int 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; + } - /* calculate spi clock prescaller using max_hz */ - data = ((CONFIG_SYS_TCLK / 2) / hz) + 0x10; - data = data < KWSPI_CLKPRESCL_MIN ? KWSPI_CLKPRESCL_MIN : data; - data = data > KWSPI_CLKPRESCL_MASK ? KWSPI_CLKPRESCL_MASK : data; + data = ((sppr & 0x6) << 5) | ((sppr & 0x1) << 4) | spr; /* program spi clock prescaler using max_hz */ writel(KWSPI_ADRLEN_3BYTE | data, ®->cfg); |