Merge tag 'block-5.11-2021-01-10' of git://git.kernel.dk/linux-block
[linux/fpc-iii.git] / drivers / gpu / drm / mcde / mcde_clk_div.c
blob038821d2ef8044ba1f2ae61636f22ed04ab30da7
1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/clk-provider.h>
3 #include <linux/regulator/consumer.h>
5 #include "mcde_drm.h"
6 #include "mcde_display_regs.h"
8 /* The MCDE internal clock dividers for FIFO A and B */
9 struct mcde_clk_div {
10 struct clk_hw hw;
11 struct mcde *mcde;
12 u32 cr;
13 u32 cr_div;
16 static int mcde_clk_div_enable(struct clk_hw *hw)
18 struct mcde_clk_div *cdiv = container_of(hw, struct mcde_clk_div, hw);
19 struct mcde *mcde = cdiv->mcde;
20 u32 val;
22 spin_lock(&mcde->fifo_crx1_lock);
23 val = readl(mcde->regs + cdiv->cr);
25 * Select the PLL72 (LCD) clock as parent
26 * FIXME: implement other parents.
28 val &= ~MCDE_CRX1_CLKSEL_MASK;
29 val |= MCDE_CRX1_CLKSEL_CLKPLL72 << MCDE_CRX1_CLKSEL_SHIFT;
30 /* Internal clock */
31 val |= MCDE_CRA1_CLKTYPE_TVXCLKSEL1;
33 /* Clear then set the divider */
34 val &= ~(MCDE_CRX1_BCD | MCDE_CRX1_PCD_MASK);
35 val |= cdiv->cr_div;
37 writel(val, mcde->regs + cdiv->cr);
38 spin_unlock(&mcde->fifo_crx1_lock);
40 return 0;
43 static int mcde_clk_div_choose_div(struct clk_hw *hw, unsigned long rate,
44 unsigned long *prate, bool set_parent)
46 int best_div = 1, div;
47 struct clk_hw *parent = clk_hw_get_parent(hw);
48 unsigned long best_prate = 0;
49 unsigned long best_diff = ~0ul;
50 int max_div = (1 << MCDE_CRX1_PCD_BITS) - 1;
52 for (div = 1; div < max_div; div++) {
53 unsigned long this_prate, div_rate, diff;
55 if (set_parent)
56 this_prate = clk_hw_round_rate(parent, rate * div);
57 else
58 this_prate = *prate;
59 div_rate = DIV_ROUND_UP_ULL(this_prate, div);
60 diff = abs(rate - div_rate);
62 if (diff < best_diff) {
63 best_div = div;
64 best_diff = diff;
65 best_prate = this_prate;
69 *prate = best_prate;
70 return best_div;
73 static long mcde_clk_div_round_rate(struct clk_hw *hw, unsigned long rate,
74 unsigned long *prate)
76 int div = mcde_clk_div_choose_div(hw, rate, prate, true);
78 return DIV_ROUND_UP_ULL(*prate, div);
81 static unsigned long mcde_clk_div_recalc_rate(struct clk_hw *hw,
82 unsigned long prate)
84 struct mcde_clk_div *cdiv = container_of(hw, struct mcde_clk_div, hw);
85 struct mcde *mcde = cdiv->mcde;
86 u32 cr;
87 int div;
90 * If the MCDE is not powered we can't access registers.
91 * It will come up with 0 in the divider register bits, which
92 * means "divide by 2".
94 if (!regulator_is_enabled(mcde->epod))
95 return DIV_ROUND_UP_ULL(prate, 2);
97 cr = readl(mcde->regs + cdiv->cr);
98 if (cr & MCDE_CRX1_BCD)
99 return prate;
101 /* 0 in the PCD means "divide by 2", 1 means "divide by 3" etc */
102 div = cr & MCDE_CRX1_PCD_MASK;
103 div += 2;
105 return DIV_ROUND_UP_ULL(prate, div);
108 static int mcde_clk_div_set_rate(struct clk_hw *hw, unsigned long rate,
109 unsigned long prate)
111 struct mcde_clk_div *cdiv = container_of(hw, struct mcde_clk_div, hw);
112 int div = mcde_clk_div_choose_div(hw, rate, &prate, false);
113 u32 cr = 0;
116 * We cache the CR bits to set the divide in the state so that
117 * we can call this before we can even write to the hardware.
119 if (div == 1) {
120 /* Bypass clock divider */
121 cr |= MCDE_CRX1_BCD;
122 } else {
123 div -= 2;
124 cr |= div & MCDE_CRX1_PCD_MASK;
126 cdiv->cr_div = cr;
128 return 0;
131 static const struct clk_ops mcde_clk_div_ops = {
132 .enable = mcde_clk_div_enable,
133 .recalc_rate = mcde_clk_div_recalc_rate,
134 .round_rate = mcde_clk_div_round_rate,
135 .set_rate = mcde_clk_div_set_rate,
138 int mcde_init_clock_divider(struct mcde *mcde)
140 struct device *dev = mcde->dev;
141 struct mcde_clk_div *fifoa;
142 struct mcde_clk_div *fifob;
143 const char *parent_name;
144 struct clk_init_data fifoa_init = {
145 .name = "fifoa",
146 .ops = &mcde_clk_div_ops,
147 .parent_names = &parent_name,
148 .num_parents = 1,
149 .flags = CLK_SET_RATE_PARENT,
151 struct clk_init_data fifob_init = {
152 .name = "fifob",
153 .ops = &mcde_clk_div_ops,
154 .parent_names = &parent_name,
155 .num_parents = 1,
156 .flags = CLK_SET_RATE_PARENT,
158 int ret;
160 spin_lock_init(&mcde->fifo_crx1_lock);
161 parent_name = __clk_get_name(mcde->lcd_clk);
163 /* Allocate 2 clocks */
164 fifoa = devm_kzalloc(dev, sizeof(*fifoa), GFP_KERNEL);
165 if (!fifoa)
166 return -ENOMEM;
167 fifob = devm_kzalloc(dev, sizeof(*fifob), GFP_KERNEL);
168 if (!fifob)
169 return -ENOMEM;
171 fifoa->mcde = mcde;
172 fifoa->cr = MCDE_CRA1;
173 fifoa->hw.init = &fifoa_init;
174 ret = devm_clk_hw_register(dev, &fifoa->hw);
175 if (ret) {
176 dev_err(dev, "error registering FIFO A clock divider\n");
177 return ret;
179 mcde->fifoa_clk = fifoa->hw.clk;
181 fifob->mcde = mcde;
182 fifob->cr = MCDE_CRB1;
183 fifob->hw.init = &fifob_init;
184 ret = devm_clk_hw_register(dev, &fifob->hw);
185 if (ret) {
186 dev_err(dev, "error registering FIFO B clock divider\n");
187 return ret;
189 mcde->fifob_clk = fifob->hw.clk;
191 return 0;