mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-28 15:41:40 +00:00
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>
This commit is contained in:
parent
76a516452b
commit
037818c544
1 changed files with 55 additions and 5 deletions
|
@ -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 */
|
||||
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;
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
data = ((sppr & 0x6) << 5) | ((sppr & 0x1) << 4) | spr;
|
||||
|
||||
/* program spi clock prescaler using max_hz */
|
||||
writel(KWSPI_ADRLEN_3BYTE | data, ®->cfg);
|
||||
|
|
Loading…
Reference in a new issue