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