android13/u-boot/drivers/clk/rockchip/clk_rk3562.c

2051 lines
50 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2022 Rockchip Electronics Co., Ltd
* Author: Finley Xiao <finley.xiao@rock-chips.com>
*/
#include <common.h>
#include <clk-uclass.h>
#include <dm.h>
#include <syscon.h>
#include <asm/arch/clock.h>
#include <asm/arch/cru_rk3562.h>
#include <asm/arch/hardware.h>
#include <asm/io.h>
#include <dm/lists.h>
#include <dt-bindings/clock/rk3562-cru.h>
DECLARE_GLOBAL_DATA_PTR;
#define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1))
static struct rockchip_pll_rate_table rk3562_pll_rates[] = {
/* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */
RK3036_PLL_RATE(1608000000, 1, 67, 1, 1, 1, 0),
RK3036_PLL_RATE(1416000000, 1, 118, 2, 1, 1, 0),
RK3036_PLL_RATE(1296000000, 1, 108, 2, 1, 1, 0),
RK3036_PLL_RATE(1200000000, 1, 100, 2, 1, 1, 0),
RK3036_PLL_RATE(1188000000, 1, 99, 2, 1, 1, 0),
RK3036_PLL_RATE(1104000000, 1, 92, 2, 1, 1, 0),
RK3036_PLL_RATE(1008000000, 1, 84, 2, 1, 1, 0),
RK3036_PLL_RATE(1000000000, 3, 250, 2, 1, 1, 0),
RK3036_PLL_RATE(912000000, 1, 76, 2, 1, 1, 0),
RK3036_PLL_RATE(816000000, 1, 68, 2, 1, 1, 0),
RK3036_PLL_RATE(705600000, 2, 235, 4, 1, 0, 3355443),
RK3036_PLL_RATE(611520000, 4, 611, 6, 1, 0, 8724152),
RK3036_PLL_RATE(600000000, 1, 100, 4, 1, 1, 0),
RK3036_PLL_RATE(594000000, 1, 99, 4, 1, 1, 0),
RK3036_PLL_RATE(500000000, 1, 125, 6, 1, 1, 0),
RK3036_PLL_RATE(408000000, 1, 68, 2, 2, 1, 0),
RK3036_PLL_RATE(312000000, 1, 78, 6, 1, 1, 0),
RK3036_PLL_RATE(216000000, 1, 72, 4, 2, 1, 0),
RK3036_PLL_RATE(96000000, 1, 96, 6, 4, 1, 0),
{ /* sentinel */ },
};
static struct rockchip_pll_clock rk3562_pll_clks[] = {
[APLL] = PLL(pll_rk3328, PLL_APLL, RK3562_PLL_CON(0),
RK3562_MODE_CON, 0, 10, 0, rk3562_pll_rates),
[GPLL] = PLL(pll_rk3328, PLL_GPLL, RK3562_PLL_CON(24),
RK3562_MODE_CON, 2, 10, 0, rk3562_pll_rates),
[VPLL] = PLL(pll_rk3328, PLL_VPLL, RK3562_PLL_CON(32),
RK3562_MODE_CON, 6, 10, 0, rk3562_pll_rates),
[HPLL] = PLL(pll_rk3328, PLL_HPLL, RK3562_PLL_CON(40),
RK3562_MODE_CON, 8, 10, 0, rk3562_pll_rates),
[CPLL] = PLL(pll_rk3328, PLL_CPLL, RK3562_PMU1_PLL_CON(0),
RK3562_PMU1_MODE_CON, 0, 10, 0, rk3562_pll_rates),
[DPLL] = PLL(pll_rk3328, PLL_DPLL, RK3562_SUBDDR_PLL_CON(0),
RK3562_SUBDDR_MODE_CON, 0, 10, 0, NULL),
};
#define RK3562_CPUCLK_RATE(_rate, _aclk_m_core, _pclk_dbg) \
{ \
.rate = _rate##U, \
.aclk_div = _aclk_m_core, \
.pclk_div = _pclk_dbg, \
}
static struct rockchip_cpu_rate_table rk3562_cpu_rates[] = {
RK3562_CPUCLK_RATE(1416000000, 1, 8),
RK3562_CPUCLK_RATE(1296000000, 1, 8),
RK3562_CPUCLK_RATE(1200000000, 1, 8),
RK3562_CPUCLK_RATE(1104000000, 1, 8),
RK3562_CPUCLK_RATE(1008000000, 1, 8),
RK3562_CPUCLK_RATE(912000000, 1, 6),
RK3562_CPUCLK_RATE(816000000, 1, 6),
RK3562_CPUCLK_RATE(600000000, 1, 6),
RK3562_CPUCLK_RATE(408000000, 1, 4),
{ /* sentinel */ },
};
#ifndef CONFIG_SPL_BUILD
#define RK3562_CLK_DUMP(_id, _name) \
{ \
.id = _id, \
.name = _name, \
}
static const struct rk3562_clk_info clks_dump[] = {
RK3562_CLK_DUMP(PLL_APLL, "apll"),
RK3562_CLK_DUMP(PLL_GPLL, "gpll"),
RK3562_CLK_DUMP(PLL_VPLL, "vpll"),
RK3562_CLK_DUMP(PLL_HPLL, "hpll"),
RK3562_CLK_DUMP(PLL_CPLL, "cpll"),
RK3562_CLK_DUMP(PLL_DPLL, "dpll"),
RK3562_CLK_DUMP(ACLK_BUS, "aclk_bus"),
RK3562_CLK_DUMP(HCLK_BUS, "hclk_bus"),
RK3562_CLK_DUMP(PCLK_BUS, "pclk_bus"),
RK3562_CLK_DUMP(ACLK_PERI, "aclk_peri"),
RK3562_CLK_DUMP(HCLK_PERI, "hclk_peri"),
RK3562_CLK_DUMP(PCLK_PERI, "pclk_peri"),
};
#endif
/*
*
* rational_best_approximation(31415, 10000,
* (1 << 8) - 1, (1 << 5) - 1, &n, &d);
*
* you may look at given_numerator as a fixed point number,
* with the fractional part size described in given_denominator.
*
* for theoretical background, see:
* http://en.wikipedia.org/wiki/Continued_fraction
*/
static void rational_best_approximation(unsigned long given_numerator,
unsigned long given_denominator,
unsigned long max_numerator,
unsigned long max_denominator,
unsigned long *best_numerator,
unsigned long *best_denominator)
{
unsigned long n, d, n0, d0, n1, d1;
n = given_numerator;
d = given_denominator;
n0 = 0;
d1 = 0;
n1 = 1;
d0 = 1;
for (;;) {
unsigned long t, a;
if (n1 > max_numerator || d1 > max_denominator) {
n1 = n0;
d1 = d0;
break;
}
if (d == 0)
break;
t = d;
a = n / d;
d = n % d;
n = t;
t = n0 + a * n1;
n0 = n1;
n1 = t;
t = d0 + a * d1;
d0 = d1;
d1 = t;
}
*best_numerator = n1;
*best_denominator = d1;
}
static int rk3562_armclk_set_rate(struct rk3562_clk_priv *priv, ulong new_rate)
{
const struct rockchip_cpu_rate_table *rate;
struct rk3562_cru *cru = priv->cru;
ulong old_rate;
rate = rockchip_get_cpu_settings(rk3562_cpu_rates, new_rate);
if (!rate) {
printf("%s unsupported rate\n", __func__);
return -EINVAL;
}
/*
* set up dependent divisors for DBG and ACLK clocks.
*/
old_rate = rockchip_pll_get_rate(&rk3562_pll_clks[APLL], priv->cru,
APLL);
if (old_rate == new_rate) {
rk_clrsetreg(&cru->clksel_con[11], ACLK_CORE_PRE_DIV_MASK,
rate->aclk_div << ACLK_CORE_PRE_DIV_SHIFT);
rk_clrsetreg(&cru->clksel_con[12], PCLK_DBG_PRE_DIV_MASK,
rate->pclk_div << PCLK_DBG_PRE_DIV_SHIFT);
rk_clrsetreg(&cru->clksel_con[10], CLK_CORE_PRE_DIV_MASK, 0);
} else if (old_rate > new_rate) {
if (rockchip_pll_set_rate(&rk3562_pll_clks[APLL],
priv->cru, APLL, new_rate))
return -EINVAL;
rk_clrsetreg(&cru->clksel_con[11], ACLK_CORE_PRE_DIV_MASK,
rate->aclk_div << ACLK_CORE_PRE_DIV_SHIFT);
rk_clrsetreg(&cru->clksel_con[12], PCLK_DBG_PRE_DIV_MASK,
rate->pclk_div << PCLK_DBG_PRE_DIV_SHIFT);
rk_clrsetreg(&cru->clksel_con[10], CLK_CORE_PRE_DIV_MASK, 0);
} else if (old_rate < new_rate) {
rk_clrsetreg(&cru->clksel_con[11], ACLK_CORE_PRE_DIV_MASK,
rate->aclk_div << ACLK_CORE_PRE_DIV_SHIFT);
rk_clrsetreg(&cru->clksel_con[12], PCLK_DBG_PRE_DIV_MASK,
rate->pclk_div << PCLK_DBG_PRE_DIV_SHIFT);
rk_clrsetreg(&cru->clksel_con[10], CLK_CORE_PRE_DIV_MASK, 0);
if (rockchip_pll_set_rate(&rk3562_pll_clks[APLL],
priv->cru, APLL, new_rate))
return -EINVAL;
}
return 0;
}
static ulong rk3562_bus_get_rate(struct rk3562_clk_priv *priv, ulong clk_id)
{
struct rk3562_cru *cru = priv->cru;
u32 sel, con, div;
ulong rate;
switch (clk_id) {
case ACLK_BUS:
con = readl(&cru->clksel_con[40]);
sel = (con & ACLK_BUS_SEL_MASK) >> ACLK_BUS_SEL_SHIFT;
div = (con & ACLK_BUS_DIV_MASK) >> ACLK_BUS_DIV_SHIFT;
break;
case HCLK_BUS:
con = readl(&cru->clksel_con[40]);
sel = (con & HCLK_BUS_SEL_MASK) >> HCLK_BUS_SEL_SHIFT;
div = (con & HCLK_BUS_DIV_MASK) >> HCLK_BUS_DIV_SHIFT;
break;
case PCLK_BUS:
con = readl(&cru->clksel_con[41]);
sel = (con & PCLK_BUS_SEL_MASK) >> PCLK_BUS_SEL_SHIFT;
div = (con & PCLK_BUS_DIV_MASK) >> PCLK_BUS_DIV_SHIFT;
break;
default:
return -ENOENT;
}
if (sel == ACLK_BUS_SEL_CPLL)
rate = priv->cpll_hz;
else
rate = priv->gpll_hz;
return DIV_TO_RATE(rate, div);
}
static ulong rk3562_bus_set_rate(struct rk3562_clk_priv *priv, ulong clk_id,
ulong rate)
{
struct rk3562_cru *cru = priv->cru;
u32 sel, div;
if (priv->cpll_hz % rate == 0) {
sel = ACLK_BUS_SEL_CPLL;
div = DIV_ROUND_UP(priv->cpll_hz, rate);
} else {
sel= ACLK_BUS_SEL_GPLL;
div = DIV_ROUND_UP(priv->gpll_hz, rate);
}
switch (clk_id) {
case ACLK_BUS:
rk_clrsetreg(&cru->clksel_con[40],
ACLK_BUS_SEL_MASK | ACLK_BUS_DIV_MASK,
(sel << ACLK_BUS_SEL_SHIFT) |
((div - 1) << ACLK_BUS_DIV_SHIFT));
break;
case HCLK_BUS:
rk_clrsetreg(&cru->clksel_con[40],
HCLK_BUS_SEL_MASK | HCLK_BUS_DIV_MASK,
(sel << HCLK_BUS_SEL_SHIFT) |
((div - 1) << HCLK_BUS_DIV_SHIFT));
break;
case PCLK_BUS:
rk_clrsetreg(&cru->clksel_con[41],
PCLK_BUS_SEL_MASK | PCLK_BUS_DIV_MASK,
(sel << PCLK_BUS_SEL_SHIFT) |
((div - 1) << PCLK_BUS_DIV_SHIFT));
break;
default:
return -ENOENT;
}
return rk3562_bus_get_rate(priv, clk_id);
}
static ulong rk3562_peri_get_rate(struct rk3562_clk_priv *priv, ulong clk_id)
{
struct rk3562_cru *cru = priv->cru;
u32 sel, con, div;
ulong rate;
switch (clk_id) {
case ACLK_PERI:
con = readl(&cru->periclksel_con[0]);
sel = (con & ACLK_PERI_SEL_MASK) >> ACLK_PERI_SEL_SHIFT;
div = (con & ACLK_PERI_DIV_MASK) >> ACLK_PERI_DIV_SHIFT;
break;
case HCLK_PERI:
con = readl(&cru->periclksel_con[0]);
sel = (con & HCLK_PERI_SEL_MASK) >> HCLK_PERI_SEL_SHIFT;
div = (con & HCLK_PERI_DIV_MASK) >> HCLK_PERI_DIV_SHIFT;
break;
case PCLK_PERI:
con = readl(&cru->periclksel_con[1]);
sel = (con & PCLK_PERI_SEL_MASK) >> PCLK_PERI_SEL_SHIFT;
div = (con & PCLK_PERI_DIV_MASK) >> PCLK_PERI_DIV_SHIFT;
break;
default:
return -ENOENT;
}
if (sel == ACLK_PERI_SEL_CPLL)
rate = priv->cpll_hz;
else
rate = priv->gpll_hz;
return DIV_TO_RATE(rate, div);
}
static ulong rk3562_peri_set_rate(struct rk3562_clk_priv *priv, ulong clk_id,
ulong rate)
{
struct rk3562_cru *cru = priv->cru;
u32 sel, div;
if (priv->cpll_hz % rate == 0) {
sel = ACLK_PERI_SEL_CPLL;
div = DIV_ROUND_UP(priv->cpll_hz, rate);
} else {
sel= ACLK_PERI_SEL_GPLL;
div = DIV_ROUND_UP(priv->gpll_hz, rate);
}
switch (clk_id) {
case ACLK_PERI:
rk_clrsetreg(&cru->periclksel_con[0],
ACLK_PERI_SEL_MASK | ACLK_PERI_DIV_MASK,
(sel << ACLK_PERI_SEL_SHIFT) |
((div - 1) << ACLK_PERI_DIV_SHIFT));
break;
case HCLK_PERI:
rk_clrsetreg(&cru->periclksel_con[0],
HCLK_PERI_SEL_MASK | HCLK_PERI_DIV_MASK,
(sel << HCLK_PERI_SEL_SHIFT) |
((div - 1) << HCLK_PERI_DIV_SHIFT));
break;
case PCLK_PERI:
rk_clrsetreg(&cru->periclksel_con[1],
PCLK_PERI_SEL_MASK | PCLK_PERI_DIV_MASK,
(sel << PCLK_PERI_SEL_SHIFT) |
((div - 1) << PCLK_PERI_DIV_SHIFT));
break;
default:
return -ENOENT;
}
return rk3562_peri_get_rate(priv, clk_id);
}
static ulong rk3562_i2c_get_rate(struct rk3562_clk_priv *priv, ulong clk_id)
{
struct rk3562_cru *cru = priv->cru;
u32 sel, con, div;
ulong rate;
switch (clk_id) {
case CLK_PMU0_I2C0:
con = readl(&cru->pmu0clksel_con[3]);
sel = (con & CLK_PMU0_I2C0_SEL_MASK) >> CLK_PMU0_I2C0_SEL_SHIFT;
if (sel == CLK_PMU0_I2C0_SEL_200M)
rate = 200 * MHz;
else if (sel == CLK_PMU0_I2C0_SEL_24M)
rate = OSC_HZ;
else
rate = 32768;
div = (con & CLK_PMU0_I2C0_DIV_MASK) >> CLK_PMU0_I2C0_DIV_SHIFT;
return DIV_TO_RATE(rate, div);
case CLK_I2C:
case CLK_I2C1:
case CLK_I2C2:
case CLK_I2C3:
case CLK_I2C4:
case CLK_I2C5:
con = readl(&cru->clksel_con[41]);
sel = (con & CLK_I2C_SEL_MASK) >> CLK_I2C_SEL_SHIFT;
if (sel == CLK_I2C_SEL_200M)
rate = 200 * MHz;
else if (sel == CLK_I2C_SEL_100M)
rate = 100 * MHz;
else if (sel == CLK_I2C_SEL_50M)
rate = 50 * MHz;
else
rate = OSC_HZ;
break;
default:
return -ENOENT;
}
return rate;
}
static ulong rk3562_i2c_set_rate(struct rk3562_clk_priv *priv, ulong clk_id,
ulong rate)
{
struct rk3562_cru *cru = priv->cru;
u32 sel, div;
switch (clk_id) {
case CLK_PMU0_I2C0:
if (rate == 200 * MHz) {
sel = CLK_PMU0_I2C0_SEL_200M;
div = 1;
} else if (rate == OSC_HZ) {
sel = CLK_PMU0_I2C0_SEL_24M;
div = 1;
} else if (rate == 32768) {
sel = CLK_PMU0_I2C0_SEL_32K;
div = 1;
} else {
sel = CLK_PMU0_I2C0_SEL_200M;
div = DIV_ROUND_UP(200 * MHz, rate);
assert(div - 1 <= 31);
}
rk_clrsetreg(&cru->pmu0clksel_con[3], CLK_PMU0_I2C0_DIV_MASK,
(div - 1) << CLK_PMU0_I2C0_DIV_SHIFT);
rk_clrsetreg(&cru->pmu0clksel_con[3], CLK_PMU0_I2C0_SEL_MASK,
sel << CLK_PMU0_I2C0_SEL_SHIFT);
break;
case CLK_I2C:
case CLK_I2C2:
case CLK_I2C3:
case CLK_I2C4:
case CLK_I2C5:
if (rate == 200 * MHz)
sel = CLK_I2C_SEL_200M;
else if (rate == 100 * MHz)
sel = CLK_I2C_SEL_100M;
else if (rate == 50 * MHz)
sel = CLK_I2C_SEL_50M;
else
sel = CLK_I2C_SEL_24M;
rk_clrsetreg(&cru->clksel_con[41], CLK_I2C_SEL_MASK,
sel << CLK_I2C_SEL_SHIFT);
break;
default:
return -ENOENT;
}
return rk3562_i2c_get_rate(priv, clk_id);
}
static ulong rk3562_uart_get_rate(struct rk3562_clk_priv *priv, ulong clk_id)
{
struct rk3562_cru *cru = priv->cru;
u32 reg, con, fracdiv, div, src, p_src, p_rate;
unsigned long m, n;
switch (clk_id) {
case SCLK_PMU1_UART0:
con = readl(&cru->pmu1clksel_con[2]);
src = (con & CLK_PMU1_UART0_SEL_MASK) >>
CLK_PMU1_UART0_SEL_SHIFT;
div = (con & CLK_PMU1_UART0_SRC_DIV_MASK) >>
CLK_PMU1_UART0_SRC_DIV_SHIFT;
if (src == CLK_UART_SEL_SRC) {
return DIV_TO_RATE(priv->cpll_hz, div);
} else if (src == CLK_UART_SEL_FRAC) {
fracdiv = readl(&cru->pmu1clksel_con[3]);
n = fracdiv & CLK_UART_FRAC_NUMERATOR_MASK;
n >>= CLK_UART_FRAC_NUMERATOR_SHIFT;
m = fracdiv & CLK_UART_FRAC_DENOMINATOR_MASK;
m >>= CLK_UART_FRAC_DENOMINATOR_SHIFT;
return DIV_TO_RATE(priv->cpll_hz, div) * n / m;
} else {
return OSC_HZ;
}
case SCLK_UART1:
reg = 21;
break;
case SCLK_UART2:
reg = 23;
break;
case SCLK_UART3:
reg = 25;
break;
case SCLK_UART4:
reg = 27;
break;
case SCLK_UART5:
reg = 29;
break;
case SCLK_UART6:
reg = 31;
break;
case SCLK_UART7:
reg = 33;
break;
case SCLK_UART8:
reg = 35;
break;
case SCLK_UART9:
reg = 37;
break;
default:
return -ENOENT;
}
con = readl(&cru->periclksel_con[reg]);
src = (con & CLK_UART_SEL_MASK) >> CLK_UART_SEL_SHIFT;
div = (con & CLK_UART_SRC_DIV_MASK) >> CLK_UART_SRC_DIV_SHIFT;
p_src = (con & CLK_UART_SRC_SEL_MASK) >> CLK_UART_SRC_SEL_SHIFT;
if (p_src == CLK_UART_SRC_SEL_GPLL)
p_rate = priv->gpll_hz;
else
p_rate = priv->cpll_hz;
if (src == CLK_UART_SEL_SRC) {
return DIV_TO_RATE(p_rate, div);
} else if (src == CLK_UART_SEL_FRAC) {
fracdiv = readl(&cru->periclksel_con[reg + 1]);
n = fracdiv & CLK_UART_FRAC_NUMERATOR_MASK;
n >>= CLK_UART_FRAC_NUMERATOR_SHIFT;
m = fracdiv & CLK_UART_FRAC_DENOMINATOR_MASK;
m >>= CLK_UART_FRAC_DENOMINATOR_SHIFT;
return DIV_TO_RATE(p_rate, div) * n / m;
} else {
return OSC_HZ;
}
}
static ulong rk3562_uart_set_rate(struct rk3562_clk_priv *priv, ulong clk_id,
ulong rate)
{
struct rk3562_cru *cru = priv->cru;
u32 reg, clk_src, uart_src, div;
unsigned long m = 0, n = 0, val;
switch (clk_id) {
case SCLK_PMU1_UART0:
if (priv->cpll_hz % rate == 0) {
uart_src = CLK_UART_SEL_SRC;
div = DIV_ROUND_UP(priv->cpll_hz, rate);
} else if (rate == OSC_HZ) {
uart_src = CLK_UART_SEL_XIN24M;
div = 2;
} else {
uart_src = CLK_UART_SEL_FRAC;
div = 2;
rational_best_approximation(rate, priv->cpll_hz / div,
GENMASK(16 - 1, 0),
GENMASK(16 - 1, 0),
&n, &m);
}
rk_clrsetreg(&cru->pmu1clksel_con[2],
CLK_PMU1_UART0_SEL_MASK |
CLK_PMU1_UART0_SRC_DIV_MASK,
(uart_src << CLK_PMU1_UART0_SEL_SHIFT) |
((div - 1) << CLK_PMU1_UART0_SRC_DIV_SHIFT));
if (m && n) {
val = n << CLK_UART_FRAC_NUMERATOR_SHIFT | m;
writel(val, &cru->pmu1clksel_con[3]);
}
return rk3562_uart_get_rate(priv, clk_id);
case SCLK_UART1:
reg = 21;
break;
case SCLK_UART2:
reg = 23;
break;
case SCLK_UART3:
reg = 25;
break;
case SCLK_UART4:
reg = 27;
break;
case SCLK_UART5:
reg = 29;
break;
case SCLK_UART6:
reg = 31;
break;
case SCLK_UART7:
reg = 33;
break;
case SCLK_UART8:
reg = 35;
break;
case SCLK_UART9:
reg = 37;
break;
default:
return -ENOENT;
}
if (priv->gpll_hz % rate == 0) {
clk_src = CLK_UART_SRC_SEL_GPLL;
uart_src = CLK_UART_SEL_SRC;
div = DIV_ROUND_UP(priv->gpll_hz, rate);
} else if (priv->cpll_hz % rate == 0) {
clk_src = CLK_UART_SRC_SEL_CPLL;
uart_src = CLK_UART_SEL_SRC;
div = DIV_ROUND_UP(priv->cpll_hz, rate);
} else if (rate == OSC_HZ) {
clk_src = CLK_UART_SRC_SEL_GPLL;
uart_src = CLK_UART_SEL_XIN24M;
div = 2;
} else {
clk_src = CLK_UART_SRC_SEL_GPLL;
uart_src = CLK_UART_SEL_FRAC;
div = 2;
rational_best_approximation(rate, priv->gpll_hz / div,
GENMASK(16 - 1, 0),
GENMASK(16 - 1, 0),
&n, &m);
}
rk_clrsetreg(&cru->periclksel_con[reg],
CLK_UART_SEL_MASK | CLK_UART_SRC_SEL_MASK |
CLK_UART_SRC_DIV_MASK,
(clk_src << CLK_UART_SRC_SEL_SHIFT) |
(uart_src << CLK_UART_SEL_SHIFT) |
((div - 1) << CLK_UART_SRC_DIV_SHIFT));
if (m && n) {
val = n << CLK_UART_FRAC_NUMERATOR_SHIFT | m;
writel(val, &cru->periclksel_con[reg + 1]);
}
return rk3562_uart_get_rate(priv, clk_id);
}
static ulong rk3562_pwm_get_rate(struct rk3562_clk_priv *priv, ulong clk_id)
{
struct rk3562_cru *cru = priv->cru;
u32 sel, con, div, mask, shift;
ulong rate;
switch (clk_id) {
case CLK_PMU1_PWM0:
con = readl(&cru->pmu1clksel_con[4]);
sel = (con & CLK_PMU1_PWM0_SEL_MASK) >> CLK_PMU1_PWM0_SEL_SHIFT;
if (sel == CLK_PMU1_PWM0_SEL_200M)
rate = 200 * MHz;
else if (sel == CLK_PMU1_PWM0_SEL_24M)
rate = OSC_HZ;
else
rate = 32768;
div = (con & CLK_PMU1_PWM0_DIV_MASK) >> CLK_PMU1_PWM0_DIV_SHIFT;
return DIV_TO_RATE(rate, div);
case CLK_PWM1_PERI:
mask = CLK_PWM1_PERI_SEL_MASK;
shift = CLK_PWM1_PERI_SEL_SHIFT;
break;
case CLK_PWM2_PERI:
mask = CLK_PWM2_PERI_SEL_MASK;
shift = CLK_PWM2_PERI_SEL_SHIFT;
break;
case CLK_PWM3_PERI:
mask = CLK_PWM3_PERI_SEL_MASK;
shift = CLK_PWM3_PERI_SEL_SHIFT;
break;
default:
return -ENOENT;
}
con = readl(&cru->periclksel_con[40]);
sel = (con & mask) >> shift;
if (sel == CLK_PWM_SEL_100M)
rate = 100 * MHz;
else if (sel == CLK_PWM_SEL_50M)
rate = 50 * MHz;
else
rate = OSC_HZ;
return rate;
}
static ulong rk3562_pwm_set_rate(struct rk3562_clk_priv *priv, ulong clk_id,
ulong rate)
{
struct rk3562_cru *cru = priv->cru;
u32 sel, div, mask, shift;
switch (clk_id) {
case CLK_PMU1_PWM0:
if (rate == 200 * MHz) {
sel = CLK_PMU1_PWM0_SEL_200M;
div = 1;
} else if (rate == OSC_HZ) {
sel = CLK_PMU1_PWM0_SEL_24M;
div = 1;
} else if (rate == 32768) {
sel = CLK_PMU1_PWM0_SEL_32K;
div = 1;
} else {
sel = CLK_PMU1_PWM0_SEL_200M;
div = DIV_ROUND_UP(200 * MHz, rate);
assert(div - 1 <= 3);
}
rk_clrsetreg(&cru->pmu1clksel_con[4], CLK_PMU1_PWM0_DIV_MASK,
(div - 1) << CLK_PMU1_PWM0_DIV_SHIFT);
rk_clrsetreg(&cru->pmu1clksel_con[4], CLK_PMU1_PWM0_SEL_MASK,
sel << CLK_PMU1_PWM0_SEL_SHIFT);
return rk3562_pwm_get_rate(priv, clk_id);
case CLK_PWM1_PERI:
mask = CLK_PWM1_PERI_SEL_MASK;
shift = CLK_PWM1_PERI_SEL_SHIFT;
break;
case CLK_PWM2_PERI:
mask = CLK_PWM2_PERI_SEL_MASK;
shift = CLK_PWM2_PERI_SEL_SHIFT;
break;
case CLK_PWM3_PERI:
mask = CLK_PWM3_PERI_SEL_MASK;
shift = CLK_PWM3_PERI_SEL_SHIFT;
break;
default:
return -ENOENT;
}
if (rate == 100 * MHz)
sel = CLK_PWM_SEL_100M;
else if (rate == 50 * MHz)
sel = CLK_PWM_SEL_50M;
else
sel = CLK_PWM_SEL_24M;
rk_clrsetreg(&cru->periclksel_con[40], mask, sel << shift);
return rk3562_pwm_get_rate(priv, clk_id);
}
static ulong rk3562_spi_get_rate(struct rk3562_clk_priv *priv, ulong clk_id)
{
struct rk3562_cru *cru = priv->cru;
u32 sel, con, div, mask, shift;
ulong rate;
switch (clk_id) {
case CLK_PMU1_SPI0:
con = readl(&cru->pmu1clksel_con[4]);
sel = (con & CLK_PMU1_SPI0_SEL_MASK) >> CLK_PMU1_SPI0_SEL_SHIFT;
if (sel == CLK_PMU1_SPI0_SEL_200M)
rate = 200 * MHz;
else if (sel == CLK_PMU1_SPI0_SEL_24M)
rate = OSC_HZ;
else
rate = 32768;
div = (con & CLK_PMU1_SPI0_DIV_MASK) >> CLK_PMU1_SPI0_DIV_SHIFT;
return DIV_TO_RATE(rate, div);
case CLK_SPI1:
mask = CLK_SPI1_SEL_MASK;
shift = CLK_SPI1_SEL_SHIFT;
break;
case CLK_SPI2:
mask = CLK_SPI2_SEL_MASK;
shift = CLK_SPI2_SEL_SHIFT;
break;
default:
return -ENOENT;
}
con = readl(&cru->periclksel_con[20]);
sel = (con & mask) >> shift;
if (sel == CLK_SPI_SEL_200M)
rate = 200 * MHz;
else if (sel == CLK_SPI_SEL_100M)
rate = 100 * MHz;
else if (sel == CLK_SPI_SEL_50M)
rate = 50 * MHz;
else
rate = OSC_HZ;
return rate;
}
static ulong rk3562_spi_set_rate(struct rk3562_clk_priv *priv, ulong clk_id,
ulong rate)
{
struct rk3562_cru *cru = priv->cru;
u32 sel, div, mask, shift;
switch (clk_id) {
case CLK_PMU1_SPI0:
if (rate == 200 * MHz) {
sel = CLK_PMU1_SPI0_SEL_200M;
div = 1;
} else if (rate == OSC_HZ) {
sel = CLK_PMU1_SPI0_SEL_24M;
div = 1;
} else if (rate == 32768) {
sel = CLK_PMU1_SPI0_SEL_32K;
div = 1;
} else {
sel = CLK_PMU1_SPI0_SEL_200M;
div = DIV_ROUND_UP(200 * MHz, rate);
assert(div - 1 <= 3);
}
rk_clrsetreg(&cru->pmu1clksel_con[4], CLK_PMU1_SPI0_DIV_MASK,
(div - 1) << CLK_PMU1_SPI0_DIV_SHIFT);
rk_clrsetreg(&cru->pmu1clksel_con[4], CLK_PMU1_SPI0_SEL_MASK,
sel << CLK_PMU1_SPI0_SEL_SHIFT);
return rk3562_spi_get_rate(priv, clk_id);
case CLK_SPI1:
mask = CLK_SPI1_SEL_MASK;
shift = CLK_SPI1_SEL_SHIFT;
break;
case CLK_SPI2:
mask = CLK_SPI2_SEL_MASK;
shift = CLK_SPI2_SEL_SHIFT;
break;
default:
return -ENOENT;
}
if (rate == 200 * MHz)
sel = CLK_SPI_SEL_200M;
else if (rate == 100 * MHz)
sel = CLK_SPI_SEL_100M;
else if (rate == 50 * MHz)
sel = CLK_SPI_SEL_50M;
else
sel = CLK_SPI_SEL_24M;
rk_clrsetreg(&cru->periclksel_con[20], mask, sel << shift);
return rk3562_spi_get_rate(priv, clk_id);
}
static ulong rk3562_tsadc_get_rate(struct rk3562_clk_priv *priv, ulong clk_id)
{
struct rk3562_cru *cru = priv->cru;
u32 div, con;
con = readl(&cru->clksel_con[43]);
switch (clk_id) {
case CLK_TSADC_TSEN:
div = (con & CLK_TSADC_TSEN_DIV_MASK) >>
CLK_TSADC_TSEN_DIV_SHIFT;
break;
case CLK_TSADC:
div = (con & CLK_TSADC_DIV_MASK) >> CLK_TSADC_DIV_SHIFT;
break;
default:
return -ENOENT;
}
return DIV_TO_RATE(OSC_HZ, div);
}
static ulong rk3562_tsadc_set_rate(struct rk3562_clk_priv *priv, ulong clk_id,
ulong rate)
{
struct rk3562_cru *cru = priv->cru;
u32 div, mask, shift;
switch (clk_id) {
case CLK_TSADC_TSEN:
mask = CLK_TSADC_TSEN_DIV_MASK;
shift = CLK_TSADC_TSEN_DIV_SHIFT;
break;
case CLK_TSADC:
mask = CLK_TSADC_DIV_MASK;
shift = CLK_TSADC_DIV_SHIFT;
break;
default:
return -ENOENT;
}
div = DIV_ROUND_UP(OSC_HZ, rate);
rk_clrsetreg(&cru->clksel_con[43], mask, (div - 1) << shift);
return rk3562_tsadc_get_rate(priv, clk_id);
}
static ulong rk3562_saradc_get_rate(struct rk3562_clk_priv *priv, ulong clk_id)
{
struct rk3562_cru *cru = priv->cru;
u32 div, con;
switch (clk_id) {
case CLK_SARADC_VCCIO156:
con = readl(&cru->clksel_con[44]);
div = (con & CLK_SARADC_VCCIO156_DIV_MASK) >>
CLK_SARADC_VCCIO156_DIV_SHIFT;
break;
case CLK_SARADC:
con = readl(&cru->periclksel_con[46]);
div = (con & CLK_SARADC_DIV_MASK) >> CLK_SARADC_DIV_SHIFT;
break;
default:
return -ENOENT;
}
return DIV_TO_RATE(OSC_HZ, div);
}
static ulong rk3562_saradc_set_rate(struct rk3562_clk_priv *priv, ulong clk_id,
ulong rate)
{
struct rk3562_cru *cru = priv->cru;
u32 div;
switch (clk_id) {
case CLK_SARADC_VCCIO156:
div = DIV_ROUND_UP(OSC_HZ, rate);
rk_clrsetreg(&cru->clksel_con[44], CLK_SARADC_VCCIO156_DIV_MASK,
(div - 1) << CLK_SARADC_VCCIO156_DIV_SHIFT);
break;
case CLK_SARADC:
div = DIV_ROUND_UP(OSC_HZ, rate);
rk_clrsetreg(&cru->periclksel_con[46], CLK_SARADC_DIV_MASK,
(div - 1) << CLK_SARADC_DIV_SHIFT);
break;
default:
return -ENOENT;
}
return rk3562_saradc_get_rate(priv, clk_id);
}
static ulong rk3562_sfc_get_rate(struct rk3562_clk_priv *priv)
{
struct rk3562_cru *cru = priv->cru;
u32 div, sel, con, parent;
con = readl(&cru->periclksel_con[20]);
div = (con & SCLK_SFC_DIV_MASK) >> SCLK_SFC_DIV_SHIFT;
sel = (con & SCLK_SFC_SEL_MASK) >> SCLK_SFC_SEL_SHIFT;
if (sel == SCLK_SFC_SRC_SEL_GPLL)
parent = priv->gpll_hz;
else if (sel == SCLK_SFC_SRC_SEL_CPLL)
parent = priv->cpll_hz;
else
parent = OSC_HZ;
return DIV_TO_RATE(parent, div);
}
static ulong rk3562_sfc_set_rate(struct rk3562_clk_priv *priv, ulong rate)
{
struct rk3562_cru *cru = priv->cru;
int div, sel;
if (OSC_HZ % rate == 0) {
div = DIV_ROUND_UP(OSC_HZ, rate);
sel = SCLK_SFC_SRC_SEL_24M;
} else if ((priv->cpll_hz % rate) == 0) {
div = DIV_ROUND_UP(priv->cpll_hz, rate);
sel = SCLK_SFC_SRC_SEL_CPLL;
} else {
div = DIV_ROUND_UP(priv->gpll_hz, rate);
sel = SCLK_SFC_SRC_SEL_GPLL;
}
assert(div - 1 <= 255);
rk_clrsetreg(&cru->periclksel_con[20],
SCLK_SFC_SEL_MASK | SCLK_SFC_DIV_MASK,
sel << SCLK_SFC_SEL_SHIFT |
(div - 1) << SCLK_SFC_DIV_SHIFT);
return rk3562_sfc_get_rate(priv);
}
static ulong rk3562_emmc_get_rate(struct rk3562_clk_priv *priv, ulong clk_id)
{
struct rk3562_cru *cru = priv->cru;
u32 div, sel, con, parent;
switch (clk_id) {
case CCLK_EMMC:
con = readl(&cru->periclksel_con[18]);
div = (con & CCLK_EMMC_DIV_MASK) >> CCLK_EMMC_DIV_SHIFT;
sel = (con & CCLK_EMMC_SEL_MASK) >> CCLK_EMMC_SEL_SHIFT;
if (sel == CCLK_EMMC_SEL_GPLL)
parent = priv->gpll_hz;
else if (sel == CCLK_EMMC_SEL_CPLL)
parent = priv->cpll_hz;
else if (sel == CCLK_EMMC_SEL_HPLL)
parent = priv->hpll_hz;
else
parent = OSC_HZ;
break;
case BCLK_EMMC:
con = readl(&cru->periclksel_con[19]);
div = (con & BCLK_EMMC_DIV_MASK) >> BCLK_EMMC_DIV_SHIFT;
sel = (con & BCLK_EMMC_SEL_MASK) >> BCLK_EMMC_SEL_SHIFT;
if (sel == BCLK_EMMC_SEL_GPLL)
parent = priv->gpll_hz;
else
parent = priv->cpll_hz;
break;
default:
return -ENOENT;
}
return DIV_TO_RATE(parent, div);
}
static ulong rk3562_emmc_set_rate(struct rk3562_clk_priv *priv, ulong clk_id,
ulong rate)
{
struct rk3562_cru *cru = priv->cru;
int div, sel;
switch (clk_id) {
case CCLK_EMMC:
if (OSC_HZ % rate == 0) {
div = DIV_ROUND_UP(OSC_HZ, rate);
sel = CCLK_EMMC_SEL_24M;
} else if ((priv->cpll_hz % rate) == 0) {
div = DIV_ROUND_UP(priv->cpll_hz, rate);
sel = CCLK_EMMC_SEL_CPLL;
} else if ((priv->hpll_hz % rate) == 0) {
div = DIV_ROUND_UP(priv->hpll_hz, rate);
sel = CCLK_EMMC_SEL_HPLL;
} else {
div = DIV_ROUND_UP(priv->gpll_hz, rate);
sel = CCLK_EMMC_SEL_GPLL;
}
rk_clrsetreg(&cru->periclksel_con[18],
CCLK_EMMC_SEL_MASK | CCLK_EMMC_DIV_MASK,
sel << CCLK_EMMC_SEL_SHIFT |
(div - 1) << CCLK_EMMC_DIV_SHIFT);
break;
case BCLK_EMMC:
if ((priv->cpll_hz % rate) == 0) {
div = DIV_ROUND_UP(priv->cpll_hz, rate);
sel = BCLK_EMMC_SEL_CPLL;
} else {
div = DIV_ROUND_UP(priv->gpll_hz, rate);
sel = BCLK_EMMC_SEL_GPLL;
}
rk_clrsetreg(&cru->periclksel_con[19],
BCLK_EMMC_SEL_MASK | BCLK_EMMC_DIV_MASK,
sel << BCLK_EMMC_SEL_SHIFT |
(div - 1) << BCLK_EMMC_DIV_SHIFT);
break;
default:
return -ENOENT;
}
return rk3562_emmc_get_rate(priv, clk_id);
}
static ulong rk3562_sdmmc_get_rate(struct rk3562_clk_priv *priv, ulong clk_id)
{
struct rk3562_cru *cru = priv->cru;
u32 div, sel, con;
ulong prate;
switch (clk_id) {
case HCLK_SDMMC0:
case CCLK_SDMMC0:
case SCLK_SDMMC0_SAMPLE:
con = readl(&cru->periclksel_con[16]);
div = (con & CCLK_SDMMC0_DIV_MASK) >> CCLK_SDMMC0_DIV_SHIFT;
sel = (con & CCLK_SDMMC0_SEL_MASK) >> CCLK_SDMMC0_SEL_SHIFT;
break;
case HCLK_SDMMC1:
case CCLK_SDMMC1:
case SCLK_SDMMC1_SAMPLE:
con = readl(&cru->periclksel_con[17]);
div = (con & CCLK_SDMMC1_DIV_MASK) >> CCLK_SDMMC1_DIV_SHIFT;
sel = (con & CCLK_SDMMC1_SEL_MASK) >> CCLK_SDMMC1_SEL_SHIFT;
break;
default:
return -ENOENT;
}
if (sel == CCLK_SDMMC_SEL_GPLL)
prate = priv->gpll_hz;
else if (sel == CCLK_SDMMC_SEL_CPLL)
prate = priv->cpll_hz;
else if (sel == CCLK_SDMMC_SEL_HPLL)
prate = priv->hpll_hz;
else
prate = OSC_HZ;
return DIV_TO_RATE(prate, div);
}
static ulong rk3562_sdmmc_set_rate(struct rk3562_clk_priv *priv,
ulong clk_id, ulong rate)
{
struct rk3562_cru *cru = priv->cru;
u32 div, sel;
if (OSC_HZ % rate == 0) {
div = DIV_ROUND_UP(OSC_HZ, rate);
sel = CCLK_SDMMC_SEL_24M;
} else if ((priv->cpll_hz % rate) == 0) {
div = DIV_ROUND_UP(priv->cpll_hz, rate);
sel = CCLK_SDMMC_SEL_CPLL;
} else if ((priv->hpll_hz % rate) == 0) {
div = DIV_ROUND_UP(priv->hpll_hz, rate);
sel = CCLK_SDMMC_SEL_HPLL;
} else {
div = DIV_ROUND_UP(priv->gpll_hz, rate);
sel = CCLK_SDMMC_SEL_CPLL;
}
switch (clk_id) {
case HCLK_SDMMC0:
case CCLK_SDMMC0:
rk_clrsetreg(&cru->periclksel_con[16],
CCLK_SDMMC0_SEL_MASK | CCLK_SDMMC0_DIV_MASK,
sel << CCLK_SDMMC0_SEL_SHIFT |
(div - 1) << CCLK_SDMMC0_DIV_SHIFT);
break;
case HCLK_SDMMC1:
case CCLK_SDMMC1:
rk_clrsetreg(&cru->periclksel_con[17],
CCLK_SDMMC1_SEL_MASK | CCLK_SDMMC1_DIV_MASK,
sel << CCLK_SDMMC1_SEL_SHIFT |
(div - 1) << CCLK_SDMMC1_DIV_SHIFT);
break;
default:
return -ENOENT;
}
return rk3562_sdmmc_get_rate(priv, clk_id);
}
static ulong rk3562_vop_get_rate(struct rk3562_clk_priv *priv, ulong clk_id)
{
struct rk3562_cru *cru = priv->cru;
u32 con, sel, div;
ulong prate;
switch (clk_id) {
case ACLK_VOP:
con = readl(&cru->clksel_con[28]);
div = (con & ACLK_VOP_DIV_MASK) >> ACLK_VOP_DIV_SHIFT;
sel = (con & ACLK_VOP_SEL_MASK) >> ACLK_VOP_SEL_SHIFT;
if (sel == ACLK_VOP_SEL_GPLL)
prate = priv->gpll_hz;
else if (sel == ACLK_VOP_SEL_CPLL)
prate = priv->cpll_hz;
else if (sel == ACLK_VOP_SEL_HPLL)
prate = priv->hpll_hz;
else if (sel == ACLK_VOP_SEL_VPLL)
prate = priv->vpll_hz;
else
return -ENOENT;
return DIV_TO_RATE(prate, div);
case DCLK_VOP:
con = readl(&cru->clksel_con[30]);
div = (con & DCLK_VOP_DIV_MASK) >> DCLK_VOP_DIV_SHIFT;
sel = (con & DCLK_VOP_SEL_MASK) >> DCLK_VOP_SEL_SHIFT;
if (sel == DCLK_VOP_SEL_VPLL)
priv->vpll_hz =
rockchip_pll_get_rate(&rk3562_pll_clks[VPLL],
priv->cru, VPLL);
break;
case DCLK_VOP1:
con = readl(&cru->clksel_con[31]);
div = (con & DCLK_VOP1_DIV_MASK) >> DCLK_VOP1_DIV_SHIFT;
sel = (con & DCLK_VOP1_SEL_MASK) >> DCLK_VOP1_SEL_SHIFT;
break;
default:
return -ENOENT;
}
if (sel == DCLK_VOP_SEL_GPLL)
prate = priv->gpll_hz;
else if (sel == DCLK_VOP_SEL_HPLL)
prate = priv->hpll_hz;
else if (sel == DCLK_VOP_SEL_VPLL)
prate = priv->vpll_hz;
else
return -ENOENT;
return DIV_TO_RATE(prate, div);
}
#define RK3562_VOP_PLL_LIMIT_FREQ 594000000
static ulong rk3562_vop_set_rate(struct rk3562_clk_priv *priv, ulong clk_id,
ulong rate)
{
struct rk3562_cru *cru = priv->cru;
u32 i, div, sel, best_div = 0, best_sel = 0;
ulong pll_rate, now, best_rate = 0;
switch (clk_id) {
case ACLK_VOP:
if ((priv->cpll_hz % rate) == 0) {
div = DIV_ROUND_UP(priv->cpll_hz, rate);
sel = ACLK_VOP_SEL_CPLL;
} else if ((priv->hpll_hz % rate) == 0) {
div = DIV_ROUND_UP(priv->hpll_hz, rate);
sel = ACLK_VOP_SEL_HPLL;
} else if ((priv->vpll_hz % rate) == 0) {
div = DIV_ROUND_UP(priv->vpll_hz, rate);
sel = ACLK_VOP_SEL_VPLL;
} else {
div = DIV_ROUND_UP(priv->gpll_hz, rate);
sel = ACLK_VOP_SEL_GPLL;
}
rk_clrsetreg(&cru->clksel_con[28],
ACLK_VOP_SEL_MASK | ACLK_VOP_DIV_MASK,
sel << ACLK_VOP_SEL_SHIFT |
((div - 1) << ACLK_VOP_DIV_SHIFT));
return rk3562_vop_get_rate(priv, clk_id);
case DCLK_VOP:
div = DIV_ROUND_UP(RK3562_VOP_PLL_LIMIT_FREQ, rate);
if (div % 2)
div = div + 1;
rk_clrsetreg(&cru->clksel_con[30],
DCLK_VOP_SEL_MASK | DCLK_VOP_DIV_MASK,
DCLK_VOP_SEL_VPLL << DCLK_VOP_SEL_SHIFT |
((div - 1) << DCLK_VOP_DIV_SHIFT));
rockchip_pll_set_rate(&rk3562_pll_clks[VPLL], priv->cru,
VPLL, div * rate);
break;
case DCLK_VOP1:
for (i = 0; i <= DCLK_VOP_SEL_APLL; i++) {
switch (i) {
case DCLK_VOP_SEL_GPLL:
pll_rate = priv->gpll_hz;
break;
case DCLK_VOP_SEL_HPLL:
pll_rate = priv->hpll_hz;
break;
case DCLK_VOP_SEL_VPLL:
case DCLK_VOP_SEL_APLL:
continue;
default:
printf("do not support this vop pll sel\n");
return -EINVAL;
}
div = DIV_ROUND_UP(pll_rate, rate);
if (div > 255)
continue;
now = pll_rate / div;
if (abs(rate - now) < abs(rate - best_rate)) {
best_rate = now;
best_div = div;
best_sel = i;
}
debug("p_rate=%lu, best_rate=%lu, div=%u, sel=%u\n",
pll_rate, best_rate, best_div, best_sel);
}
if (best_rate) {
rk_clrsetreg(&cru->clksel_con[31],
DCLK_VOP1_SEL_MASK | DCLK_VOP1_DIV_MASK,
best_sel << DCLK_VOP1_SEL_SHIFT |
(best_div - 1) << DCLK_VOP1_DIV_SHIFT);
} else {
printf("do not support this vop freq %lu\n", rate);
return -EINVAL;
}
break;
default:
return -ENOENT;
}
return rk3562_vop_get_rate(priv, clk_id);
}
static ulong rk3562_gmac_get_rate(struct rk3562_clk_priv *priv, ulong clk_id)
{
struct rk3562_cru *cru = priv->cru;
u32 con, sel, div;
ulong prate;
switch (clk_id) {
case CLK_GMAC_125M_CRU_I:
con = readl(&cru->clksel_con[45]);
sel = (con & CLK_GMAC_125M_SEL_MASK) >> CLK_GMAC_125M_SEL_SHIFT;
if (sel == CLK_GMAC_125M)
return 125000000;
else
return OSC_HZ;
case CLK_GMAC_50M_CRU_I:
con = readl(&cru->clksel_con[45]);
sel = (con & CLK_GMAC_50M_SEL_MASK) >> CLK_GMAC_50M_SEL_SHIFT;
if (sel == CLK_GMAC_50M)
return 50000000;
else
return OSC_HZ;
case CLK_MAC100_50M_MATRIX:
con = readl(&cru->clksel_con[47]);
sel = (con & CLK_GMAC_50M_SEL_MASK) >> CLK_GMAC_50M_SEL_SHIFT;
if (sel == CLK_GMAC_50M)
return 50000000;
else
return OSC_HZ;
case CLK_GMAC_ETH_OUT2IO:
con = readl(&cru->clksel_con[46]);
sel = (con & CLK_GMAC_ETH_OUT2IO_SEL_MASK) >> CLK_GMAC_ETH_OUT2IO_SEL_SHIFT;
div = (con & CLK_GMAC_ETH_OUT2IO_DIV_MASK) >> CLK_GMAC_ETH_OUT2IO_DIV_SHIFT;
if (sel == CLK_GMAC_ETH_OUT2IO_GPLL)
prate = priv->gpll_hz;
else
prate = priv->cpll_hz;
break;
default:
return -ENOENT;
}
return DIV_TO_RATE(prate, div);
}
static ulong rk3562_gmac_set_rate(struct rk3562_clk_priv *priv, ulong clk_id,
ulong rate)
{
struct rk3562_cru *cru = priv->cru;
u32 sel, div;
switch (clk_id) {
case CLK_GMAC_125M_CRU_I:
if (rate == 125000000)
sel = CLK_GMAC_125M;
else
sel = CLK_GMAC_24M;
rk_clrsetreg(&cru->clksel_con[45], CLK_GMAC_125M_SEL_MASK,
sel << CLK_GMAC_125M_SEL_SHIFT);
break;
case CLK_GMAC_50M_CRU_I:
if (rate == 50000000)
sel = CLK_GMAC_50M;
else
sel = CLK_GMAC_24M;
rk_clrsetreg(&cru->clksel_con[45], CLK_GMAC_50M_SEL_MASK,
sel << CLK_GMAC_50M_SEL_SHIFT);
break;
case CLK_MAC100_50M_MATRIX:
if (rate == 50000000)
sel = CLK_GMAC_50M;
else
sel = CLK_GMAC_24M;
rk_clrsetreg(&cru->clksel_con[47], CLK_GMAC_50M_SEL_MASK,
sel << CLK_GMAC_50M_SEL_SHIFT);
break;
case CLK_GMAC_ETH_OUT2IO:
if ((priv->cpll_hz % rate) == 0) {
div = DIV_ROUND_UP(priv->cpll_hz, rate);
sel = CLK_GMAC_ETH_OUT2IO_CPLL;
} else {
div = DIV_ROUND_UP(priv->gpll_hz, rate);
sel = CLK_GMAC_ETH_OUT2IO_GPLL;
}
rk_clrsetreg(&cru->clksel_con[46],
CLK_GMAC_ETH_OUT2IO_SEL_MASK | CLK_GMAC_ETH_OUT2IO_DIV_MASK,
sel << CLK_GMAC_ETH_OUT2IO_SEL_SHIFT |
(div - 1) << CLK_GMAC_ETH_OUT2IO_DIV_SHIFT);
break;
default:
return -ENOENT;
}
return rk3562_gmac_get_rate(priv, clk_id);
}
static ulong rk3562_clk_get_rate(struct clk *clk)
{
struct rk3562_clk_priv *priv = dev_get_priv(clk->dev);
ulong rate = 0;
if (!priv->gpll_hz || !priv->cpll_hz || !priv->hpll_hz) {
printf("%s: gpll=%lu, cpll=%lu, hpll=%lu\n",
__func__, priv->gpll_hz, priv->cpll_hz, priv->hpll_hz);
return -ENOENT;
}
switch (clk->id) {
case PLL_APLL:
case ARMCLK:
rate = rockchip_pll_get_rate(&rk3562_pll_clks[APLL], priv->cru,
APLL);
break;
case PLL_GPLL:
rate = rockchip_pll_get_rate(&rk3562_pll_clks[GPLL], priv->cru,
GPLL);
break;
case PLL_VPLL:
rate = rockchip_pll_get_rate(&rk3562_pll_clks[VPLL], priv->cru,
VPLL);
break;
case PLL_HPLL:
rate = rockchip_pll_get_rate(&rk3562_pll_clks[HPLL], priv->cru,
HPLL);
break;
case PLL_CPLL:
rate = rockchip_pll_get_rate(&rk3562_pll_clks[CPLL], priv->cru,
CPLL);
break;
case PLL_DPLL:
rate = rockchip_pll_get_rate(&rk3562_pll_clks[DPLL], priv->cru,
DPLL);
break;
case ACLK_BUS:
case HCLK_BUS:
case PCLK_BUS:
rate = rk3562_bus_get_rate(priv, clk->id);
break;
case ACLK_PERI:
case HCLK_PERI:
case PCLK_PERI:
rate = rk3562_peri_get_rate(priv, clk->id);
break;
case CLK_PMU0_I2C0:
case CLK_I2C:
case CLK_I2C1:
case CLK_I2C2:
case CLK_I2C3:
case CLK_I2C4:
case CLK_I2C5:
rate = rk3562_i2c_get_rate(priv, clk->id);
break;
case SCLK_PMU1_UART0:
case SCLK_UART1:
case SCLK_UART2:
case SCLK_UART3:
case SCLK_UART4:
case SCLK_UART5:
case SCLK_UART6:
case SCLK_UART7:
case SCLK_UART8:
case SCLK_UART9:
rate = rk3562_uart_get_rate(priv, clk->id);
break;
case CLK_PMU1_PWM0:
case CLK_PWM1_PERI:
case CLK_PWM2_PERI:
case CLK_PWM3_PERI:
rate = rk3562_pwm_get_rate(priv, clk->id);
break;
case CLK_PMU1_SPI0:
case CLK_SPI1:
case CLK_SPI2:
rate = rk3562_spi_get_rate(priv, clk->id);
break;
case CLK_TSADC:
case CLK_TSADC_TSEN:
rate = rk3562_tsadc_get_rate(priv, clk->id);
break;
case CLK_SARADC:
case CLK_SARADC_VCCIO156:
rate = rk3562_saradc_get_rate(priv, clk->id);
break;
case SCLK_SFC:
rate = rk3562_sfc_get_rate(priv);
break;
case CCLK_EMMC:
case BCLK_EMMC:
rate = rk3562_emmc_get_rate(priv, clk->id);
break;
case HCLK_SDMMC0:
case HCLK_SDMMC1:
case CCLK_SDMMC0:
case CCLK_SDMMC1:
case SCLK_SDMMC0_SAMPLE:
case SCLK_SDMMC1_SAMPLE:
rate = rk3562_sdmmc_get_rate(priv, clk->id);
break;
case ACLK_VOP:
case DCLK_VOP:
case DCLK_VOP1:
rate = rk3562_vop_get_rate(priv, clk->id);
break;
case CLK_GMAC_125M_CRU_I:
case CLK_GMAC_50M_CRU_I:
case CLK_GMAC_ETH_OUT2IO:
case CLK_MAC100_50M_MATRIX:
rate = rk3562_gmac_get_rate(priv, clk->id);
break;
case CLK_WDTNS:
rate = OSC_HZ;
break;
default:
return -ENOENT;
}
return rate;
};
static ulong rk3562_clk_set_rate(struct clk *clk, ulong rate)
{
struct rk3562_clk_priv *priv = dev_get_priv(clk->dev);
ulong ret = 0;
if (!priv->gpll_hz || !priv->cpll_hz || !priv->hpll_hz) {
printf("%s: gpll=%lu, cpll=%lu, hpll=%lu\n",
__func__, priv->gpll_hz, priv->cpll_hz, priv->hpll_hz);
return -ENOENT;
}
debug("%s: id=%ld, rate=%ld\n", __func__, clk->id, rate);
switch (clk->id) {
case PLL_APLL:
case ARMCLK:
if (priv->armclk_hz)
rk3562_armclk_set_rate(priv, rate);
priv->armclk_hz = rate;
break;
case PLL_GPLL:
ret = rockchip_pll_set_rate(&rk3562_pll_clks[GPLL], priv->cru,
GPLL, rate);
priv->gpll_hz = rockchip_pll_get_rate(&rk3562_pll_clks[GPLL],
priv->cru, GPLL);
break;
case PLL_VPLL:
ret = rockchip_pll_set_rate(&rk3562_pll_clks[VPLL], priv->cru,
VPLL, rate);
priv->vpll_hz = rockchip_pll_get_rate(&rk3562_pll_clks[VPLL],
priv->cru, VPLL);
break;
case PLL_HPLL:
ret = rockchip_pll_set_rate(&rk3562_pll_clks[HPLL], priv->cru,
HPLL, rate);
priv->hpll_hz = rockchip_pll_get_rate(&rk3562_pll_clks[HPLL],
priv->cru, HPLL);
break;
case ACLK_BUS:
case HCLK_BUS:
case PCLK_BUS:
ret = rk3562_bus_set_rate(priv, clk->id, rate);
break;
case ACLK_PERI:
case HCLK_PERI:
case PCLK_PERI:
ret = rk3562_peri_set_rate(priv, clk->id, rate);
break;
case CLK_PMU0_I2C0:
case CLK_I2C:
case CLK_I2C1:
case CLK_I2C2:
case CLK_I2C3:
case CLK_I2C4:
case CLK_I2C5:
ret = rk3562_i2c_set_rate(priv, clk->id, rate);
break;
case SCLK_PMU1_UART0:
case SCLK_UART1:
case SCLK_UART2:
case SCLK_UART3:
case SCLK_UART4:
case SCLK_UART5:
case SCLK_UART6:
case SCLK_UART7:
case SCLK_UART8:
case SCLK_UART9:
ret = rk3562_uart_set_rate(priv, clk->id, rate);
break;
case CLK_PMU1_PWM0:
case CLK_PWM1_PERI:
case CLK_PWM2_PERI:
case CLK_PWM3_PERI:
ret = rk3562_pwm_set_rate(priv, clk->id, rate);
break;
case CLK_PMU1_SPI0:
case CLK_SPI1:
case CLK_SPI2:
ret = rk3562_spi_set_rate(priv, clk->id, rate);
break;
case CLK_TSADC:
case CLK_TSADC_TSEN:
ret = rk3562_tsadc_set_rate(priv, clk->id, rate);
break;
case CLK_SARADC:
case CLK_SARADC_VCCIO156:
ret = rk3562_saradc_set_rate(priv, clk->id, rate);
break;
case SCLK_SFC:
ret = rk3562_sfc_set_rate(priv, rate);
break;
case CCLK_EMMC:
case BCLK_EMMC:
ret = rk3562_emmc_set_rate(priv, clk->id, rate);
break;
case HCLK_SDMMC0:
case HCLK_SDMMC1:
case CCLK_SDMMC0:
case CCLK_SDMMC1:
ret = rk3562_sdmmc_set_rate(priv, clk->id, rate);
break;
case ACLK_VOP:
case DCLK_VOP:
case DCLK_VOP1:
ret = rk3562_vop_set_rate(priv, clk->id, rate);
break;
case CLK_GMAC_125M_CRU_I:
case CLK_GMAC_50M_CRU_I:
case CLK_GMAC_ETH_OUT2IO:
case CLK_MAC100_50M_MATRIX:
ret = rk3562_gmac_set_rate(priv, clk->id, rate);
break;
default:
return -ENOENT;
}
return ret;
};
#define ROCKCHIP_MMC_DELAY_SEL BIT(11)
#define ROCKCHIP_MMC_DEGREE_SHIFT 1
#define ROCKCHIP_MMC_DEGREE_MASK (0x3 << ROCKCHIP_MMC_DEGREE_SHIFT)
#define ROCKCHIP_MMC_DELAYNUM_SHIFT 3
#define ROCKCHIP_MMC_DELAYNUM_MASK (0xff << ROCKCHIP_MMC_DELAYNUM_SHIFT)
#define PSECS_PER_SEC 1000000000000LL
/*
* Each fine delay is between 44ps-77ps. Assume each fine delay is 60ps to
* simplify calculations. So 45degs could be anywhere between 33deg and 57.8deg.
*/
#define ROCKCHIP_MMC_DELAY_ELEMENT_PSEC 60
int rk3562_mmc_get_phase(struct clk *clk)
{
struct rk3562_clk_priv *priv = dev_get_priv(clk->dev);
struct rk3562_cru *cru = priv->cru;
u32 raw_value, delay_num;
u16 degrees = 0;
ulong rate;
rate = rk3562_clk_get_rate(clk);
if (rate < 0)
return rate;
if (clk->id == SCLK_SDMMC0_SAMPLE)
raw_value = readl(&cru->sdmmc0_con[1]);
else if (clk->id == SCLK_SDMMC0_SAMPLE)
raw_value = readl(&cru->sdmmc1_con[1]);
else
return -ENONET;
raw_value &= ROCKCHIP_MMC_DEGREE_MASK;
degrees = (raw_value >> ROCKCHIP_MMC_DEGREE_SHIFT) * 90;
if (raw_value & ROCKCHIP_MMC_DELAY_SEL) {
/* degrees/delaynum * 10000 */
unsigned long factor = (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10) *
36 * (rate / 1000000);
delay_num = (raw_value & ROCKCHIP_MMC_DELAYNUM_MASK);
delay_num >>= ROCKCHIP_MMC_DELAYNUM_SHIFT;
degrees += DIV_ROUND_CLOSEST(delay_num * factor, 10000);
}
return degrees % 360;
}
int rk3562_mmc_set_phase(struct clk *clk, u32 degrees)
{
struct rk3562_clk_priv *priv = dev_get_priv(clk->dev);
struct rk3562_cru *cru = priv->cru;
u8 nineties, remainder, delay_num;
u32 raw_value, delay;
ulong rate;
rate = rk3562_clk_get_rate(clk);
if (rate < 0)
return rate;
nineties = degrees / 90;
remainder = (degrees % 90);
/*
* Convert to delay; do a little extra work to make sure we
* don't overflow 32-bit / 64-bit numbers.
*/
delay = 10000000; /* PSECS_PER_SEC / 10000 / 10 */
delay *= remainder;
delay = DIV_ROUND_CLOSEST(delay, (rate / 1000) * 36 *
(ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10));
delay_num = (u8)min_t(u32, delay, 255);
raw_value = delay_num ? ROCKCHIP_MMC_DELAY_SEL : 0;
raw_value |= delay_num << ROCKCHIP_MMC_DELAYNUM_SHIFT;
raw_value |= nineties << ROCKCHIP_MMC_DEGREE_SHIFT;
if (clk->id == SCLK_SDMMC0_SAMPLE)
writel(raw_value | 0xffff0000, &cru->sdmmc0_con[1]);
else
writel(raw_value | 0xffff0000, &cru->sdmmc1_con[1]);
debug("mmc set_phase(%d) delay_nums=%u reg=%#x actual_degrees=%d\n",
degrees, delay_num, raw_value, rk3562_mmc_get_phase(clk));
return 0;
}
static int rk3562_clk_get_phase(struct clk *clk)
{
int ret;
switch (clk->id) {
case SCLK_SDMMC0_SAMPLE:
case SCLK_SDMMC1_SAMPLE:
ret = rk3562_mmc_get_phase(clk);
break;
default:
return -ENOENT;
}
return ret;
}
static int rk3562_clk_set_phase(struct clk *clk, int degrees)
{
int ret;
switch (clk->id) {
case SCLK_SDMMC0_SAMPLE:
case SCLK_SDMMC1_SAMPLE:
ret = rk3562_mmc_set_phase(clk, degrees);
break;
default:
return -ENOENT;
}
return ret;
}
static struct clk_ops rk3562_clk_ops = {
.get_rate = rk3562_clk_get_rate,
.set_rate = rk3562_clk_set_rate,
.get_phase = rk3562_clk_get_phase,
.set_phase = rk3562_clk_set_phase,
};
#ifndef CONFIG_SPL_BUILD
/**
* soc_clk_dump() - Print clock frequencies
* Returns zero on success
*
* Implementation for the clk dump command.
*/
int soc_clk_dump(void)
{
const struct rk3562_clk_info *clk_dump;
struct rk3562_clk_priv *priv;
struct udevice *cru_dev;
struct clk clk;
ulong clk_count = ARRAY_SIZE(clks_dump);
ulong rate;
int i, ret;
ret = uclass_get_device_by_driver(UCLASS_CLK,
DM_GET_DRIVER(rockchip_rk3562_cru),
&cru_dev);
if (ret) {
printf("%s failed to get cru device\n", __func__);
return ret;
}
priv = dev_get_priv(cru_dev);
printf("CLK: (%s. arm: enter %lu KHz, init %lu KHz, kernel %lu%s)\n",
priv->sync_kernel ? "sync kernel" : "uboot",
priv->armclk_enter_hz / 1000,
priv->armclk_init_hz / 1000,
priv->set_armclk_rate ? priv->armclk_hz / 1000 : 0,
priv->set_armclk_rate ? " KHz" : "N/A");
for (i = 0; i < clk_count; i++) {
clk_dump = &clks_dump[i];
if (clk_dump->name) {
clk.id = clk_dump->id;
ret = clk_request(cru_dev, &clk);
if (ret < 0)
return ret;
rate = clk_get_rate(&clk);
clk_free(&clk);
if (i == 0) {
if (rate < 0)
printf(" %s %s\n", clk_dump->name,
"unknown");
else
printf(" %s %lu KHz\n", clk_dump->name,
rate / 1000);
} else {
if (rate < 0)
printf(" %s %s\n", clk_dump->name,
"unknown");
else
printf(" %s %lu KHz\n", clk_dump->name,
rate / 1000);
}
}
}
return 0;
}
#endif
static void rk3562_clk_init(struct rk3562_clk_priv *priv)
{
int ret;
priv->sync_kernel = false;
if (!priv->armclk_enter_hz)
priv->armclk_enter_hz =
rockchip_pll_get_rate(&rk3562_pll_clks[APLL],
priv->cru, APLL);
if (!priv->armclk_init_hz) {
#if defined(CONFIG_SPL_BUILD) || defined(CONFIG_SUPPORT_USBPLUG)
ret = rk3562_armclk_set_rate(priv, APLL_HZ);
if (!ret)
priv->armclk_init_hz = APLL_HZ;
#else
struct clk clk;
ret = rockchip_get_scmi_clk(&clk.dev);
if (ret) {
printf("Failed to get scmi clk dev\n");
return;
}
clk.id = ARMCLK;
ret = clk_set_rate(&clk, CPU_PVTPLL_HZ);
if (ret < 0) {
printf("Failed to set scmi cpu %dhz\n", CPU_PVTPLL_HZ);
return;
} else {
priv->armclk_init_hz = CPU_PVTPLL_HZ;
}
#endif
}
if (priv->cpll_hz != CPLL_HZ) {
ret = rockchip_pll_set_rate(&rk3562_pll_clks[CPLL], priv->cru,
CPLL, CPLL_HZ);
if (!ret)
priv->cpll_hz = CPLL_HZ;
}
if (priv->gpll_hz != GPLL_HZ) {
ret = rockchip_pll_set_rate(&rk3562_pll_clks[GPLL], priv->cru,
GPLL, GPLL_HZ);
if (!ret)
priv->gpll_hz = GPLL_HZ;
}
if (priv->hpll_hz != HPLL_HZ) {
ret = rockchip_pll_set_rate(&rk3562_pll_clks[HPLL], priv->cru,
HPLL, HPLL_HZ);
if (!ret)
priv->hpll_hz = HPLL_HZ;
}
}
static int rk3562_clk_probe(struct udevice *dev)
{
struct rk3562_clk_priv *priv = dev_get_priv(dev);
int ret;
rk3562_clk_init(priv);
/* Process 'assigned-{clocks/clock-parents/clock-rates}' properties */
ret = clk_set_defaults(dev);
if (ret)
debug("%s clk_set_defaults failed %d\n", __func__, ret);
else
priv->sync_kernel = true;
return 0;
}
static int rk3562_clk_ofdata_to_platdata(struct udevice *dev)
{
struct rk3562_clk_priv *priv = dev_get_priv(dev);
priv->cru = dev_read_addr_ptr(dev);
return 0;
}
static int rk3562_clk_bind(struct udevice *dev)
{
struct udevice *sys_child, *sf_child;
struct softreset_reg *sf_priv;
struct sysreset_reg *priv;
int ret;
/* The reset driver does not have a device node, so bind it here */
ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset",
&sys_child);
if (ret) {
debug("Warning: No sysreset driver: ret=%d\n", ret);
} else {
priv = malloc(sizeof(struct sysreset_reg));
priv->glb_srst_fst_value = offsetof(struct rk3562_cru,
glb_srst_fst);
priv->glb_srst_snd_value = offsetof(struct rk3562_cru,
glb_srst_snd);
sys_child->priv = priv;
}
ret = device_bind_driver_to_node(dev, "rockchip_reset", "reset",
dev_ofnode(dev), &sf_child);
if (ret) {
debug("Warning: No rockchip reset driver: ret=%d\n", ret);
} else {
sf_priv = malloc(sizeof(struct softreset_reg));
sf_priv->sf_reset_offset = offsetof(struct rk3562_cru,
softrst_con[0]);
/* (0x30444 - 0x400) / 4 + 1 = 49170 */
sf_priv->sf_reset_num = 49170;
sf_child->priv = sf_priv;
}
return 0;
}
static const struct udevice_id rk3562_clk_ids[] = {
{ .compatible = "rockchip,rk3562-cru" },
{ }
};
U_BOOT_DRIVER(rockchip_rk3562_cru) = {
.name = "rockchip_rk3562_cru",
.id = UCLASS_CLK,
.of_match = rk3562_clk_ids,
.priv_auto_alloc_size = sizeof(struct rk3562_clk_priv),
.ofdata_to_platdata = rk3562_clk_ofdata_to_platdata,
.ops = &rk3562_clk_ops,
.bind = rk3562_clk_bind,
.probe = rk3562_clk_probe,
};
/* spl scmi clk */
#ifdef CONFIG_SPL_BUILD
static ulong rk3562_crypto_get_rate(struct rk3562_clk_priv *priv, ulong clk_id)
{
struct rk3562_cru *cru = priv->cru;
u32 sel, con;
ulong rate;
con = readl(&cru->periclksel_con[43]);
switch (clk_id) {
case CLK_CORE_CRYPTO:
sel = (con & CLK_CORE_CRYPTO_SEL_MASK) >>
CLK_CORE_CRYPTO_SEL_SHIFT;
if (sel == CLK_CORE_CRYPTO_SEL_200M)
rate = 200 * MHz;
else if (sel == CLK_CORE_CRYPTO_SEL_100M)
rate = 100 * MHz;
else
rate = OSC_HZ;
break;
case CLK_PKA_CRYPTO:
sel = (con & CLK_PKA_CRYPTO_SEL_MASK) >>
CLK_PKA_CRYPTO_SEL_SHIFT;
if (sel == CLK_PKA_CRYPTO_SEL_300M)
rate = 300 * MHz;
else if (sel == CLK_PKA_CRYPTO_SEL_200M)
rate = 200 * MHz;
else if (sel == CLK_PKA_CRYPTO_SEL_100M)
rate = 100 * MHz;
else
rate = OSC_HZ;
break;
default:
return -ENOENT;
}
return rate;
}
static ulong rk3562_crypto_set_rate(struct rk3562_clk_priv *priv, ulong clk_id,
ulong rate)
{
struct rk3562_cru *cru = priv->cru;
u32 mask, shift, sel;
switch (clk_id) {
case CLK_CORE_CRYPTO:
mask = CLK_CORE_CRYPTO_SEL_MASK;
shift = CLK_CORE_CRYPTO_SEL_SHIFT;
if (rate == 200 * MHz)
sel = CLK_CORE_CRYPTO_SEL_200M;
else if (rate == 100 * MHz)
sel = CLK_CORE_CRYPTO_SEL_100M;
else
sel = CLK_CORE_CRYPTO_SEL_24M;
break;
case CLK_PKA_CRYPTO:
mask = CLK_PKA_CRYPTO_SEL_MASK;
shift = CLK_PKA_CRYPTO_SEL_SHIFT;
if (rate == 300 * MHz)
sel = CLK_PKA_CRYPTO_SEL_300M;
else if (rate == 200 * MHz)
sel = CLK_PKA_CRYPTO_SEL_200M;
else if (rate == 100 * MHz)
sel = CLK_PKA_CRYPTO_SEL_100M;
else
sel = CLK_PKA_CRYPTO_SEL_24M;
break;
default:
return -ENOENT;
}
rk_clrsetreg(&cru->periclksel_con[43], mask, sel << shift);
return rk3562_crypto_get_rate(priv, clk_id);
}
static ulong rk3562_clk_scmi_get_rate(struct clk *clk)
{
struct rk3562_clk_priv *priv = dev_get_priv(clk->dev);
switch (clk->id) {
case CLK_CORE_CRYPTO:
case CLK_PKA_CRYPTO:
return rk3562_crypto_get_rate(priv, clk->id);
default:
return -ENOENT;
}
};
static ulong rk3562_clk_scmi_set_rate(struct clk *clk, ulong rate)
{
struct rk3562_clk_priv *priv = dev_get_priv(clk->dev);
switch (clk->id) {
case CLK_CORE_CRYPTO:
case CLK_PKA_CRYPTO:
return rk3562_crypto_set_rate(priv, clk->id, rate);
default:
return -ENOENT;
}
return 0;
};
static int rk3562_scmi_clk_ofdata_to_platdata(struct udevice *dev)
{
struct rk3562_clk_priv *priv = dev_get_priv(dev);
priv->cru = (struct rk3562_cru *)0xff100000;
return 0;
}
/* A fake scmi driver for SPL/TPL where smccc agent is not available. */
static const struct clk_ops scmi_clk_ops = {
.get_rate = rk3562_clk_scmi_get_rate,
.set_rate = rk3562_clk_scmi_set_rate,
};
U_BOOT_DRIVER(scmi_clock) = {
.name = "scmi_clk",
.id = UCLASS_CLK,
.ops = &scmi_clk_ops,
.priv_auto_alloc_size = sizeof(struct rk3562_clk_priv),
.ofdata_to_platdata = rk3562_scmi_clk_ofdata_to_platdata,
};
#endif