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