1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Xilinx VCU Init
4 *
5 * Copyright (C) 2016 - 2017 Xilinx, Inc.
6 *
7 * Contacts Dhaval Shah <dshah@xilinx.com>
8 */
9 #include <linux/bitfield.h>
10 #include <linux/clk.h>
11 #include <linux/clk-provider.h>
12 #include <linux/device.h>
13 #include <linux/errno.h>
14 #include <linux/gpio/consumer.h>
15 #include <linux/io.h>
16 #include <linux/mfd/syscon.h>
17 #include <linux/mfd/syscon/xlnx-vcu.h>
18 #include <linux/module.h>
19 #include <linux/mod_devicetable.h>
20 #include <linux/platform_device.h>
21 #include <linux/regmap.h>
22
23 #include <dt-bindings/clock/xlnx-vcu.h>
24
25 #define VCU_PLL_CTRL 0x24
26 #define VCU_PLL_CTRL_RESET BIT(0)
27 #define VCU_PLL_CTRL_POR_IN BIT(1)
28 #define VCU_PLL_CTRL_PWR_POR BIT(2)
29 #define VCU_PLL_CTRL_BYPASS BIT(3)
30 #define VCU_PLL_CTRL_FBDIV GENMASK(14, 8)
31 #define VCU_PLL_CTRL_CLKOUTDIV GENMASK(18, 16)
32
33 #define VCU_PLL_CFG 0x28
34 #define VCU_PLL_CFG_RES GENMASK(3, 0)
35 #define VCU_PLL_CFG_CP GENMASK(8, 5)
36 #define VCU_PLL_CFG_LFHF GENMASK(12, 10)
37 #define VCU_PLL_CFG_LOCK_CNT GENMASK(22, 13)
38 #define VCU_PLL_CFG_LOCK_DLY GENMASK(31, 25)
39 #define VCU_ENC_CORE_CTRL 0x30
40 #define VCU_ENC_MCU_CTRL 0x34
41 #define VCU_DEC_CORE_CTRL 0x38
42 #define VCU_DEC_MCU_CTRL 0x3c
43 #define VCU_PLL_STATUS 0x60
44 #define VCU_PLL_STATUS_LOCK_STATUS BIT(0)
45
46 #define MHZ 1000000
47 #define FVCO_MIN (1500U * MHZ)
48 #define FVCO_MAX (3000U * MHZ)
49
50 /**
51 * struct xvcu_device - Xilinx VCU init device structure
52 * @dev: Platform device
53 * @pll_ref: pll ref clock source
54 * @aclk: axi clock source
55 * @reset_gpio: vcu reset gpio
56 * @logicore_reg_ba: logicore reg base address
57 * @vcu_slcr_ba: vcu_slcr Register base address
58 * @pll: handle for the VCU PLL
59 * @pll_post: handle for the VCU PLL post divider
60 * @clk_data: clocks provided by the vcu clock provider
61 */
62 struct xvcu_device {
63 struct device *dev;
64 struct clk *pll_ref;
65 struct clk *aclk;
66 struct gpio_desc *reset_gpio;
67 struct regmap *logicore_reg_ba;
68 void __iomem *vcu_slcr_ba;
69 struct clk_hw *pll;
70 struct clk_hw *pll_post;
71 struct clk_hw_onecell_data *clk_data;
72 };
73
74 static const struct regmap_config vcu_settings_regmap_config = {
75 .name = "regmap",
76 .reg_bits = 32,
77 .val_bits = 32,
78 .reg_stride = 4,
79 .max_register = 0xfff,
80 .cache_type = REGCACHE_NONE,
81 };
82
83 /**
84 * struct xvcu_pll_cfg - Helper data
85 * @fbdiv: The integer portion of the feedback divider to the PLL
86 * @cp: PLL charge pump control
87 * @res: PLL loop filter resistor control
88 * @lfhf: PLL loop filter high frequency capacitor control
89 * @lock_dly: Lock circuit configuration settings for lock windowsize
90 * @lock_cnt: Lock circuit counter setting
91 */
92 struct xvcu_pll_cfg {
93 u32 fbdiv;
94 u32 cp;
95 u32 res;
96 u32 lfhf;
97 u32 lock_dly;
98 u32 lock_cnt;
99 };
100
101 static const struct xvcu_pll_cfg xvcu_pll_cfg[] = {
102 { 25, 3, 10, 3, 63, 1000 },
103 { 26, 3, 10, 3, 63, 1000 },
104 { 27, 4, 6, 3, 63, 1000 },
105 { 28, 4, 6, 3, 63, 1000 },
106 { 29, 4, 6, 3, 63, 1000 },
107 { 30, 4, 6, 3, 63, 1000 },
108 { 31, 6, 1, 3, 63, 1000 },
109 { 32, 6, 1, 3, 63, 1000 },
110 { 33, 4, 10, 3, 63, 1000 },
111 { 34, 5, 6, 3, 63, 1000 },
112 { 35, 5, 6, 3, 63, 1000 },
113 { 36, 5, 6, 3, 63, 1000 },
114 { 37, 5, 6, 3, 63, 1000 },
115 { 38, 5, 6, 3, 63, 975 },
116 { 39, 3, 12, 3, 63, 950 },
117 { 40, 3, 12, 3, 63, 925 },
118 { 41, 3, 12, 3, 63, 900 },
119 { 42, 3, 12, 3, 63, 875 },
120 { 43, 3, 12, 3, 63, 850 },
121 { 44, 3, 12, 3, 63, 850 },
122 { 45, 3, 12, 3, 63, 825 },
123 { 46, 3, 12, 3, 63, 800 },
124 { 47, 3, 12, 3, 63, 775 },
125 { 48, 3, 12, 3, 63, 775 },
126 { 49, 3, 12, 3, 63, 750 },
127 { 50, 3, 12, 3, 63, 750 },
128 { 51, 3, 2, 3, 63, 725 },
129 { 52, 3, 2, 3, 63, 700 },
130 { 53, 3, 2, 3, 63, 700 },
131 { 54, 3, 2, 3, 63, 675 },
132 { 55, 3, 2, 3, 63, 675 },
133 { 56, 3, 2, 3, 63, 650 },
134 { 57, 3, 2, 3, 63, 650 },
135 { 58, 3, 2, 3, 63, 625 },
136 { 59, 3, 2, 3, 63, 625 },
137 { 60, 3, 2, 3, 63, 625 },
138 { 61, 3, 2, 3, 63, 600 },
139 { 62, 3, 2, 3, 63, 600 },
140 { 63, 3, 2, 3, 63, 600 },
141 { 64, 3, 2, 3, 63, 600 },
142 { 65, 3, 2, 3, 63, 600 },
143 { 66, 3, 2, 3, 63, 600 },
144 { 67, 3, 2, 3, 63, 600 },
145 { 68, 3, 2, 3, 63, 600 },
146 { 69, 3, 2, 3, 63, 600 },
147 { 70, 3, 2, 3, 63, 600 },
148 { 71, 3, 2, 3, 63, 600 },
149 { 72, 3, 2, 3, 63, 600 },
150 { 73, 3, 2, 3, 63, 600 },
151 { 74, 3, 2, 3, 63, 600 },
152 { 75, 3, 2, 3, 63, 600 },
153 { 76, 3, 2, 3, 63, 600 },
154 { 77, 3, 2, 3, 63, 600 },
155 { 78, 3, 2, 3, 63, 600 },
156 { 79, 3, 2, 3, 63, 600 },
157 { 80, 3, 2, 3, 63, 600 },
158 { 81, 3, 2, 3, 63, 600 },
159 { 82, 3, 2, 3, 63, 600 },
160 { 83, 4, 2, 3, 63, 600 },
161 { 84, 4, 2, 3, 63, 600 },
162 { 85, 4, 2, 3, 63, 600 },
163 { 86, 4, 2, 3, 63, 600 },
164 { 87, 4, 2, 3, 63, 600 },
165 { 88, 4, 2, 3, 63, 600 },
166 { 89, 4, 2, 3, 63, 600 },
167 { 90, 4, 2, 3, 63, 600 },
168 { 91, 4, 2, 3, 63, 600 },
169 { 92, 4, 2, 3, 63, 600 },
170 { 93, 4, 2, 3, 63, 600 },
171 { 94, 4, 2, 3, 63, 600 },
172 { 95, 4, 2, 3, 63, 600 },
173 { 96, 4, 2, 3, 63, 600 },
174 { 97, 4, 2, 3, 63, 600 },
175 { 98, 4, 2, 3, 63, 600 },
176 { 99, 4, 2, 3, 63, 600 },
177 { 100, 4, 2, 3, 63, 600 },
178 { 101, 4, 2, 3, 63, 600 },
179 { 102, 4, 2, 3, 63, 600 },
180 { 103, 5, 2, 3, 63, 600 },
181 { 104, 5, 2, 3, 63, 600 },
182 { 105, 5, 2, 3, 63, 600 },
183 { 106, 5, 2, 3, 63, 600 },
184 { 107, 3, 4, 3, 63, 600 },
185 { 108, 3, 4, 3, 63, 600 },
186 { 109, 3, 4, 3, 63, 600 },
187 { 110, 3, 4, 3, 63, 600 },
188 { 111, 3, 4, 3, 63, 600 },
189 { 112, 3, 4, 3, 63, 600 },
190 { 113, 3, 4, 3, 63, 600 },
191 { 114, 3, 4, 3, 63, 600 },
192 { 115, 3, 4, 3, 63, 600 },
193 { 116, 3, 4, 3, 63, 600 },
194 { 117, 3, 4, 3, 63, 600 },
195 { 118, 3, 4, 3, 63, 600 },
196 { 119, 3, 4, 3, 63, 600 },
197 { 120, 3, 4, 3, 63, 600 },
198 { 121, 3, 4, 3, 63, 600 },
199 { 122, 3, 4, 3, 63, 600 },
200 { 123, 3, 4, 3, 63, 600 },
201 { 124, 3, 4, 3, 63, 600 },
202 { 125, 3, 4, 3, 63, 600 },
203 };
204
205 /**
206 * xvcu_read - Read from the VCU register space
207 * @iomem: vcu reg space base address
208 * @offset: vcu reg offset from base
209 *
210 * Return: Returns 32bit value from VCU register specified
211 *
212 */
xvcu_read(void __iomem * iomem,u32 offset)213 static inline u32 xvcu_read(void __iomem *iomem, u32 offset)
214 {
215 return ioread32(iomem + offset);
216 }
217
218 /**
219 * xvcu_write - Write to the VCU register space
220 * @iomem: vcu reg space base address
221 * @offset: vcu reg offset from base
222 * @value: Value to write
223 */
xvcu_write(void __iomem * iomem,u32 offset,u32 value)224 static inline void xvcu_write(void __iomem *iomem, u32 offset, u32 value)
225 {
226 iowrite32(value, iomem + offset);
227 }
228
229 #define to_vcu_pll(_hw) container_of(_hw, struct vcu_pll, hw)
230
231 struct vcu_pll {
232 struct clk_hw hw;
233 void __iomem *reg_base;
234 unsigned long fvco_min;
235 unsigned long fvco_max;
236 };
237
xvcu_pll_wait_for_lock(struct vcu_pll * pll)238 static int xvcu_pll_wait_for_lock(struct vcu_pll *pll)
239 {
240 void __iomem *base = pll->reg_base;
241 unsigned long timeout;
242 u32 lock_status;
243
244 timeout = jiffies + msecs_to_jiffies(2000);
245 do {
246 lock_status = xvcu_read(base, VCU_PLL_STATUS);
247 if (lock_status & VCU_PLL_STATUS_LOCK_STATUS)
248 return 0;
249 } while (!time_after(jiffies, timeout));
250
251 return -ETIMEDOUT;
252 }
253
xvcu_register_pll_post(struct device * dev,const char * name,const struct clk_hw * parent_hw,void __iomem * reg_base)254 static struct clk_hw *xvcu_register_pll_post(struct device *dev,
255 const char *name,
256 const struct clk_hw *parent_hw,
257 void __iomem *reg_base)
258 {
259 u32 div;
260 u32 vcu_pll_ctrl;
261
262 /*
263 * The output divider of the PLL must be set to 1/2 to meet the
264 * timing in the design.
265 */
266 vcu_pll_ctrl = xvcu_read(reg_base, VCU_PLL_CTRL);
267 div = FIELD_GET(VCU_PLL_CTRL_CLKOUTDIV, vcu_pll_ctrl);
268 if (div != 1)
269 return ERR_PTR(-EINVAL);
270
271 return clk_hw_register_fixed_factor(dev, "vcu_pll_post",
272 clk_hw_get_name(parent_hw),
273 CLK_SET_RATE_PARENT, 1, 2);
274 }
275
xvcu_find_cfg(int div)276 static const struct xvcu_pll_cfg *xvcu_find_cfg(int div)
277 {
278 const struct xvcu_pll_cfg *cfg = NULL;
279 unsigned int i;
280
281 for (i = 0; i < ARRAY_SIZE(xvcu_pll_cfg) - 1; i++)
282 if (xvcu_pll_cfg[i].fbdiv == div)
283 cfg = &xvcu_pll_cfg[i];
284
285 return cfg;
286 }
287
xvcu_pll_set_div(struct vcu_pll * pll,int div)288 static int xvcu_pll_set_div(struct vcu_pll *pll, int div)
289 {
290 void __iomem *base = pll->reg_base;
291 const struct xvcu_pll_cfg *cfg = NULL;
292 u32 vcu_pll_ctrl;
293 u32 cfg_val;
294
295 cfg = xvcu_find_cfg(div);
296 if (!cfg)
297 return -EINVAL;
298
299 vcu_pll_ctrl = xvcu_read(base, VCU_PLL_CTRL);
300 vcu_pll_ctrl &= ~VCU_PLL_CTRL_FBDIV;
301 vcu_pll_ctrl |= FIELD_PREP(VCU_PLL_CTRL_FBDIV, cfg->fbdiv);
302 xvcu_write(base, VCU_PLL_CTRL, vcu_pll_ctrl);
303
304 cfg_val = FIELD_PREP(VCU_PLL_CFG_RES, cfg->res) |
305 FIELD_PREP(VCU_PLL_CFG_CP, cfg->cp) |
306 FIELD_PREP(VCU_PLL_CFG_LFHF, cfg->lfhf) |
307 FIELD_PREP(VCU_PLL_CFG_LOCK_CNT, cfg->lock_cnt) |
308 FIELD_PREP(VCU_PLL_CFG_LOCK_DLY, cfg->lock_dly);
309 xvcu_write(base, VCU_PLL_CFG, cfg_val);
310
311 return 0;
312 }
313
xvcu_pll_determine_rate(struct clk_hw * hw,struct clk_rate_request * req)314 static int xvcu_pll_determine_rate(struct clk_hw *hw,
315 struct clk_rate_request *req)
316 {
317 struct vcu_pll *pll = to_vcu_pll(hw);
318 unsigned int feedback_div;
319
320 req->rate = clamp_t(unsigned long, req->rate, pll->fvco_min,
321 pll->fvco_max);
322
323 feedback_div = DIV_ROUND_CLOSEST_ULL(req->rate, req->best_parent_rate);
324 feedback_div = clamp_t(unsigned int, feedback_div, 25, 125);
325
326 req->rate = req->best_parent_rate * feedback_div;
327
328 return 0;
329 }
330
xvcu_pll_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)331 static unsigned long xvcu_pll_recalc_rate(struct clk_hw *hw,
332 unsigned long parent_rate)
333 {
334 struct vcu_pll *pll = to_vcu_pll(hw);
335 void __iomem *base = pll->reg_base;
336 unsigned int div;
337 u32 vcu_pll_ctrl;
338
339 vcu_pll_ctrl = xvcu_read(base, VCU_PLL_CTRL);
340 div = FIELD_GET(VCU_PLL_CTRL_FBDIV, vcu_pll_ctrl);
341
342 return div * parent_rate;
343 }
344
xvcu_pll_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)345 static int xvcu_pll_set_rate(struct clk_hw *hw,
346 unsigned long rate, unsigned long parent_rate)
347 {
348 struct vcu_pll *pll = to_vcu_pll(hw);
349
350 return xvcu_pll_set_div(pll, rate / parent_rate);
351 }
352
xvcu_pll_enable(struct clk_hw * hw)353 static int xvcu_pll_enable(struct clk_hw *hw)
354 {
355 struct vcu_pll *pll = to_vcu_pll(hw);
356 void __iomem *base = pll->reg_base;
357 u32 vcu_pll_ctrl;
358 int ret;
359
360 vcu_pll_ctrl = xvcu_read(base, VCU_PLL_CTRL);
361 vcu_pll_ctrl |= VCU_PLL_CTRL_BYPASS;
362 xvcu_write(base, VCU_PLL_CTRL, vcu_pll_ctrl);
363
364 vcu_pll_ctrl = xvcu_read(base, VCU_PLL_CTRL);
365 vcu_pll_ctrl &= ~VCU_PLL_CTRL_POR_IN;
366 vcu_pll_ctrl &= ~VCU_PLL_CTRL_PWR_POR;
367 vcu_pll_ctrl &= ~VCU_PLL_CTRL_RESET;
368 xvcu_write(base, VCU_PLL_CTRL, vcu_pll_ctrl);
369
370 ret = xvcu_pll_wait_for_lock(pll);
371 if (ret) {
372 pr_err("VCU PLL is not locked\n");
373 goto err;
374 }
375
376 vcu_pll_ctrl = xvcu_read(base, VCU_PLL_CTRL);
377 vcu_pll_ctrl &= ~VCU_PLL_CTRL_BYPASS;
378 xvcu_write(base, VCU_PLL_CTRL, vcu_pll_ctrl);
379
380 err:
381 return ret;
382 }
383
xvcu_pll_disable(struct clk_hw * hw)384 static void xvcu_pll_disable(struct clk_hw *hw)
385 {
386 struct vcu_pll *pll = to_vcu_pll(hw);
387 void __iomem *base = pll->reg_base;
388 u32 vcu_pll_ctrl;
389
390 vcu_pll_ctrl = xvcu_read(base, VCU_PLL_CTRL);
391 vcu_pll_ctrl |= VCU_PLL_CTRL_POR_IN;
392 vcu_pll_ctrl |= VCU_PLL_CTRL_PWR_POR;
393 vcu_pll_ctrl |= VCU_PLL_CTRL_RESET;
394 xvcu_write(base, VCU_PLL_CTRL, vcu_pll_ctrl);
395 }
396
397 static const struct clk_ops vcu_pll_ops = {
398 .enable = xvcu_pll_enable,
399 .disable = xvcu_pll_disable,
400 .determine_rate = xvcu_pll_determine_rate,
401 .recalc_rate = xvcu_pll_recalc_rate,
402 .set_rate = xvcu_pll_set_rate,
403 };
404
xvcu_register_pll(struct device * dev,void __iomem * reg_base,const char * name,const char * parent,unsigned long flags)405 static struct clk_hw *xvcu_register_pll(struct device *dev,
406 void __iomem *reg_base,
407 const char *name, const char *parent,
408 unsigned long flags)
409 {
410 struct vcu_pll *pll;
411 struct clk_hw *hw;
412 struct clk_init_data init;
413 int ret;
414
415 init.name = name;
416 init.parent_names = &parent;
417 init.ops = &vcu_pll_ops;
418 init.num_parents = 1;
419 init.flags = flags;
420
421 pll = devm_kmalloc(dev, sizeof(*pll), GFP_KERNEL);
422 if (!pll)
423 return ERR_PTR(-ENOMEM);
424
425 pll->hw.init = &init;
426 pll->reg_base = reg_base;
427 pll->fvco_min = FVCO_MIN;
428 pll->fvco_max = FVCO_MAX;
429
430 hw = &pll->hw;
431 ret = devm_clk_hw_register(dev, hw);
432 if (ret)
433 return ERR_PTR(ret);
434
435 clk_hw_set_rate_range(hw, pll->fvco_min, pll->fvco_max);
436
437 return hw;
438 }
439
xvcu_clk_hw_register_leaf(struct device * dev,const char * name,const struct clk_parent_data * parent_data,u8 num_parents,void __iomem * reg)440 static struct clk_hw *xvcu_clk_hw_register_leaf(struct device *dev,
441 const char *name,
442 const struct clk_parent_data *parent_data,
443 u8 num_parents,
444 void __iomem *reg)
445 {
446 u8 mux_flags = CLK_MUX_ROUND_CLOSEST;
447 u8 divider_flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO |
448 CLK_DIVIDER_ROUND_CLOSEST;
449 struct clk_hw *mux = NULL;
450 struct clk_hw *divider = NULL;
451 struct clk_hw *gate = NULL;
452 char *name_mux;
453 char *name_div;
454 int err;
455 /* Protect register shared by clocks */
456 spinlock_t *lock;
457
458 lock = devm_kzalloc(dev, sizeof(*lock), GFP_KERNEL);
459 if (!lock)
460 return ERR_PTR(-ENOMEM);
461 spin_lock_init(lock);
462
463 name_mux = devm_kasprintf(dev, GFP_KERNEL, "%s%s", name, "_mux");
464 if (!name_mux)
465 return ERR_PTR(-ENOMEM);
466 mux = clk_hw_register_mux_parent_data(dev, name_mux,
467 parent_data, num_parents,
468 CLK_SET_RATE_PARENT,
469 reg, 0, 1, mux_flags, lock);
470 if (IS_ERR(mux))
471 return mux;
472
473 name_div = devm_kasprintf(dev, GFP_KERNEL, "%s%s", name, "_div");
474 if (!name_div) {
475 err = -ENOMEM;
476 goto unregister_mux;
477 }
478 divider = clk_hw_register_divider_parent_hw(dev, name_div, mux,
479 CLK_SET_RATE_PARENT,
480 reg, 4, 6, divider_flags,
481 lock);
482 if (IS_ERR(divider)) {
483 err = PTR_ERR(divider);
484 goto unregister_mux;
485 }
486
487 gate = clk_hw_register_gate_parent_hw(dev, name, divider,
488 CLK_SET_RATE_PARENT, reg, 12, 0,
489 lock);
490 if (IS_ERR(gate)) {
491 err = PTR_ERR(gate);
492 goto unregister_divider;
493 }
494
495 return gate;
496
497 unregister_divider:
498 clk_hw_unregister_divider(divider);
499 unregister_mux:
500 clk_hw_unregister_mux(mux);
501
502 return ERR_PTR(err);
503 }
504
xvcu_clk_hw_unregister_leaf(struct clk_hw * hw)505 static void xvcu_clk_hw_unregister_leaf(struct clk_hw *hw)
506 {
507 struct clk_hw *gate = hw;
508 struct clk_hw *divider;
509 struct clk_hw *mux;
510
511 if (!gate)
512 return;
513
514 divider = clk_hw_get_parent(gate);
515 clk_hw_unregister_gate(gate);
516 if (!divider)
517 return;
518
519 mux = clk_hw_get_parent(divider);
520 clk_hw_unregister_mux(mux);
521 if (!divider)
522 return;
523
524 clk_hw_unregister_divider(divider);
525 }
526
xvcu_register_clock_provider(struct xvcu_device * xvcu)527 static int xvcu_register_clock_provider(struct xvcu_device *xvcu)
528 {
529 struct device *dev = xvcu->dev;
530 struct clk_parent_data parent_data[2] = { 0 };
531 struct clk_hw_onecell_data *data;
532 struct clk_hw **hws;
533 struct clk_hw *hw;
534 void __iomem *reg_base = xvcu->vcu_slcr_ba;
535
536 data = devm_kzalloc(dev, struct_size(data, hws, CLK_XVCU_NUM_CLOCKS), GFP_KERNEL);
537 if (!data)
538 return -ENOMEM;
539 data->num = CLK_XVCU_NUM_CLOCKS;
540 hws = data->hws;
541
542 xvcu->clk_data = data;
543
544 hw = xvcu_register_pll(dev, reg_base,
545 "vcu_pll", __clk_get_name(xvcu->pll_ref),
546 CLK_SET_RATE_NO_REPARENT | CLK_OPS_PARENT_ENABLE);
547 if (IS_ERR(hw))
548 return PTR_ERR(hw);
549 xvcu->pll = hw;
550
551 hw = xvcu_register_pll_post(dev, "vcu_pll_post", xvcu->pll, reg_base);
552 if (IS_ERR(hw))
553 return PTR_ERR(hw);
554 xvcu->pll_post = hw;
555
556 parent_data[0].fw_name = "pll_ref";
557 parent_data[1].hw = xvcu->pll_post;
558
559 hws[CLK_XVCU_ENC_CORE] =
560 xvcu_clk_hw_register_leaf(dev, "venc_core_clk",
561 parent_data,
562 ARRAY_SIZE(parent_data),
563 reg_base + VCU_ENC_CORE_CTRL);
564 hws[CLK_XVCU_ENC_MCU] =
565 xvcu_clk_hw_register_leaf(dev, "venc_mcu_clk",
566 parent_data,
567 ARRAY_SIZE(parent_data),
568 reg_base + VCU_ENC_MCU_CTRL);
569 hws[CLK_XVCU_DEC_CORE] =
570 xvcu_clk_hw_register_leaf(dev, "vdec_core_clk",
571 parent_data,
572 ARRAY_SIZE(parent_data),
573 reg_base + VCU_DEC_CORE_CTRL);
574 hws[CLK_XVCU_DEC_MCU] =
575 xvcu_clk_hw_register_leaf(dev, "vdec_mcu_clk",
576 parent_data,
577 ARRAY_SIZE(parent_data),
578 reg_base + VCU_DEC_MCU_CTRL);
579
580 return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, data);
581 }
582
xvcu_unregister_clock_provider(struct xvcu_device * xvcu)583 static void xvcu_unregister_clock_provider(struct xvcu_device *xvcu)
584 {
585 struct clk_hw_onecell_data *data = xvcu->clk_data;
586 struct clk_hw **hws = data->hws;
587
588 if (!IS_ERR_OR_NULL(hws[CLK_XVCU_DEC_MCU]))
589 xvcu_clk_hw_unregister_leaf(hws[CLK_XVCU_DEC_MCU]);
590 if (!IS_ERR_OR_NULL(hws[CLK_XVCU_DEC_CORE]))
591 xvcu_clk_hw_unregister_leaf(hws[CLK_XVCU_DEC_CORE]);
592 if (!IS_ERR_OR_NULL(hws[CLK_XVCU_ENC_MCU]))
593 xvcu_clk_hw_unregister_leaf(hws[CLK_XVCU_ENC_MCU]);
594 if (!IS_ERR_OR_NULL(hws[CLK_XVCU_ENC_CORE]))
595 xvcu_clk_hw_unregister_leaf(hws[CLK_XVCU_ENC_CORE]);
596 if (!IS_ERR_OR_NULL(xvcu->pll_post))
597 clk_hw_unregister_fixed_factor(xvcu->pll_post);
598 }
599
600 /**
601 * xvcu_probe - Probe existence of the logicoreIP
602 * and initialize PLL
603 *
604 * @pdev: Pointer to the platform_device structure
605 *
606 * Return: Returns 0 on success
607 * Negative error code otherwise
608 */
xvcu_probe(struct platform_device * pdev)609 static int xvcu_probe(struct platform_device *pdev)
610 {
611 struct resource *res;
612 struct xvcu_device *xvcu;
613 void __iomem *regs;
614 int ret;
615
616 xvcu = devm_kzalloc(&pdev->dev, sizeof(*xvcu), GFP_KERNEL);
617 if (!xvcu)
618 return -ENOMEM;
619
620 xvcu->dev = &pdev->dev;
621 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vcu_slcr");
622 if (!res) {
623 dev_err(&pdev->dev, "get vcu_slcr memory resource failed.\n");
624 return -ENODEV;
625 }
626
627 xvcu->vcu_slcr_ba = devm_ioremap(&pdev->dev, res->start,
628 resource_size(res));
629 if (!xvcu->vcu_slcr_ba) {
630 dev_err(&pdev->dev, "vcu_slcr register mapping failed.\n");
631 return -ENOMEM;
632 }
633
634 xvcu->logicore_reg_ba =
635 syscon_regmap_lookup_by_compatible("xlnx,vcu-settings");
636 if (IS_ERR(xvcu->logicore_reg_ba)) {
637 dev_info(&pdev->dev,
638 "could not find xlnx,vcu-settings: trying direct register access\n");
639
640 res = platform_get_resource_byname(pdev,
641 IORESOURCE_MEM, "logicore");
642 if (!res) {
643 dev_err(&pdev->dev, "get logicore memory resource failed.\n");
644 return -ENODEV;
645 }
646
647 regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
648 if (!regs) {
649 dev_err(&pdev->dev, "logicore register mapping failed.\n");
650 return -ENOMEM;
651 }
652
653 xvcu->logicore_reg_ba =
654 devm_regmap_init_mmio(&pdev->dev, regs,
655 &vcu_settings_regmap_config);
656 if (IS_ERR(xvcu->logicore_reg_ba)) {
657 dev_err(&pdev->dev, "failed to init regmap\n");
658 return PTR_ERR(xvcu->logicore_reg_ba);
659 }
660 }
661
662 xvcu->aclk = devm_clk_get(&pdev->dev, "aclk");
663 if (IS_ERR(xvcu->aclk)) {
664 dev_err(&pdev->dev, "Could not get aclk clock\n");
665 return PTR_ERR(xvcu->aclk);
666 }
667
668 xvcu->pll_ref = devm_clk_get(&pdev->dev, "pll_ref");
669 if (IS_ERR(xvcu->pll_ref)) {
670 dev_err(&pdev->dev, "Could not get pll_ref clock\n");
671 return PTR_ERR(xvcu->pll_ref);
672 }
673
674 ret = clk_prepare_enable(xvcu->aclk);
675 if (ret) {
676 dev_err(&pdev->dev, "aclk clock enable failed\n");
677 return ret;
678 }
679
680 /*
681 * Do the Gasket isolation and put the VCU out of reset
682 * Bit 0 : Gasket isolation
683 * Bit 1 : put VCU out of reset
684 */
685 xvcu->reset_gpio = devm_gpiod_get_optional(&pdev->dev, "reset",
686 GPIOD_OUT_LOW);
687 if (IS_ERR(xvcu->reset_gpio)) {
688 ret = PTR_ERR(xvcu->reset_gpio);
689 dev_err_probe(&pdev->dev, ret, "failed to get reset gpio for vcu.\n");
690 goto error_get_gpio;
691 }
692
693 if (xvcu->reset_gpio) {
694 gpiod_set_value(xvcu->reset_gpio, 0);
695 /* min 2 clock cycle of vcu pll_ref, slowest freq is 33.33KHz */
696 usleep_range(60, 120);
697 gpiod_set_value(xvcu->reset_gpio, 1);
698 usleep_range(60, 120);
699 } else {
700 dev_dbg(&pdev->dev, "No reset gpio info found in dts for VCU. This may result in incorrect functionality if VCU isolation is removed after initialization in designs where the VCU reset is driven by gpio.\n");
701 }
702
703 regmap_write(xvcu->logicore_reg_ba, VCU_GASKET_INIT, VCU_GASKET_VALUE);
704
705 ret = xvcu_register_clock_provider(xvcu);
706 if (ret) {
707 dev_err(&pdev->dev, "failed to register clock provider\n");
708 goto error_clk_provider;
709 }
710
711 dev_set_drvdata(&pdev->dev, xvcu);
712
713 return 0;
714
715 error_clk_provider:
716 xvcu_unregister_clock_provider(xvcu);
717 error_get_gpio:
718 clk_disable_unprepare(xvcu->aclk);
719 return ret;
720 }
721
722 /**
723 * xvcu_remove - Insert gasket isolation
724 * and disable the clock
725 * @pdev: Pointer to the platform_device structure
726 *
727 * Return: Returns 0 on success
728 * Negative error code otherwise
729 */
xvcu_remove(struct platform_device * pdev)730 static void xvcu_remove(struct platform_device *pdev)
731 {
732 struct xvcu_device *xvcu;
733
734 xvcu = platform_get_drvdata(pdev);
735
736 xvcu_unregister_clock_provider(xvcu);
737
738 /* Add the Gasket isolation and put the VCU in reset. */
739 if (xvcu->reset_gpio) {
740 gpiod_set_value(xvcu->reset_gpio, 0);
741 /* min 2 clock cycle of vcu pll_ref, slowest freq is 33.33KHz */
742 usleep_range(60, 120);
743 gpiod_set_value(xvcu->reset_gpio, 1);
744 usleep_range(60, 120);
745 }
746 regmap_write(xvcu->logicore_reg_ba, VCU_GASKET_INIT, 0);
747
748 clk_disable_unprepare(xvcu->aclk);
749 }
750
751 static const struct of_device_id xvcu_of_id_table[] = {
752 { .compatible = "xlnx,vcu" },
753 { .compatible = "xlnx,vcu-logicoreip-1.0" },
754 { }
755 };
756 MODULE_DEVICE_TABLE(of, xvcu_of_id_table);
757
758 static struct platform_driver xvcu_driver = {
759 .driver = {
760 .name = "xilinx-vcu",
761 .of_match_table = xvcu_of_id_table,
762 },
763 .probe = xvcu_probe,
764 .remove = xvcu_remove,
765 };
766
767 module_platform_driver(xvcu_driver);
768
769 MODULE_AUTHOR("Dhaval Shah <dshah@xilinx.com>");
770 MODULE_DESCRIPTION("Xilinx VCU init Driver");
771 MODULE_LICENSE("GPL v2");
772