Message ID | 1490691517-9291-2-git-send-email-philipp.tomsich@theobroma-systems.com |
---|---|
State | Superseded |
Delegated to: | Simon Glass |
Headers | show |
Hi Philipp, On 28 March 2017 at 02:58, 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> > --- > > drivers/clk/rockchip/clk_rk3399.c | 69 +++++++++++++++++++++++++++++++++++++++ > 1 file changed, 69 insertions(+) > > diff --git a/drivers/clk/rockchip/clk_rk3399.c b/drivers/clk/rockchip/clk_rk3399.c > index f778ddf..b7c5a35 100644 > --- a/drivers/clk/rockchip/clk_rk3399.c > +++ b/drivers/clk/rockchip/clk_rk3399.c > @@ -605,6 +605,67 @@ static ulong rk3399_i2c_set_clk(struct rk3399_cru *cru, ulong clk_id, uint hz) > return DIV_TO_RATE(GPLL_HZ, src_clk_div); > } > > +#define SPI_CLK_REG_MASK(bus) \ > + (CLK_SPI_PLL_DIV_CON_MASK << \ > + CLK_SPI ##bus## _PLL_DIV_CON_SHIFT | \ > + CLK_SPI_PLL_SEL_MASK << \ > + CLK_SPI ##bus## _PLL_SEL_SHIFT) > + > +#define SPI_CLK_REG_VALUE(bus, clk_div) \ > + ((clk_div - 1) << \ > + CLK_SPI ##bus## _PLL_DIV_CON_SHIFT | \ > + CLK_SPI_PLL_SEL_GPLL << \ > + CLK_SPI ##bus## _PLL_SEL_SHIFT) > + > +#define SPI_CLK_DIV_VALUE(con, bus) \ > + (con >> CLK_SPI ##bus## _PLL_DIV_CON_SHIFT) & \ > + CLK_SPI_PLL_DIV_CON_MASK; I'm really not keen on this macro pasting as it makes it hard to find things. Can we instead have something like: static const u8 spi_shift[] = { CLK_SPI0_PLL_SEL_SHIFT, CLK_SPI1_PLL_SEL_SHIFT, ... }; and then read it from the array? Since there are multiple pieces you might want: struct spi_reg_layout { u8 sel_shift; u8 div_shift; u8 sel_mask; u8 div_mask; }; static const struct spi_reg_layout spi_reg_layout[] = { { ... }, { ... }, This is how Tegra does things, for example. > + > +static ulong rk3399_spi_get_clk(struct rk3399_cru *cru, ulong clk_id) > +{ > + u32 div, con; > + > + switch (clk_id) { > + case SCLK_SPI1: > + con = readl(&cru->clksel_con[59]); > + div = SPI_CLK_DIV_VALUE(con, 1); > + break; > + case SCLK_SPI5: > + con = readl(&cru->clksel_con[58]); > + div = SPI_CLK_DIV_VALUE(con, 5); > + break; > + default: > + error("%s: SPI clk-id %ld not supported\n", __func__, clk_id); > + return -EINVAL; > + } > + > + return DIV_TO_RATE(GPLL_HZ, div); > +} > + > +static ulong rk3399_spi_set_clk(struct rk3399_cru *cru, ulong clk_id, uint hz) > +{ > + int src_clk_div; > + > + src_clk_div = GPLL_HZ / hz; > + assert((src_clk_div - 1) < 127); > + > + switch (clk_id) { > + case SCLK_SPI1: > + rk_clrsetreg(&cru->clksel_con[59], SPI_CLK_REG_MASK(1), > + I2C_CLK_REG_VALUE(1, src_clk_div)); > + break; > + case SCLK_SPI5: > + rk_clrsetreg(&cru->clksel_con[58], I2C_CLK_REG_MASK(5), > + I2C_CLK_REG_VALUE(5, src_clk_div)); > + break; > + default: > + error("%s: SPI clk-id %ld not supported\n", __func__, clk_id); > + return -EINVAL; > + } > + > + 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 +841,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 +883,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); > -- > 1.9.1 > Regards, Simon
diff --git a/drivers/clk/rockchip/clk_rk3399.c b/drivers/clk/rockchip/clk_rk3399.c index f778ddf..b7c5a35 100644 --- a/drivers/clk/rockchip/clk_rk3399.c +++ b/drivers/clk/rockchip/clk_rk3399.c @@ -605,6 +605,67 @@ static ulong rk3399_i2c_set_clk(struct rk3399_cru *cru, ulong clk_id, uint hz) return DIV_TO_RATE(GPLL_HZ, src_clk_div); } +#define SPI_CLK_REG_MASK(bus) \ + (CLK_SPI_PLL_DIV_CON_MASK << \ + CLK_SPI ##bus## _PLL_DIV_CON_SHIFT | \ + CLK_SPI_PLL_SEL_MASK << \ + CLK_SPI ##bus## _PLL_SEL_SHIFT) + +#define SPI_CLK_REG_VALUE(bus, clk_div) \ + ((clk_div - 1) << \ + CLK_SPI ##bus## _PLL_DIV_CON_SHIFT | \ + CLK_SPI_PLL_SEL_GPLL << \ + CLK_SPI ##bus## _PLL_SEL_SHIFT) + +#define SPI_CLK_DIV_VALUE(con, bus) \ + (con >> CLK_SPI ##bus## _PLL_DIV_CON_SHIFT) & \ + CLK_SPI_PLL_DIV_CON_MASK; + +static ulong rk3399_spi_get_clk(struct rk3399_cru *cru, ulong clk_id) +{ + u32 div, con; + + switch (clk_id) { + case SCLK_SPI1: + con = readl(&cru->clksel_con[59]); + div = SPI_CLK_DIV_VALUE(con, 1); + break; + case SCLK_SPI5: + con = readl(&cru->clksel_con[58]); + div = SPI_CLK_DIV_VALUE(con, 5); + break; + default: + error("%s: SPI clk-id %ld not supported\n", __func__, clk_id); + return -EINVAL; + } + + return DIV_TO_RATE(GPLL_HZ, div); +} + +static ulong rk3399_spi_set_clk(struct rk3399_cru *cru, ulong clk_id, uint hz) +{ + int src_clk_div; + + src_clk_div = GPLL_HZ / hz; + assert((src_clk_div - 1) < 127); + + switch (clk_id) { + case SCLK_SPI1: + rk_clrsetreg(&cru->clksel_con[59], SPI_CLK_REG_MASK(1), + I2C_CLK_REG_VALUE(1, src_clk_div)); + break; + case SCLK_SPI5: + rk_clrsetreg(&cru->clksel_con[58], I2C_CLK_REG_MASK(5), + I2C_CLK_REG_VALUE(5, src_clk_div)); + break; + default: + error("%s: SPI clk-id %ld not supported\n", __func__, clk_id); + return -EINVAL; + } + + 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 +841,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 +883,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);