[U-Boot] [PATCH v3 1/7] rockchip: clk: rk3399: add clock support for SCLK_SPI1 and SCLK_SPI5
Philipp Tomsich
philipp.tomsich at theobroma-systems.com
Mon Apr 17 15:43:46 UTC 2017
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 at theobroma-systems.com>
Tested-by: Jakob Unterwurzacher <jakob.unterwurzacher at theobroma-systems.com>
Tested-by: Klaus Goger <klaus.goger at theobroma-systems.com>
Cover-Letter:
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(-)
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);
--
1.9.1
More information about the U-Boot
mailing list