Message ID | 1492443832-50881-2-git-send-email-philipp.tomsich@theobroma-systems.com |
---|---|
State | Superseded |
Delegated to: | Simon Glass |
Headers | show |
On 17 April 2017 at 09:43, Philipp Tomsich < philipp.tomsich@theobroma-systems.com> wrote: > This change adds support for configuring the module clocks for SPI1 and > SPI5 from the 594MHz GPLL. > > Note that the driver (rk_spi.c) always sets this to 99MHz, but the > implemented functionality is more general and will also support > different clock configurations. > > X-AffectedPlatforms: RK3399-Q7 > Signed-off-by: Philipp Tomsich <philipp.tomsich@theobroma-systems.com> > Tested-by: Jakob Unterwurzacher < jakob.unterwurzacher@theobroma-systems.com> > Tested-by: Klaus Goger <klaus.goger@theobroma-systems.com> > > Cover-Letter: Odd that this came through - is it the capital L? > rockchip: spi: rk3399: add SPI support for the RK3399 > > This series adds SPI support for the RK3399 (SPI1 and SPI5). This > consists of the following individual changes: > - clock support for the SPI blocks clocked from GRF (i.e. SPI1, SPI2, > SPI 4 and SPI5) > - pinctrl for SPI1 and SPI5 > - changes the SPI module input clock to 198MHz (instead of 99MHz) for > the RK3399 to improve the available bitrates at higher frequencies > (e.g. adding the 39MBit and 28MBit operating points) > - modifies the calculation of the top frequency permissible (as the > 49.5MBit operating point had not been permissible due to a hard > limit at 48MBit) > END > > --- > > Changes in v3: > - replaced macro-pasting with a lookup table to improve readability > (as requested by Simon) > > Changes in v2: > - fixes a wrong macro usage, which caused the SPI module input clock > frequency to be significantly higher than intended > - frequencies have now been validated using an oscilloscope (keep in mind > that all frequencies are derived from a 99MHz module input clock) at the > following measurement points (assuming the other fix for the usage of > DIV_RATE from the series): > * 1 MHz ... 0.99 MHz > * 5 MHz ... 4.95 MHz > * 10 MHz ... 9.9 MHz > * 30 MHz ... 33 MHz > * 50 MHz ... 49.5 MHz > > drivers/clk/rockchip/clk_rk3399.c | 114 ++++++++++++++++++++++++++++++++++++-- > 1 file changed, 108 insertions(+), 6 deletions(-) Acked-by: Simon Glass <sjg@chromium.org>
On 17 April 2017 at 21:59, Simon Glass <sjg@chromium.org> wrote: > On 17 April 2017 at 09:43, Philipp Tomsich > <philipp.tomsich@theobroma-systems.com> wrote: >> This change adds support for configuring the module clocks for SPI1 and >> SPI5 from the 594MHz GPLL. >> >> Note that the driver (rk_spi.c) always sets this to 99MHz, but the >> implemented functionality is more general and will also support >> different clock configurations. >> >> X-AffectedPlatforms: RK3399-Q7 >> Signed-off-by: Philipp Tomsich <philipp.tomsich@theobroma-systems.com> >> Tested-by: Jakob Unterwurzacher >> <jakob.unterwurzacher@theobroma-systems.com> >> Tested-by: Klaus Goger <klaus.goger@theobroma-systems.com> >> >> Cover-Letter: > > Odd that this came through - is it the capital L? > > >> rockchip: spi: rk3399: add SPI support for the RK3399 >> >> This series adds SPI support for the RK3399 (SPI1 and SPI5). This >> consists of the following individual changes: >> - clock support for the SPI blocks clocked from GRF (i.e. SPI1, SPI2, >> SPI 4 and SPI5) >> - pinctrl for SPI1 and SPI5 >> - changes the SPI module input clock to 198MHz (instead of 99MHz) for >> the RK3399 to improve the available bitrates at higher frequencies >> (e.g. adding the 39MBit and 28MBit operating points) >> - modifies the calculation of the top frequency permissible (as the >> 49.5MBit operating point had not been permissible due to a hard >> limit at 48MBit) >> END >> >> --- >> >> Changes in v3: >> - replaced macro-pasting with a lookup table to improve readability >> (as requested by Simon) >> >> Changes in v2: >> - fixes a wrong macro usage, which caused the SPI module input clock >> frequency to be significantly higher than intended >> - frequencies have now been validated using an oscilloscope (keep in mind >> that all frequencies are derived from a 99MHz module input clock) at the >> following measurement points (assuming the other fix for the usage of >> DIV_RATE from the series): >> * 1 MHz ... 0.99 MHz >> * 5 MHz ... 4.95 MHz >> * 10 MHz ... 9.9 MHz >> * 30 MHz ... 33 MHz >> * 50 MHz ... 49.5 MHz >> >> drivers/clk/rockchip/clk_rk3399.c | 114 >> ++++++++++++++++++++++++++++++++++++-- >> 1 file changed, 108 insertions(+), 6 deletions(-) > > Acked-by: Simon Glass <sjg@chromium.org> Applied to u-boot-rockchip/next, thanks!
diff --git a/drivers/clk/rockchip/clk_rk3399.c b/drivers/clk/rockchip/clk_rk3399.c index f778ddf..fab36fa 100644 --- a/drivers/clk/rockchip/clk_rk3399.c +++ b/drivers/clk/rockchip/clk_rk3399.c @@ -1,5 +1,6 @@ /* * (C) Copyright 2015 Google, Inc + * (C) 2017 Theobroma Systems Design und Consulting GmbH * * SPDX-License-Identifier: GPL-2.0 */ @@ -207,12 +208,15 @@ enum { DCLK_VOP_DIV_CON_SHIFT = 0, /* CLKSEL_CON58 */ - CLK_SPI_PLL_SEL_MASK = 1, - CLK_SPI_PLL_SEL_CPLL = 0, - CLK_SPI_PLL_SEL_GPLL = 1, - CLK_SPI_PLL_DIV_CON_MASK = 0x7f, - CLK_SPI5_PLL_DIV_CON_SHIFT = 8, - CLK_SPI5_PLL_SEL_SHIFT = 15, + CLK_SPI_PLL_SEL_WIDTH = 1, + CLK_SPI_PLL_SEL_MASK = ((1 < CLK_SPI_PLL_SEL_WIDTH) - 1), + CLK_SPI_PLL_SEL_CPLL = 0, + CLK_SPI_PLL_SEL_GPLL = 1, + CLK_SPI_PLL_DIV_CON_WIDTH = 7, + CLK_SPI_PLL_DIV_CON_MASK = ((1 << CLK_SPI_PLL_DIV_CON_WIDTH) - 1), + + CLK_SPI5_PLL_DIV_CON_SHIFT = 8, + CLK_SPI5_PLL_SEL_SHIFT = 15, /* CLKSEL_CON59 */ CLK_SPI1_PLL_SEL_SHIFT = 15, @@ -605,6 +609,96 @@ static ulong rk3399_i2c_set_clk(struct rk3399_cru *cru, ulong clk_id, uint hz) return DIV_TO_RATE(GPLL_HZ, src_clk_div); } +/* + * RK3399 SPI clocks have a common divider-width (7 bits) and a single bit + * to select either CPLL or GPLL as the clock-parent. The location within + * the enclosing CLKSEL_CON (i.e. div_shift and sel_shift) are variable. + */ + +struct spi_clkreg { + uint8_t reg; /* CLKSEL_CON[reg] register in CRU */ + uint8_t div_shift; + uint8_t sel_shift; +}; + +/* + * The entries are numbered relative to their offset from SCLK_SPI0. + * + * Note that SCLK_SPI3 (which is configured via PMUCRU and requires different + * logic is not supported). + */ +static const struct spi_clkreg spi_clkregs[] = { + [0] = { .reg = 59, + .div_shift = CLK_SPI0_PLL_DIV_CON_SHIFT, + .sel_shift = CLK_SPI0_PLL_SEL_SHIFT, }, + [1] = { .reg = 59, + .div_shift = CLK_SPI1_PLL_DIV_CON_SHIFT, + .sel_shift = CLK_SPI1_PLL_SEL_SHIFT, }, + [2] = { .reg = 60, + .div_shift = CLK_SPI2_PLL_DIV_CON_SHIFT, + .sel_shift = CLK_SPI2_PLL_SEL_SHIFT, }, + [3] = { .reg = 60, + .div_shift = CLK_SPI4_PLL_DIV_CON_SHIFT, + .sel_shift = CLK_SPI4_PLL_SEL_SHIFT, }, + [4] = { .reg = 58, + .div_shift = CLK_SPI5_PLL_DIV_CON_SHIFT, + .sel_shift = CLK_SPI5_PLL_SEL_SHIFT, }, +}; + +static inline u32 extract_bits(u32 val, unsigned width, unsigned shift) +{ + return (val >> shift) & ((1 << width) - 1); +} + +static ulong rk3399_spi_get_clk(struct rk3399_cru *cru, ulong clk_id) +{ + const struct spi_clkreg *spiclk = NULL; + u32 div, val; + + switch (clk_id) { + case SCLK_SPI0 ... SCLK_SPI5: + spiclk = &spi_clkregs[clk_id - SCLK_SPI0]; + break; + + default: + error("%s: SPI clk-id %ld not supported\n", __func__, clk_id); + return -EINVAL; + } + + val = readl(&cru->clksel_con[spiclk->reg]); + div = extract_bits(val, CLK_SPI_PLL_DIV_CON_WIDTH, spiclk->div_shift); + + return DIV_TO_RATE(GPLL_HZ, div); +} + +static ulong rk3399_spi_set_clk(struct rk3399_cru *cru, ulong clk_id, uint hz) +{ + const struct spi_clkreg *spiclk = NULL; + int src_clk_div; + + src_clk_div = GPLL_HZ / hz; + assert((src_clk_div - 1) < 127); + + switch (clk_id) { + case SCLK_SPI1 ... SCLK_SPI5: + spiclk = &spi_clkregs[clk_id - SCLK_SPI0]; + break; + + default: + error("%s: SPI clk-id %ld not supported\n", __func__, clk_id); + return -EINVAL; + } + + rk_clrsetreg(&cru->clksel_con[spiclk->reg], + ((CLK_SPI_PLL_DIV_CON_MASK << spiclk->div_shift) | + (CLK_SPI_PLL_SEL_GPLL << spiclk->sel_shift)), + ((src_clk_div << spiclk->div_shift) | + (CLK_SPI_PLL_SEL_GPLL << spiclk->sel_shift))); + + + return DIV_TO_RATE(GPLL_HZ, src_clk_div); +} + static ulong rk3399_vop_set_clk(struct rk3399_cru *cru, ulong clk_id, u32 hz) { struct pll_div vpll_config = {0}; @@ -780,6 +874,10 @@ static ulong rk3399_clk_get_rate(struct clk *clk) case SCLK_I2C7: rate = rk3399_i2c_get_clk(priv->cru, clk->id); break; + case SCLK_SPI1: + case SCLK_SPI5: + rate = rk3399_spi_get_clk(priv->cru, clk->id); + break; case SCLK_UART0: case SCLK_UART2: return 24000000; @@ -818,6 +916,10 @@ static ulong rk3399_clk_set_rate(struct clk *clk, ulong rate) case SCLK_I2C7: ret = rk3399_i2c_set_clk(priv->cru, clk->id, rate); break; + case SCLK_SPI1: + case SCLK_SPI5: + ret = rk3399_spi_set_clk(priv->cru, clk->id, rate); + break; case DCLK_VOP0: case DCLK_VOP1: ret = rk3399_vop_set_clk(priv->cru, clk->id, rate);