xref: /linux/drivers/clk/xilinx/xlnx_vcu.c (revision b4ada0618eed0fbd1b1630f73deb048c592b06a1)
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  */
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  */
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 
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 
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 
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 
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 
314 static long xvcu_pll_round_rate(struct clk_hw *hw,
315 				unsigned long rate, unsigned long *parent_rate)
316 {
317 	struct vcu_pll *pll = to_vcu_pll(hw);
318 	unsigned int feedback_div;
319 
320 	rate = clamp_t(unsigned long, rate, pll->fvco_min, pll->fvco_max);
321 
322 	feedback_div = DIV_ROUND_CLOSEST_ULL(rate, *parent_rate);
323 	feedback_div = clamp_t(unsigned int, feedback_div, 25, 125);
324 
325 	return *parent_rate * feedback_div;
326 }
327 
328 static unsigned long xvcu_pll_recalc_rate(struct clk_hw *hw,
329 					  unsigned long parent_rate)
330 {
331 	struct vcu_pll *pll = to_vcu_pll(hw);
332 	void __iomem *base = pll->reg_base;
333 	unsigned int div;
334 	u32 vcu_pll_ctrl;
335 
336 	vcu_pll_ctrl = xvcu_read(base, VCU_PLL_CTRL);
337 	div = FIELD_GET(VCU_PLL_CTRL_FBDIV, vcu_pll_ctrl);
338 
339 	return div * parent_rate;
340 }
341 
342 static int xvcu_pll_set_rate(struct clk_hw *hw,
343 			     unsigned long rate, unsigned long parent_rate)
344 {
345 	struct vcu_pll *pll = to_vcu_pll(hw);
346 
347 	return xvcu_pll_set_div(pll, rate / parent_rate);
348 }
349 
350 static int xvcu_pll_enable(struct clk_hw *hw)
351 {
352 	struct vcu_pll *pll = to_vcu_pll(hw);
353 	void __iomem *base = pll->reg_base;
354 	u32 vcu_pll_ctrl;
355 	int ret;
356 
357 	vcu_pll_ctrl = xvcu_read(base, VCU_PLL_CTRL);
358 	vcu_pll_ctrl |= VCU_PLL_CTRL_BYPASS;
359 	xvcu_write(base, VCU_PLL_CTRL, vcu_pll_ctrl);
360 
361 	vcu_pll_ctrl = xvcu_read(base, VCU_PLL_CTRL);
362 	vcu_pll_ctrl &= ~VCU_PLL_CTRL_POR_IN;
363 	vcu_pll_ctrl &= ~VCU_PLL_CTRL_PWR_POR;
364 	vcu_pll_ctrl &= ~VCU_PLL_CTRL_RESET;
365 	xvcu_write(base, VCU_PLL_CTRL, vcu_pll_ctrl);
366 
367 	ret = xvcu_pll_wait_for_lock(pll);
368 	if (ret) {
369 		pr_err("VCU PLL is not locked\n");
370 		goto err;
371 	}
372 
373 	vcu_pll_ctrl = xvcu_read(base, VCU_PLL_CTRL);
374 	vcu_pll_ctrl &= ~VCU_PLL_CTRL_BYPASS;
375 	xvcu_write(base, VCU_PLL_CTRL, vcu_pll_ctrl);
376 
377 err:
378 	return ret;
379 }
380 
381 static void xvcu_pll_disable(struct clk_hw *hw)
382 {
383 	struct vcu_pll *pll = to_vcu_pll(hw);
384 	void __iomem *base = pll->reg_base;
385 	u32 vcu_pll_ctrl;
386 
387 	vcu_pll_ctrl = xvcu_read(base, VCU_PLL_CTRL);
388 	vcu_pll_ctrl |= VCU_PLL_CTRL_POR_IN;
389 	vcu_pll_ctrl |= VCU_PLL_CTRL_PWR_POR;
390 	vcu_pll_ctrl |= VCU_PLL_CTRL_RESET;
391 	xvcu_write(base, VCU_PLL_CTRL, vcu_pll_ctrl);
392 }
393 
394 static const struct clk_ops vcu_pll_ops = {
395 	.enable = xvcu_pll_enable,
396 	.disable = xvcu_pll_disable,
397 	.round_rate = xvcu_pll_round_rate,
398 	.recalc_rate = xvcu_pll_recalc_rate,
399 	.set_rate = xvcu_pll_set_rate,
400 };
401 
402 static struct clk_hw *xvcu_register_pll(struct device *dev,
403 					void __iomem *reg_base,
404 					const char *name, const char *parent,
405 					unsigned long flags)
406 {
407 	struct vcu_pll *pll;
408 	struct clk_hw *hw;
409 	struct clk_init_data init;
410 	int ret;
411 
412 	init.name = name;
413 	init.parent_names = &parent;
414 	init.ops = &vcu_pll_ops;
415 	init.num_parents = 1;
416 	init.flags = flags;
417 
418 	pll = devm_kmalloc(dev, sizeof(*pll), GFP_KERNEL);
419 	if (!pll)
420 		return ERR_PTR(-ENOMEM);
421 
422 	pll->hw.init = &init;
423 	pll->reg_base = reg_base;
424 	pll->fvco_min = FVCO_MIN;
425 	pll->fvco_max = FVCO_MAX;
426 
427 	hw = &pll->hw;
428 	ret = devm_clk_hw_register(dev, hw);
429 	if (ret)
430 		return ERR_PTR(ret);
431 
432 	clk_hw_set_rate_range(hw, pll->fvco_min, pll->fvco_max);
433 
434 	return hw;
435 }
436 
437 static struct clk_hw *xvcu_clk_hw_register_leaf(struct device *dev,
438 						const char *name,
439 						const struct clk_parent_data *parent_data,
440 						u8 num_parents,
441 						void __iomem *reg)
442 {
443 	u8 mux_flags = CLK_MUX_ROUND_CLOSEST;
444 	u8 divider_flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO |
445 			   CLK_DIVIDER_ROUND_CLOSEST;
446 	struct clk_hw *mux = NULL;
447 	struct clk_hw *divider = NULL;
448 	struct clk_hw *gate = NULL;
449 	char *name_mux;
450 	char *name_div;
451 	int err;
452 	/* Protect register shared by clocks */
453 	spinlock_t *lock;
454 
455 	lock = devm_kzalloc(dev, sizeof(*lock), GFP_KERNEL);
456 	if (!lock)
457 		return ERR_PTR(-ENOMEM);
458 	spin_lock_init(lock);
459 
460 	name_mux = devm_kasprintf(dev, GFP_KERNEL, "%s%s", name, "_mux");
461 	if (!name_mux)
462 		return ERR_PTR(-ENOMEM);
463 	mux = clk_hw_register_mux_parent_data(dev, name_mux,
464 					      parent_data, num_parents,
465 					      CLK_SET_RATE_PARENT,
466 					      reg, 0, 1, mux_flags, lock);
467 	if (IS_ERR(mux))
468 		return mux;
469 
470 	name_div = devm_kasprintf(dev, GFP_KERNEL, "%s%s", name, "_div");
471 	if (!name_div) {
472 		err = -ENOMEM;
473 		goto unregister_mux;
474 	}
475 	divider = clk_hw_register_divider_parent_hw(dev, name_div, mux,
476 						    CLK_SET_RATE_PARENT,
477 						    reg, 4, 6, divider_flags,
478 						    lock);
479 	if (IS_ERR(divider)) {
480 		err = PTR_ERR(divider);
481 		goto unregister_mux;
482 	}
483 
484 	gate = clk_hw_register_gate_parent_hw(dev, name, divider,
485 					      CLK_SET_RATE_PARENT, reg, 12, 0,
486 					      lock);
487 	if (IS_ERR(gate)) {
488 		err = PTR_ERR(gate);
489 		goto unregister_divider;
490 	}
491 
492 	return gate;
493 
494 unregister_divider:
495 	clk_hw_unregister_divider(divider);
496 unregister_mux:
497 	clk_hw_unregister_mux(mux);
498 
499 	return ERR_PTR(err);
500 }
501 
502 static void xvcu_clk_hw_unregister_leaf(struct clk_hw *hw)
503 {
504 	struct clk_hw *gate = hw;
505 	struct clk_hw *divider;
506 	struct clk_hw *mux;
507 
508 	if (!gate)
509 		return;
510 
511 	divider = clk_hw_get_parent(gate);
512 	clk_hw_unregister_gate(gate);
513 	if (!divider)
514 		return;
515 
516 	mux = clk_hw_get_parent(divider);
517 	clk_hw_unregister_mux(mux);
518 	if (!divider)
519 		return;
520 
521 	clk_hw_unregister_divider(divider);
522 }
523 
524 static int xvcu_register_clock_provider(struct xvcu_device *xvcu)
525 {
526 	struct device *dev = xvcu->dev;
527 	struct clk_parent_data parent_data[2] = { 0 };
528 	struct clk_hw_onecell_data *data;
529 	struct clk_hw **hws;
530 	struct clk_hw *hw;
531 	void __iomem *reg_base = xvcu->vcu_slcr_ba;
532 
533 	data = devm_kzalloc(dev, struct_size(data, hws, CLK_XVCU_NUM_CLOCKS), GFP_KERNEL);
534 	if (!data)
535 		return -ENOMEM;
536 	data->num = CLK_XVCU_NUM_CLOCKS;
537 	hws = data->hws;
538 
539 	xvcu->clk_data = data;
540 
541 	hw = xvcu_register_pll(dev, reg_base,
542 			       "vcu_pll", __clk_get_name(xvcu->pll_ref),
543 			       CLK_SET_RATE_NO_REPARENT | CLK_OPS_PARENT_ENABLE);
544 	if (IS_ERR(hw))
545 		return PTR_ERR(hw);
546 	xvcu->pll = hw;
547 
548 	hw = xvcu_register_pll_post(dev, "vcu_pll_post", xvcu->pll, reg_base);
549 	if (IS_ERR(hw))
550 		return PTR_ERR(hw);
551 	xvcu->pll_post = hw;
552 
553 	parent_data[0].fw_name = "pll_ref";
554 	parent_data[1].hw = xvcu->pll_post;
555 
556 	hws[CLK_XVCU_ENC_CORE] =
557 		xvcu_clk_hw_register_leaf(dev, "venc_core_clk",
558 					  parent_data,
559 					  ARRAY_SIZE(parent_data),
560 					  reg_base + VCU_ENC_CORE_CTRL);
561 	hws[CLK_XVCU_ENC_MCU] =
562 		xvcu_clk_hw_register_leaf(dev, "venc_mcu_clk",
563 					  parent_data,
564 					  ARRAY_SIZE(parent_data),
565 					  reg_base + VCU_ENC_MCU_CTRL);
566 	hws[CLK_XVCU_DEC_CORE] =
567 		xvcu_clk_hw_register_leaf(dev, "vdec_core_clk",
568 					  parent_data,
569 					  ARRAY_SIZE(parent_data),
570 					  reg_base + VCU_DEC_CORE_CTRL);
571 	hws[CLK_XVCU_DEC_MCU] =
572 		xvcu_clk_hw_register_leaf(dev, "vdec_mcu_clk",
573 					  parent_data,
574 					  ARRAY_SIZE(parent_data),
575 					  reg_base + VCU_DEC_MCU_CTRL);
576 
577 	return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, data);
578 }
579 
580 static void xvcu_unregister_clock_provider(struct xvcu_device *xvcu)
581 {
582 	struct clk_hw_onecell_data *data = xvcu->clk_data;
583 	struct clk_hw **hws = data->hws;
584 
585 	if (!IS_ERR_OR_NULL(hws[CLK_XVCU_DEC_MCU]))
586 		xvcu_clk_hw_unregister_leaf(hws[CLK_XVCU_DEC_MCU]);
587 	if (!IS_ERR_OR_NULL(hws[CLK_XVCU_DEC_CORE]))
588 		xvcu_clk_hw_unregister_leaf(hws[CLK_XVCU_DEC_CORE]);
589 	if (!IS_ERR_OR_NULL(hws[CLK_XVCU_ENC_MCU]))
590 		xvcu_clk_hw_unregister_leaf(hws[CLK_XVCU_ENC_MCU]);
591 	if (!IS_ERR_OR_NULL(hws[CLK_XVCU_ENC_CORE]))
592 		xvcu_clk_hw_unregister_leaf(hws[CLK_XVCU_ENC_CORE]);
593 	if (!IS_ERR_OR_NULL(xvcu->pll_post))
594 		clk_hw_unregister_fixed_factor(xvcu->pll_post);
595 }
596 
597 /**
598  * xvcu_probe - Probe existence of the logicoreIP
599  *			and initialize PLL
600  *
601  * @pdev:	Pointer to the platform_device structure
602  *
603  * Return:	Returns 0 on success
604  *		Negative error code otherwise
605  */
606 static int xvcu_probe(struct platform_device *pdev)
607 {
608 	struct resource *res;
609 	struct xvcu_device *xvcu;
610 	void __iomem *regs;
611 	int ret;
612 
613 	xvcu = devm_kzalloc(&pdev->dev, sizeof(*xvcu), GFP_KERNEL);
614 	if (!xvcu)
615 		return -ENOMEM;
616 
617 	xvcu->dev = &pdev->dev;
618 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vcu_slcr");
619 	if (!res) {
620 		dev_err(&pdev->dev, "get vcu_slcr memory resource failed.\n");
621 		return -ENODEV;
622 	}
623 
624 	xvcu->vcu_slcr_ba = devm_ioremap(&pdev->dev, res->start,
625 					 resource_size(res));
626 	if (!xvcu->vcu_slcr_ba) {
627 		dev_err(&pdev->dev, "vcu_slcr register mapping failed.\n");
628 		return -ENOMEM;
629 	}
630 
631 	xvcu->logicore_reg_ba =
632 		syscon_regmap_lookup_by_compatible("xlnx,vcu-settings");
633 	if (IS_ERR(xvcu->logicore_reg_ba)) {
634 		dev_info(&pdev->dev,
635 			 "could not find xlnx,vcu-settings: trying direct register access\n");
636 
637 		res = platform_get_resource_byname(pdev,
638 						   IORESOURCE_MEM, "logicore");
639 		if (!res) {
640 			dev_err(&pdev->dev, "get logicore memory resource failed.\n");
641 			return -ENODEV;
642 		}
643 
644 		regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
645 		if (!regs) {
646 			dev_err(&pdev->dev, "logicore register mapping failed.\n");
647 			return -ENOMEM;
648 		}
649 
650 		xvcu->logicore_reg_ba =
651 			devm_regmap_init_mmio(&pdev->dev, regs,
652 					      &vcu_settings_regmap_config);
653 		if (IS_ERR(xvcu->logicore_reg_ba)) {
654 			dev_err(&pdev->dev, "failed to init regmap\n");
655 			return PTR_ERR(xvcu->logicore_reg_ba);
656 		}
657 	}
658 
659 	xvcu->aclk = devm_clk_get(&pdev->dev, "aclk");
660 	if (IS_ERR(xvcu->aclk)) {
661 		dev_err(&pdev->dev, "Could not get aclk clock\n");
662 		return PTR_ERR(xvcu->aclk);
663 	}
664 
665 	xvcu->pll_ref = devm_clk_get(&pdev->dev, "pll_ref");
666 	if (IS_ERR(xvcu->pll_ref)) {
667 		dev_err(&pdev->dev, "Could not get pll_ref clock\n");
668 		return PTR_ERR(xvcu->pll_ref);
669 	}
670 
671 	ret = clk_prepare_enable(xvcu->aclk);
672 	if (ret) {
673 		dev_err(&pdev->dev, "aclk clock enable failed\n");
674 		return ret;
675 	}
676 
677 	/*
678 	 * Do the Gasket isolation and put the VCU out of reset
679 	 * Bit 0 : Gasket isolation
680 	 * Bit 1 : put VCU out of reset
681 	 */
682 	xvcu->reset_gpio = devm_gpiod_get_optional(&pdev->dev, "reset",
683 						   GPIOD_OUT_LOW);
684 	if (IS_ERR(xvcu->reset_gpio)) {
685 		ret = PTR_ERR(xvcu->reset_gpio);
686 		dev_err_probe(&pdev->dev, ret, "failed to get reset gpio for vcu.\n");
687 		goto error_get_gpio;
688 	}
689 
690 	if (xvcu->reset_gpio) {
691 		gpiod_set_value(xvcu->reset_gpio, 0);
692 		/* min 2 clock cycle of vcu pll_ref, slowest freq is 33.33KHz */
693 		usleep_range(60, 120);
694 		gpiod_set_value(xvcu->reset_gpio, 1);
695 		usleep_range(60, 120);
696 	} else {
697 		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");
698 	}
699 
700 	regmap_write(xvcu->logicore_reg_ba, VCU_GASKET_INIT, VCU_GASKET_VALUE);
701 
702 	ret = xvcu_register_clock_provider(xvcu);
703 	if (ret) {
704 		dev_err(&pdev->dev, "failed to register clock provider\n");
705 		goto error_clk_provider;
706 	}
707 
708 	dev_set_drvdata(&pdev->dev, xvcu);
709 
710 	return 0;
711 
712 error_clk_provider:
713 	xvcu_unregister_clock_provider(xvcu);
714 error_get_gpio:
715 	clk_disable_unprepare(xvcu->aclk);
716 	return ret;
717 }
718 
719 /**
720  * xvcu_remove - Insert gasket isolation
721  *			and disable the clock
722  * @pdev:	Pointer to the platform_device structure
723  *
724  * Return:	Returns 0 on success
725  *		Negative error code otherwise
726  */
727 static void xvcu_remove(struct platform_device *pdev)
728 {
729 	struct xvcu_device *xvcu;
730 
731 	xvcu = platform_get_drvdata(pdev);
732 
733 	xvcu_unregister_clock_provider(xvcu);
734 
735 	/* Add the Gasket isolation and put the VCU in reset. */
736 	if (xvcu->reset_gpio) {
737 		gpiod_set_value(xvcu->reset_gpio, 0);
738 		/* min 2 clock cycle of vcu pll_ref, slowest freq is 33.33KHz */
739 		usleep_range(60, 120);
740 		gpiod_set_value(xvcu->reset_gpio, 1);
741 		usleep_range(60, 120);
742 	}
743 	regmap_write(xvcu->logicore_reg_ba, VCU_GASKET_INIT, 0);
744 
745 	clk_disable_unprepare(xvcu->aclk);
746 }
747 
748 static const struct of_device_id xvcu_of_id_table[] = {
749 	{ .compatible = "xlnx,vcu" },
750 	{ .compatible = "xlnx,vcu-logicoreip-1.0" },
751 	{ }
752 };
753 MODULE_DEVICE_TABLE(of, xvcu_of_id_table);
754 
755 static struct platform_driver xvcu_driver = {
756 	.driver = {
757 		.name           = "xilinx-vcu",
758 		.of_match_table = xvcu_of_id_table,
759 	},
760 	.probe                  = xvcu_probe,
761 	.remove                 = xvcu_remove,
762 };
763 
764 module_platform_driver(xvcu_driver);
765 
766 MODULE_AUTHOR("Dhaval Shah <dshah@xilinx.com>");
767 MODULE_DESCRIPTION("Xilinx VCU init Driver");
768 MODULE_LICENSE("GPL v2");
769