[PATCH v1 2/7] clk: rockchip: rk3568: add i2s3 clk
Elaine Zhang
zhangqing at rock-chips.com
Tue Oct 10 10:51:50 CEST 2023
Change-Id: If20fe16260d2b584d4216d1dbabffcb25478fb1d
Signed-off-by: Elaine Zhang <zhangqing at rock-chips.com>
---
.../include/asm/arch-rockchip/cru_rk3568.h | 36 +++
drivers/clk/rockchip/clk_rk3568.c | 218 ++++++++++++++++++
2 files changed, 254 insertions(+)
diff --git a/arch/arm/include/asm/arch-rockchip/cru_rk3568.h b/arch/arm/include/asm/arch-rockchip/cru_rk3568.h
index 9c7ddd751f72..0306ce57e369 100644
--- a/arch/arm/include/asm/arch-rockchip/cru_rk3568.h
+++ b/arch/arm/include/asm/arch-rockchip/cru_rk3568.h
@@ -211,6 +211,31 @@ enum {
ACLK_PERIMID_SEL_100M,
ACLK_PERIMID_SEL_24M,
+ /* CRU_CLK_SEL21_CON */
+ I2S3_MCLKOUT_TX_SEL_SHIFT = 15,
+ I2S3_MCLKOUT_TX_SEL_MASK = 1 << I2S3_MCLKOUT_TX_SEL_SHIFT,
+ I2S3_MCLKOUT_TX_SEL_MCLK = 0,
+ I2S3_MCLKOUT_TX_SEL_12M,
+ CLK_I2S3_SEL_SHIFT = 10,
+ CLK_I2S3_SEL_MASK = 0x3 << CLK_I2S3_SEL_SHIFT,
+ CLK_I2S3_SEL_SRC = 0,
+ CLK_I2S3_SEL_FRAC,
+ CLK_I2S3_SEL_CLKIN,
+ CLK_I2S3_SEL_XIN12M,
+ CLK_I2S3_SRC_SEL_SHIFT = 8,
+ CLK_I2S3_SRC_SEL_MASK = 0x3 << CLK_I2S3_SRC_SEL_SHIFT,
+ CLK_I2S3_SRC_SEL_GPLL = 0,
+ CLK_I2S3_SRC_SEL_CPLL,
+ CLK_I2S3_SRC_SEL_NPLL,
+ CLK_I2S3_SRC_DIV_SHIFT = 0,
+ CLK_I2S3_SRC_DIV_MASK = 0x7f << CLK_I2S3_SRC_DIV_SHIFT,
+
+ /* CRU_CLK_SEL22_CON */
+ CLK_I2S3_FRAC_NUMERATOR_SHIFT = 16,
+ CLK_I2S3_FRAC_NUMERATOR_MASK = 0xffff << 16,
+ CLK_I2S3_FRAC_DENOMINATOR_SHIFT = 0,
+ CLK_I2S3_FRAC_DENOMINATOR_MASK = 0xffff,
+
/* CRU_CLK_SEL27_CON */
CLK_CRYPTO_PKA_SEL_SHIFT = 6,
CLK_CRYPTO_PKA_SEL_MASK = 3 << CLK_CRYPTO_PKA_SEL_SHIFT,
@@ -502,5 +527,16 @@ enum {
/* CRU_CLK_SEL82_CON */
CPLL_100M_DIV_SHIFT = 0,
CPLL_100M_DIV_MASK = 0x1f << CPLL_100M_DIV_SHIFT,
+
+ /* GRF_SOC_CON2 */
+ I2S3_MCLKOUT_SEL_SHIFT = 15,
+ I2S3_MCLKOUT_SEL_MASK = 0x1 << I2S3_MCLKOUT_SEL_SHIFT,
+ I2S3_MCLKOUT_SEL_RX = 0,
+ I2S3_MCLKOUT_SEL_TX,
+ I2S3_MCLK_IOE_SEL_SHIFT = 3,
+ I2S3_MCLK_IOE_SEL_MASK = 0x1 << I2S3_MCLK_IOE_SEL_SHIFT,
+ I2S3_MCLK_IOE_SEL_CLKIN = 0,
+ I2S3_MCLK_IOE_SEL_CLKOUT,
+
};
#endif
diff --git a/drivers/clk/rockchip/clk_rk3568.c b/drivers/clk/rockchip/clk_rk3568.c
index 599b7b130eb9..469014439be4 100644
--- a/drivers/clk/rockchip/clk_rk3568.c
+++ b/drivers/clk/rockchip/clk_rk3568.c
@@ -13,6 +13,7 @@
#include <asm/arch-rockchip/cru_rk3568.h>
#include <asm/arch-rockchip/clock.h>
#include <asm/arch-rockchip/hardware.h>
+#include <asm/arch-rockchip/grf_rk3568.h>
#include <asm/io.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
@@ -2326,6 +2327,170 @@ static ulong rk3568_uart_set_rate(struct rk3568_clk_priv *priv,
return rk3568_uart_get_rate(priv, clk_id);
}
+#ifndef CONFIG_SPL_BUILD
+static ulong rk3568_i2s3_get_rate(struct rk3568_clk_priv *priv, ulong clk_id)
+{
+ struct rk3568_cru *cru = priv->cru;
+ struct rk3568_grf *grf = priv->grf;
+ u32 con, div, src, p_rate;
+ u32 reg, fracdiv, p_src;
+ unsigned long m, n;
+
+ switch (clk_id) {
+ case I2S3_MCLKOUT_TX:
+ con = readl(&cru->clksel_con[21]);
+ src = (con & I2S3_MCLKOUT_TX_SEL_MASK) >>
+ I2S3_MCLKOUT_TX_SEL_SHIFT;
+ if (src == I2S3_MCLKOUT_TX_SEL_12M)
+ p_rate = 12000000;
+ else
+ p_rate = rk3568_i2s3_get_rate(priv, MCLK_I2S3_2CH_TX);
+ return p_rate;
+ case I2S3_MCLKOUT_RX:
+ con = readl(&cru->clksel_con[83]);
+ src = (con & I2S3_MCLKOUT_TX_SEL_MASK) >>
+ I2S3_MCLKOUT_TX_SEL_SHIFT;
+ if (src == I2S3_MCLKOUT_TX_SEL_12M)
+ p_rate = 12000000;
+ else
+ p_rate = rk3568_i2s3_get_rate(priv, MCLK_I2S3_2CH_RX);
+ return p_rate;
+ case I2S3_MCLKOUT:
+ con = readl(&grf->soc_con2);
+ src = (con & I2S3_MCLKOUT_SEL_MASK)
+ >> I2S3_MCLKOUT_SEL_SHIFT;
+ if (src == I2S3_MCLKOUT_SEL_RX)
+ p_rate = rk3568_i2s3_get_rate(priv, I2S3_MCLKOUT_RX);
+ else
+ p_rate = rk3568_i2s3_get_rate(priv, I2S3_MCLKOUT_TX);
+ return p_rate;
+ case MCLK_I2S3_2CH_RX:
+ reg = 83;
+ break;
+ case MCLK_I2S3_2CH_TX:
+ reg = 21;
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ con = readl(&cru->clksel_con[reg]);
+ src = (con & CLK_I2S3_SEL_MASK) >> CLK_I2S3_SEL_SHIFT;
+ div = (con & CLK_I2S3_SRC_DIV_MASK) >> CLK_I2S3_SRC_DIV_SHIFT;
+ p_src = (con & CLK_I2S3_SRC_SEL_MASK) >> CLK_I2S3_SRC_SEL_SHIFT;
+ if (p_src == CLK_I2S3_SRC_SEL_GPLL)
+ p_rate = priv->gpll_hz;
+ else if (p_src == CLK_I2S3_SRC_SEL_CPLL)
+ p_rate = priv->cpll_hz;
+ else
+ p_rate = priv->npll_hz;
+ if (src == CLK_I2S3_SEL_SRC) {
+ return DIV_TO_RATE(p_rate, div);
+ } else if (src == CLK_I2S3_SEL_FRAC) {
+ fracdiv = readl(&cru->clksel_con[reg + 1]);
+ n = fracdiv & CLK_I2S3_FRAC_NUMERATOR_MASK;
+ n >>= CLK_I2S3_FRAC_NUMERATOR_SHIFT;
+ m = fracdiv & CLK_I2S3_FRAC_DENOMINATOR_MASK;
+ m >>= CLK_I2S3_FRAC_DENOMINATOR_SHIFT;
+ return DIV_TO_RATE(p_rate, div) * n / m;
+ } else {
+ return OSC_HZ / 2;
+ }
+}
+
+static ulong rk3568_i2s3_set_rate(struct rk3568_clk_priv *priv,
+ ulong clk_id, ulong rate)
+{
+ struct rk3568_cru *cru = priv->cru;
+ struct rk3568_grf *grf = priv->grf;
+ u32 reg, con, clk_src, i2s_src, div;
+ unsigned long m = 0, n = 0, val;
+
+ if (priv->gpll_hz % rate == 0) {
+ clk_src = CLK_I2S3_SRC_SEL_GPLL;
+ i2s_src = CLK_I2S3_SEL_SRC;
+ div = DIV_ROUND_UP(priv->gpll_hz, rate);
+ } else if (priv->cpll_hz % rate == 0) {
+ clk_src = CLK_I2S3_SRC_SEL_CPLL;
+ i2s_src = CLK_I2S3_SEL_SRC;
+ div = DIV_ROUND_UP(priv->gpll_hz, rate);
+ } else if (rate == OSC_HZ / 2) {
+ clk_src = CLK_I2S3_SRC_SEL_GPLL;
+ i2s_src = CLK_I2S3_SEL_XIN12M;
+ div = 1;
+ } else {
+ clk_src = CLK_I2S3_SRC_SEL_GPLL;
+ i2s_src = CLK_I2S3_SEL_FRAC;
+ div = 1;
+ rational_best_approximation(rate, priv->gpll_hz / div,
+ GENMASK(16 - 1, 0),
+ GENMASK(16 - 1, 0),
+ &m, &n);
+ }
+
+ switch (clk_id) {
+ case I2S3_MCLKOUT_TX:
+ if (rate == 12000000) {
+ rk_clrsetreg(&cru->clksel_con[21],
+ I2S3_MCLKOUT_TX_SEL_MASK,
+ I2S3_MCLKOUT_TX_SEL_12M <<
+ I2S3_MCLKOUT_TX_SEL_SHIFT);
+ } else {
+ rk3568_i2s3_set_rate(priv, MCLK_I2S3_2CH_TX, rate),
+ rk_clrsetreg(&cru->clksel_con[21],
+ I2S3_MCLKOUT_TX_SEL_MASK,
+ I2S3_MCLKOUT_TX_SEL_MCLK <<
+ I2S3_MCLKOUT_TX_SEL_SHIFT);
+ }
+ return rk3568_i2s3_get_rate(priv, clk_id);
+ case I2S3_MCLKOUT_RX:
+ if (rate == 12000000) {
+ rk_clrsetreg(&cru->clksel_con[83],
+ I2S3_MCLKOUT_TX_SEL_MASK,
+ I2S3_MCLKOUT_TX_SEL_12M <<
+ I2S3_MCLKOUT_TX_SEL_SHIFT);
+ } else {
+ rk3568_i2s3_set_rate(priv, MCLK_I2S3_2CH_RX, rate),
+ rk_clrsetreg(&cru->clksel_con[21],
+ I2S3_MCLKOUT_TX_SEL_MASK,
+ I2S3_MCLKOUT_TX_SEL_MCLK <<
+ I2S3_MCLKOUT_TX_SEL_SHIFT);
+ }
+ return rk3568_i2s3_get_rate(priv, clk_id);
+ case I2S3_MCLKOUT:
+ con = readl(&grf->soc_con2);
+ clk_src = (con & I2S3_MCLKOUT_SEL_MASK)
+ >> I2S3_MCLKOUT_SEL_SHIFT;
+ if (clk_src == I2S3_MCLKOUT_SEL_RX)
+ rk3568_i2s3_set_rate(priv, I2S3_MCLKOUT_RX, rate);
+ else
+ rk3568_i2s3_set_rate(priv, I2S3_MCLKOUT_TX, rate);
+ return rk3568_i2s3_get_rate(priv, clk_id);
+ case MCLK_I2S3_2CH_RX:
+ reg = 83;
+ break;
+ case MCLK_I2S3_2CH_TX:
+ reg = 21;
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ rk_clrsetreg(&cru->clksel_con[reg],
+ CLK_I2S3_SEL_MASK | CLK_I2S3_SRC_SEL_MASK |
+ CLK_I2S3_SRC_DIV_MASK,
+ (clk_src << CLK_I2S3_SRC_SEL_SHIFT) |
+ (i2s_src << CLK_I2S3_SEL_SHIFT) |
+ ((div - 1) << CLK_I2S3_SRC_DIV_SHIFT));
+ if (m && n) {
+ val = m << CLK_I2S3_FRAC_NUMERATOR_SHIFT | n;
+ writel(val, &cru->clksel_con[reg + 1]);
+ }
+ return rk3568_i2s3_get_rate(priv, clk_id);
+}
+
+#endif
+
static ulong rk3568_clk_get_rate(struct clk *clk)
{
struct rk3568_clk_priv *priv = dev_get_priv(clk->dev);
@@ -2463,6 +2628,13 @@ static ulong rk3568_clk_get_rate(struct clk *clk)
case TCLK_WDT_NS:
rate = OSC_HZ;
break;
+ case I2S3_MCLKOUT_RX:
+ case I2S3_MCLKOUT_TX:
+ case MCLK_I2S3_2CH_RX:
+ case MCLK_I2S3_2CH_TX:
+ case I2S3_MCLKOUT:
+ rate = rk3568_i2s3_get_rate(priv, clk->id);
+ break;
#endif
case SCLK_UART1:
case SCLK_UART2:
@@ -2648,6 +2820,13 @@ static ulong rk3568_clk_set_rate(struct clk *clk, ulong rate)
case TCLK_WDT_NS:
ret = OSC_HZ;
break;
+ case I2S3_MCLKOUT_RX:
+ case I2S3_MCLKOUT_TX:
+ case MCLK_I2S3_2CH_RX:
+ case MCLK_I2S3_2CH_TX:
+ case I2S3_MCLKOUT:
+ ret = rk3568_i2s3_set_rate(priv, clk->id, rate);
+ break;
#endif
case SCLK_UART1:
case SCLK_UART2:
@@ -2824,6 +3003,42 @@ static int rk3568_rkvdec_set_parent(struct clk *clk, struct clk *parent)
return 0;
}
+static int __maybe_unused rk3568_i2s3_set_parent(struct clk *clk,
+ struct clk *parent)
+{
+ struct rk3568_clk_priv *priv = dev_get_priv(clk->dev);
+ struct rk3568_grf *grf = priv->grf;
+
+ switch (clk->id) {
+ case I2S3_MCLK_IOE:
+ if (parent->id == I2S3_MCLKOUT) {
+ rk_clrsetreg(&grf->soc_con2, I2S3_MCLK_IOE_SEL_MASK,
+ I2S3_MCLK_IOE_SEL_CLKOUT <<
+ I2S3_MCLK_IOE_SEL_SHIFT);
+ } else {
+ rk_clrsetreg(&grf->soc_con2, I2S3_MCLK_IOE_SEL_MASK,
+ I2S3_MCLK_IOE_SEL_CLKIN <<
+ I2S3_MCLK_IOE_SEL_SHIFT);
+ }
+ break;
+ case I2S3_MCLKOUT:
+ if (parent->id == I2S3_MCLKOUT_RX) {
+ rk_clrsetreg(&grf->soc_con2, I2S3_MCLKOUT_SEL_MASK,
+ I2S3_MCLKOUT_SEL_RX <<
+ I2S3_MCLKOUT_SEL_SHIFT);
+ } else {
+ rk_clrsetreg(&grf->soc_con2, I2S3_MCLKOUT_SEL_MASK,
+ I2S3_MCLKOUT_SEL_TX <<
+ I2S3_MCLKOUT_SEL_SHIFT);
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int rk3568_clk_set_parent(struct clk *clk, struct clk *parent)
{
switch (clk->id) {
@@ -2848,6 +3063,9 @@ static int rk3568_clk_set_parent(struct clk *clk, struct clk *parent)
case SCLK_GMAC1_RGMII_SPEED:
case SCLK_GMAC1_RMII_SPEED:
break;
+ case I2S3_MCLK_IOE:
+ case I2S3_MCLKOUT:
+ return rk3568_i2s3_set_parent(clk, parent);
default:
return -ENOENT;
}
--
2.17.1
More information about the U-Boot
mailing list