1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/clk-provider.h>
3 #include <linux/io.h>
4 #include <linux/regulator/consumer.h>
5
6 #include "mcde_drm.h"
7 #include "mcde_display_regs.h"
8
9 /* The MCDE internal clock dividers for FIFO A and B */
10 struct mcde_clk_div {
11 struct clk_hw hw;
12 struct mcde *mcde;
13 u32 cr;
14 u32 cr_div;
15 };
16
mcde_clk_div_enable(struct clk_hw * hw)17 static int mcde_clk_div_enable(struct clk_hw *hw)
18 {
19 struct mcde_clk_div *cdiv = container_of(hw, struct mcde_clk_div, hw);
20 struct mcde *mcde = cdiv->mcde;
21 u32 val;
22
23 spin_lock(&mcde->fifo_crx1_lock);
24 val = readl(mcde->regs + cdiv->cr);
25 /*
26 * Select the PLL72 (LCD) clock as parent
27 * FIXME: implement other parents.
28 */
29 val &= ~MCDE_CRX1_CLKSEL_MASK;
30 val |= MCDE_CRX1_CLKSEL_CLKPLL72 << MCDE_CRX1_CLKSEL_SHIFT;
31 /* Internal clock */
32 val |= MCDE_CRA1_CLKTYPE_TVXCLKSEL1;
33
34 /* Clear then set the divider */
35 val &= ~(MCDE_CRX1_BCD | MCDE_CRX1_PCD_MASK);
36 val |= cdiv->cr_div;
37
38 writel(val, mcde->regs + cdiv->cr);
39 spin_unlock(&mcde->fifo_crx1_lock);
40
41 return 0;
42 }
43
mcde_clk_div_choose_div(struct clk_hw * hw,unsigned long rate,unsigned long * prate,bool set_parent)44 static int mcde_clk_div_choose_div(struct clk_hw *hw, unsigned long rate,
45 unsigned long *prate, bool set_parent)
46 {
47 int best_div = 1, div;
48 struct clk_hw *parent = clk_hw_get_parent(hw);
49 unsigned long best_prate = 0;
50 unsigned long best_diff = ~0ul;
51 int max_div = (1 << MCDE_CRX1_PCD_BITS) - 1;
52
53 for (div = 1; div < max_div; div++) {
54 unsigned long this_prate, div_rate, diff;
55
56 if (set_parent)
57 this_prate = clk_hw_round_rate(parent, rate * div);
58 else
59 this_prate = *prate;
60 div_rate = DIV_ROUND_UP_ULL(this_prate, div);
61 diff = abs(rate - div_rate);
62
63 if (diff < best_diff) {
64 best_div = div;
65 best_diff = diff;
66 best_prate = this_prate;
67 }
68 }
69
70 *prate = best_prate;
71 return best_div;
72 }
73
mcde_clk_div_determine_rate(struct clk_hw * hw,struct clk_rate_request * req)74 static int mcde_clk_div_determine_rate(struct clk_hw *hw,
75 struct clk_rate_request *req)
76 {
77 int div = mcde_clk_div_choose_div(hw, req->rate,
78 &req->best_parent_rate, true);
79
80 req->rate = DIV_ROUND_UP_ULL(req->best_parent_rate, div);
81
82 return 0;
83 }
84
mcde_clk_div_recalc_rate(struct clk_hw * hw,unsigned long prate)85 static unsigned long mcde_clk_div_recalc_rate(struct clk_hw *hw,
86 unsigned long prate)
87 {
88 struct mcde_clk_div *cdiv = container_of(hw, struct mcde_clk_div, hw);
89 struct mcde *mcde = cdiv->mcde;
90 u32 cr;
91 int div;
92
93 /*
94 * If the MCDE is not powered we can't access registers.
95 * It will come up with 0 in the divider register bits, which
96 * means "divide by 2".
97 */
98 if (!regulator_is_enabled(mcde->epod))
99 return DIV_ROUND_UP_ULL(prate, 2);
100
101 cr = readl(mcde->regs + cdiv->cr);
102 if (cr & MCDE_CRX1_BCD)
103 return prate;
104
105 /* 0 in the PCD means "divide by 2", 1 means "divide by 3" etc */
106 div = cr & MCDE_CRX1_PCD_MASK;
107 div += 2;
108
109 return DIV_ROUND_UP_ULL(prate, div);
110 }
111
mcde_clk_div_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long prate)112 static int mcde_clk_div_set_rate(struct clk_hw *hw, unsigned long rate,
113 unsigned long prate)
114 {
115 struct mcde_clk_div *cdiv = container_of(hw, struct mcde_clk_div, hw);
116 int div = mcde_clk_div_choose_div(hw, rate, &prate, false);
117 u32 cr = 0;
118
119 /*
120 * We cache the CR bits to set the divide in the state so that
121 * we can call this before we can even write to the hardware.
122 */
123 if (div == 1) {
124 /* Bypass clock divider */
125 cr |= MCDE_CRX1_BCD;
126 } else {
127 div -= 2;
128 cr |= div & MCDE_CRX1_PCD_MASK;
129 }
130 cdiv->cr_div = cr;
131
132 return 0;
133 }
134
135 static const struct clk_ops mcde_clk_div_ops = {
136 .enable = mcde_clk_div_enable,
137 .recalc_rate = mcde_clk_div_recalc_rate,
138 .determine_rate = mcde_clk_div_determine_rate,
139 .set_rate = mcde_clk_div_set_rate,
140 };
141
mcde_init_clock_divider(struct mcde * mcde)142 int mcde_init_clock_divider(struct mcde *mcde)
143 {
144 struct device *dev = mcde->dev;
145 struct mcde_clk_div *fifoa;
146 struct mcde_clk_div *fifob;
147 const char *parent_name;
148 struct clk_init_data fifoa_init = {
149 .name = "fifoa",
150 .ops = &mcde_clk_div_ops,
151 .parent_names = &parent_name,
152 .num_parents = 1,
153 .flags = CLK_SET_RATE_PARENT,
154 };
155 struct clk_init_data fifob_init = {
156 .name = "fifob",
157 .ops = &mcde_clk_div_ops,
158 .parent_names = &parent_name,
159 .num_parents = 1,
160 .flags = CLK_SET_RATE_PARENT,
161 };
162 int ret;
163
164 spin_lock_init(&mcde->fifo_crx1_lock);
165 parent_name = __clk_get_name(mcde->lcd_clk);
166
167 /* Allocate 2 clocks */
168 fifoa = devm_kzalloc(dev, sizeof(*fifoa), GFP_KERNEL);
169 if (!fifoa)
170 return -ENOMEM;
171 fifob = devm_kzalloc(dev, sizeof(*fifob), GFP_KERNEL);
172 if (!fifob)
173 return -ENOMEM;
174
175 fifoa->mcde = mcde;
176 fifoa->cr = MCDE_CRA1;
177 fifoa->hw.init = &fifoa_init;
178 ret = devm_clk_hw_register(dev, &fifoa->hw);
179 if (ret) {
180 dev_err(dev, "error registering FIFO A clock divider\n");
181 return ret;
182 }
183 mcde->fifoa_clk = fifoa->hw.clk;
184
185 fifob->mcde = mcde;
186 fifob->cr = MCDE_CRB1;
187 fifob->hw.init = &fifob_init;
188 ret = devm_clk_hw_register(dev, &fifob->hw);
189 if (ret) {
190 dev_err(dev, "error registering FIFO B clock divider\n");
191 return ret;
192 }
193 mcde->fifob_clk = fifob->hw.clk;
194
195 return 0;
196 }
197