From bd3767143403a8e62ad29d6218ae6c7142e1898a Mon Sep 17 00:00:00 2001 From: Philipp Tomsich Date: Thu, 20 Apr 2017 22:05:51 +0200 Subject: rockchip: spi: rk_spi: dynamically select an module input rate The original clock/bitrate selection code for the rk_spi driver was a bit limited, as it always selected a 99MHz input clock rate (which would allow for a maximum bitrate of 49.5MBit/s), but returned -EINVAL if a bitrate higher than 48MHz was requested. To give us better control over the bitrate (i.e. add more operating points, especially at "higher" bitrate---such as above 9MBit/s), we try to choose 4x the maximum frequency (clamped to 50MBit) from the DTS instead of 99MHz... for most use-cases this will yield a frequency of 198MHz, but is flexible to go beyond this in future configurations. This also rewrites the check to allow frequencies of up to half the SPI module rate as bitrates and then clamps to whatever the DTS allows as a maximum (board-specific) frequency and does away with the -EINVAL when trying to select a bitrate (for cases that exceeded the hard limit) and instead consistently clamps to the lower of the hard limit, the soft limit for the SPI bus (from the DTS) or the soft limit for the SPI slave device. This replaces "rockchip: spi: rk_spi: select 198MHz input to the SPI module for the RK3399" "rockchip: spi: rk_spi: improve clocking code for the RK3399" from earlier versions of this series. Signed-off-by: Philipp Tomsich --- drivers/spi/rk_spi.c | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) (limited to 'drivers/spi/rk_spi.c') diff --git a/drivers/spi/rk_spi.c b/drivers/spi/rk_spi.c index 3e44f1795e3..0c627d963d8 100644 --- a/drivers/spi/rk_spi.c +++ b/drivers/spi/rk_spi.c @@ -190,6 +190,26 @@ static int rockchip_spi_ofdata_to_platdata(struct udevice *bus) return 0; } +static int rockchip_spi_calc_modclk(ulong max_freq) +{ + unsigned div; + const unsigned long gpll_hz = 594000000UL; + + /* + * We need to find an input clock that provides at least twice + * the maximum frequency and can be generated from the assumed + * speed of GPLL (594MHz) using an integer divider. + * + * To give us more achievable bitrates at higher speeds (these + * are generated by dividing by an even 16-bit integer from + * this frequency), we try to have an input frequency of at + * least 4x our max_freq. + */ + + div = DIV_ROUND_UP(gpll_hz, max_freq * 4); + return gpll_hz / div; +} + static int rockchip_spi_probe(struct udevice *bus) { struct rockchip_spi_platdata *plat = dev_get_platdata(bus); @@ -207,11 +227,13 @@ static int rockchip_spi_probe(struct udevice *bus) priv->last_transaction_us = timer_get_us(); priv->max_freq = plat->frequency; - /* - * Use 99 MHz as our clock since it divides nicely into 594 MHz which - * is the assumed speed for CLK_GENERAL. - */ - ret = clk_set_rate(&priv->clk, 99000000); + /* Clamp the value from the DTS against any hardware limits */ + if (priv->max_freq > ROCKCHIP_SPI_MAX_RATE) + priv->max_freq = ROCKCHIP_SPI_MAX_RATE; + + /* Find a module-input clock that fits with the max_freq setting */ + ret = clk_set_rate(&priv->clk, + rockchip_spi_calc_modclk(priv->max_freq)); if (ret < 0) { debug("%s: Failed to set clock: %d\n", __func__, ret); return ret; @@ -371,10 +393,10 @@ static int rockchip_spi_set_speed(struct udevice *bus, uint speed) { struct rockchip_spi_priv *priv = dev_get_priv(bus); - if (speed > ROCKCHIP_SPI_MAX_RATE) - return -EINVAL; + /* Clamp to the maximum frequency specified in the DTS */ if (speed > priv->max_freq) speed = priv->max_freq; + priv->speed_hz = speed; return 0; -- cgit v1.2.3 From 9fc354e246fe466ad634617e12d092d6053503ed Mon Sep 17 00:00:00 2001 From: Philipp Tomsich Date: Thu, 20 Apr 2017 22:05:52 +0200 Subject: rockchip: spi: rewrite rkspi_set_clk for a more conservative baudrate setting The baudrate in rkspi was calculated by using an integer division (which implicitly discarded any fractional result), then rounding to an even number and finally clamping to 0xfffe using a bitwise AND operator. This introduced two issues: 1) for very small baudrates (overflowing the 0xfffe range), the bitwise-AND generates rather random-looking (wildly varying) actual output bitrates 2) for higher baudrates, the calculation tends to 'err towards a higher baudrate' with the actual error increasing as the dividers become very small. E.g., with a 99MHz input clock, a request for a 20MBit baudrate (99/20 = 4.95), a 24.75 MBit would be use (which amounts to a 23.75% error)... for a 34 MBit request this would be an actual outbout of 49.5 Mbit (i.e. a 45% error). This change rewrites the divider selection (i.e. baudrate calculation) by making sure that a) for the normal case: the largest representable baudrate below the requested rate will be chosen; b) for the denormal case (i.e. when the divider can no longer be represented), the lowest representable baudrate is chosen. Even though the denormal case (b) may be of little concern in real world applications (even with a 198MHz input clock, this will only happen at below approx. 3kHz/3kBit), our board-verification team kept complaining. Signed-off-by: Philipp Tomsich Tested-by: Klaus Goger --- drivers/spi/rk_spi.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) (limited to 'drivers/spi/rk_spi.c') diff --git a/drivers/spi/rk_spi.c b/drivers/spi/rk_spi.c index 0c627d963d8..050eacb27cc 100644 --- a/drivers/spi/rk_spi.c +++ b/drivers/spi/rk_spi.c @@ -79,12 +79,31 @@ static void rkspi_enable_chip(struct rockchip_spi *regs, bool enable) static void rkspi_set_clk(struct rockchip_spi_priv *priv, uint speed) { - uint clk_div; + /* + * We should try not to exceed the speed requested by the caller: + * when selecting a divider, we need to make sure we round up. + */ + uint clk_div = DIV_ROUND_UP(priv->input_rate, speed); + + /* The baudrate register (BAUDR) is defined as a 32bit register where + * the upper 16bit are reserved and having 'Fsclk_out' in the lower + * 16bits with 'Fsclk_out' defined as follows: + * + * Fsclk_out = Fspi_clk/ SCKDV + * Where SCKDV is any even value between 2 and 65534. + */ + if (clk_div > 0xfffe) { + clk_div = 0xfffe; + debug("%s: can't divide down to %d hz (actual will be %d hz)\n", + __func__, speed, priv->input_rate / clk_div); + } + + /* Round up to the next even 16bit number */ + clk_div = (clk_div + 1) & 0xfffe; - clk_div = clk_get_divisor(priv->input_rate, speed); debug("spi speed %u, div %u\n", speed, clk_div); - writel(clk_div, &priv->regs->baudr); + clrsetbits_le32(&priv->regs->baudr, 0xffff, clk_div); priv->last_speed_hz = speed; } -- cgit v1.2.3 From cdeb4d780aacacb03d06f616fb34323a6c719268 Mon Sep 17 00:00:00 2001 From: Jakob Unterwurzacher Date: Thu, 20 Apr 2017 22:05:54 +0200 Subject: rockchip: spi: enable support for the rk_spi driver for the RK3399 The existing Rockchip SPI (rk_spi.c) driver also matches the hardware block found in the RK3399. This has been confirmed both with SPI NOR flashes and general SPI transfers on the RK3399-Q7 for SPI1 and SPI5. This change adds the 'rockchip,rk3399-spi' string to its compatible list to allow reuse of the existing driver. X-AffectedPlatforms: RK3399-Q7 Signed-off-by: Philipp Tomsich Tested-by: Jakob Unterwurzacher Acked-by: Simon Glass --- drivers/spi/rk_spi.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/spi/rk_spi.c') diff --git a/drivers/spi/rk_spi.c b/drivers/spi/rk_spi.c index 050eacb27cc..ea209801a73 100644 --- a/drivers/spi/rk_spi.c +++ b/drivers/spi/rk_spi.c @@ -444,6 +444,7 @@ static const struct dm_spi_ops rockchip_spi_ops = { static const struct udevice_id rockchip_spi_ids[] = { { .compatible = "rockchip,rk3288-spi" }, + { .compatible = "rockchip,rk3399-spi" }, { } }; -- cgit v1.2.3