diff mbox

[U-Boot,1/8] rockchip: clk: rk3399: add clock support for SCLK_SPI1 and SCLK_SPI5

Message ID 1490691517-9291-2-git-send-email-philipp.tomsich@theobroma-systems.com
State Superseded
Delegated to: Simon Glass
Headers show

Commit Message

Philipp Tomsich March 28, 2017, 8:58 a.m. UTC
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(+)

Comments

Simon Glass April 1, 2017, 4:23 a.m. UTC | #1
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 mbox

Patch

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);