From 124c0977a0c8a7696c0c9fe93f675cf3cee2b368 Mon Sep 17 00:00:00 2001 From: Elaine Zhang Date: Wed, 6 May 2020 09:38:43 +0800 Subject: [PATCH] clk: rockchip: add a COMPOSITE_DCLK clock-type The CLK_SET_RATE_PARENT flag make the parent clock and the child clk is 1:1. If the DCLK frequency is too low, the PLL frequency will be very low, which will affect the output waveform quality of PLL, and PLL locking may be abnormal, so add a new COMPOSITE_DCLK clock-type to handle that. Change-Id: If9bee9ebf157fcf034aed246b3aa1cff503ef9cf Signed-off-by: Elaine Zhang --- drivers/clk/rockchip/Makefile | 1 + drivers/clk/rockchip/clk-dclk-divider.c | 6 ++-- drivers/clk/rockchip/clk.c | 10 +++++++ drivers/clk/rockchip/clk.h | 38 +++++++++++++++++++++++++ include/linux/clk-provider.h | 2 ++ 5 files changed, 54 insertions(+), 3 deletions(-) diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile index a99e4d9bbae1..c90f6a648bfd 100644 --- a/drivers/clk/rockchip/Makefile +++ b/drivers/clk/rockchip/Makefile @@ -13,6 +13,7 @@ clk-rockchip-y += clk-inverter.o clk-rockchip-y += clk-mmc-phase.o clk-rockchip-y += clk-muxgrf.o clk-rockchip-y += clk-ddr.o +clk-rockchip-y += clk-dclk-divider.o clk-rockchip-$(CONFIG_RESET_CONTROLLER) += softrst.o obj-$(CONFIG_CLK_PX30) += clk-px30.o diff --git a/drivers/clk/rockchip/clk-dclk-divider.c b/drivers/clk/rockchip/clk-dclk-divider.c index 88cf7ab82a57..77c35b42207e 100644 --- a/drivers/clk/rockchip/clk-dclk-divider.c +++ b/drivers/clk/rockchip/clk-dclk-divider.c @@ -18,7 +18,7 @@ static unsigned long clk_dclk_recalc_rate(struct clk_hw *hw, struct clk_divider *divider = to_clk_divider(hw); unsigned int val; - val = clk_readl(divider->reg) >> divider->shift; + val = readl(divider->reg) >> divider->shift; val &= div_mask(divider->width); return DIV_ROUND_UP_ULL(((u64)parent_rate), val + 1); @@ -57,11 +57,11 @@ static int clk_dclk_set_rate(struct clk_hw *hw, unsigned long rate, if (divider->flags & CLK_DIVIDER_HIWORD_MASK) { val = div_mask(divider->width) << (divider->shift + 16); } else { - val = clk_readl(divider->reg); + val = readl(divider->reg); val &= ~(div_mask(divider->width) << divider->shift); } val |= value << divider->shift; - clk_writel(val, divider->reg); + writel(val, divider->reg); if (divider->lock) spin_unlock_irqrestore(divider->lock, flags); diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c index 1248fec27116..70de8d32f700 100644 --- a/drivers/clk/rockchip/clk.c +++ b/drivers/clk/rockchip/clk.c @@ -588,6 +588,16 @@ void rockchip_clk_register_branches(struct rockchip_clk_provider *ctx, list->div_width, list->div_flags, ctx->reg_base, &ctx->lock); break; + case branch_dclk_divider: + clk = rockchip_clk_register_dclk_branch(list->name, + list->parent_names, list->num_parents, + ctx->reg_base, list->muxdiv_offset, list->mux_shift, + list->mux_width, list->mux_flags, + list->div_offset, list->div_shift, list->div_width, + list->div_flags, list->div_table, + list->gate_offset, list->gate_shift, + list->gate_flags, flags, list->max_prate, &ctx->lock); + break; } /* none of the cases above matched */ diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h index f4c8bceab018..ad2b6a446162 100644 --- a/drivers/clk/rockchip/clk.h +++ b/drivers/clk/rockchip/clk.h @@ -398,6 +398,7 @@ enum rockchip_clk_branch_type { branch_factor, branch_ddrclk, branch_half_divider, + branch_dclk_divider, }; struct rockchip_clk_branch { @@ -889,6 +890,28 @@ struct rockchip_clk_branch { .gate_offset = -1, \ } +#define COMPOSITE_DCLK(_id, cname, pnames, f, mo, ms, mw, mf, ds, dw,\ + df, go, gs, gf, prate) \ + { \ + .id = _id, \ + .branch_type = branch_dclk_divider, \ + .name = cname, \ + .parent_names = pnames, \ + .num_parents = ARRAY_SIZE(pnames), \ + .flags = f, \ + .muxdiv_offset = mo, \ + .mux_shift = ms, \ + .mux_width = mw, \ + .mux_flags = mf, \ + .div_shift = ds, \ + .div_width = dw, \ + .div_flags = df, \ + .gate_offset = go, \ + .gate_shift = gs, \ + .gate_flags = gf, \ + .max_prate = prate, \ + } + /* SGRF clocks are only accessible from secure mode, so not controllable */ #define SGRF_GATE(_id, cname, pname) \ FACTOR(_id, cname, pname, 0, 1, 1) @@ -928,6 +951,21 @@ struct clk *rockchip_clk_register_halfdiv(const char *name, u8 gate_flags, unsigned long flags, spinlock_t *lock); +struct clk *rockchip_clk_register_dclk_branch(const char *name, + const char *const *parent_names, + u8 num_parents, + void __iomem *base, + int muxdiv_offset, u8 mux_shift, + u8 mux_width, u8 mux_flags, + int div_offset, u8 div_shift, + u8 div_width, u8 div_flags, + struct clk_div_table *div_table, + int gate_offset, + u8 gate_shift, u8 gate_flags, + unsigned long flags, + unsigned long max_prate, + spinlock_t *lock); + #ifdef CONFIG_RESET_CONTROLLER void rockchip_register_softrst(struct device_node *np, unsigned int num_regs, diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 723f298c359b..1759bea2f18d 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -574,6 +574,7 @@ struct clk_div_table { * @reg: register containing the divider * @shift: shift to the divider bit field * @width: width of the divider bit field + * @max_prate: the maximum frequency of the parent clock * @table: array of value/divider pairs, last entry should have div = 0 * @lock: register lock * @@ -613,6 +614,7 @@ struct clk_divider { u8 shift; u8 width; u8 flags; + unsigned long max_prate; const struct clk_div_table *table; spinlock_t *lock; };