]> rtime.felk.cvut.cz Git - zynq/linux.git/blob - drivers/soc/xilinx/xlnx_vcu.c
soc: xilinx: vcu: Provided API to get number of cores
[zynq/linux.git] / drivers / soc / xilinx / xlnx_vcu.c
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/clk.h>
10 #include <linux/device.h>
11 #include <linux/errno.h>
12 #include <linux/io.h>
13 #include <linux/module.h>
14 #include <linux/of_platform.h>
15 #include <linux/platform_device.h>
16
17 #include <soc/xilinx/xlnx_vcu.h>
18
19 /* Address map for different registers implemented in the VCU LogiCORE IP. */
20 #define VCU_ECODER_ENABLE               0x00
21 #define VCU_DECODER_ENABLE              0x04
22 #define VCU_MEMORY_DEPTH                0x08
23 #define VCU_ENC_COLOR_DEPTH             0x0c
24 #define VCU_ENC_VERTICAL_RANGE          0x10
25 #define VCU_ENC_FRAME_SIZE_X            0x14
26 #define VCU_ENC_FRAME_SIZE_Y            0x18
27 #define VCU_ENC_COLOR_FORMAT            0x1c
28 #define VCU_ENC_FPS                     0x20
29 #define VCU_MCU_CLK                     0x24
30 #define VCU_CORE_CLK                    0x28
31 #define VCU_PLL_BYPASS                  0x2c
32 #define VCU_ENC_CLK                     0x30
33 #define VCU_PLL_CLK                     0x34
34 #define VCU_ENC_VIDEO_STANDARD          0x38
35 #define VCU_STATUS                      0x3c
36 #define VCU_AXI_ENC_CLK                 0x40
37 #define VCU_AXI_DEC_CLK                 0x44
38 #define VCU_AXI_MCU_CLK                 0x48
39 #define VCU_DEC_VIDEO_STANDARD          0x4c
40 #define VCU_DEC_FRAME_SIZE_X            0x50
41 #define VCU_DEC_FRAME_SIZE_Y            0x54
42 #define VCU_DEC_FPS                     0x58
43 #define VCU_BUFFER_B_FRAME              0x5c
44 #define VCU_WPP_EN                      0x60
45 #define VCU_PLL_CLK_DEC                 0x64
46 #define VCU_NUM_CORE                    0x6c
47 #define VCU_GASKET_INIT                 0x74
48 #define VCU_GASKET_VALUE                0x03
49
50 /* vcu slcr registers, bitmask and shift */
51 #define VCU_PLL_CTRL                    0x24
52 #define VCU_PLL_CTRL_RESET_MASK         0x01
53 #define VCU_PLL_CTRL_RESET_SHIFT        0
54 #define VCU_PLL_CTRL_BYPASS_MASK        0x01
55 #define VCU_PLL_CTRL_BYPASS_SHIFT       3
56 #define VCU_PLL_CTRL_FBDIV_MASK         0x7f
57 #define VCU_PLL_CTRL_FBDIV_SHIFT        8
58 #define VCU_PLL_CTRL_POR_IN_MASK        0x01
59 #define VCU_PLL_CTRL_POR_IN_SHIFT       1
60 #define VCU_PLL_CTRL_PWR_POR_MASK       0x01
61 #define VCU_PLL_CTRL_PWR_POR_SHIFT      2
62 #define VCU_PLL_CTRL_CLKOUTDIV_MASK     0x03
63 #define VCU_PLL_CTRL_CLKOUTDIV_SHIFT    16
64 #define VCU_PLL_CTRL_DEFAULT            0
65 #define VCU_PLL_DIV2                    2
66
67 #define VCU_PLL_CFG                     0x28
68 #define VCU_PLL_CFG_RES_MASK            0x0f
69 #define VCU_PLL_CFG_RES_SHIFT           0
70 #define VCU_PLL_CFG_CP_MASK             0x0f
71 #define VCU_PLL_CFG_CP_SHIFT            5
72 #define VCU_PLL_CFG_LFHF_MASK           0x03
73 #define VCU_PLL_CFG_LFHF_SHIFT          10
74 #define VCU_PLL_CFG_LOCK_CNT_MASK       0x03ff
75 #define VCU_PLL_CFG_LOCK_CNT_SHIFT      13
76 #define VCU_PLL_CFG_LOCK_DLY_MASK       0x7f
77 #define VCU_PLL_CFG_LOCK_DLY_SHIFT      25
78 #define VCU_ENC_CORE_CTRL               0x30
79 #define VCU_ENC_MCU_CTRL                0x34
80 #define VCU_DEC_CORE_CTRL               0x38
81 #define VCU_DEC_MCU_CTRL                0x3c
82 #define VCU_PLL_DIVISOR_MASK            0x3f
83 #define VCU_PLL_DIVISOR_SHIFT           4
84 #define VCU_SRCSEL_MASK                 0x01
85 #define VCU_SRCSEL_SHIFT                0
86 #define VCU_SRCSEL_PLL                  1
87
88 #define VCU_PLL_STATUS                  0x60
89 #define VCU_PLL_STATUS_LOCK_STATUS_MASK 0x01
90
91 #define MHZ                             1000000
92 #define FVCO_MIN                        (1500U * MHZ)
93 #define FVCO_MAX                        (3000U * MHZ)
94 #define DIVISOR_MIN                     0
95 #define DIVISOR_MAX                     63
96 #define FRAC                            100
97 #define LIMIT                           (10 * MHZ)
98
99 /**
100  * struct xvcu_device - Xilinx VCU init device structure
101  * @dev: Platform device
102  * @pll_ref: pll ref clock source
103  * @aclk: axi clock source
104  * @logicore_reg_ba: logicore reg base address
105  * @vcu_slcr_ba: vcu_slcr Register base address
106  * @coreclk: core clock frequency
107  */
108 struct xvcu_device {
109         struct device *dev;
110         struct clk *pll_ref;
111         struct clk *aclk;
112         void __iomem *logicore_reg_ba;
113         void __iomem *vcu_slcr_ba;
114         u32 coreclk;
115 };
116
117 /**
118  * struct xvcu_pll_cfg - Helper data
119  * @fbdiv: The integer portion of the feedback divider to the PLL
120  * @cp: PLL charge pump control
121  * @res: PLL loop filter resistor control
122  * @lfhf: PLL loop filter high frequency capacitor control
123  * @lock_dly: Lock circuit configuration settings for lock windowsize
124  * @lock_cnt: Lock circuit counter setting
125  */
126 struct xvcu_pll_cfg {
127         u32 fbdiv;
128         u32 cp;
129         u32 res;
130         u32 lfhf;
131         u32 lock_dly;
132         u32 lock_cnt;
133 };
134
135 static const struct xvcu_pll_cfg xvcu_pll_cfg[] = {
136         { 25, 3, 10, 3, 63, 1000 },
137         { 26, 3, 10, 3, 63, 1000 },
138         { 27, 4, 6, 3, 63, 1000 },
139         { 28, 4, 6, 3, 63, 1000 },
140         { 29, 4, 6, 3, 63, 1000 },
141         { 30, 4, 6, 3, 63, 1000 },
142         { 31, 6, 1, 3, 63, 1000 },
143         { 32, 6, 1, 3, 63, 1000 },
144         { 33, 4, 10, 3, 63, 1000 },
145         { 34, 5, 6, 3, 63, 1000 },
146         { 35, 5, 6, 3, 63, 1000 },
147         { 36, 5, 6, 3, 63, 1000 },
148         { 37, 5, 6, 3, 63, 1000 },
149         { 38, 5, 6, 3, 63, 975 },
150         { 39, 3, 12, 3, 63, 950 },
151         { 40, 3, 12, 3, 63, 925 },
152         { 41, 3, 12, 3, 63, 900 },
153         { 42, 3, 12, 3, 63, 875 },
154         { 43, 3, 12, 3, 63, 850 },
155         { 44, 3, 12, 3, 63, 850 },
156         { 45, 3, 12, 3, 63, 825 },
157         { 46, 3, 12, 3, 63, 800 },
158         { 47, 3, 12, 3, 63, 775 },
159         { 48, 3, 12, 3, 63, 775 },
160         { 49, 3, 12, 3, 63, 750 },
161         { 50, 3, 12, 3, 63, 750 },
162         { 51, 3, 2, 3, 63, 725 },
163         { 52, 3, 2, 3, 63, 700 },
164         { 53, 3, 2, 3, 63, 700 },
165         { 54, 3, 2, 3, 63, 675 },
166         { 55, 3, 2, 3, 63, 675 },
167         { 56, 3, 2, 3, 63, 650 },
168         { 57, 3, 2, 3, 63, 650 },
169         { 58, 3, 2, 3, 63, 625 },
170         { 59, 3, 2, 3, 63, 625 },
171         { 60, 3, 2, 3, 63, 625 },
172         { 61, 3, 2, 3, 63, 600 },
173         { 62, 3, 2, 3, 63, 600 },
174         { 63, 3, 2, 3, 63, 600 },
175         { 64, 3, 2, 3, 63, 600 },
176         { 65, 3, 2, 3, 63, 600 },
177         { 66, 3, 2, 3, 63, 600 },
178         { 67, 3, 2, 3, 63, 600 },
179         { 68, 3, 2, 3, 63, 600 },
180         { 69, 3, 2, 3, 63, 600 },
181         { 70, 3, 2, 3, 63, 600 },
182         { 71, 3, 2, 3, 63, 600 },
183         { 72, 3, 2, 3, 63, 600 },
184         { 73, 3, 2, 3, 63, 600 },
185         { 74, 3, 2, 3, 63, 600 },
186         { 75, 3, 2, 3, 63, 600 },
187         { 76, 3, 2, 3, 63, 600 },
188         { 77, 3, 2, 3, 63, 600 },
189         { 78, 3, 2, 3, 63, 600 },
190         { 79, 3, 2, 3, 63, 600 },
191         { 80, 3, 2, 3, 63, 600 },
192         { 81, 3, 2, 3, 63, 600 },
193         { 82, 3, 2, 3, 63, 600 },
194         { 83, 4, 2, 3, 63, 600 },
195         { 84, 4, 2, 3, 63, 600 },
196         { 85, 4, 2, 3, 63, 600 },
197         { 86, 4, 2, 3, 63, 600 },
198         { 87, 4, 2, 3, 63, 600 },
199         { 88, 4, 2, 3, 63, 600 },
200         { 89, 4, 2, 3, 63, 600 },
201         { 90, 4, 2, 3, 63, 600 },
202         { 91, 4, 2, 3, 63, 600 },
203         { 92, 4, 2, 3, 63, 600 },
204         { 93, 4, 2, 3, 63, 600 },
205         { 94, 4, 2, 3, 63, 600 },
206         { 95, 4, 2, 3, 63, 600 },
207         { 96, 4, 2, 3, 63, 600 },
208         { 97, 4, 2, 3, 63, 600 },
209         { 98, 4, 2, 3, 63, 600 },
210         { 99, 4, 2, 3, 63, 600 },
211         { 100, 4, 2, 3, 63, 600 },
212         { 101, 4, 2, 3, 63, 600 },
213         { 102, 4, 2, 3, 63, 600 },
214         { 103, 5, 2, 3, 63, 600 },
215         { 104, 5, 2, 3, 63, 600 },
216         { 105, 5, 2, 3, 63, 600 },
217         { 106, 5, 2, 3, 63, 600 },
218         { 107, 3, 4, 3, 63, 600 },
219         { 108, 3, 4, 3, 63, 600 },
220         { 109, 3, 4, 3, 63, 600 },
221         { 110, 3, 4, 3, 63, 600 },
222         { 111, 3, 4, 3, 63, 600 },
223         { 112, 3, 4, 3, 63, 600 },
224         { 113, 3, 4, 3, 63, 600 },
225         { 114, 3, 4, 3, 63, 600 },
226         { 115, 3, 4, 3, 63, 600 },
227         { 116, 3, 4, 3, 63, 600 },
228         { 117, 3, 4, 3, 63, 600 },
229         { 118, 3, 4, 3, 63, 600 },
230         { 119, 3, 4, 3, 63, 600 },
231         { 120, 3, 4, 3, 63, 600 },
232         { 121, 3, 4, 3, 63, 600 },
233         { 122, 3, 4, 3, 63, 600 },
234         { 123, 3, 4, 3, 63, 600 },
235         { 124, 3, 4, 3, 63, 600 },
236         { 125, 3, 4, 3, 63, 600 },
237 };
238
239 /**
240  * xvcu_read - Read from the VCU register space
241  * @iomem:      vcu reg space base address
242  * @offset:     vcu reg offset from base
243  *
244  * Return:      Returns 32bit value from VCU register specified
245  *
246  */
247 static inline u32 xvcu_read(void __iomem *iomem, u32 offset)
248 {
249         return ioread32(iomem + offset);
250 }
251
252 /**
253  * xvcu_write - Write to the VCU register space
254  * @iomem:      vcu reg space base address
255  * @offset:     vcu reg offset from base
256  * @value:      Value to write
257  */
258 static inline void xvcu_write(void __iomem *iomem, u32 offset, u32 value)
259 {
260         iowrite32(value, iomem + offset);
261 }
262
263 /**
264  * xvcu_write_field_reg - Write to the vcu reg field
265  * @iomem:      vcu reg space base address
266  * @offset:     vcu reg offset from base
267  * @field:      vcu reg field to write to
268  * @mask:       vcu reg mask
269  * @shift:      vcu reg number of bits to shift the bitfield
270  */
271 static void xvcu_write_field_reg(void __iomem *iomem, int offset,
272                                  u32 field, u32 mask, int shift)
273 {
274         u32 val = xvcu_read(iomem, offset);
275
276         val &= ~(mask << shift);
277         val |= (field & mask) << shift;
278
279         xvcu_write(iomem, offset, val);
280 }
281
282 /**
283  * xvcu_get_color_depth - read the color depth register
284  * @xvcu:       Pointer to the xvcu_device structure
285  *
286  * Return:      Returns 32bit value
287  *
288  */
289 u32 xvcu_get_color_depth(struct xvcu_device *xvcu)
290 {
291         return xvcu_read(xvcu->logicore_reg_ba, VCU_ENC_COLOR_DEPTH);
292 }
293 EXPORT_SYMBOL_GPL(xvcu_get_color_depth);
294
295 /**
296  * xvcu_get_memory_depth - read the memory depth register
297  * @xvcu:       Pointer to the xvcu_device structure
298  *
299  * Return:      Returns 32bit value
300  *
301  */
302 u32 xvcu_get_memory_depth(struct xvcu_device *xvcu)
303 {
304         return xvcu_read(xvcu->logicore_reg_ba, VCU_MEMORY_DEPTH);
305 }
306 EXPORT_SYMBOL_GPL(xvcu_get_memory_depth);
307
308 /**
309  * xvcu_get_clock_frequency - provide the core clock frequency
310  * @xvcu:       Pointer to the xvcu_device structure
311  *
312  * Return:      Returns 32bit value
313  *
314  */
315 u32 xvcu_get_clock_frequency(struct xvcu_device *xvcu)
316 {
317         return xvcu->coreclk;
318 }
319 EXPORT_SYMBOL_GPL(xvcu_get_clock_frequency);
320
321 /**
322  * xvcu_get_num_cores - read the number of core register
323  * @xvcu:       Pointer to the xvcu_device structure
324  *
325  * Return:      Returns 32bit value
326  *
327  */
328 u32 xvcu_get_num_cores(struct xvcu_device *xvcu)
329 {
330         return xvcu_read(xvcu->logicore_reg_ba, VCU_NUM_CORE);
331 }
332 EXPORT_SYMBOL_GPL(xvcu_get_num_cores);
333
334 /**
335  * xvcu_set_vcu_pll_info - Set the VCU PLL info
336  * @xvcu:       Pointer to the xvcu_device structure
337  *
338  * Programming the VCU PLL based on the user configuration
339  * (ref clock freq, core clock freq, mcu clock freq).
340  * Core clock frequency has higher priority than mcu clock frequency
341  * Errors in following cases
342  *    - When mcu or clock clock get from logicoreIP is 0
343  *    - When VCU PLL DIV related bits value other than 1
344  *    - When proper data not found for given data
345  *    - When sis570_1 clocksource related operation failed
346  *
347  * Return:      Returns status, either success or error+reason
348  */
349 static int xvcu_set_vcu_pll_info(struct xvcu_device *xvcu)
350 {
351         u32 refclk, coreclk, mcuclk, inte, deci;
352         u32 divisor_mcu, divisor_core, fvco;
353         u32 clkoutdiv, vcu_pll_ctrl, pll_clk;
354         u32 cfg_val, mod, ctrl;
355         int ret, i;
356         const struct xvcu_pll_cfg *found = NULL;
357
358         inte = xvcu_read(xvcu->logicore_reg_ba, VCU_PLL_CLK);
359         deci = xvcu_read(xvcu->logicore_reg_ba, VCU_PLL_CLK_DEC);
360         coreclk = xvcu_read(xvcu->logicore_reg_ba, VCU_CORE_CLK) * MHZ;
361         mcuclk = xvcu_read(xvcu->logicore_reg_ba, VCU_MCU_CLK) * MHZ;
362         if (!mcuclk || !coreclk) {
363                 dev_err(xvcu->dev, "Invalid mcu and core clock data\n");
364                 return -EINVAL;
365         }
366
367         refclk = (inte * MHZ) + (deci * (MHZ / FRAC));
368         dev_dbg(xvcu->dev, "Ref clock from logicoreIP is %uHz\n", refclk);
369         dev_dbg(xvcu->dev, "Core clock from logicoreIP is %uHz\n", coreclk);
370         dev_dbg(xvcu->dev, "Mcu clock from logicoreIP is %uHz\n", mcuclk);
371
372         clk_disable_unprepare(xvcu->pll_ref);
373         ret = clk_set_rate(xvcu->pll_ref, refclk);
374         if (ret)
375                 dev_warn(xvcu->dev, "failed to set logicoreIP refclk rate\n");
376
377         ret = clk_prepare_enable(xvcu->pll_ref);
378         if (ret) {
379                 dev_err(xvcu->dev, "failed to enable pll_ref clock source\n");
380                 return ret;
381         }
382
383         refclk = clk_get_rate(xvcu->pll_ref);
384
385         /*
386          * The divide-by-2 should be always enabled (==1)
387          * to meet the timing in the design.
388          * Otherwise, it's an error
389          */
390         vcu_pll_ctrl = xvcu_read(xvcu->vcu_slcr_ba, VCU_PLL_CTRL);
391         clkoutdiv = vcu_pll_ctrl >> VCU_PLL_CTRL_CLKOUTDIV_SHIFT;
392         clkoutdiv = clkoutdiv & VCU_PLL_CTRL_CLKOUTDIV_MASK;
393         if (clkoutdiv != 1) {
394                 dev_err(xvcu->dev, "clkoutdiv value is invalid\n");
395                 return -EINVAL;
396         }
397
398         for (i = ARRAY_SIZE(xvcu_pll_cfg) - 1; i >= 0; i--) {
399                 const struct xvcu_pll_cfg *cfg = &xvcu_pll_cfg[i];
400
401                 fvco = cfg->fbdiv * refclk;
402                 if (fvco >= FVCO_MIN && fvco <= FVCO_MAX) {
403                         pll_clk = fvco / VCU_PLL_DIV2;
404                         if (fvco % VCU_PLL_DIV2 != 0)
405                                 pll_clk++;
406                         mod = pll_clk % coreclk;
407                         if (mod < LIMIT) {
408                                 divisor_core = pll_clk / coreclk;
409                         } else if (coreclk - mod < LIMIT) {
410                                 divisor_core = pll_clk / coreclk;
411                                 divisor_core++;
412                         } else {
413                                 continue;
414                         }
415                         if (divisor_core >= DIVISOR_MIN &&
416                             divisor_core <= DIVISOR_MAX) {
417                                 found = cfg;
418                                 divisor_mcu = pll_clk / mcuclk;
419                                 mod = pll_clk % mcuclk;
420                                 if (mcuclk - mod < LIMIT)
421                                         divisor_mcu++;
422                                 break;
423                         }
424                 }
425         }
426
427         if (!found) {
428                 dev_err(xvcu->dev, "Invalid clock combination.\n");
429                 return -EINVAL;
430         }
431
432         xvcu->coreclk = pll_clk / divisor_core;
433         mcuclk = pll_clk / divisor_mcu;
434         dev_dbg(xvcu->dev, "Actual Ref clock freq is %uHz\n", refclk);
435         dev_dbg(xvcu->dev, "Actual Core clock freq is %uHz\n", xvcu->coreclk);
436         dev_dbg(xvcu->dev, "Actual Mcu clock freq is %uHz\n", mcuclk);
437
438         vcu_pll_ctrl &= ~(VCU_PLL_CTRL_FBDIV_MASK << VCU_PLL_CTRL_FBDIV_SHIFT);
439         vcu_pll_ctrl |= (found->fbdiv & VCU_PLL_CTRL_FBDIV_MASK) <<
440                          VCU_PLL_CTRL_FBDIV_SHIFT;
441         vcu_pll_ctrl &= ~(VCU_PLL_CTRL_POR_IN_MASK <<
442                           VCU_PLL_CTRL_POR_IN_SHIFT);
443         vcu_pll_ctrl |= (VCU_PLL_CTRL_DEFAULT & VCU_PLL_CTRL_POR_IN_MASK) <<
444                          VCU_PLL_CTRL_POR_IN_SHIFT;
445         vcu_pll_ctrl &= ~(VCU_PLL_CTRL_PWR_POR_MASK <<
446                           VCU_PLL_CTRL_PWR_POR_SHIFT);
447         vcu_pll_ctrl |= (VCU_PLL_CTRL_DEFAULT & VCU_PLL_CTRL_PWR_POR_MASK) <<
448                          VCU_PLL_CTRL_PWR_POR_SHIFT;
449         xvcu_write(xvcu->vcu_slcr_ba, VCU_PLL_CTRL, vcu_pll_ctrl);
450
451         /* Set divisor for the core and mcu clock */
452         ctrl = xvcu_read(xvcu->vcu_slcr_ba, VCU_ENC_CORE_CTRL);
453         ctrl &= ~(VCU_PLL_DIVISOR_MASK << VCU_PLL_DIVISOR_SHIFT);
454         ctrl |= (divisor_core & VCU_PLL_DIVISOR_MASK) <<
455                  VCU_PLL_DIVISOR_SHIFT;
456         ctrl &= ~(VCU_SRCSEL_MASK << VCU_SRCSEL_SHIFT);
457         ctrl |= (VCU_SRCSEL_PLL & VCU_SRCSEL_MASK) << VCU_SRCSEL_SHIFT;
458         xvcu_write(xvcu->vcu_slcr_ba, VCU_ENC_CORE_CTRL, ctrl);
459
460         ctrl = xvcu_read(xvcu->vcu_slcr_ba, VCU_DEC_CORE_CTRL);
461         ctrl &= ~(VCU_PLL_DIVISOR_MASK << VCU_PLL_DIVISOR_SHIFT);
462         ctrl |= (divisor_core & VCU_PLL_DIVISOR_MASK) <<
463                  VCU_PLL_DIVISOR_SHIFT;
464         ctrl &= ~(VCU_SRCSEL_MASK << VCU_SRCSEL_SHIFT);
465         ctrl |= (VCU_SRCSEL_PLL & VCU_SRCSEL_MASK) << VCU_SRCSEL_SHIFT;
466         xvcu_write(xvcu->vcu_slcr_ba, VCU_DEC_CORE_CTRL, ctrl);
467
468         ctrl = xvcu_read(xvcu->vcu_slcr_ba, VCU_ENC_MCU_CTRL);
469         ctrl &= ~(VCU_PLL_DIVISOR_MASK << VCU_PLL_DIVISOR_SHIFT);
470         ctrl |= (divisor_mcu & VCU_PLL_DIVISOR_MASK) << VCU_PLL_DIVISOR_SHIFT;
471         ctrl &= ~(VCU_SRCSEL_MASK << VCU_SRCSEL_SHIFT);
472         ctrl |= (VCU_SRCSEL_PLL & VCU_SRCSEL_MASK) << VCU_SRCSEL_SHIFT;
473         xvcu_write(xvcu->vcu_slcr_ba, VCU_ENC_MCU_CTRL, ctrl);
474
475         ctrl = xvcu_read(xvcu->vcu_slcr_ba, VCU_DEC_MCU_CTRL);
476         ctrl &= ~(VCU_PLL_DIVISOR_MASK << VCU_PLL_DIVISOR_SHIFT);
477         ctrl |= (divisor_mcu & VCU_PLL_DIVISOR_MASK) << VCU_PLL_DIVISOR_SHIFT;
478         ctrl &= ~(VCU_SRCSEL_MASK << VCU_SRCSEL_SHIFT);
479         ctrl |= (VCU_SRCSEL_PLL & VCU_SRCSEL_MASK) << VCU_SRCSEL_SHIFT;
480         xvcu_write(xvcu->vcu_slcr_ba, VCU_DEC_MCU_CTRL, ctrl);
481
482         /* Set RES, CP, LFHF, LOCK_CNT and LOCK_DLY cfg values */
483         cfg_val = (found->res << VCU_PLL_CFG_RES_SHIFT) |
484                    (found->cp << VCU_PLL_CFG_CP_SHIFT) |
485                    (found->lfhf << VCU_PLL_CFG_LFHF_SHIFT) |
486                    (found->lock_cnt << VCU_PLL_CFG_LOCK_CNT_SHIFT) |
487                    (found->lock_dly << VCU_PLL_CFG_LOCK_DLY_SHIFT);
488         xvcu_write(xvcu->vcu_slcr_ba, VCU_PLL_CFG, cfg_val);
489
490         return 0;
491 }
492
493 /**
494  * xvcu_set_pll - PLL init sequence
495  * @xvcu:       Pointer to the xvcu_device structure
496  *
497  * Call the api to set the PLL info and once that is done then
498  * init the PLL sequence to make the PLL stable.
499  *
500  * Return:      Returns status, either success or error+reason
501  */
502 static int xvcu_set_pll(struct xvcu_device *xvcu)
503 {
504         u32 lock_status;
505         unsigned long timeout;
506         int ret;
507
508         ret = xvcu_set_vcu_pll_info(xvcu);
509         if (ret) {
510                 dev_err(xvcu->dev, "failed to set pll info\n");
511                 return ret;
512         }
513
514         xvcu_write_field_reg(xvcu->vcu_slcr_ba, VCU_PLL_CTRL,
515                              1, VCU_PLL_CTRL_BYPASS_MASK,
516                              VCU_PLL_CTRL_BYPASS_SHIFT);
517         xvcu_write_field_reg(xvcu->vcu_slcr_ba, VCU_PLL_CTRL,
518                              1, VCU_PLL_CTRL_RESET_MASK,
519                              VCU_PLL_CTRL_RESET_SHIFT);
520         xvcu_write_field_reg(xvcu->vcu_slcr_ba, VCU_PLL_CTRL,
521                              0, VCU_PLL_CTRL_RESET_MASK,
522                              VCU_PLL_CTRL_RESET_SHIFT);
523         /*
524          * Defined the timeout for the max time to wait the
525          * PLL_STATUS to be locked.
526          */
527         timeout = jiffies + msecs_to_jiffies(2000);
528         do {
529                 lock_status = xvcu_read(xvcu->vcu_slcr_ba, VCU_PLL_STATUS);
530                 if (lock_status & VCU_PLL_STATUS_LOCK_STATUS_MASK) {
531                         xvcu_write_field_reg(xvcu->vcu_slcr_ba, VCU_PLL_CTRL,
532                                              0, VCU_PLL_CTRL_BYPASS_MASK,
533                                              VCU_PLL_CTRL_BYPASS_SHIFT);
534                         return 0;
535                 }
536         } while (!time_after(jiffies, timeout));
537
538         /* PLL is not locked even after the timeout of the 2sec */
539         dev_err(xvcu->dev, "PLL is not locked\n");
540         return -ETIMEDOUT;
541 }
542
543 /**
544  * xvcu_probe - Probe existence of the logicoreIP
545  *                      and initialize PLL
546  *
547  * @pdev:       Pointer to the platform_device structure
548  *
549  * Return:      Returns 0 on success
550  *              Negative error code otherwise
551  */
552 static int xvcu_probe(struct platform_device *pdev)
553 {
554         struct resource *res;
555         struct xvcu_device *xvcu;
556         int ret;
557
558         xvcu = devm_kzalloc(&pdev->dev, sizeof(*xvcu), GFP_KERNEL);
559         if (!xvcu)
560                 return -ENOMEM;
561
562         xvcu->dev = &pdev->dev;
563         res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vcu_slcr");
564         if (!res) {
565                 dev_err(&pdev->dev, "get vcu_slcr memory resource failed.\n");
566                 return -ENODEV;
567         }
568
569         xvcu->vcu_slcr_ba = devm_ioremap_nocache(&pdev->dev, res->start,
570                                                  resource_size(res));
571         if (!xvcu->vcu_slcr_ba) {
572                 dev_err(&pdev->dev, "vcu_slcr register mapping failed.\n");
573                 return -ENOMEM;
574         }
575
576         res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "logicore");
577         if (!res) {
578                 dev_err(&pdev->dev, "get logicore memory resource failed.\n");
579                 return -ENODEV;
580         }
581
582         xvcu->logicore_reg_ba = devm_ioremap_nocache(&pdev->dev, res->start,
583                                                      resource_size(res));
584         if (!xvcu->logicore_reg_ba) {
585                 dev_err(&pdev->dev, "logicore register mapping failed.\n");
586                 return -ENOMEM;
587         }
588
589         xvcu->aclk = devm_clk_get(&pdev->dev, "aclk");
590         if (IS_ERR(xvcu->aclk)) {
591                 dev_err(&pdev->dev, "Could not get aclk clock\n");
592                 return PTR_ERR(xvcu->aclk);
593         }
594
595         xvcu->pll_ref = devm_clk_get(&pdev->dev, "pll_ref");
596         if (IS_ERR(xvcu->pll_ref)) {
597                 dev_err(&pdev->dev, "Could not get pll_ref clock\n");
598                 return PTR_ERR(xvcu->pll_ref);
599         }
600
601         ret = clk_prepare_enable(xvcu->aclk);
602         if (ret) {
603                 dev_err(&pdev->dev, "aclk clock enable failed\n");
604                 return ret;
605         }
606
607         ret = clk_prepare_enable(xvcu->pll_ref);
608         if (ret) {
609                 dev_err(&pdev->dev, "pll_ref clock enable failed\n");
610                 goto error_aclk;
611         }
612
613         /*
614          * Do the Gasket isolation and put the VCU out of reset
615          * Bit 0 : Gasket isolation
616          * Bit 1 : put VCU out of reset
617          */
618         xvcu_write(xvcu->logicore_reg_ba, VCU_GASKET_INIT, VCU_GASKET_VALUE);
619
620         /* Do the PLL Settings based on the ref clk,core and mcu clk freq */
621         ret = xvcu_set_pll(xvcu);
622         if (ret) {
623                 dev_err(&pdev->dev, "Failed to set the pll\n");
624                 goto error_pll_ref;
625         }
626
627         dev_set_drvdata(&pdev->dev, xvcu);
628
629         ret = of_platform_populate(xvcu->dev->of_node, NULL, NULL, &pdev->dev);
630         if (ret) {
631                 dev_err(&pdev->dev, "Failed to register allegro codecs\n");
632                 goto error_pll_ref;
633         }
634         dev_info(&pdev->dev, "%s: Probed successfully\n", __func__);
635
636         return 0;
637
638 error_pll_ref:
639         clk_disable_unprepare(xvcu->pll_ref);
640 error_aclk:
641         clk_disable_unprepare(xvcu->aclk);
642         return ret;
643 }
644
645 /**
646  * xvcu_remove - Depopulate the child nodes, Insert gasket isolation
647  *                      and disable the clock
648  * @pdev:       Pointer to the platform_device structure
649  *
650  * Return:      Returns 0 on success
651  *              Negative error code otherwise
652  */
653 static int xvcu_remove(struct platform_device *pdev)
654 {
655         struct xvcu_device *xvcu;
656
657         xvcu = platform_get_drvdata(pdev);
658         if (!xvcu)
659                 return -ENODEV;
660
661         of_platform_depopulate(&pdev->dev);
662
663         /* Add the the Gasket isolation and put the VCU in reset. */
664         xvcu_write(xvcu->logicore_reg_ba, VCU_GASKET_INIT, 0);
665
666         clk_disable_unprepare(xvcu->pll_ref);
667         clk_disable_unprepare(xvcu->aclk);
668
669         return 0;
670 }
671
672 static const struct of_device_id xvcu_of_id_table[] = {
673         { .compatible = "xlnx,vcu" },
674         { .compatible = "xlnx,vcu-logicoreip-1.0" },
675         { }
676 };
677 MODULE_DEVICE_TABLE(of, xvcu_of_id_table);
678
679 static struct platform_driver xvcu_driver = {
680         .driver = {
681                 .name           = "xilinx-vcu",
682                 .of_match_table = xvcu_of_id_table,
683         },
684         .probe                  = xvcu_probe,
685         .remove                 = xvcu_remove,
686 };
687
688 module_platform_driver(xvcu_driver);
689
690 MODULE_AUTHOR("Dhaval Shah <dshah@xilinx.com>");
691 MODULE_DESCRIPTION("Xilinx VCU init Driver");
692 MODULE_LICENSE("GPL v2");