u-boot/drivers/clk/rockchip/clk_rk3568.c
Jonas Karlman 0b6afc3993 clk: rockchip: rk356x: Fix set rate of SCLK_SFC clock
The SCLK_SFC can be set to a rate of 24, 50, 75, 100, 125 or 150 MHz.

However, clk_set_rate() will fail unless one of those exact rates are
used, and with newer and updated device tree files that contain
spi-max-frequency values that does not exactly match these rates use of
SPI flash may fail.

Fix this by using the highest possible rate that exceeds or is equal to
the requested rate.

Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
Reviewed-by: Kever Yang <kever.yang@rock-chips.com>
2024-04-26 15:47:04 +08:00

2986 lines
70 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2021 Rockchip Electronics Co., Ltd
* Author: Elaine Zhang <zhangqing@rock-chips.com>
*/
#include <common.h>
#include <bitfield.h>
#include <clk-uclass.h>
#include <dm.h>
#include <errno.h>
#include <syscon.h>
#include <asm/arch-rockchip/cru_rk3568.h>
#include <asm/arch-rockchip/clock.h>
#include <asm/arch-rockchip/hardware.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
#include <dt-bindings/clock/rk3568-cru.h>
DECLARE_GLOBAL_DATA_PTR;
#if CONFIG_IS_ENABLED(OF_PLATDATA)
struct rk3568_clk_plat {
struct dtd_rockchip_rk3568_cru dtd;
};
struct rk3568_pmuclk_plat {
struct dtd_rockchip_rk3568_pmucru dtd;
};
#endif
#define RK3568_CPUCLK_RATE(_rate, _aclk_div, _pclk_div) \
{ \
.rate = _rate##U, \
.aclk_div = _aclk_div, \
.pclk_div = _pclk_div, \
}
#define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1))
static struct rockchip_cpu_rate_table rk3568_cpu_rates[] = {
RK3568_CPUCLK_RATE(1416000000, 1, 5),
RK3568_CPUCLK_RATE(1296000000, 1, 5),
RK3568_CPUCLK_RATE(1200000000, 1, 3),
RK3568_CPUCLK_RATE(1104000000, 1, 3),
RK3568_CPUCLK_RATE(1008000000, 1, 3),
RK3568_CPUCLK_RATE(912000000, 1, 3),
RK3568_CPUCLK_RATE(816000000, 1, 3),
RK3568_CPUCLK_RATE(600000000, 1, 1),
RK3568_CPUCLK_RATE(408000000, 1, 1),
{ /* sentinel */ },
};
static struct rockchip_pll_rate_table rk3568_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(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(400000000, 1, 100, 6, 1, 1, 0),
RK3036_PLL_RATE(200000000, 1, 100, 6, 2, 1, 0),
RK3036_PLL_RATE(100000000, 1, 150, 6, 6, 1, 0),
{ /* sentinel */ },
};
static struct rockchip_pll_clock rk3568_pll_clks[] = {
[APLL] = PLL(pll_rk3328, PLL_APLL, RK3568_PLL_CON(0),
RK3568_MODE_CON, 0, 10, 0, rk3568_pll_rates),
[DPLL] = PLL(pll_rk3328, PLL_DPLL, RK3568_PLL_CON(8),
RK3568_MODE_CON, 2, 10, 0, NULL),
[CPLL] = PLL(pll_rk3328, PLL_CPLL, RK3568_PLL_CON(24),
RK3568_MODE_CON, 4, 10, 0, rk3568_pll_rates),
[GPLL] = PLL(pll_rk3328, PLL_HPLL, RK3568_PLL_CON(16),
RK3568_MODE_CON, 6, 10, 0, rk3568_pll_rates),
[NPLL] = PLL(pll_rk3328, PLL_NPLL, RK3568_PLL_CON(32),
RK3568_MODE_CON, 10, 10, 0, rk3568_pll_rates),
[VPLL] = PLL(pll_rk3328, PLL_VPLL, RK3568_PLL_CON(40),
RK3568_MODE_CON, 12, 10, 0, rk3568_pll_rates),
[PPLL] = PLL(pll_rk3328, PLL_PPLL, RK3568_PMU_PLL_CON(0),
RK3568_PMU_MODE, 0, 10, 0, rk3568_pll_rates),
[HPLL] = PLL(pll_rk3328, PLL_HPLL, RK3568_PMU_PLL_CON(16),
RK3568_PMU_MODE, 2, 10, 0, rk3568_pll_rates),
};
#ifndef CONFIG_SPL_BUILD
static ulong
rk3568_pmu_pll_set_rate(struct rk3568_clk_priv *priv,
ulong pll_id, ulong rate)
{
struct udevice *pmucru_dev;
struct rk3568_pmuclk_priv *pmu_priv;
int ret;
ret = uclass_get_device_by_driver(UCLASS_CLK,
DM_DRIVER_GET(rockchip_rk3568_pmucru),
&pmucru_dev);
if (ret) {
printf("%s: could not find pmucru device\n", __func__);
return ret;
}
pmu_priv = dev_get_priv(pmucru_dev);
rockchip_pll_set_rate(&rk3568_pll_clks[pll_id],
pmu_priv->pmucru, pll_id, rate);
return 0;
}
#endif
static ulong rk3568_pmu_pll_get_rate(struct rk3568_clk_priv *priv,
ulong pll_id)
{
struct udevice *pmucru_dev;
struct rk3568_pmuclk_priv *pmu_priv;
int ret;
ret = uclass_get_device_by_driver(UCLASS_CLK,
DM_DRIVER_GET(rockchip_rk3568_pmucru),
&pmucru_dev);
if (ret) {
printf("%s: could not find pmucru device\n", __func__);
return ret;
}
pmu_priv = dev_get_priv(pmucru_dev);
return rockchip_pll_get_rate(&rk3568_pll_clks[pll_id],
pmu_priv->pmucru, pll_id);
}
/*
*
* 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 ulong rk3568_rtc32k_get_pmuclk(struct rk3568_pmuclk_priv *priv)
{
struct rk3568_pmucru *pmucru = priv->pmucru;
unsigned long m, n;
u32 fracdiv;
fracdiv = readl(&pmucru->pmu_clksel_con[1]);
m = fracdiv & RTC32K_FRAC_NUMERATOR_MASK;
m >>= RTC32K_FRAC_NUMERATOR_SHIFT;
n = fracdiv & RTC32K_FRAC_DENOMINATOR_MASK;
n >>= RTC32K_FRAC_DENOMINATOR_SHIFT;
return OSC_HZ * m / n;
}
static ulong rk3568_rtc32k_set_pmuclk(struct rk3568_pmuclk_priv *priv,
ulong rate)
{
struct rk3568_pmucru *pmucru = priv->pmucru;
unsigned long m, n, val;
rk_clrsetreg(&pmucru->pmu_clksel_con[0], RTC32K_SEL_MASK,
RTC32K_SEL_OSC0_DIV32K << RTC32K_SEL_SHIFT);
rational_best_approximation(rate, OSC_HZ,
GENMASK(16 - 1, 0),
GENMASK(16 - 1, 0),
&m, &n);
val = m << RTC32K_FRAC_NUMERATOR_SHIFT | n;
writel(val, &pmucru->pmu_clksel_con[1]);
return rk3568_rtc32k_get_pmuclk(priv);
}
static ulong rk3568_i2c_get_pmuclk(struct rk3568_pmuclk_priv *priv,
ulong clk_id)
{
struct rk3568_pmucru *pmucru = priv->pmucru;
u32 div, con;
switch (clk_id) {
case CLK_I2C0:
con = readl(&pmucru->pmu_clksel_con[3]);
div = (con & CLK_I2C0_DIV_MASK) >> CLK_I2C0_DIV_SHIFT;
break;
default:
return -ENOENT;
}
return DIV_TO_RATE(priv->ppll_hz, div);
}
static ulong rk3568_i2c_set_pmuclk(struct rk3568_pmuclk_priv *priv,
ulong clk_id, ulong rate)
{
struct rk3568_pmucru *pmucru = priv->pmucru;
int src_clk_div;
src_clk_div = DIV_ROUND_UP(priv->ppll_hz, rate);
assert(src_clk_div - 1 <= 127);
switch (clk_id) {
case CLK_I2C0:
rk_clrsetreg(&pmucru->pmu_clksel_con[3], CLK_I2C0_DIV_MASK,
(src_clk_div - 1) << CLK_I2C0_DIV_SHIFT);
break;
default:
return -ENOENT;
}
return rk3568_i2c_get_pmuclk(priv, clk_id);
}
static ulong rk3568_pwm_get_pmuclk(struct rk3568_pmuclk_priv *priv,
ulong clk_id)
{
struct rk3568_pmucru *pmucru = priv->pmucru;
u32 div, sel, con, parent;
switch (clk_id) {
case CLK_PWM0:
con = readl(&pmucru->pmu_clksel_con[6]);
sel = (con & CLK_PWM0_SEL_MASK) >> CLK_PWM0_SEL_SHIFT;
div = (con & CLK_PWM0_DIV_MASK) >> CLK_PWM0_DIV_SHIFT;
if (sel == CLK_PWM0_SEL_XIN24M)
parent = OSC_HZ;
else
parent = priv->ppll_hz;
break;
default:
return -ENOENT;
}
return DIV_TO_RATE(parent, div);
}
static ulong rk3568_pwm_set_pmuclk(struct rk3568_pmuclk_priv *priv,
ulong clk_id, ulong rate)
{
struct rk3568_pmucru *pmucru = priv->pmucru;
int src_clk_div;
switch (clk_id) {
case CLK_PWM0:
if (rate == OSC_HZ) {
rk_clrsetreg(&pmucru->pmu_clksel_con[6],
CLK_PWM0_SEL_MASK | CLK_PWM0_DIV_MASK,
(CLK_PWM0_SEL_XIN24M <<
CLK_PWM0_SEL_SHIFT) |
0 << CLK_PWM0_SEL_SHIFT);
} else {
src_clk_div = DIV_ROUND_UP(priv->ppll_hz, rate);
assert(src_clk_div - 1 <= 127);
rk_clrsetreg(&pmucru->pmu_clksel_con[6],
CLK_PWM0_DIV_MASK | CLK_PWM0_DIV_MASK,
(CLK_PWM0_SEL_PPLL << CLK_PWM0_SEL_SHIFT) |
(src_clk_div - 1) << CLK_PWM0_DIV_SHIFT);
}
break;
default:
return -ENOENT;
}
return rk3568_pwm_get_pmuclk(priv, clk_id);
}
static ulong rk3568_pmu_get_pmuclk(struct rk3568_pmuclk_priv *priv)
{
struct rk3568_pmucru *pmucru = priv->pmucru;
u32 div, con, sel, parent;
con = readl(&pmucru->pmu_clksel_con[2]);
sel = (con & PCLK_PDPMU_SEL_MASK) >> PCLK_PDPMU_SEL_SHIFT;
div = (con & PCLK_PDPMU_DIV_MASK) >> PCLK_PDPMU_DIV_SHIFT;
if (sel)
parent = GPLL_HZ;
else
parent = priv->ppll_hz;
return DIV_TO_RATE(parent, div);
}
static ulong rk3568_pmu_set_pmuclk(struct rk3568_pmuclk_priv *priv,
ulong rate)
{
struct rk3568_pmucru *pmucru = priv->pmucru;
int src_clk_div;
src_clk_div = DIV_ROUND_UP(priv->ppll_hz, rate);
assert(src_clk_div - 1 <= 31);
rk_clrsetreg(&pmucru->pmu_clksel_con[2],
PCLK_PDPMU_DIV_MASK | PCLK_PDPMU_SEL_MASK,
(PCLK_PDPMU_SEL_PPLL << PCLK_PDPMU_SEL_SHIFT) |
((src_clk_div - 1) << PCLK_PDPMU_DIV_SHIFT));
return rk3568_pmu_get_pmuclk(priv);
}
static ulong rk3568_pmuclk_get_rate(struct clk *clk)
{
struct rk3568_pmuclk_priv *priv = dev_get_priv(clk->dev);
ulong rate = 0;
if (!priv->ppll_hz) {
printf("%s ppll=%lu\n", __func__, priv->ppll_hz);
return -ENOENT;
}
debug("%s %ld\n", __func__, clk->id);
switch (clk->id) {
case PLL_PPLL:
rate = rockchip_pll_get_rate(&rk3568_pll_clks[PPLL],
priv->pmucru, PPLL);
break;
case PLL_HPLL:
rate = rockchip_pll_get_rate(&rk3568_pll_clks[HPLL],
priv->pmucru, HPLL);
break;
case CLK_RTC_32K:
case CLK_RTC32K_FRAC:
rate = rk3568_rtc32k_get_pmuclk(priv);
break;
case CLK_I2C0:
rate = rk3568_i2c_get_pmuclk(priv, clk->id);
break;
case CLK_PWM0:
rate = rk3568_pwm_get_pmuclk(priv, clk->id);
break;
case PCLK_PMU:
rate = rk3568_pmu_get_pmuclk(priv);
break;
default:
return -ENOENT;
}
return rate;
}
static ulong rk3568_pmuclk_set_rate(struct clk *clk, ulong rate)
{
struct rk3568_pmuclk_priv *priv = dev_get_priv(clk->dev);
ulong ret = 0;
if (!priv->ppll_hz) {
printf("%s ppll=%lu\n", __func__, priv->ppll_hz);
return -ENOENT;
}
debug("%s %ld %ld\n", __func__, clk->id, rate);
switch (clk->id) {
case PLL_PPLL:
ret = rockchip_pll_set_rate(&rk3568_pll_clks[PPLL],
priv->pmucru, PPLL, rate);
priv->ppll_hz = rockchip_pll_get_rate(&rk3568_pll_clks[PPLL],
priv->pmucru, PPLL);
break;
case PLL_HPLL:
ret = rockchip_pll_set_rate(&rk3568_pll_clks[HPLL],
priv->pmucru, HPLL, rate);
priv->hpll_hz = rockchip_pll_get_rate(&rk3568_pll_clks[HPLL],
priv->pmucru, HPLL);
break;
case CLK_RTC_32K:
case CLK_RTC32K_FRAC:
ret = rk3568_rtc32k_set_pmuclk(priv, rate);
break;
case CLK_I2C0:
ret = rk3568_i2c_set_pmuclk(priv, clk->id, rate);
break;
case CLK_PWM0:
ret = rk3568_pwm_set_pmuclk(priv, clk->id, rate);
break;
case PCLK_PMU:
ret = rk3568_pmu_set_pmuclk(priv, rate);
break;
case CLK_PCIEPHY0_REF:
case CLK_PCIEPHY1_REF:
case CLK_PCIEPHY2_REF:
return 0;
default:
return -ENOENT;
}
return ret;
}
static int rk3568_rtc32k_set_parent(struct clk *clk, struct clk *parent)
{
struct rk3568_pmuclk_priv *priv = dev_get_priv(clk->dev);
struct rk3568_pmucru *pmucru = priv->pmucru;
if (parent->id == CLK_RTC32K_FRAC)
rk_clrsetreg(&pmucru->pmu_clksel_con[0], RTC32K_SEL_MASK,
RTC32K_SEL_OSC0_DIV32K << RTC32K_SEL_SHIFT);
else
rk_clrsetreg(&pmucru->pmu_clksel_con[0], RTC32K_SEL_MASK,
RTC32K_SEL_OSC1_32K << RTC32K_SEL_SHIFT);
return 0;
}
static int rk3568_pmuclk_set_parent(struct clk *clk, struct clk *parent)
{
switch (clk->id) {
case CLK_RTC_32K:
return rk3568_rtc32k_set_parent(clk, parent);
default:
return -ENOENT;
}
}
static struct clk_ops rk3568_pmuclk_ops = {
.get_rate = rk3568_pmuclk_get_rate,
.set_rate = rk3568_pmuclk_set_rate,
.set_parent = rk3568_pmuclk_set_parent,
};
static int rk3568_pmuclk_probe(struct udevice *dev)
{
struct rk3568_pmuclk_priv *priv = dev_get_priv(dev);
int ret = 0;
if (priv->ppll_hz != PPLL_HZ) {
ret = rockchip_pll_set_rate(&rk3568_pll_clks[PPLL],
priv->pmucru,
PPLL, PPLL_HZ);
if (!ret)
priv->ppll_hz = PPLL_HZ;
}
/* Ungate PCIe30phy refclk_m and refclk_n */
rk_clrsetreg(&priv->pmucru->pmu_clkgate_con[2], 0x3 << 13, 0 << 13);
return 0;
}
static int rk3568_pmuclk_ofdata_to_platdata(struct udevice *dev)
{
struct rk3568_pmuclk_priv *priv = dev_get_priv(dev);
priv->pmucru = dev_read_addr_ptr(dev);
return 0;
}
static int rk3568_pmuclk_bind(struct udevice *dev)
{
#if CONFIG_IS_ENABLED(RESET_ROCKCHIP)
int ret = 0;
ret = offsetof(struct rk3568_pmucru, pmu_softrst_con[0]);
ret = rockchip_reset_bind(dev, ret, 1);
if (ret)
debug("Warning: pmucru software reset driver bind failed\n");
#endif
return 0;
}
static const struct udevice_id rk3568_pmuclk_ids[] = {
{ .compatible = "rockchip,rk3568-pmucru" },
{ }
};
U_BOOT_DRIVER(rockchip_rk3568_pmucru) = {
.name = "rockchip_rk3568_pmucru",
.id = UCLASS_CLK,
.of_match = rk3568_pmuclk_ids,
.priv_auto = sizeof(struct rk3568_pmuclk_priv),
.of_to_plat = rk3568_pmuclk_ofdata_to_platdata,
.ops = &rk3568_pmuclk_ops,
.bind = rk3568_pmuclk_bind,
.probe = rk3568_pmuclk_probe,
#if CONFIG_IS_ENABLED(OF_PLATDATA)
.plat_auto = sizeof(struct rk3568_pmuclk_plat),
#endif
};
static int rk3568_armclk_set_clk(struct rk3568_clk_priv *priv, ulong hz)
{
struct rk3568_cru *cru = priv->cru;
const struct rockchip_cpu_rate_table *rate;
ulong old_rate;
rate = rockchip_get_cpu_settings(rk3568_cpu_rates, hz);
if (!rate) {
printf("%s unsupported rate\n", __func__);
return -EINVAL;
}
rk_clrsetreg(&cru->clksel_con[0],
CLK_CORE_PRE_SEL_MASK,
(CLK_CORE_PRE_SEL_SRC << CLK_CORE_PRE_SEL_SHIFT));
rk_clrsetreg(&cru->clksel_con[2],
SCLK_CORE_PRE_SEL_MASK |
SCLK_CORE_SRC_SEL_MASK |
SCLK_CORE_SRC_DIV_MASK,
(SCLK_CORE_PRE_SEL_SRC <<
SCLK_CORE_PRE_SEL_SHIFT) |
(SCLK_CORE_SRC_SEL_APLL <<
SCLK_CORE_SRC_SEL_SHIFT) |
(1 << SCLK_CORE_SRC_DIV_SHIFT));
/*
* set up dependent divisors for DBG and ACLK clocks.
*/
old_rate = rockchip_pll_get_rate(&rk3568_pll_clks[APLL],
priv->cru, APLL);
if (old_rate > hz) {
if (rockchip_pll_set_rate(&rk3568_pll_clks[APLL],
priv->cru, APLL, hz))
return -EINVAL;
rk_clrsetreg(&cru->clksel_con[3],
GICCLK_CORE_DIV_MASK | ATCLK_CORE_DIV_MASK,
rate->pclk_div << GICCLK_CORE_DIV_SHIFT |
rate->pclk_div << ATCLK_CORE_DIV_SHIFT);
rk_clrsetreg(&cru->clksel_con[4],
PERIPHCLK_CORE_PRE_DIV_MASK |
PCLK_CORE_PRE_DIV_MASK,
rate->pclk_div << PCLK_CORE_PRE_DIV_SHIFT |
rate->pclk_div << PERIPHCLK_CORE_PRE_DIV_SHIFT);
rk_clrsetreg(&cru->clksel_con[5],
ACLK_CORE_NDFT_DIV_MASK,
rate->aclk_div << ACLK_CORE_NDFT_DIV_SHIFT);
} else if (old_rate < hz) {
rk_clrsetreg(&cru->clksel_con[3],
GICCLK_CORE_DIV_MASK | ATCLK_CORE_DIV_MASK,
rate->pclk_div << GICCLK_CORE_DIV_SHIFT |
rate->pclk_div << ATCLK_CORE_DIV_SHIFT);
rk_clrsetreg(&cru->clksel_con[4],
PERIPHCLK_CORE_PRE_DIV_MASK |
PCLK_CORE_PRE_DIV_MASK,
rate->pclk_div << PCLK_CORE_PRE_DIV_SHIFT |
rate->pclk_div << PERIPHCLK_CORE_PRE_DIV_SHIFT);
rk_clrsetreg(&cru->clksel_con[5],
ACLK_CORE_NDFT_DIV_MASK,
rate->aclk_div << ACLK_CORE_NDFT_DIV_SHIFT);
if (rockchip_pll_set_rate(&rk3568_pll_clks[APLL],
priv->cru, APLL, hz))
return -EINVAL;
}
return 0;
}
static ulong rk3568_cpll_div_get_rate(struct rk3568_clk_priv *priv,
ulong clk_id)
{
struct rk3568_cru *cru = priv->cru;
int div, mask, shift, con;
switch (clk_id) {
case CPLL_500M:
con = 78;
mask = CPLL_500M_DIV_MASK;
shift = CPLL_500M_DIV_SHIFT;
break;
case CPLL_333M:
con = 79;
mask = CPLL_333M_DIV_MASK;
shift = CPLL_333M_DIV_SHIFT;
break;
case CPLL_250M:
con = 79;
mask = CPLL_250M_DIV_MASK;
shift = CPLL_250M_DIV_SHIFT;
break;
case CPLL_125M:
con = 80;
mask = CPLL_125M_DIV_MASK;
shift = CPLL_125M_DIV_SHIFT;
break;
case CPLL_100M:
con = 82;
mask = CPLL_100M_DIV_MASK;
shift = CPLL_100M_DIV_SHIFT;
break;
case CPLL_62P5M:
con = 80;
mask = CPLL_62P5M_DIV_MASK;
shift = CPLL_62P5M_DIV_SHIFT;
break;
case CPLL_50M:
con = 81;
mask = CPLL_50M_DIV_MASK;
shift = CPLL_50M_DIV_SHIFT;
break;
case CPLL_25M:
con = 81;
mask = CPLL_25M_DIV_MASK;
shift = CPLL_25M_DIV_SHIFT;
break;
default:
return -ENOENT;
}
div = (readl(&cru->clksel_con[con]) & mask) >> shift;
return DIV_TO_RATE(priv->cpll_hz, div);
}
static ulong rk3568_cpll_div_set_rate(struct rk3568_clk_priv *priv,
ulong clk_id, ulong rate)
{
struct rk3568_cru *cru = priv->cru;
int div, mask, shift, con;
switch (clk_id) {
case CPLL_500M:
con = 78;
mask = CPLL_500M_DIV_MASK;
shift = CPLL_500M_DIV_SHIFT;
break;
case CPLL_333M:
con = 79;
mask = CPLL_333M_DIV_MASK;
shift = CPLL_333M_DIV_SHIFT;
break;
case CPLL_250M:
con = 79;
mask = CPLL_250M_DIV_MASK;
shift = CPLL_250M_DIV_SHIFT;
break;
case CPLL_125M:
con = 80;
mask = CPLL_125M_DIV_MASK;
shift = CPLL_125M_DIV_SHIFT;
break;
case CPLL_100M:
con = 82;
mask = CPLL_100M_DIV_MASK;
shift = CPLL_100M_DIV_SHIFT;
break;
case CPLL_62P5M:
con = 80;
mask = CPLL_62P5M_DIV_MASK;
shift = CPLL_62P5M_DIV_SHIFT;
break;
case CPLL_50M:
con = 81;
mask = CPLL_50M_DIV_MASK;
shift = CPLL_50M_DIV_SHIFT;
break;
case CPLL_25M:
con = 81;
mask = CPLL_25M_DIV_MASK;
shift = CPLL_25M_DIV_SHIFT;
break;
default:
return -ENOENT;
}
div = DIV_ROUND_UP(priv->cpll_hz, rate);
if (clk_id == CPLL_25M)
assert(div - 1 <= 63);
else
assert(div - 1 <= 31);
rk_clrsetreg(&cru->clksel_con[con],
mask, (div - 1) << shift);
return rk3568_cpll_div_get_rate(priv, clk_id);
}
static ulong rk3568_bus_get_clk(struct rk3568_clk_priv *priv, ulong clk_id)
{
struct rk3568_cru *cru = priv->cru;
u32 con, sel, rate;
switch (clk_id) {
case ACLK_BUS:
con = readl(&cru->clksel_con[50]);
sel = (con & ACLK_BUS_SEL_MASK) >> ACLK_BUS_SEL_SHIFT;
if (sel == ACLK_BUS_SEL_200M)
rate = 200 * MHz;
else if (sel == ACLK_BUS_SEL_150M)
rate = 150 * MHz;
else if (sel == ACLK_BUS_SEL_100M)
rate = 100 * MHz;
else
rate = OSC_HZ;
break;
case PCLK_BUS:
case PCLK_WDT_NS:
con = readl(&cru->clksel_con[50]);
sel = (con & PCLK_BUS_SEL_MASK) >> PCLK_BUS_SEL_SHIFT;
if (sel == PCLK_BUS_SEL_100M)
rate = 100 * MHz;
else if (sel == PCLK_BUS_SEL_75M)
rate = 75 * MHz;
else if (sel == PCLK_BUS_SEL_50M)
rate = 50 * MHz;
else
rate = OSC_HZ;
break;
default:
return -ENOENT;
}
return rate;
}
static ulong rk3568_bus_set_clk(struct rk3568_clk_priv *priv,
ulong clk_id, ulong rate)
{
struct rk3568_cru *cru = priv->cru;
int src_clk;
switch (clk_id) {
case ACLK_BUS:
if (rate == 200 * MHz)
src_clk = ACLK_BUS_SEL_200M;
else if (rate == 150 * MHz)
src_clk = ACLK_BUS_SEL_150M;
else if (rate == 100 * MHz)
src_clk = ACLK_BUS_SEL_100M;
else
src_clk = ACLK_BUS_SEL_24M;
rk_clrsetreg(&cru->clksel_con[50],
ACLK_BUS_SEL_MASK,
src_clk << ACLK_BUS_SEL_SHIFT);
break;
case PCLK_BUS:
case PCLK_WDT_NS:
if (rate == 100 * MHz)
src_clk = PCLK_BUS_SEL_100M;
else if (rate == 75 * MHz)
src_clk = PCLK_BUS_SEL_75M;
else if (rate == 50 * MHz)
src_clk = PCLK_BUS_SEL_50M;
else
src_clk = PCLK_BUS_SEL_24M;
rk_clrsetreg(&cru->clksel_con[50],
PCLK_BUS_SEL_MASK,
src_clk << PCLK_BUS_SEL_SHIFT);
break;
default:
printf("do not support this bus freq\n");
return -EINVAL;
}
return rk3568_bus_get_clk(priv, clk_id);
}
static ulong rk3568_perimid_get_clk(struct rk3568_clk_priv *priv, ulong clk_id)
{
struct rk3568_cru *cru = priv->cru;
u32 con, sel, rate;
switch (clk_id) {
case ACLK_PERIMID:
con = readl(&cru->clksel_con[10]);
sel = (con & ACLK_PERIMID_SEL_MASK) >> ACLK_PERIMID_SEL_SHIFT;
if (sel == ACLK_PERIMID_SEL_300M)
rate = 300 * MHz;
else if (sel == ACLK_PERIMID_SEL_200M)
rate = 200 * MHz;
else if (sel == ACLK_PERIMID_SEL_100M)
rate = 100 * MHz;
else
rate = OSC_HZ;
break;
case HCLK_PERIMID:
con = readl(&cru->clksel_con[10]);
sel = (con & HCLK_PERIMID_SEL_MASK) >> HCLK_PERIMID_SEL_SHIFT;
if (sel == HCLK_PERIMID_SEL_150M)
rate = 150 * MHz;
else if (sel == HCLK_PERIMID_SEL_100M)
rate = 100 * MHz;
else if (sel == HCLK_PERIMID_SEL_75M)
rate = 75 * MHz;
else
rate = OSC_HZ;
break;
default:
return -ENOENT;
}
return rate;
}
static ulong rk3568_perimid_set_clk(struct rk3568_clk_priv *priv,
ulong clk_id, ulong rate)
{
struct rk3568_cru *cru = priv->cru;
int src_clk;
switch (clk_id) {
case ACLK_PERIMID:
if (rate == 300 * MHz)
src_clk = ACLK_PERIMID_SEL_300M;
else if (rate == 200 * MHz)
src_clk = ACLK_PERIMID_SEL_200M;
else if (rate == 100 * MHz)
src_clk = ACLK_PERIMID_SEL_100M;
else
src_clk = ACLK_PERIMID_SEL_24M;
rk_clrsetreg(&cru->clksel_con[10],
ACLK_PERIMID_SEL_MASK,
src_clk << ACLK_PERIMID_SEL_SHIFT);
break;
case HCLK_PERIMID:
if (rate == 150 * MHz)
src_clk = HCLK_PERIMID_SEL_150M;
else if (rate == 100 * MHz)
src_clk = HCLK_PERIMID_SEL_100M;
else if (rate == 75 * MHz)
src_clk = HCLK_PERIMID_SEL_75M;
else
src_clk = HCLK_PERIMID_SEL_24M;
rk_clrsetreg(&cru->clksel_con[10],
HCLK_PERIMID_SEL_MASK,
src_clk << HCLK_PERIMID_SEL_SHIFT);
break;
default:
printf("do not support this permid freq\n");
return -EINVAL;
}
return rk3568_perimid_get_clk(priv, clk_id);
}
static ulong rk3568_top_get_clk(struct rk3568_clk_priv *priv, ulong clk_id)
{
struct rk3568_cru *cru = priv->cru;
u32 con, sel, rate;
switch (clk_id) {
case ACLK_TOP_HIGH:
con = readl(&cru->clksel_con[73]);
sel = (con & ACLK_TOP_HIGH_SEL_MASK) >> ACLK_TOP_HIGH_SEL_SHIFT;
if (sel == ACLK_TOP_HIGH_SEL_500M)
rate = 500 * MHz;
else if (sel == ACLK_TOP_HIGH_SEL_400M)
rate = 400 * MHz;
else if (sel == ACLK_TOP_HIGH_SEL_300M)
rate = 300 * MHz;
else
rate = OSC_HZ;
break;
case ACLK_TOP_LOW:
con = readl(&cru->clksel_con[73]);
sel = (con & ACLK_TOP_LOW_SEL_MASK) >> ACLK_TOP_LOW_SEL_SHIFT;
if (sel == ACLK_TOP_LOW_SEL_400M)
rate = 400 * MHz;
else if (sel == ACLK_TOP_LOW_SEL_300M)
rate = 300 * MHz;
else if (sel == ACLK_TOP_LOW_SEL_200M)
rate = 200 * MHz;
else
rate = OSC_HZ;
break;
case HCLK_TOP:
con = readl(&cru->clksel_con[73]);
sel = (con & HCLK_TOP_SEL_MASK) >> HCLK_TOP_SEL_SHIFT;
if (sel == HCLK_TOP_SEL_150M)
rate = 150 * MHz;
else if (sel == HCLK_TOP_SEL_100M)
rate = 100 * MHz;
else if (sel == HCLK_TOP_SEL_75M)
rate = 75 * MHz;
else
rate = OSC_HZ;
break;
case PCLK_TOP:
con = readl(&cru->clksel_con[73]);
sel = (con & PCLK_TOP_SEL_MASK) >> PCLK_TOP_SEL_SHIFT;
if (sel == PCLK_TOP_SEL_100M)
rate = 100 * MHz;
else if (sel == PCLK_TOP_SEL_75M)
rate = 75 * MHz;
else if (sel == PCLK_TOP_SEL_50M)
rate = 50 * MHz;
else
rate = OSC_HZ;
break;
default:
return -ENOENT;
}
return rate;
}
static ulong rk3568_top_set_clk(struct rk3568_clk_priv *priv,
ulong clk_id, ulong rate)
{
struct rk3568_cru *cru = priv->cru;
int src_clk;
switch (clk_id) {
case ACLK_TOP_HIGH:
if (rate == 500 * MHz)
src_clk = ACLK_TOP_HIGH_SEL_500M;
else if (rate == 400 * MHz)
src_clk = ACLK_TOP_HIGH_SEL_400M;
else if (rate == 300 * MHz)
src_clk = ACLK_TOP_HIGH_SEL_300M;
else
src_clk = ACLK_TOP_HIGH_SEL_24M;
rk_clrsetreg(&cru->clksel_con[73],
ACLK_TOP_HIGH_SEL_MASK,
src_clk << ACLK_TOP_HIGH_SEL_SHIFT);
break;
case ACLK_TOP_LOW:
if (rate == 400 * MHz)
src_clk = ACLK_TOP_LOW_SEL_400M;
else if (rate == 300 * MHz)
src_clk = ACLK_TOP_LOW_SEL_300M;
else if (rate == 200 * MHz)
src_clk = ACLK_TOP_LOW_SEL_200M;
else
src_clk = ACLK_TOP_LOW_SEL_24M;
rk_clrsetreg(&cru->clksel_con[73],
ACLK_TOP_LOW_SEL_MASK,
src_clk << ACLK_TOP_LOW_SEL_SHIFT);
break;
case HCLK_TOP:
if (rate == 150 * MHz)
src_clk = HCLK_TOP_SEL_150M;
else if (rate == 100 * MHz)
src_clk = HCLK_TOP_SEL_100M;
else if (rate == 75 * MHz)
src_clk = HCLK_TOP_SEL_75M;
else
src_clk = HCLK_TOP_SEL_24M;
rk_clrsetreg(&cru->clksel_con[73],
HCLK_TOP_SEL_MASK,
src_clk << HCLK_TOP_SEL_SHIFT);
break;
case PCLK_TOP:
if (rate == 100 * MHz)
src_clk = PCLK_TOP_SEL_100M;
else if (rate == 75 * MHz)
src_clk = PCLK_TOP_SEL_75M;
else if (rate == 50 * MHz)
src_clk = PCLK_TOP_SEL_50M;
else
src_clk = PCLK_TOP_SEL_24M;
rk_clrsetreg(&cru->clksel_con[73],
PCLK_TOP_SEL_MASK,
src_clk << PCLK_TOP_SEL_SHIFT);
break;
default:
printf("do not support this permid freq\n");
return -EINVAL;
}
return rk3568_top_get_clk(priv, clk_id);
}
static ulong rk3568_i2c_get_clk(struct rk3568_clk_priv *priv, ulong clk_id)
{
struct rk3568_cru *cru = priv->cru;
u32 sel, con;
ulong rate;
switch (clk_id) {
case CLK_I2C1:
case CLK_I2C2:
case CLK_I2C3:
case CLK_I2C4:
case CLK_I2C5:
con = readl(&cru->clksel_con[71]);
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_CPLL_100M)
rate = 100 * MHz;
else
rate = OSC_HZ;
break;
default:
return -ENOENT;
}
return rate;
}
static ulong rk3568_i2c_set_clk(struct rk3568_clk_priv *priv, ulong clk_id,
ulong rate)
{
struct rk3568_cru *cru = priv->cru;
int src_clk;
if (rate == 200 * MHz)
src_clk = CLK_I2C_SEL_200M;
else if (rate == 100 * MHz)
src_clk = CLK_I2C_SEL_100M;
else
src_clk = CLK_I2C_SEL_24M;
switch (clk_id) {
case CLK_I2C1:
case CLK_I2C2:
case CLK_I2C3:
case CLK_I2C4:
case CLK_I2C5:
rk_clrsetreg(&cru->clksel_con[71], CLK_I2C_SEL_MASK,
src_clk << CLK_I2C_SEL_SHIFT);
break;
default:
return -ENOENT;
}
return rk3568_i2c_get_clk(priv, clk_id);
}
static ulong rk3568_spi_get_clk(struct rk3568_clk_priv *priv, ulong clk_id)
{
struct rk3568_cru *cru = priv->cru;
u32 sel, con;
con = readl(&cru->clksel_con[72]);
switch (clk_id) {
case CLK_SPI0:
sel = (con & CLK_SPI0_SEL_MASK) >> CLK_SPI0_SEL_SHIFT;
break;
case CLK_SPI1:
sel = (con & CLK_SPI1_SEL_MASK) >> CLK_SPI1_SEL_SHIFT;
break;
case CLK_SPI2:
sel = (con & CLK_SPI2_SEL_MASK) >> CLK_SPI2_SEL_SHIFT;
break;
case CLK_SPI3:
sel = (con & CLK_SPI3_SEL_MASK) >> CLK_SPI3_SEL_SHIFT;
break;
default:
return -ENOENT;
}
switch (sel) {
case CLK_SPI_SEL_200M:
return 200 * MHz;
case CLK_SPI_SEL_24M:
return OSC_HZ;
case CLK_SPI_SEL_CPLL_100M:
return 100 * MHz;
default:
return -ENOENT;
}
}
static ulong rk3568_spi_set_clk(struct rk3568_clk_priv *priv,
ulong clk_id, ulong rate)
{
struct rk3568_cru *cru = priv->cru;
int src_clk;
if (rate == 200 * MHz)
src_clk = CLK_SPI_SEL_200M;
else if (rate == 100 * MHz)
src_clk = CLK_SPI_SEL_CPLL_100M;
else
src_clk = CLK_SPI_SEL_24M;
switch (clk_id) {
case CLK_SPI0:
rk_clrsetreg(&cru->clksel_con[72],
CLK_SPI0_SEL_MASK,
src_clk << CLK_SPI0_SEL_SHIFT);
break;
case CLK_SPI1:
rk_clrsetreg(&cru->clksel_con[72],
CLK_SPI1_SEL_MASK,
src_clk << CLK_SPI1_SEL_SHIFT);
break;
case CLK_SPI2:
rk_clrsetreg(&cru->clksel_con[72],
CLK_SPI2_SEL_MASK,
src_clk << CLK_SPI2_SEL_SHIFT);
break;
case CLK_SPI3:
rk_clrsetreg(&cru->clksel_con[72],
CLK_SPI3_SEL_MASK,
src_clk << CLK_SPI3_SEL_SHIFT);
break;
default:
return -ENOENT;
}
return rk3568_spi_get_clk(priv, clk_id);
}
static ulong rk3568_pwm_get_clk(struct rk3568_clk_priv *priv, ulong clk_id)
{
struct rk3568_cru *cru = priv->cru;
u32 sel, con;
con = readl(&cru->clksel_con[72]);
switch (clk_id) {
case CLK_PWM1:
sel = (con & CLK_PWM1_SEL_MASK) >> CLK_PWM1_SEL_SHIFT;
break;
case CLK_PWM2:
sel = (con & CLK_PWM2_SEL_MASK) >> CLK_PWM2_SEL_SHIFT;
break;
case CLK_PWM3:
sel = (con & CLK_PWM3_SEL_MASK) >> CLK_PWM3_SEL_SHIFT;
break;
default:
return -ENOENT;
}
switch (sel) {
case CLK_PWM_SEL_100M:
return 100 * MHz;
case CLK_PWM_SEL_24M:
return OSC_HZ;
case CLK_PWM_SEL_CPLL_100M:
return 100 * MHz;
default:
return -ENOENT;
}
}
static ulong rk3568_pwm_set_clk(struct rk3568_clk_priv *priv,
ulong clk_id, ulong rate)
{
struct rk3568_cru *cru = priv->cru;
int src_clk;
if (rate == 100 * MHz)
src_clk = CLK_PWM_SEL_100M;
else
src_clk = CLK_PWM_SEL_24M;
switch (clk_id) {
case CLK_PWM1:
rk_clrsetreg(&cru->clksel_con[72],
CLK_PWM1_SEL_MASK,
src_clk << CLK_PWM1_SEL_SHIFT);
break;
case CLK_PWM2:
rk_clrsetreg(&cru->clksel_con[72],
CLK_PWM2_SEL_MASK,
src_clk << CLK_PWM2_SEL_SHIFT);
break;
case CLK_PWM3:
rk_clrsetreg(&cru->clksel_con[72],
CLK_PWM3_SEL_MASK,
src_clk << CLK_PWM3_SEL_SHIFT);
break;
default:
return -ENOENT;
}
return rk3568_pwm_get_clk(priv, clk_id);
}
static ulong rk3568_adc_get_clk(struct rk3568_clk_priv *priv, ulong clk_id)
{
struct rk3568_cru *cru = priv->cru;
u32 div, sel, con, prate;
switch (clk_id) {
case CLK_SARADC:
return OSC_HZ;
case CLK_TSADC_TSEN:
con = readl(&cru->clksel_con[51]);
div = (con & CLK_TSADC_TSEN_DIV_MASK) >>
CLK_TSADC_TSEN_DIV_SHIFT;
sel = (con & CLK_TSADC_TSEN_SEL_MASK) >>
CLK_TSADC_TSEN_SEL_SHIFT;
if (sel == CLK_TSADC_TSEN_SEL_24M)
prate = OSC_HZ;
else
prate = 100 * MHz;
return DIV_TO_RATE(prate, div);
case CLK_TSADC:
con = readl(&cru->clksel_con[51]);
div = (con & CLK_TSADC_DIV_MASK) >> CLK_TSADC_DIV_SHIFT;
prate = rk3568_adc_get_clk(priv, CLK_TSADC_TSEN);
return DIV_TO_RATE(prate, div);
default:
return -ENOENT;
}
}
static ulong rk3568_adc_set_clk(struct rk3568_clk_priv *priv,
ulong clk_id, ulong rate)
{
struct rk3568_cru *cru = priv->cru;
int src_clk_div;
ulong prate = 0;
switch (clk_id) {
case CLK_SARADC:
return OSC_HZ;
case CLK_TSADC_TSEN:
if (!(OSC_HZ % rate)) {
src_clk_div = DIV_ROUND_UP(OSC_HZ, rate);
assert(src_clk_div - 1 <= 7);
rk_clrsetreg(&cru->clksel_con[51],
CLK_TSADC_TSEN_SEL_MASK |
CLK_TSADC_TSEN_DIV_MASK,
(CLK_TSADC_TSEN_SEL_24M <<
CLK_TSADC_TSEN_SEL_SHIFT) |
(src_clk_div - 1) <<
CLK_TSADC_TSEN_DIV_SHIFT);
} else {
src_clk_div = DIV_ROUND_UP(100 * MHz, rate);
assert(src_clk_div - 1 <= 7);
rk_clrsetreg(&cru->clksel_con[51],
CLK_TSADC_TSEN_SEL_MASK |
CLK_TSADC_TSEN_DIV_MASK,
(CLK_TSADC_TSEN_SEL_100M <<
CLK_TSADC_TSEN_SEL_SHIFT) |
(src_clk_div - 1) <<
CLK_TSADC_TSEN_DIV_SHIFT);
}
break;
case CLK_TSADC:
prate = rk3568_adc_get_clk(priv, CLK_TSADC_TSEN);
src_clk_div = DIV_ROUND_UP(prate, rate);
assert(src_clk_div - 1 <= 128);
rk_clrsetreg(&cru->clksel_con[51],
CLK_TSADC_DIV_MASK,
(src_clk_div - 1) << CLK_TSADC_DIV_SHIFT);
break;
default:
return -ENOENT;
}
return rk3568_adc_get_clk(priv, clk_id);
}
static ulong rk3568_crypto_get_rate(struct rk3568_clk_priv *priv, ulong clk_id)
{
struct rk3568_cru *cru = priv->cru;
u32 sel, con;
switch (clk_id) {
case ACLK_SECURE_FLASH:
case ACLK_CRYPTO_NS:
con = readl(&cru->clksel_con[27]);
sel = (con & ACLK_SECURE_FLASH_SEL_MASK) >>
ACLK_SECURE_FLASH_SEL_SHIFT;
if (sel == ACLK_SECURE_FLASH_SEL_200M)
return 200 * MHz;
else if (sel == ACLK_SECURE_FLASH_SEL_150M)
return 150 * MHz;
else if (sel == ACLK_SECURE_FLASH_SEL_100M)
return 100 * MHz;
else
return 24 * MHz;
case HCLK_SECURE_FLASH:
case HCLK_CRYPTO_NS:
case CLK_CRYPTO_NS_RNG:
con = readl(&cru->clksel_con[27]);
sel = (con & HCLK_SECURE_FLASH_SEL_MASK) >>
HCLK_SECURE_FLASH_SEL_SHIFT;
if (sel == HCLK_SECURE_FLASH_SEL_150M)
return 150 * MHz;
else if (sel == HCLK_SECURE_FLASH_SEL_100M)
return 100 * MHz;
else if (sel == HCLK_SECURE_FLASH_SEL_75M)
return 75 * MHz;
else
return 24 * MHz;
case CLK_CRYPTO_NS_CORE:
con = readl(&cru->clksel_con[27]);
sel = (con & CLK_CRYPTO_CORE_SEL_MASK) >>
CLK_CRYPTO_CORE_SEL_SHIFT;
if (sel == CLK_CRYPTO_CORE_SEL_200M)
return 200 * MHz;
else if (sel == CLK_CRYPTO_CORE_SEL_150M)
return 150 * MHz;
else
return 100 * MHz;
case CLK_CRYPTO_NS_PKA:
con = readl(&cru->clksel_con[27]);
sel = (con & CLK_CRYPTO_PKA_SEL_MASK) >>
CLK_CRYPTO_PKA_SEL_SHIFT;
if (sel == CLK_CRYPTO_PKA_SEL_300M)
return 300 * MHz;
else if (sel == CLK_CRYPTO_PKA_SEL_200M)
return 200 * MHz;
else
return 100 * MHz;
default:
return -ENOENT;
}
}
static ulong rk3568_crypto_set_rate(struct rk3568_clk_priv *priv,
ulong clk_id, ulong rate)
{
struct rk3568_cru *cru = priv->cru;
u32 src_clk, mask, shift;
switch (clk_id) {
case ACLK_SECURE_FLASH:
case ACLK_CRYPTO_NS:
mask = ACLK_SECURE_FLASH_SEL_MASK;
shift = ACLK_SECURE_FLASH_SEL_SHIFT;
if (rate == 200 * MHz)
src_clk = ACLK_SECURE_FLASH_SEL_200M;
else if (rate == 150 * MHz)
src_clk = ACLK_SECURE_FLASH_SEL_150M;
else if (rate == 100 * MHz)
src_clk = ACLK_SECURE_FLASH_SEL_100M;
else
src_clk = ACLK_SECURE_FLASH_SEL_24M;
break;
case HCLK_SECURE_FLASH:
case HCLK_CRYPTO_NS:
case CLK_CRYPTO_NS_RNG:
mask = HCLK_SECURE_FLASH_SEL_MASK;
shift = HCLK_SECURE_FLASH_SEL_SHIFT;
if (rate == 150 * MHz)
src_clk = HCLK_SECURE_FLASH_SEL_150M;
else if (rate == 100 * MHz)
src_clk = HCLK_SECURE_FLASH_SEL_100M;
else if (rate == 75 * MHz)
src_clk = HCLK_SECURE_FLASH_SEL_75M;
else
src_clk = HCLK_SECURE_FLASH_SEL_24M;
break;
case CLK_CRYPTO_NS_CORE:
mask = CLK_CRYPTO_CORE_SEL_MASK;
shift = CLK_CRYPTO_CORE_SEL_SHIFT;
if (rate == 200 * MHz)
src_clk = CLK_CRYPTO_CORE_SEL_200M;
else if (rate == 150 * MHz)
src_clk = CLK_CRYPTO_CORE_SEL_150M;
else
src_clk = CLK_CRYPTO_CORE_SEL_100M;
break;
case CLK_CRYPTO_NS_PKA:
mask = CLK_CRYPTO_PKA_SEL_MASK;
shift = CLK_CRYPTO_PKA_SEL_SHIFT;
if (rate == 300 * MHz)
src_clk = CLK_CRYPTO_PKA_SEL_300M;
else if (rate == 200 * MHz)
src_clk = CLK_CRYPTO_PKA_SEL_200M;
else
src_clk = CLK_CRYPTO_PKA_SEL_100M;
break;
default:
return -ENOENT;
}
rk_clrsetreg(&cru->clksel_con[27], mask, src_clk << shift);
return rk3568_crypto_get_rate(priv, clk_id);
}
static ulong rk3568_sdmmc_get_clk(struct rk3568_clk_priv *priv, ulong clk_id)
{
struct rk3568_cru *cru = priv->cru;
u32 sel, con;
switch (clk_id) {
case HCLK_SDMMC0:
case CLK_SDMMC0:
con = readl(&cru->clksel_con[30]);
sel = (con & CLK_SDMMC0_SEL_MASK) >> CLK_SDMMC0_SEL_SHIFT;
break;
case CLK_SDMMC1:
con = readl(&cru->clksel_con[30]);
sel = (con & CLK_SDMMC1_SEL_MASK) >> CLK_SDMMC1_SEL_SHIFT;
break;
case CLK_SDMMC2:
con = readl(&cru->clksel_con[32]);
sel = (con & CLK_SDMMC2_SEL_MASK) >> CLK_SDMMC2_SEL_SHIFT;
break;
default:
return -ENOENT;
}
switch (sel) {
case CLK_SDMMC_SEL_24M:
return OSC_HZ;
case CLK_SDMMC_SEL_400M:
return 400 * MHz;
case CLK_SDMMC_SEL_300M:
return 300 * MHz;
case CLK_SDMMC_SEL_100M:
return 100 * MHz;
case CLK_SDMMC_SEL_50M:
return 50 * MHz;
case CLK_SDMMC_SEL_750K:
return 750 * KHz;
default:
return -ENOENT;
}
}
static ulong rk3568_sdmmc_set_clk(struct rk3568_clk_priv *priv,
ulong clk_id, ulong rate)
{
struct rk3568_cru *cru = priv->cru;
int src_clk;
switch (rate) {
case OSC_HZ:
case 26 * MHz:
case 25 * MHz:
src_clk = CLK_SDMMC_SEL_24M;
break;
case 400 * MHz:
src_clk = CLK_SDMMC_SEL_400M;
break;
case 300 * MHz:
src_clk = CLK_SDMMC_SEL_300M;
break;
case 100 * MHz:
src_clk = CLK_SDMMC_SEL_100M;
break;
case 52 * MHz:
case 50 * MHz:
src_clk = CLK_SDMMC_SEL_50M;
break;
case 750 * KHz:
case 400 * KHz:
src_clk = CLK_SDMMC_SEL_750K;
break;
default:
return -ENOENT;
}
switch (clk_id) {
case HCLK_SDMMC0:
case CLK_SDMMC0:
rk_clrsetreg(&cru->clksel_con[30],
CLK_SDMMC0_SEL_MASK,
src_clk << CLK_SDMMC0_SEL_SHIFT);
break;
case CLK_SDMMC1:
rk_clrsetreg(&cru->clksel_con[30],
CLK_SDMMC1_SEL_MASK,
src_clk << CLK_SDMMC1_SEL_SHIFT);
break;
case CLK_SDMMC2:
rk_clrsetreg(&cru->clksel_con[32],
CLK_SDMMC2_SEL_MASK,
src_clk << CLK_SDMMC2_SEL_SHIFT);
break;
default:
return -ENOENT;
}
return rk3568_sdmmc_get_clk(priv, clk_id);
}
static ulong rk3568_sfc_get_clk(struct rk3568_clk_priv *priv)
{
struct rk3568_cru *cru = priv->cru;
u32 sel, con;
con = readl(&cru->clksel_con[28]);
sel = (con & SCLK_SFC_SEL_MASK) >> SCLK_SFC_SEL_SHIFT;
switch (sel) {
case SCLK_SFC_SEL_24M:
return OSC_HZ;
case SCLK_SFC_SEL_50M:
return 50 * MHz;
case SCLK_SFC_SEL_75M:
return 75 * MHz;
case SCLK_SFC_SEL_100M:
return 100 * MHz;
case SCLK_SFC_SEL_125M:
return 125 * MHz;
case SCLK_SFC_SEL_150M:
return 150 * MHz;
default:
return -ENOENT;
}
}
static ulong rk3568_sfc_set_clk(struct rk3568_clk_priv *priv, ulong rate)
{
struct rk3568_cru *cru = priv->cru;
int src_clk;
if (rate >= 150 * MHz)
src_clk = SCLK_SFC_SEL_150M;
else if (rate >= 125 * MHz)
src_clk = SCLK_SFC_SEL_125M;
else if (rate >= 100 * MHz)
src_clk = SCLK_SFC_SEL_100M;
else if (rate >= 75 * MHz)
src_clk = SCLK_SFC_SEL_75M;
else if (rate >= 50 * MHz)
src_clk = SCLK_SFC_SEL_50M;
else if (rate >= OSC_HZ)
src_clk = SCLK_SFC_SEL_24M;
else
return -ENOENT;
rk_clrsetreg(&cru->clksel_con[28],
SCLK_SFC_SEL_MASK,
src_clk << SCLK_SFC_SEL_SHIFT);
return rk3568_sfc_get_clk(priv);
}
static ulong rk3568_nand_get_clk(struct rk3568_clk_priv *priv)
{
struct rk3568_cru *cru = priv->cru;
u32 sel, con;
con = readl(&cru->clksel_con[28]);
sel = (con & NCLK_NANDC_SEL_MASK) >> NCLK_NANDC_SEL_SHIFT;
switch (sel) {
case NCLK_NANDC_SEL_200M:
return 200 * MHz;
case NCLK_NANDC_SEL_150M:
return 150 * MHz;
case NCLK_NANDC_SEL_100M:
return 100 * MHz;
case NCLK_NANDC_SEL_24M:
return OSC_HZ;
default:
return -ENOENT;
}
}
static ulong rk3568_nand_set_clk(struct rk3568_clk_priv *priv, ulong rate)
{
struct rk3568_cru *cru = priv->cru;
int src_clk;
switch (rate) {
case OSC_HZ:
src_clk = NCLK_NANDC_SEL_24M;
break;
case 100 * MHz:
src_clk = NCLK_NANDC_SEL_100M;
break;
case 150 * MHz:
src_clk = NCLK_NANDC_SEL_150M;
break;
case 200 * MHz:
src_clk = NCLK_NANDC_SEL_200M;
break;
default:
return -ENOENT;
}
rk_clrsetreg(&cru->clksel_con[28],
NCLK_NANDC_SEL_MASK,
src_clk << NCLK_NANDC_SEL_SHIFT);
return rk3568_nand_get_clk(priv);
}
static ulong rk3568_emmc_get_clk(struct rk3568_clk_priv *priv)
{
struct rk3568_cru *cru = priv->cru;
u32 sel, con;
con = readl(&cru->clksel_con[28]);
sel = (con & CCLK_EMMC_SEL_MASK) >> CCLK_EMMC_SEL_SHIFT;
switch (sel) {
case CCLK_EMMC_SEL_200M:
return 200 * MHz;
case CCLK_EMMC_SEL_150M:
return 150 * MHz;
case CCLK_EMMC_SEL_100M:
return 100 * MHz;
case CCLK_EMMC_SEL_50M:
return 50 * MHz;
case CCLK_EMMC_SEL_375K:
return 375 * KHz;
case CCLK_EMMC_SEL_24M:
return OSC_HZ;
default:
return -ENOENT;
}
}
static ulong rk3568_emmc_set_clk(struct rk3568_clk_priv *priv, ulong rate)
{
struct rk3568_cru *cru = priv->cru;
int src_clk;
switch (rate) {
case OSC_HZ:
case 26 * MHz:
case 25 * MHz:
src_clk = CCLK_EMMC_SEL_24M;
break;
case 52 * MHz:
case 50 * MHz:
src_clk = CCLK_EMMC_SEL_50M;
break;
case 100 * MHz:
src_clk = CCLK_EMMC_SEL_100M;
break;
case 150 * MHz:
src_clk = CCLK_EMMC_SEL_150M;
break;
case 200 * MHz:
src_clk = CCLK_EMMC_SEL_200M;
break;
case 400 * KHz:
case 375 * KHz:
src_clk = CCLK_EMMC_SEL_375K;
break;
default:
return -ENOENT;
}
rk_clrsetreg(&cru->clksel_con[28],
CCLK_EMMC_SEL_MASK,
src_clk << CCLK_EMMC_SEL_SHIFT);
return rk3568_emmc_get_clk(priv);
}
static ulong rk3568_emmc_get_bclk(struct rk3568_clk_priv *priv)
{
struct rk3568_cru *cru = priv->cru;
u32 sel, con;
con = readl(&cru->clksel_con[28]);
sel = (con & BCLK_EMMC_SEL_MASK) >> BCLK_EMMC_SEL_SHIFT;
switch (sel) {
case BCLK_EMMC_SEL_200M:
return 200 * MHz;
case BCLK_EMMC_SEL_150M:
return 150 * MHz;
case BCLK_EMMC_SEL_125M:
return 125 * MHz;
default:
return -ENOENT;
}
}
static ulong rk3568_emmc_set_bclk(struct rk3568_clk_priv *priv, ulong rate)
{
struct rk3568_cru *cru = priv->cru;
int src_clk;
switch (rate) {
case 200 * MHz:
src_clk = BCLK_EMMC_SEL_200M;
break;
case 150 * MHz:
src_clk = BCLK_EMMC_SEL_150M;
break;
case 125 * MHz:
src_clk = BCLK_EMMC_SEL_125M;
break;
default:
return -ENOENT;
}
rk_clrsetreg(&cru->clksel_con[28],
BCLK_EMMC_SEL_MASK,
src_clk << BCLK_EMMC_SEL_SHIFT);
return rk3568_emmc_get_bclk(priv);
}
#ifndef CONFIG_SPL_BUILD
static ulong rk3568_aclk_vop_get_clk(struct rk3568_clk_priv *priv)
{
struct rk3568_cru *cru = priv->cru;
u32 div, sel, con, parent;
con = readl(&cru->clksel_con[38]);
div = (con & ACLK_VOP_PRE_DIV_MASK) >> ACLK_VOP_PRE_DIV_SHIFT;
sel = (con & ACLK_VOP_PRE_SEL_MASK) >> ACLK_VOP_PRE_SEL_SHIFT;
if (sel == ACLK_VOP_PRE_SEL_GPLL)
parent = priv->gpll_hz;
else if (sel == ACLK_VOP_PRE_SEL_CPLL)
parent = priv->cpll_hz;
else if (sel == ACLK_VOP_PRE_SEL_VPLL)
parent = priv->vpll_hz;
else
parent = priv->hpll_hz;
return DIV_TO_RATE(parent, div);
}
static ulong rk3568_aclk_vop_set_clk(struct rk3568_clk_priv *priv, ulong rate)
{
struct rk3568_cru *cru = priv->cru;
int src_clk_div, src_clk_mux;
if ((priv->cpll_hz % rate) == 0) {
src_clk_div = DIV_ROUND_UP(priv->cpll_hz, rate);
src_clk_mux = ACLK_VOP_PRE_SEL_CPLL;
} else {
src_clk_div = DIV_ROUND_UP(priv->gpll_hz, rate);
src_clk_mux = ACLK_VOP_PRE_SEL_GPLL;
}
assert(src_clk_div - 1 <= 31);
rk_clrsetreg(&cru->clksel_con[38],
ACLK_VOP_PRE_SEL_MASK | ACLK_VOP_PRE_DIV_MASK,
src_clk_mux << ACLK_VOP_PRE_SEL_SHIFT |
(src_clk_div - 1) << ACLK_VOP_PRE_DIV_SHIFT);
return rk3568_aclk_vop_get_clk(priv);
}
static ulong rk3568_dclk_vop_get_clk(struct rk3568_clk_priv *priv, ulong clk_id)
{
struct rk3568_cru *cru = priv->cru;
u32 conid, div, sel, con, parent;
switch (clk_id) {
case DCLK_VOP0:
conid = 39;
break;
case DCLK_VOP1:
conid = 40;
break;
case DCLK_VOP2:
conid = 41;
break;
default:
return -ENOENT;
}
con = readl(&cru->clksel_con[conid]);
div = (con & DCLK0_VOP_DIV_MASK) >> DCLK0_VOP_DIV_SHIFT;
sel = (con & DCLK0_VOP_SEL_MASK) >> DCLK0_VOP_SEL_SHIFT;
if (sel == DCLK_VOP_SEL_HPLL)
parent = rk3568_pmu_pll_get_rate(priv, HPLL);
else if (sel == DCLK_VOP_SEL_VPLL)
parent = rockchip_pll_get_rate(&rk3568_pll_clks[VPLL],
priv->cru, VPLL);
else if (sel == DCLK_VOP_SEL_GPLL)
parent = priv->gpll_hz;
else if (sel == DCLK_VOP_SEL_CPLL)
parent = priv->cpll_hz;
else
return -ENOENT;
return DIV_TO_RATE(parent, div);
}
#define RK3568_VOP_PLL_LIMIT_FREQ 600000000
static ulong rk3568_dclk_vop_set_clk(struct rk3568_clk_priv *priv,
ulong clk_id, ulong rate)
{
struct rk3568_cru *cru = priv->cru;
ulong pll_rate, now, best_rate = 0;
u32 i, conid, con, sel, div, best_div = 0, best_sel = 0;
switch (clk_id) {
case DCLK_VOP0:
conid = 39;
break;
case DCLK_VOP1:
conid = 40;
break;
case DCLK_VOP2:
conid = 41;
break;
default:
return -ENOENT;
}
con = readl(&cru->clksel_con[conid]);
sel = (con & DCLK0_VOP_SEL_MASK) >> DCLK0_VOP_SEL_SHIFT;
if (sel == DCLK_VOP_SEL_HPLL) {
div = 1;
rk_clrsetreg(&cru->clksel_con[conid],
DCLK0_VOP_DIV_MASK | DCLK0_VOP_SEL_MASK,
(DCLK_VOP_SEL_HPLL << DCLK0_VOP_SEL_SHIFT) |
((div - 1) << DCLK0_VOP_DIV_SHIFT));
rk3568_pmu_pll_set_rate(priv, HPLL, div * rate);
} else if (sel == DCLK_VOP_SEL_VPLL) {
div = DIV_ROUND_UP(RK3568_VOP_PLL_LIMIT_FREQ, rate);
rk_clrsetreg(&cru->clksel_con[conid],
DCLK0_VOP_DIV_MASK | DCLK0_VOP_SEL_MASK,
(DCLK_VOP_SEL_VPLL << DCLK0_VOP_SEL_SHIFT) |
((div - 1) << DCLK0_VOP_DIV_SHIFT));
rockchip_pll_set_rate(&rk3568_pll_clks[VPLL],
priv->cru, VPLL, div * rate);
} else {
for (i = sel; i <= DCLK_VOP_SEL_CPLL; i++) {
switch (i) {
case DCLK_VOP_SEL_GPLL:
pll_rate = priv->gpll_hz;
break;
case DCLK_VOP_SEL_CPLL:
pll_rate = priv->cpll_hz;
break;
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[conid],
DCLK0_VOP_DIV_MASK | DCLK0_VOP_SEL_MASK,
best_sel << DCLK0_VOP_SEL_SHIFT |
(best_div - 1) << DCLK0_VOP_DIV_SHIFT);
} else {
printf("do not support this vop freq %lu\n", rate);
return -EINVAL;
}
}
return rk3568_dclk_vop_get_clk(priv, clk_id);
}
static ulong rk3568_gmac_src_get_clk(struct rk3568_clk_priv *priv,
ulong mac_id)
{
struct rk3568_cru *cru = priv->cru;
u32 sel, con;
con = readl(&cru->clksel_con[31 + mac_id * 2]);
sel = (con & CLK_MAC0_2TOP_SEL_MASK) >> CLK_MAC0_2TOP_SEL_SHIFT;
switch (sel) {
case CLK_MAC0_2TOP_SEL_125M:
return 125 * MHz;
case CLK_MAC0_2TOP_SEL_50M:
return 50 * MHz;
case CLK_MAC0_2TOP_SEL_25M:
return 25 * MHz;
case CLK_MAC0_2TOP_SEL_PPLL:
return rk3568_pmu_pll_get_rate(priv, HPLL);
default:
return -ENOENT;
}
}
static ulong rk3568_gmac_src_set_clk(struct rk3568_clk_priv *priv,
ulong mac_id, ulong rate)
{
struct rk3568_cru *cru = priv->cru;
int src_clk;
switch (rate) {
case 125 * MHz:
src_clk = CLK_MAC0_2TOP_SEL_125M;
break;
case 50 * MHz:
src_clk = CLK_MAC0_2TOP_SEL_50M;
break;
case 25 * MHz:
src_clk = CLK_MAC0_2TOP_SEL_25M;
break;
default:
return -ENOENT;
}
rk_clrsetreg(&cru->clksel_con[31 + mac_id * 2],
CLK_MAC0_2TOP_SEL_MASK,
src_clk << CLK_MAC0_2TOP_SEL_SHIFT);
return rk3568_gmac_src_get_clk(priv, mac_id);
}
static ulong rk3568_gmac_out_get_clk(struct rk3568_clk_priv *priv,
ulong mac_id)
{
struct rk3568_cru *cru = priv->cru;
u32 sel, con;
con = readl(&cru->clksel_con[31 + mac_id * 2]);
sel = (con & CLK_MAC0_OUT_SEL_MASK) >> CLK_MAC0_OUT_SEL_SHIFT;
switch (sel) {
case CLK_MAC0_OUT_SEL_125M:
return 125 * MHz;
case CLK_MAC0_OUT_SEL_50M:
return 50 * MHz;
case CLK_MAC0_OUT_SEL_25M:
return 25 * MHz;
case CLK_MAC0_OUT_SEL_24M:
return OSC_HZ;
default:
return -ENOENT;
}
}
static ulong rk3568_gmac_out_set_clk(struct rk3568_clk_priv *priv,
ulong mac_id, ulong rate)
{
struct rk3568_cru *cru = priv->cru;
int src_clk;
switch (rate) {
case 125 * MHz:
src_clk = CLK_MAC0_OUT_SEL_125M;
break;
case 50 * MHz:
src_clk = CLK_MAC0_OUT_SEL_50M;
break;
case 25 * MHz:
src_clk = CLK_MAC0_OUT_SEL_25M;
break;
case 24 * MHz:
src_clk = CLK_MAC0_OUT_SEL_24M;
break;
default:
return -ENOENT;
}
rk_clrsetreg(&cru->clksel_con[31 + mac_id * 2],
CLK_MAC0_OUT_SEL_MASK,
src_clk << CLK_MAC0_OUT_SEL_SHIFT);
return rk3568_gmac_out_get_clk(priv, mac_id);
}
static ulong rk3568_gmac_ptp_ref_get_clk(struct rk3568_clk_priv *priv,
ulong mac_id)
{
struct rk3568_cru *cru = priv->cru;
u32 sel, con;
con = readl(&cru->clksel_con[31 + mac_id * 2]);
sel = (con & CLK_GMAC0_PTP_REF_SEL_MASK) >> CLK_GMAC0_PTP_REF_SEL_SHIFT;
switch (sel) {
case CLK_GMAC0_PTP_REF_SEL_62_5M:
return 62500 * KHz;
case CLK_GMAC0_PTP_REF_SEL_100M:
return 100 * MHz;
case CLK_GMAC0_PTP_REF_SEL_50M:
return 50 * MHz;
case CLK_GMAC0_PTP_REF_SEL_24M:
return OSC_HZ;
default:
return -ENOENT;
}
}
static ulong rk3568_gmac_ptp_ref_set_clk(struct rk3568_clk_priv *priv,
ulong mac_id, ulong rate)
{
struct rk3568_cru *cru = priv->cru;
int src_clk;
switch (rate) {
case 62500 * KHz:
src_clk = CLK_GMAC0_PTP_REF_SEL_62_5M;
break;
case 100 * MHz:
src_clk = CLK_GMAC0_PTP_REF_SEL_100M;
break;
case 50 * MHz:
src_clk = CLK_GMAC0_PTP_REF_SEL_50M;
break;
case 24 * MHz:
src_clk = CLK_GMAC0_PTP_REF_SEL_24M;
break;
default:
return -ENOENT;
}
rk_clrsetreg(&cru->clksel_con[31 + mac_id * 2],
CLK_GMAC0_PTP_REF_SEL_MASK,
src_clk << CLK_GMAC0_PTP_REF_SEL_SHIFT);
return rk3568_gmac_ptp_ref_get_clk(priv, mac_id);
}
static ulong rk3568_gmac_tx_rx_set_clk(struct rk3568_clk_priv *priv,
ulong mac_id, ulong rate)
{
struct rk3568_cru *cru = priv->cru;
u32 con, sel, div_sel;
con = readl(&cru->clksel_con[31 + mac_id * 2]);
sel = (con & RMII0_MODE_MASK) >> RMII0_MODE_SHIFT;
if (sel == RMII0_MODE_SEL_RGMII) {
if (rate == 2500000)
div_sel = RGMII0_CLK_SEL_2_5M;
else if (rate == 25000000)
div_sel = RGMII0_CLK_SEL_25M;
else
div_sel = RGMII0_CLK_SEL_125M;
rk_clrsetreg(&cru->clksel_con[31 + mac_id * 2],
RGMII0_CLK_SEL_MASK,
div_sel << RGMII0_CLK_SEL_SHIFT);
} else if (sel == RMII0_MODE_SEL_RMII) {
if (rate == 2500000)
div_sel = RMII0_CLK_SEL_2_5M;
else
div_sel = RMII0_CLK_SEL_25M;
rk_clrsetreg(&cru->clksel_con[31 + mac_id * 2],
RMII0_CLK_SEL_MASK,
div_sel << RMII0_CLK_SEL_SHIFT);
}
return 0;
}
static ulong rk3568_ebc_get_clk(struct rk3568_clk_priv *priv)
{
struct rk3568_cru *cru = priv->cru;
u32 con, div, p_rate;
con = readl(&cru->clksel_con[79]);
div = (con & CPLL_333M_DIV_MASK) >> CPLL_333M_DIV_SHIFT;
p_rate = DIV_TO_RATE(priv->cpll_hz, div);
con = readl(&cru->clksel_con[43]);
div = (con & DCLK_EBC_SEL_MASK) >> DCLK_EBC_SEL_SHIFT;
switch (div) {
case DCLK_EBC_SEL_GPLL_400M:
return 400 * MHz;
case DCLK_EBC_SEL_CPLL_333M:
return p_rate;
case DCLK_EBC_SEL_GPLL_200M:
return 200 * MHz;
default:
return -ENOENT;
}
}
static ulong rk3568_ebc_set_clk(struct rk3568_clk_priv *priv, ulong rate)
{
struct rk3568_cru *cru = priv->cru;
int src_clk_div;
src_clk_div = DIV_ROUND_UP(priv->cpll_hz, rate);
assert(src_clk_div - 1 <= 31);
rk_clrsetreg(&cru->clksel_con[79],
CPLL_333M_DIV_MASK,
(src_clk_div - 1) << CPLL_333M_DIV_SHIFT);
rk_clrsetreg(&cru->clksel_con[43],
DCLK_EBC_SEL_MASK,
DCLK_EBC_SEL_CPLL_333M << DCLK_EBC_SEL_SHIFT);
return rk3568_ebc_get_clk(priv);
}
static ulong rk3568_rkvdec_get_clk(struct rk3568_clk_priv *priv, ulong clk_id)
{
struct rk3568_cru *cru = priv->cru;
u32 con, div, src, p_rate;
switch (clk_id) {
case ACLK_RKVDEC_PRE:
case ACLK_RKVDEC:
con = readl(&cru->clksel_con[47]);
src = (con & ACLK_RKVDEC_SEL_MASK) >> ACLK_RKVDEC_SEL_SHIFT;
div = (con & ACLK_RKVDEC_DIV_MASK) >> ACLK_RKVDEC_DIV_SHIFT;
if (src == ACLK_RKVDEC_SEL_CPLL)
p_rate = priv->cpll_hz;
else
p_rate = priv->gpll_hz;
return DIV_TO_RATE(p_rate, div);
case CLK_RKVDEC_CORE:
con = readl(&cru->clksel_con[49]);
src = (con & CLK_RKVDEC_CORE_SEL_MASK)
>> CLK_RKVDEC_CORE_SEL_SHIFT;
div = (con & CLK_RKVDEC_CORE_DIV_MASK)
>> CLK_RKVDEC_CORE_DIV_SHIFT;
if (src == CLK_RKVDEC_CORE_SEL_CPLL)
p_rate = priv->cpll_hz;
else if (src == CLK_RKVDEC_CORE_SEL_NPLL)
p_rate = priv->npll_hz;
else if (src == CLK_RKVDEC_CORE_SEL_VPLL)
p_rate = priv->vpll_hz;
else
p_rate = priv->gpll_hz;
return DIV_TO_RATE(p_rate, div);
default:
return -ENOENT;
}
}
static ulong rk3568_rkvdec_set_clk(struct rk3568_clk_priv *priv,
ulong clk_id, ulong rate)
{
struct rk3568_cru *cru = priv->cru;
int src_clk_div, src, p_rate;
switch (clk_id) {
case ACLK_RKVDEC_PRE:
case ACLK_RKVDEC:
src = (readl(&cru->clksel_con[47]) & ACLK_RKVDEC_SEL_MASK)
>> ACLK_RKVDEC_SEL_SHIFT;
if (src == ACLK_RKVDEC_SEL_CPLL)
p_rate = priv->cpll_hz;
else
p_rate = priv->gpll_hz;
src_clk_div = DIV_ROUND_UP(p_rate, rate);
assert(src_clk_div - 1 <= 31);
rk_clrsetreg(&cru->clksel_con[47],
ACLK_RKVDEC_SEL_MASK |
ACLK_RKVDEC_DIV_MASK,
(src << ACLK_RKVDEC_SEL_SHIFT) |
(src_clk_div - 1) << ACLK_RKVDEC_DIV_SHIFT);
break;
case CLK_RKVDEC_CORE:
src = (readl(&cru->clksel_con[49]) & CLK_RKVDEC_CORE_SEL_MASK)
>> CLK_RKVDEC_CORE_SEL_SHIFT;
if (src == CLK_RKVDEC_CORE_SEL_CPLL)
p_rate = priv->cpll_hz;
else if (src == CLK_RKVDEC_CORE_SEL_NPLL)
p_rate = priv->npll_hz;
else if (src == CLK_RKVDEC_CORE_SEL_VPLL)
p_rate = priv->vpll_hz;
else
p_rate = priv->gpll_hz;
src_clk_div = DIV_ROUND_UP(p_rate, rate);
assert(src_clk_div - 1 <= 31);
rk_clrsetreg(&cru->clksel_con[49],
CLK_RKVDEC_CORE_SEL_MASK |
CLK_RKVDEC_CORE_DIV_MASK,
(src << CLK_RKVDEC_CORE_SEL_SHIFT) |
(src_clk_div - 1) << CLK_RKVDEC_CORE_DIV_SHIFT);
break;
default:
return -ENOENT;
}
return rk3568_rkvdec_get_clk(priv, clk_id);
}
#endif
static ulong rk3568_uart_get_rate(struct rk3568_clk_priv *priv, ulong clk_id)
{
struct rk3568_cru *cru = priv->cru;
u32 reg, con, fracdiv, div, src, p_src, p_rate;
unsigned long m, n;
switch (clk_id) {
case SCLK_UART1:
reg = 52;
break;
case SCLK_UART2:
reg = 54;
break;
case SCLK_UART3:
reg = 56;
break;
case SCLK_UART4:
reg = 58;
break;
case SCLK_UART5:
reg = 60;
break;
case SCLK_UART6:
reg = 62;
break;
case SCLK_UART7:
reg = 64;
break;
case SCLK_UART8:
reg = 66;
break;
case SCLK_UART9:
reg = 68;
break;
default:
return -ENOENT;
}
con = readl(&cru->clksel_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 if (p_src == CLK_UART_SRC_SEL_CPLL)
p_rate = priv->cpll_hz;
else
p_rate = 480000000;
if (src == CLK_UART_SEL_SRC) {
return DIV_TO_RATE(p_rate, div);
} else if (src == CLK_UART_SEL_FRAC) {
fracdiv = readl(&cru->clksel_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 rk3568_uart_set_rate(struct rk3568_clk_priv *priv,
ulong clk_id, ulong rate)
{
struct rk3568_cru *cru = priv->cru;
u32 reg, clk_src, uart_src, div;
unsigned long m = 0, n = 0, val;
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->gpll_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),
&m, &n);
}
switch (clk_id) {
case SCLK_UART1:
reg = 52;
break;
case SCLK_UART2:
reg = 54;
break;
case SCLK_UART3:
reg = 56;
break;
case SCLK_UART4:
reg = 58;
break;
case SCLK_UART5:
reg = 60;
break;
case SCLK_UART6:
reg = 62;
break;
case SCLK_UART7:
reg = 64;
break;
case SCLK_UART8:
reg = 66;
break;
case SCLK_UART9:
reg = 68;
break;
default:
return -ENOENT;
}
rk_clrsetreg(&cru->clksel_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 = m << CLK_UART_FRAC_NUMERATOR_SHIFT | n;
writel(val, &cru->clksel_con[reg + 1]);
}
return rk3568_uart_get_rate(priv, clk_id);
}
static ulong rk3568_clk_get_rate(struct clk *clk)
{
struct rk3568_clk_priv *priv = dev_get_priv(clk->dev);
ulong rate = 0;
if (!priv->gpll_hz) {
printf("%s gpll=%lu\n", __func__, priv->gpll_hz);
return -ENOENT;
}
switch (clk->id) {
case PLL_APLL:
case ARMCLK:
rate = rockchip_pll_get_rate(&rk3568_pll_clks[APLL], priv->cru,
APLL);
break;
case PLL_CPLL:
rate = rockchip_pll_get_rate(&rk3568_pll_clks[CPLL], priv->cru,
CPLL);
break;
case PLL_GPLL:
rate = rockchip_pll_get_rate(&rk3568_pll_clks[GPLL], priv->cru,
GPLL);
break;
case PLL_NPLL:
rate = rockchip_pll_get_rate(&rk3568_pll_clks[NPLL], priv->cru,
NPLL);
break;
case PLL_VPLL:
rate = rockchip_pll_get_rate(&rk3568_pll_clks[VPLL], priv->cru,
VPLL);
break;
case PLL_DPLL:
rate = rockchip_pll_get_rate(&rk3568_pll_clks[DPLL], priv->cru,
DPLL);
break;
case ACLK_BUS:
case PCLK_BUS:
case PCLK_WDT_NS:
rate = rk3568_bus_get_clk(priv, clk->id);
break;
case ACLK_PERIMID:
case HCLK_PERIMID:
rate = rk3568_perimid_get_clk(priv, clk->id);
break;
case ACLK_TOP_HIGH:
case ACLK_TOP_LOW:
case HCLK_TOP:
case PCLK_TOP:
rate = rk3568_top_get_clk(priv, clk->id);
break;
case CLK_I2C1:
case CLK_I2C2:
case CLK_I2C3:
case CLK_I2C4:
case CLK_I2C5:
rate = rk3568_i2c_get_clk(priv, clk->id);
break;
case CLK_SPI0:
case CLK_SPI1:
case CLK_SPI2:
case CLK_SPI3:
rate = rk3568_spi_get_clk(priv, clk->id);
break;
case CLK_PWM1:
case CLK_PWM2:
case CLK_PWM3:
rate = rk3568_pwm_get_clk(priv, clk->id);
break;
case CLK_SARADC:
case CLK_TSADC_TSEN:
case CLK_TSADC:
rate = rk3568_adc_get_clk(priv, clk->id);
break;
case HCLK_SDMMC0:
case CLK_SDMMC0:
case CLK_SDMMC1:
case CLK_SDMMC2:
rate = rk3568_sdmmc_get_clk(priv, clk->id);
break;
case SCLK_SFC:
rate = rk3568_sfc_get_clk(priv);
break;
case NCLK_NANDC:
rate = rk3568_nand_get_clk(priv);
break;
case CCLK_EMMC:
rate = rk3568_emmc_get_clk(priv);
break;
case BCLK_EMMC:
rate = rk3568_emmc_get_bclk(priv);
break;
case CLK_USB3OTG0_REF:
case CLK_USB3OTG1_REF:
case TCLK_EMMC:
rate = OSC_HZ;
break;
#ifndef CONFIG_SPL_BUILD
case ACLK_VOP:
rate = rk3568_aclk_vop_get_clk(priv);
break;
case DCLK_VOP0:
case DCLK_VOP1:
case DCLK_VOP2:
rate = rk3568_dclk_vop_get_clk(priv, clk->id);
break;
case SCLK_GMAC0:
case CLK_MAC0_2TOP:
case CLK_MAC0_REFOUT:
rate = rk3568_gmac_src_get_clk(priv, 0);
break;
case CLK_MAC0_OUT:
rate = rk3568_gmac_out_get_clk(priv, 0);
break;
case CLK_GMAC0_PTP_REF:
rate = rk3568_gmac_ptp_ref_get_clk(priv, 0);
break;
case SCLK_GMAC1:
case CLK_MAC1_2TOP:
case CLK_MAC1_REFOUT:
rate = rk3568_gmac_src_get_clk(priv, 1);
break;
case CLK_MAC1_OUT:
rate = rk3568_gmac_out_get_clk(priv, 1);
break;
case CLK_GMAC1_PTP_REF:
rate = rk3568_gmac_ptp_ref_get_clk(priv, 1);
break;
case DCLK_EBC:
rate = rk3568_ebc_get_clk(priv);
break;
case ACLK_RKVDEC_PRE:
case ACLK_RKVDEC:
case CLK_RKVDEC_CORE:
rate = rk3568_rkvdec_get_clk(priv, clk->id);
break;
case TCLK_WDT_NS:
rate = OSC_HZ;
break;
#endif
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 = rk3568_uart_get_rate(priv, clk->id);
break;
case ACLK_SECURE_FLASH:
case ACLK_CRYPTO_NS:
case HCLK_SECURE_FLASH:
case HCLK_CRYPTO_NS:
case CLK_CRYPTO_NS_RNG:
case CLK_CRYPTO_NS_CORE:
case CLK_CRYPTO_NS_PKA:
rate = rk3568_crypto_get_rate(priv, clk->id);
break;
case CPLL_500M:
case CPLL_333M:
case CPLL_250M:
case CPLL_125M:
case CPLL_100M:
case CPLL_62P5M:
case CPLL_50M:
case CPLL_25M:
rate = rk3568_cpll_div_get_rate(priv, clk->id);
break;
default:
return -ENOENT;
}
return rate;
};
static ulong rk3568_clk_set_rate(struct clk *clk, ulong rate)
{
struct rk3568_clk_priv *priv = dev_get_priv(clk->dev);
ulong ret = 0;
if (!priv->gpll_hz) {
printf("%s gpll=%lu\n", __func__, priv->gpll_hz);
return -ENOENT;
}
switch (clk->id) {
case PLL_APLL:
case ARMCLK:
if (priv->armclk_hz)
rk3568_armclk_set_clk(priv, rate);
priv->armclk_hz = rate;
break;
case PLL_CPLL:
ret = rockchip_pll_set_rate(&rk3568_pll_clks[CPLL], priv->cru,
CPLL, rate);
priv->cpll_hz = rockchip_pll_get_rate(&rk3568_pll_clks[CPLL],
priv->cru, CPLL);
break;
case PLL_GPLL:
ret = rockchip_pll_set_rate(&rk3568_pll_clks[GPLL], priv->cru,
GPLL, rate);
priv->gpll_hz = rockchip_pll_get_rate(&rk3568_pll_clks[GPLL],
priv->cru, GPLL);
break;
case PLL_NPLL:
ret = rockchip_pll_set_rate(&rk3568_pll_clks[NPLL], priv->cru,
NPLL, rate);
break;
case PLL_VPLL:
ret = rockchip_pll_set_rate(&rk3568_pll_clks[VPLL], priv->cru,
VPLL, rate);
priv->vpll_hz = rockchip_pll_get_rate(&rk3568_pll_clks[VPLL],
priv->cru,
VPLL);
break;
case ACLK_BUS:
case PCLK_BUS:
case PCLK_WDT_NS:
ret = rk3568_bus_set_clk(priv, clk->id, rate);
break;
case ACLK_PERIMID:
case HCLK_PERIMID:
ret = rk3568_perimid_set_clk(priv, clk->id, rate);
break;
case ACLK_TOP_HIGH:
case ACLK_TOP_LOW:
case HCLK_TOP:
case PCLK_TOP:
ret = rk3568_top_set_clk(priv, clk->id, rate);
break;
case CLK_I2C1:
case CLK_I2C2:
case CLK_I2C3:
case CLK_I2C4:
case CLK_I2C5:
ret = rk3568_i2c_set_clk(priv, clk->id, rate);
break;
case CLK_SPI0:
case CLK_SPI1:
case CLK_SPI2:
case CLK_SPI3:
ret = rk3568_spi_set_clk(priv, clk->id, rate);
break;
case CLK_PWM1:
case CLK_PWM2:
case CLK_PWM3:
ret = rk3568_pwm_set_clk(priv, clk->id, rate);
break;
case CLK_SARADC:
case CLK_TSADC_TSEN:
case CLK_TSADC:
ret = rk3568_adc_set_clk(priv, clk->id, rate);
break;
case HCLK_SDMMC0:
case CLK_SDMMC0:
case CLK_SDMMC1:
case CLK_SDMMC2:
ret = rk3568_sdmmc_set_clk(priv, clk->id, rate);
break;
case SCLK_SFC:
ret = rk3568_sfc_set_clk(priv, rate);
break;
case NCLK_NANDC:
ret = rk3568_nand_set_clk(priv, rate);
break;
case CCLK_EMMC:
ret = rk3568_emmc_set_clk(priv, rate);
break;
case BCLK_EMMC:
ret = rk3568_emmc_set_bclk(priv, rate);
break;
case CLK_USB3OTG0_REF:
case CLK_USB3OTG1_REF:
case TCLK_EMMC:
ret = OSC_HZ;
break;
#ifndef CONFIG_SPL_BUILD
case ACLK_VOP:
ret = rk3568_aclk_vop_set_clk(priv, rate);
break;
case DCLK_VOP0:
case DCLK_VOP1:
case DCLK_VOP2:
ret = rk3568_dclk_vop_set_clk(priv, clk->id, rate);
break;
case SCLK_GMAC0:
case CLK_MAC0_2TOP:
case CLK_MAC0_REFOUT:
ret = rk3568_gmac_src_set_clk(priv, 0, rate);
break;
case CLK_MAC0_OUT:
ret = rk3568_gmac_out_set_clk(priv, 0, rate);
break;
case SCLK_GMAC0_RX_TX:
ret = rk3568_gmac_tx_rx_set_clk(priv, 0, rate);
break;
case CLK_GMAC0_PTP_REF:
ret = rk3568_gmac_ptp_ref_set_clk(priv, 0, rate);
break;
case SCLK_GMAC1:
case CLK_MAC1_2TOP:
case CLK_MAC1_REFOUT:
ret = rk3568_gmac_src_set_clk(priv, 1, rate);
break;
case CLK_MAC1_OUT:
ret = rk3568_gmac_out_set_clk(priv, 1, rate);
break;
case SCLK_GMAC1_RX_TX:
ret = rk3568_gmac_tx_rx_set_clk(priv, 1, rate);
break;
case CLK_GMAC1_PTP_REF:
ret = rk3568_gmac_ptp_ref_set_clk(priv, 1, rate);
break;
case DCLK_EBC:
ret = rk3568_ebc_set_clk(priv, rate);
break;
case ACLK_RKVDEC_PRE:
case ACLK_RKVDEC:
case CLK_RKVDEC_CORE:
ret = rk3568_rkvdec_set_clk(priv, clk->id, rate);
break;
case TCLK_WDT_NS:
ret = OSC_HZ;
break;
#endif
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 = rk3568_uart_set_rate(priv, clk->id, rate);
break;
case ACLK_SECURE_FLASH:
case ACLK_CRYPTO_NS:
case HCLK_SECURE_FLASH:
case HCLK_CRYPTO_NS:
case CLK_CRYPTO_NS_RNG:
case CLK_CRYPTO_NS_CORE:
case CLK_CRYPTO_NS_PKA:
ret = rk3568_crypto_set_rate(priv, clk->id, rate);
break;
case CPLL_500M:
case CPLL_333M:
case CPLL_250M:
case CPLL_125M:
case CPLL_100M:
case CPLL_62P5M:
case CPLL_50M:
case CPLL_25M:
ret = rk3568_cpll_div_set_rate(priv, clk->id, rate);
break;
default:
return -ENOENT;
}
return ret;
};
#if (IS_ENABLED(OF_CONTROL)) || (!IS_ENABLED(OF_PLATDATA))
static int rk3568_gmac0_src_set_parent(struct clk *clk, struct clk *parent)
{
struct rk3568_clk_priv *priv = dev_get_priv(clk->dev);
struct rk3568_cru *cru = priv->cru;
if (parent->id == CLK_MAC0_2TOP)
rk_clrsetreg(&cru->clksel_con[31],
RMII0_EXTCLK_SEL_MASK,
RMII0_EXTCLK_SEL_MAC0_TOP <<
RMII0_EXTCLK_SEL_SHIFT);
else
rk_clrsetreg(&cru->clksel_con[31],
RMII0_EXTCLK_SEL_MASK,
RMII0_EXTCLK_SEL_IO << RMII0_EXTCLK_SEL_SHIFT);
return 0;
}
static int rk3568_gmac1_src_set_parent(struct clk *clk, struct clk *parent)
{
struct rk3568_clk_priv *priv = dev_get_priv(clk->dev);
struct rk3568_cru *cru = priv->cru;
if (parent->id == CLK_MAC1_2TOP)
rk_clrsetreg(&cru->clksel_con[33],
RMII0_EXTCLK_SEL_MASK,
RMII0_EXTCLK_SEL_MAC0_TOP <<
RMII0_EXTCLK_SEL_SHIFT);
else
rk_clrsetreg(&cru->clksel_con[33],
RMII0_EXTCLK_SEL_MASK,
RMII0_EXTCLK_SEL_IO << RMII0_EXTCLK_SEL_SHIFT);
return 0;
}
static int rk3568_gmac0_tx_rx_set_parent(struct clk *clk, struct clk *parent)
{
struct rk3568_clk_priv *priv = dev_get_priv(clk->dev);
struct rk3568_cru *cru = priv->cru;
if (parent->id == SCLK_GMAC0_RGMII_SPEED)
rk_clrsetreg(&cru->clksel_con[31],
RMII0_MODE_MASK,
RMII0_MODE_SEL_RGMII << RMII0_MODE_SHIFT);
else if (parent->id == SCLK_GMAC0_RMII_SPEED)
rk_clrsetreg(&cru->clksel_con[31],
RMII0_MODE_MASK,
RMII0_MODE_SEL_RMII << RMII0_MODE_SHIFT);
else
rk_clrsetreg(&cru->clksel_con[31],
RMII0_MODE_MASK,
RMII0_MODE_SEL_GMII << RMII0_MODE_SHIFT);
return 0;
}
static int rk3568_gmac1_tx_rx_set_parent(struct clk *clk, struct clk *parent)
{
struct rk3568_clk_priv *priv = dev_get_priv(clk->dev);
struct rk3568_cru *cru = priv->cru;
if (parent->id == SCLK_GMAC1_RGMII_SPEED)
rk_clrsetreg(&cru->clksel_con[33],
RMII0_MODE_MASK,
RMII0_MODE_SEL_RGMII << RMII0_MODE_SHIFT);
else if (parent->id == SCLK_GMAC1_RMII_SPEED)
rk_clrsetreg(&cru->clksel_con[33],
RMII0_MODE_MASK,
RMII0_MODE_SEL_RMII << RMII0_MODE_SHIFT);
else
rk_clrsetreg(&cru->clksel_con[33],
RMII0_MODE_MASK,
RMII0_MODE_SEL_GMII << RMII0_MODE_SHIFT);
return 0;
}
static int rk3568_dclk_vop_set_parent(struct clk *clk, struct clk *parent)
{
struct rk3568_clk_priv *priv = dev_get_priv(clk->dev);
struct rk3568_cru *cru = priv->cru;
u32 con_id;
switch (clk->id) {
case DCLK_VOP0:
con_id = 39;
break;
case DCLK_VOP1:
con_id = 40;
break;
case DCLK_VOP2:
con_id = 41;
break;
default:
return -EINVAL;
}
if (parent->id == PLL_VPLL) {
rk_clrsetreg(&cru->clksel_con[con_id], DCLK0_VOP_SEL_MASK,
DCLK_VOP_SEL_VPLL << DCLK0_VOP_SEL_SHIFT);
} else if (parent->id == PLL_HPLL) {
rk_clrsetreg(&cru->clksel_con[con_id], DCLK0_VOP_SEL_MASK,
DCLK_VOP_SEL_HPLL << DCLK0_VOP_SEL_SHIFT);
} else if (parent->id == PLL_CPLL) {
rk_clrsetreg(&cru->clksel_con[con_id], DCLK0_VOP_SEL_MASK,
DCLK_VOP_SEL_CPLL << DCLK0_VOP_SEL_SHIFT);
} else {
rk_clrsetreg(&cru->clksel_con[con_id], DCLK0_VOP_SEL_MASK,
DCLK_VOP_SEL_GPLL << DCLK0_VOP_SEL_SHIFT);
}
return 0;
}
static int rk3568_rkvdec_set_parent(struct clk *clk, struct clk *parent)
{
struct rk3568_clk_priv *priv = dev_get_priv(clk->dev);
struct rk3568_cru *cru = priv->cru;
u32 con_id, mask, shift;
switch (clk->id) {
case ACLK_RKVDEC_PRE:
con_id = 47;
mask = ACLK_RKVDEC_SEL_MASK;
shift = ACLK_RKVDEC_SEL_SHIFT;
break;
case CLK_RKVDEC_CORE:
con_id = 49;
mask = CLK_RKVDEC_CORE_SEL_MASK;
shift = CLK_RKVDEC_CORE_SEL_SHIFT;
break;
default:
return -EINVAL;
}
if (parent->id == PLL_CPLL) {
rk_clrsetreg(&cru->clksel_con[con_id], mask,
ACLK_RKVDEC_SEL_CPLL << shift);
} else {
rk_clrsetreg(&cru->clksel_con[con_id], mask,
ACLK_RKVDEC_SEL_GPLL << shift);
}
return 0;
}
static int rk3568_clk_set_parent(struct clk *clk, struct clk *parent)
{
switch (clk->id) {
case SCLK_GMAC0:
return rk3568_gmac0_src_set_parent(clk, parent);
case SCLK_GMAC1:
return rk3568_gmac1_src_set_parent(clk, parent);
case SCLK_GMAC0_RX_TX:
return rk3568_gmac0_tx_rx_set_parent(clk, parent);
case SCLK_GMAC1_RX_TX:
return rk3568_gmac1_tx_rx_set_parent(clk, parent);
case DCLK_VOP0:
case DCLK_VOP1:
case DCLK_VOP2:
return rk3568_dclk_vop_set_parent(clk, parent);
case ACLK_RKVDEC_PRE:
case CLK_RKVDEC_CORE:
return rk3568_rkvdec_set_parent(clk, parent);
case I2S1_MCLKOUT_TX:
case SCLK_GMAC0_RGMII_SPEED:
case SCLK_GMAC0_RMII_SPEED:
case SCLK_GMAC1_RGMII_SPEED:
case SCLK_GMAC1_RMII_SPEED:
break;
default:
return -ENOENT;
}
return 0;
}
#endif
static struct clk_ops rk3568_clk_ops = {
.get_rate = rk3568_clk_get_rate,
.set_rate = rk3568_clk_set_rate,
#if (IS_ENABLED(OF_CONTROL)) || (!IS_ENABLED(OF_PLATDATA))
.set_parent = rk3568_clk_set_parent,
#endif
};
static void rk3568_clk_init(struct rk3568_clk_priv *priv)
{
int ret;
priv->sync_kernel = false;
if (!priv->armclk_enter_hz) {
priv->armclk_enter_hz =
rockchip_pll_get_rate(&rk3568_pll_clks[APLL],
priv->cru, APLL);
priv->armclk_init_hz = priv->armclk_enter_hz;
}
if (priv->armclk_init_hz != APLL_HZ) {
ret = rk3568_armclk_set_clk(priv, APLL_HZ);
if (!ret)
priv->armclk_init_hz = APLL_HZ;
}
if (priv->cpll_hz != CPLL_HZ) {
ret = rockchip_pll_set_rate(&rk3568_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(&rk3568_pll_clks[GPLL], priv->cru,
GPLL, GPLL_HZ);
if (!ret)
priv->gpll_hz = GPLL_HZ;
}
#ifdef CONFIG_SPL_BUILD
ret = rk3568_bus_set_clk(priv, ACLK_BUS, 150000000);
if (ret < 0)
printf("Fail to set the ACLK_BUS clock.\n");
#endif
priv->ppll_hz = rk3568_pmu_pll_get_rate(priv, PPLL);
priv->hpll_hz = rk3568_pmu_pll_get_rate(priv, HPLL);
}
static int rk3568_clk_probe(struct udevice *dev)
{
struct rk3568_clk_priv *priv = dev_get_priv(dev);
int ret;
priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
if (IS_ERR(priv->grf))
return PTR_ERR(priv->grf);
rk3568_clk_init(priv);
/* Process 'assigned-{clocks/clock-parents/clock-rates}' properties */
ret = clk_set_defaults(dev, 1);
if (ret)
debug("%s clk_set_defaults failed %d\n", __func__, ret);
else
priv->sync_kernel = true;
return 0;
}
static int rk3568_clk_ofdata_to_platdata(struct udevice *dev)
{
struct rk3568_clk_priv *priv = dev_get_priv(dev);
priv->cru = dev_read_addr_ptr(dev);
return 0;
}
static int rk3568_clk_bind(struct udevice *dev)
{
int ret;
struct udevice *sys_child;
struct sysreset_reg *priv;
/* 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 rk3568_cru,
glb_srst_fst);
priv->glb_srst_snd_value = offsetof(struct rk3568_cru,
glb_srsr_snd);
dev_set_priv(sys_child, priv);
}
#if CONFIG_IS_ENABLED(RESET_ROCKCHIP)
ret = offsetof(struct rk3568_cru, softrst_con[0]);
ret = rockchip_reset_bind(dev, ret, 30);
if (ret)
debug("Warning: software reset driver bind failed\n");
#endif
return 0;
}
static const struct udevice_id rk3568_clk_ids[] = {
{ .compatible = "rockchip,rk3568-cru" },
{ }
};
U_BOOT_DRIVER(rockchip_rk3568_cru) = {
.name = "rockchip_rk3568_cru",
.id = UCLASS_CLK,
.of_match = rk3568_clk_ids,
.priv_auto = sizeof(struct rk3568_clk_priv),
.of_to_plat = rk3568_clk_ofdata_to_platdata,
.ops = &rk3568_clk_ops,
.bind = rk3568_clk_bind,
.probe = rk3568_clk_probe,
#if CONFIG_IS_ENABLED(OF_PLATDATA)
.plat_auto = sizeof(struct rk3568_clk_plat),
#endif
};