rockchip: clk: rk3399: add clock support for SCLK_SPI1 and SCLK_SPI5
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> Acked-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
parent
da10dd1a72
commit
8fa6979beb
@ -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 = RATE_TO_DIV(GPLL_HZ, hz);
|
||||
assert(src_clk_div < 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,12 @@ static ulong rk3399_clk_get_rate(struct clk *clk)
|
||||
case SCLK_I2C7:
|
||||
rate = rk3399_i2c_get_clk(priv->cru, clk->id);
|
||||
break;
|
||||
case SCLK_SPI0...SCLK_SPI5:
|
||||
rate = rk3399_spi_get_clk(priv->cru, clk->id);
|
||||
break;
|
||||
case SCLK_UART0:
|
||||
case SCLK_UART2:
|
||||
return 24000000;
|
||||
case DCLK_VOP0:
|
||||
case DCLK_VOP1:
|
||||
break;
|
||||
@ -814,6 +914,9 @@ 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_SPI0...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);
|
||||
|
Loading…
Reference in New Issue
Block a user