From a5969cabbb4660eab42b6ef0412cbbd1200cf14d Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Sat, 12 Oct 2024 07:10:09 +0000
Subject: [PATCH] 修改led为gpio
---
kernel/drivers/clk/rockchip/clk-pll.c | 562 +++++++++++++++++++++++++++++++++++++++++++++++++++-----
1 files changed, 511 insertions(+), 51 deletions(-)
diff --git a/kernel/drivers/clk/rockchip/clk-pll.c b/kernel/drivers/clk/rockchip/clk-pll.c
index 76cfad1..89ecdd0 100644
--- a/kernel/drivers/clk/rockchip/clk-pll.c
+++ b/kernel/drivers/clk/rockchip/clk-pll.c
@@ -1,19 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2014 MundoReader S.L.
* Author: Heiko Stuebner <heiko@sntech.de>
*
* Copyright (c) 2015 Rockchip Electronics Co. Ltd.
* Author: Xing Zheng <zhengxing@rock-chips.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <asm/div64.h>
@@ -122,6 +113,7 @@
return 0;
}
+EXPORT_SYMBOL(rockchip_pll_clk_adaptive_scaling);
int rockchip_pll_clk_rate_to_scale(struct clk *clk, unsigned long rate)
{
@@ -145,6 +137,7 @@
return -EINVAL;
}
+EXPORT_SYMBOL(rockchip_pll_clk_rate_to_scale);
int rockchip_pll_clk_scale_to_rate(struct clk *clk, unsigned int scale)
{
@@ -168,6 +161,7 @@
return -EINVAL;
}
+EXPORT_SYMBOL(rockchip_pll_clk_scale_to_rate);
static struct rockchip_pll_rate_table *rk_pll_rate_table_get(void)
{
@@ -338,6 +332,109 @@
return rate_table;
}
+static u32
+rockchip_rk3588_pll_frac_get(u32 m, u32 p, u32 s, u64 fin_hz, u64 fvco)
+{
+ u64 fref, fout, ffrac;
+ u32 k = 0;
+
+ fref = fin_hz / p;
+ ffrac = fvco - (m * fref);
+ fout = ffrac * 65536;
+ k = fout / fref;
+ if (k > 32767) {
+ fref = fin_hz / p;
+ ffrac = ((m + 1) * fref) - fvco;
+ fout = ffrac * 65536;
+ k = ((fout * 10 / fref) + 7) / 10;
+ if (k > 32767)
+ k = 0;
+ else
+ k = ~k + 1;
+ }
+ return k;
+}
+
+static struct rockchip_pll_rate_table *
+rockchip_rk3588_pll_frac_by_auto(unsigned long fin_hz, unsigned long fout_hz)
+{
+ struct rockchip_pll_rate_table *rate_table = rk_pll_rate_table_get();
+ u64 fvco_min = 2250 * MHZ, fvco_max = 4500 * MHZ;
+ u32 p, m, s, k;
+ u64 fvco;
+
+ for (s = 0; s <= 6; s++) {
+ fvco = (u64)fout_hz << s;
+ if (fvco < fvco_min || fvco > fvco_max)
+ continue;
+ for (p = 1; p <= 4; p++) {
+ for (m = 64; m <= 1023; m++) {
+ if ((fvco >= m * fin_hz / p) && (fvco < (m + 1) * fin_hz / p)) {
+ k = rockchip_rk3588_pll_frac_get(m, p, s,
+ (u64)fin_hz,
+ fvco);
+ if (!k)
+ continue;
+ rate_table->p = p;
+ rate_table->s = s;
+ rate_table->k = k;
+ if (k > 32767)
+ rate_table->m = m + 1;
+ else
+ rate_table->m = m;
+ return rate_table;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+static struct rockchip_pll_rate_table *
+rockchip_rk3588_pll_clk_set_by_auto(struct rockchip_clk_pll *pll,
+ unsigned long fin_hz,
+ unsigned long fout_hz)
+{
+ struct rockchip_pll_rate_table *rate_table = rk_pll_rate_table_get();
+ u64 fvco_min = 2250 * MHZ, fvco_max = 4500 * MHZ;
+ u64 fout_min = 37 * MHZ, fout_max = 4500 * MHZ;
+ u32 p, m, s;
+ u64 fvco;
+
+ if (fin_hz == 0 || fout_hz == 0 || fout_hz == fin_hz)
+ return NULL;
+
+ if (fout_hz > fout_max || fout_hz < fout_min)
+ return NULL;
+
+ if (fin_hz / MHZ * MHZ == fin_hz && fout_hz / MHZ * MHZ == fout_hz) {
+ for (s = 0; s <= 6; s++) {
+ fvco = (u64)fout_hz << s;
+ if (fvco < fvco_min || fvco > fvco_max)
+ continue;
+ for (p = 2; p <= 4; p++) {
+ for (m = 64; m <= 1023; m++) {
+ if (fvco == m * fin_hz / p) {
+ rate_table->p = p;
+ rate_table->m = m;
+ rate_table->s = s;
+ rate_table->k = 0;
+ return rate_table;
+ }
+ }
+ }
+ }
+ pr_err("CANNOT FIND Fout by auto,fout = %lu\n", fout_hz);
+ } else {
+ rate_table = rockchip_rk3588_pll_frac_by_auto(fin_hz, fout_hz);
+ if (!rate_table)
+ pr_err("CANNOT FIND Fout by auto,fout = %lu\n", fout_hz);
+ else
+ return rate_table;
+ }
+ return NULL;
+}
+
static const struct rockchip_pll_rate_table *rockchip_get_pll_settings(
struct rockchip_clk_pll *pll, unsigned long rate)
{
@@ -358,6 +455,8 @@
if (pll->type == pll_rk3066)
return rockchip_rk3066_pll_clk_set_by_auto(pll, 24 * MHZ, rate);
+ else if (pll->type == pll_rk3588 || pll->type == pll_rk3588_core)
+ return rockchip_rk3588_pll_clk_set_by_auto(pll, 24 * MHZ, rate);
else
return rockchip_pll_clk_set_by_auto(pll, 24 * MHZ, rate);
}
@@ -591,10 +690,14 @@
static int rockchip_rk3036_pll_enable(struct clk_hw *hw)
{
struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
+ const struct clk_ops *pll_mux_ops = pll->pll_mux_ops;
+ struct clk_mux *pll_mux = &pll->pll_mux;
writel(HIWORD_UPDATE(0, RK3036_PLLCON1_PWRDOWN, 0),
pll->reg_base + RK3036_PLLCON(1));
rockchip_rk3036_pll_wait_lock(pll);
+
+ pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_NORM);
return 0;
}
@@ -602,6 +705,10 @@
static void rockchip_rk3036_pll_disable(struct clk_hw *hw)
{
struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
+ const struct clk_ops *pll_mux_ops = pll->pll_mux_ops;
+ struct clk_mux *pll_mux = &pll->pll_mux;
+
+ pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_SLOW);
writel(HIWORD_UPDATE(RK3036_PLLCON1_PWRDOWN,
RK3036_PLLCON1_PWRDOWN, 0),
@@ -616,7 +723,7 @@
return !(pllcon & RK3036_PLLCON1_PWRDOWN);
}
-static void rockchip_rk3036_pll_init(struct clk_hw *hw)
+static int rockchip_rk3036_pll_init(struct clk_hw *hw)
{
struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
const struct rockchip_pll_rate_table *rate;
@@ -624,14 +731,14 @@
unsigned long drate;
if (!(pll->flags & ROCKCHIP_PLL_SYNC_RATE))
- return;
+ return 0;
drate = clk_hw_get_rate(hw);
rate = rockchip_get_pll_settings(pll, drate);
/* when no rate setting for the current rate, rely on clk_set_rate */
if (!rate)
- return;
+ return 0;
rockchip_rk3036_pll_get_params(pll, &cur);
@@ -653,13 +760,15 @@
if (!parent) {
pr_warn("%s: parent of %s not available\n",
__func__, __clk_get_name(hw->clk));
- return;
+ return 0;
}
pr_debug("%s: pll %s: rate params do not match rate table, adjusting\n",
__func__, __clk_get_name(hw->clk));
rockchip_rk3036_pll_set_params(pll, rate);
}
+
+ return 0;
}
static const struct clk_ops rockchip_rk3036_pll_clk_norate_ops = {
@@ -865,7 +974,7 @@
return !(pllcon & RK3066_PLLCON3_PWRDOWN);
}
-static void rockchip_rk3066_pll_init(struct clk_hw *hw)
+static int rockchip_rk3066_pll_init(struct clk_hw *hw)
{
struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
const struct rockchip_pll_rate_table *rate;
@@ -873,14 +982,14 @@
unsigned long drate;
if (!(pll->flags & ROCKCHIP_PLL_SYNC_RATE))
- return;
+ return 0;
drate = clk_hw_get_rate(hw);
rate = rockchip_get_pll_settings(pll, drate);
/* when no rate setting for the current rate, rely on clk_set_rate */
if (!rate)
- return;
+ return 0;
rockchip_rk3066_pll_get_params(pll, &cur);
@@ -893,6 +1002,8 @@
__func__, clk_hw_get_name(hw));
rockchip_rk3066_pll_set_params(pll, rate);
}
+
+ return 0;
}
static const struct clk_ops rockchip_rk3066_pll_clk_norate_ops = {
@@ -1131,7 +1242,7 @@
return !(pllcon & RK3399_PLLCON3_PWRDOWN);
}
-static void rockchip_rk3399_pll_init(struct clk_hw *hw)
+static int rockchip_rk3399_pll_init(struct clk_hw *hw)
{
struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
const struct rockchip_pll_rate_table *rate;
@@ -1139,14 +1250,14 @@
unsigned long drate;
if (!(pll->flags & ROCKCHIP_PLL_SYNC_RATE))
- return;
+ return 0;
drate = clk_hw_get_rate(hw);
rate = rockchip_get_pll_settings(pll, drate);
/* when no rate setting for the current rate, rely on clk_set_rate */
if (!rate)
- return;
+ return 0;
rockchip_rk3399_pll_get_params(pll, &cur);
@@ -1168,13 +1279,15 @@
if (!parent) {
pr_warn("%s: parent of %s not available\n",
__func__, __clk_get_name(hw->clk));
- return;
+ return 0;
}
pr_debug("%s: pll %s: rate params do not match rate table, adjusting\n",
__func__, __clk_get_name(hw->clk));
rockchip_rk3399_pll_set_params(pll, rate);
}
+
+ return 0;
}
static const struct clk_ops rockchip_rk3399_pll_clk_norate_ops = {
@@ -1194,12 +1307,269 @@
.init = rockchip_rk3399_pll_init,
};
+/**
+ * PLL used in RK3588
+ */
+
+#define RK3588_PLLCON(i) (i * 0x4)
+#define RK3588_PLLCON0_M_MASK 0x3ff
+#define RK3588_PLLCON0_M_SHIFT 0
+#define RK3588_PLLCON1_P_MASK 0x3f
+#define RK3588_PLLCON1_P_SHIFT 0
+#define RK3588_PLLCON1_S_MASK 0x7
+#define RK3588_PLLCON1_S_SHIFT 6
+#define RK3588_PLLCON2_K_MASK 0xffff
+#define RK3588_PLLCON2_K_SHIFT 0
+#define RK3588_PLLCON1_PWRDOWN BIT(13)
+#define RK3588_PLLCON6_LOCK_STATUS BIT(15)
+
+static int rockchip_rk3588_pll_wait_lock(struct rockchip_clk_pll *pll)
+{
+ u32 pllcon;
+ int ret;
+
+ /*
+ * Lock time typical 250, max 500 input clock cycles @24MHz
+ * So define a very safe maximum of 1000us, meaning 24000 cycles.
+ */
+ ret = readl_relaxed_poll_timeout(pll->reg_base + RK3588_PLLCON(6),
+ pllcon,
+ pllcon & RK3588_PLLCON6_LOCK_STATUS,
+ 0, 1000);
+ if (ret)
+ pr_err("%s: timeout waiting for pll to lock\n", __func__);
+
+ return ret;
+}
+
+static long rockchip_rk3588_pll_round_rate(struct clk_hw *hw,
+ unsigned long drate, unsigned long *prate)
+{
+ if ((drate < 37 * MHZ) || (drate > 4500 * MHZ))
+ return -EINVAL;
+ else
+ return drate;
+}
+
+static void rockchip_rk3588_pll_get_params(struct rockchip_clk_pll *pll,
+ struct rockchip_pll_rate_table *rate)
+{
+ u32 pllcon;
+
+ pllcon = readl_relaxed(pll->reg_base + RK3588_PLLCON(0));
+ rate->m = ((pllcon >> RK3588_PLLCON0_M_SHIFT)
+ & RK3588_PLLCON0_M_MASK);
+
+ pllcon = readl_relaxed(pll->reg_base + RK3588_PLLCON(1));
+ rate->p = ((pllcon >> RK3588_PLLCON1_P_SHIFT)
+ & RK3588_PLLCON1_P_MASK);
+ rate->s = ((pllcon >> RK3588_PLLCON1_S_SHIFT)
+ & RK3588_PLLCON1_S_MASK);
+
+ pllcon = readl_relaxed(pll->reg_base + RK3588_PLLCON(2));
+ rate->k = ((pllcon >> RK3588_PLLCON2_K_SHIFT)
+ & RK3588_PLLCON2_K_MASK);
+}
+
+static unsigned long rockchip_rk3588_pll_recalc_rate(struct clk_hw *hw,
+ unsigned long prate)
+{
+ struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
+ struct rockchip_pll_rate_table cur;
+ u64 rate64 = prate, postdiv;
+
+ if (pll->sel && pll->scaling)
+ return pll->scaling;
+
+ rockchip_rk3588_pll_get_params(pll, &cur);
+ if (cur.p == 0)
+ return prate;
+
+ rate64 *= cur.m;
+ do_div(rate64, cur.p);
+
+ if (cur.k & BIT(15)) {
+ /* fractional mode */
+ u64 frac_rate64;
+
+ cur.k = (~(cur.k - 1)) & RK3588_PLLCON2_K_MASK;
+ frac_rate64 = prate * cur.k;
+ postdiv = cur.p;
+ postdiv *= 65536;
+ do_div(frac_rate64, postdiv);
+ rate64 -= frac_rate64;
+ } else {
+ /* fractional mode */
+ u64 frac_rate64 = prate * cur.k;
+
+ postdiv = cur.p;
+ postdiv *= 65536;
+ do_div(frac_rate64, postdiv);
+ rate64 += frac_rate64;
+ }
+ rate64 = rate64 >> cur.s;
+
+ return (unsigned long)rate64;
+}
+
+static int rockchip_rk3588_pll_set_params(struct rockchip_clk_pll *pll,
+ const struct rockchip_pll_rate_table *rate)
+{
+ const struct clk_ops *pll_mux_ops = pll->pll_mux_ops;
+ struct clk_mux *pll_mux = &pll->pll_mux;
+ struct rockchip_pll_rate_table cur;
+ int rate_change_remuxed = 0;
+ int cur_parent;
+ int ret;
+
+ pr_debug("%s: rate settings for %lu p: %d, m: %d, s: %d, k: %d\n",
+ __func__, rate->rate, rate->p, rate->m, rate->s, rate->k);
+
+ rockchip_rk3588_pll_get_params(pll, &cur);
+ cur.rate = 0;
+
+ if (pll->type == pll_rk3588) {
+ cur_parent = pll_mux_ops->get_parent(&pll_mux->hw);
+ if (cur_parent == PLL_MODE_NORM) {
+ pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_SLOW);
+ rate_change_remuxed = 1;
+ }
+ }
+
+ /* set pll power down */
+ writel(HIWORD_UPDATE(RK3588_PLLCON1_PWRDOWN,
+ RK3588_PLLCON1_PWRDOWN, 0),
+ pll->reg_base + RK3588_PLLCON(1));
+
+ /* update pll values */
+ writel_relaxed(HIWORD_UPDATE(rate->m, RK3588_PLLCON0_M_MASK,
+ RK3588_PLLCON0_M_SHIFT),
+ pll->reg_base + RK3588_PLLCON(0));
+
+ writel_relaxed(HIWORD_UPDATE(rate->p, RK3588_PLLCON1_P_MASK,
+ RK3588_PLLCON1_P_SHIFT) |
+ HIWORD_UPDATE(rate->s, RK3588_PLLCON1_S_MASK,
+ RK3588_PLLCON1_S_SHIFT),
+ pll->reg_base + RK3588_PLLCON(1));
+
+ writel_relaxed(HIWORD_UPDATE(rate->k, RK3588_PLLCON2_K_MASK,
+ RK3588_PLLCON2_K_SHIFT),
+ pll->reg_base + RK3588_PLLCON(2));
+
+ /* set pll power up */
+ writel(HIWORD_UPDATE(0,
+ RK3588_PLLCON1_PWRDOWN, 0),
+ pll->reg_base + RK3588_PLLCON(1));
+
+ /* wait for the pll to lock */
+ ret = rockchip_rk3588_pll_wait_lock(pll);
+ if (ret) {
+ pr_warn("%s: pll update unsuccessful, trying to restore old params\n",
+ __func__);
+ rockchip_rk3588_pll_set_params(pll, &cur);
+ }
+
+ if ((pll->type == pll_rk3588) && rate_change_remuxed)
+ pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_NORM);
+
+ return ret;
+}
+
+static int rockchip_rk3588_pll_set_rate(struct clk_hw *hw, unsigned long drate,
+ unsigned long prate)
+{
+ struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
+ const struct rockchip_pll_rate_table *rate;
+ unsigned long old_rate = rockchip_rk3588_pll_recalc_rate(hw, prate);
+ int ret;
+
+ pr_debug("%s: changing %s from %lu to %lu with a parent rate of %lu\n",
+ __func__, __clk_get_name(hw->clk), old_rate, drate, prate);
+
+ /* Get required rate settings from table */
+ rate = rockchip_get_pll_settings(pll, drate);
+ if (!rate) {
+ pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
+ drate, __clk_get_name(hw->clk));
+ return -EINVAL;
+ }
+
+ ret = rockchip_rk3588_pll_set_params(pll, rate);
+ if (ret)
+ pll->scaling = 0;
+
+ return ret;
+}
+
+static int rockchip_rk3588_pll_enable(struct clk_hw *hw)
+{
+ struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
+ const struct clk_ops *pll_mux_ops = pll->pll_mux_ops;
+ struct clk_mux *pll_mux = &pll->pll_mux;
+
+ writel(HIWORD_UPDATE(0, RK3588_PLLCON1_PWRDOWN, 0),
+ pll->reg_base + RK3588_PLLCON(1));
+ rockchip_rk3588_pll_wait_lock(pll);
+
+ pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_NORM);
+
+ return 0;
+}
+
+static void rockchip_rk3588_pll_disable(struct clk_hw *hw)
+{
+ struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
+ const struct clk_ops *pll_mux_ops = pll->pll_mux_ops;
+ struct clk_mux *pll_mux = &pll->pll_mux;
+
+ pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_SLOW);
+
+ writel(HIWORD_UPDATE(RK3588_PLLCON1_PWRDOWN,
+ RK3588_PLLCON1_PWRDOWN, 0),
+ pll->reg_base + RK3588_PLLCON(1));
+}
+
+static int rockchip_rk3588_pll_is_enabled(struct clk_hw *hw)
+{
+ struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
+ u32 pllcon = readl(pll->reg_base + RK3588_PLLCON(1));
+
+ return !(pllcon & RK3588_PLLCON1_PWRDOWN);
+}
+
+static int rockchip_rk3588_pll_init(struct clk_hw *hw)
+{
+ struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
+
+ if (!(pll->flags & ROCKCHIP_PLL_SYNC_RATE))
+ return 0;
+
+ return 0;
+}
+
+static const struct clk_ops rockchip_rk3588_pll_clk_norate_ops = {
+ .recalc_rate = rockchip_rk3588_pll_recalc_rate,
+ .enable = rockchip_rk3588_pll_enable,
+ .disable = rockchip_rk3588_pll_disable,
+ .is_enabled = rockchip_rk3588_pll_is_enabled,
+};
+
+static const struct clk_ops rockchip_rk3588_pll_clk_ops = {
+ .recalc_rate = rockchip_rk3588_pll_recalc_rate,
+ .round_rate = rockchip_rk3588_pll_round_rate,
+ .set_rate = rockchip_rk3588_pll_set_rate,
+ .enable = rockchip_rk3588_pll_enable,
+ .disable = rockchip_rk3588_pll_disable,
+ .is_enabled = rockchip_rk3588_pll_is_enabled,
+ .init = rockchip_rk3588_pll_init,
+};
+
#ifdef CONFIG_ROCKCHIP_CLK_COMPENSATION
int rockchip_pll_clk_compensation(struct clk *clk, int ppm)
{
struct clk *parent = clk_get_parent(clk);
struct rockchip_clk_pll *pll;
- static u32 frac, fbdiv;
+ static u32 frac, fbdiv, s, p;
bool negative;
u32 pllcon, pllcon0, pllcon2, fbdiv_mask, frac_mask, frac_shift;
u64 fracdiv, m, n;
@@ -1236,6 +1606,13 @@
frac_mask = RK3399_PLLCON2_FRAC_MASK;
frac_shift = RK3399_PLLCON2_FRAC_SHIFT;
break;
+ case pll_rk3588:
+ pllcon0 = RK3588_PLLCON(0);
+ pllcon2 = RK3588_PLLCON(2);
+ fbdiv_mask = RK3588_PLLCON0_M_MASK;
+ frac_mask = RK3588_PLLCON2_K_MASK;
+ frac_shift = RK3588_PLLCON2_K_SHIFT;
+ break;
default:
return -EINVAL;
}
@@ -1243,29 +1620,101 @@
negative = !!(ppm & BIT(31));
ppm = negative ? ~ppm + 1 : ppm;
- if (!frac) {
- frac = readl_relaxed(pll->reg_base + pllcon2) & frac_mask;
- fbdiv = readl_relaxed(pll->reg_base + pllcon0) & fbdiv_mask;
- }
+ switch (pll->type) {
+ case pll_rk3036:
+ case pll_rk3328:
+ case pll_rk3066:
+ case pll_rk3399:
+ /*
+ * delta frac frac ppm
+ * -------------- = (fbdiv + ----------) * ---------
+ * 1 << 24 1 << 24 1000000
+ *
+ */
+ if (!frac) {
+ frac = readl_relaxed(pll->reg_base + pllcon2) & frac_mask;
+ fbdiv = readl_relaxed(pll->reg_base + pllcon0) & fbdiv_mask;
+ }
+ m = div64_u64((uint64_t)frac * ppm, 1000000);
+ n = div64_u64((uint64_t)ppm << 24, 1000000) * fbdiv;
- /*
- * delta frac frac ppm
- * -------------- = (fbdiv + ----------) * ---------
- * 1 << 24 1 << 24 1000000
- *
- */
- m = div64_u64((uint64_t)frac * ppm, 1000000);
- n = div64_u64((uint64_t)ppm << 24, 1000000) * fbdiv;
+ fracdiv = negative ? frac - (m + n) : frac + (m + n);
- fracdiv = negative ? frac - (m + n) : frac + (m + n);
+ if (!frac || fracdiv > frac_mask)
+ return -EINVAL;
- if (!frac || fracdiv > frac_mask)
+ pllcon = readl_relaxed(pll->reg_base + pllcon2);
+ pllcon &= ~(frac_mask << frac_shift);
+ pllcon |= fracdiv << frac_shift;
+ writel_relaxed(pllcon, pll->reg_base + pllcon2);
+ break;
+ case pll_rk3588:
+ if (!fbdiv) {
+ frac = readl_relaxed(pll->reg_base + pllcon2) & frac_mask;
+ fbdiv = readl_relaxed(pll->reg_base + pllcon0) & fbdiv_mask;
+ }
+ if (!frac) {
+ pllcon = readl_relaxed(pll->reg_base + RK3588_PLLCON(1));
+ s = ((pllcon >> RK3588_PLLCON1_S_SHIFT)
+ & RK3588_PLLCON1_S_MASK);
+ p = ((pllcon >> RK3588_PLLCON1_P_SHIFT)
+ & RK3588_PLLCON1_P_MASK);
+ m = div64_u64((uint64_t)clk_get_rate(clk) * ppm, 24000000);
+ n = div64_u64((uint64_t)m * 65536 * p * (1 << s), 1000000);
+
+ if (n > 32767)
+ return -EINVAL;
+ fracdiv = negative ? ~n + 1 : n;
+ } else if (frac & BIT(15)) {
+ frac = (~(frac - 1)) & RK3588_PLLCON2_K_MASK;
+ m = div64_u64((uint64_t)frac * ppm, 100000);
+ n = div64_u64((uint64_t)ppm * 65536 * fbdiv, 100000);
+ if (negative) {
+ fracdiv = frac + (div64_u64(m + n, 10));
+ if (fracdiv > 32767)
+ return -EINVAL;
+ fracdiv = ~fracdiv + 1;
+ } else {
+ s = div64_u64(m + n, 10);
+ if (frac >= s) {
+ fracdiv = frac - s;
+ if (fracdiv > 32767)
+ return -EINVAL;
+ fracdiv = ~fracdiv + 1;
+ } else {
+ fracdiv = s - frac;
+ if (fracdiv > 32767)
+ return -EINVAL;
+ }
+ }
+ } else {
+ m = div64_u64((uint64_t)frac * ppm, 100000);
+ n = div64_u64((uint64_t)ppm * 65536 * fbdiv, 100000);
+ if (!negative) {
+ fracdiv = frac + (div64_u64(m + n, 10));
+ if (fracdiv > 32767)
+ return -EINVAL;
+ } else {
+ s = div64_u64(m + n, 10);
+ if (frac >= s) {
+ fracdiv = frac - s;
+ if (fracdiv > 32767)
+ return -EINVAL;
+ } else {
+ fracdiv = s - frac;
+ if (fracdiv > 32767)
+ return -EINVAL;
+ fracdiv = ~fracdiv + 1;
+ }
+ }
+ }
+
+ writel_relaxed(HIWORD_UPDATE(fracdiv, frac_mask, frac_shift),
+ pll->reg_base + pllcon2);
+ break;
+ default:
return -EINVAL;
-
- pllcon = readl_relaxed(pll->reg_base + pllcon2);
- pllcon &= ~(frac_mask << frac_shift);
- pllcon |= fracdiv << frac_shift;
- writel_relaxed(pllcon, pll->reg_base + pllcon2);
+ }
return 0;
}
@@ -1285,7 +1734,7 @@
unsigned long flags, u8 clk_pll_flags)
{
const char *pll_parents[3];
- struct clk_init_data init = {};
+ struct clk_init_data init;
struct rockchip_clk_pll *pll;
struct clk_mux *pll_mux;
struct clk *pll_clk, *mux_clk;
@@ -1316,12 +1765,7 @@
pll_mux->flags = 0;
pll_mux->lock = &ctx->lock;
pll_mux->hw.init = &init;
-
- if (pll_type == pll_rk3036 ||
- pll_type == pll_rk3066 ||
- pll_type == pll_rk3328 ||
- pll_type == pll_rk3399)
- pll_mux->flags |= CLK_MUX_HIWORD_MASK;
+ pll_mux->flags |= CLK_MUX_HIWORD_MASK;
/* the actual muxing is xin24m, pll-output, xin32k */
pll_parents[0] = parent_names[0];
@@ -1345,8 +1789,11 @@
init.name = pll_name;
#ifndef CONFIG_ROCKCHIP_LOW_PERFORMANCE
- /* keep all plls untouched for now */
- init.flags = flags | CLK_IGNORE_UNUSED;
+ if (clk_pll_flags & ROCKCHIP_PLL_ALLOW_POWER_DOWN)
+ init.flags = flags;
+ else
+ /* keep all plls untouched for now */
+ init.flags = flags | CLK_IGNORE_UNUSED;
#else
init.flags = flags;
#endif
@@ -1374,7 +1821,7 @@
switch (pll_type) {
case pll_rk3036:
case pll_rk3328:
- if (!pll->rate_table || IS_ERR(ctx->grf))
+ if (!pll->rate_table)
init.ops = &rockchip_rk3036_pll_clk_norate_ops;
else
init.ops = &rockchip_rk3036_pll_clk_ops;
@@ -1393,6 +1840,16 @@
init.ops = &rockchip_rk3399_pll_clk_norate_ops;
else
init.ops = &rockchip_rk3399_pll_clk_ops;
+ break;
+#endif
+#ifdef CONFIG_ROCKCHIP_PLL_RK3588
+ case pll_rk3588:
+ case pll_rk3588_core:
+ if (!pll->rate_table)
+ init.ops = &rockchip_rk3588_pll_clk_norate_ops;
+ else
+ init.ops = &rockchip_rk3588_pll_clk_ops;
+ init.flags = flags;
break;
#endif
default:
@@ -1419,6 +1876,7 @@
return mux_clk;
err_pll:
+ kfree(pll->rate_table);
clk_unregister(mux_clk);
mux_clk = pll_clk;
err_mux:
@@ -1619,6 +2077,7 @@
#ifdef CONFIG_DEBUG_FS
#include <linux/debugfs.h>
+#ifndef MODULE
static int boost_summary_show(struct seq_file *s, void *data)
{
struct rockchip_clk_pll *pll = (struct rockchip_clk_pll *)s->private;
@@ -1736,5 +2195,6 @@
return 0;
}
late_initcall(boost_debug_init);
+#endif /* MODULE */
#endif /* CONFIG_DEBUG_FS */
#endif /* CONFIG_ROCKCHIP_CLK_BOOST */
--
Gitblit v1.6.2