xref: /linux/drivers/clk/xilinx/xlnx_vcu.c (revision 522ba450b56fff29f868b1552bdc2965f55de7ed)
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