1 // SPDX-License-Identifier: GPL-2.0
5 * Copyright (C) 2016 - 2017 Xilinx, Inc.
7 * Contacts Dhaval Shah <dshah@xilinx.com>
10 #include <linux/device.h>
11 #include <linux/errno.h>
13 #include <linux/module.h>
14 #include <linux/of_platform.h>
15 #include <linux/platform_device.h>
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
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
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
85 #define VCU_PLL_STATUS 0x60
86 #define VCU_PLL_STATUS_LOCK_STATUS_MASK 0x01
89 #define FVCO_MIN (1500U * MHZ)
90 #define FVCO_MAX (3000U * MHZ)
92 #define DIVISOR_MAX 63
94 #define LIMIT (10 * MHZ)
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
109 void __iomem
*logicore_reg_ba
;
110 void __iomem
*vcu_slcr_ba
;
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
123 struct xvcu_pll_cfg
{
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 },
237 * xvcu_read - Read from the VCU register space
238 * @iomem: vcu reg space base address
239 * @offset: vcu reg offset from base
241 * Return: Returns 32bit value from VCU register specified
244 static inline u32
xvcu_read(void __iomem
*iomem
, u32 offset
)
246 return ioread32(iomem
+ offset
);
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
255 static inline void xvcu_write(void __iomem
*iomem
, u32 offset
, u32 value
)
257 iowrite32(value
, iomem
+ offset
);
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
268 static void xvcu_write_field_reg(void __iomem
*iomem
, int offset
,
269 u32 field
, u32 mask
, int shift
)
271 u32 val
= xvcu_read(iomem
, offset
);
273 val
&= ~(mask
<< shift
);
274 val
|= (field
& mask
) << shift
;
276 xvcu_write(iomem
, offset
, val
);
280 * xvcu_set_vcu_pll_info - Set the VCU PLL info
281 * @xvcu: Pointer to the xvcu_device structure
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
292 * Return: Returns status, either success or error+reason
294 static int xvcu_set_vcu_pll_info(struct xvcu_device
*xvcu
)
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
;
301 const struct xvcu_pll_cfg
*found
= NULL
;
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");
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
);
317 clk_disable_unprepare(xvcu
->pll_ref
);
318 ret
= clk_set_rate(xvcu
->pll_ref
, refclk
);
320 dev_warn(xvcu
->dev
, "failed to set logicoreIP refclk rate\n");
322 ret
= clk_prepare_enable(xvcu
->pll_ref
);
324 dev_err(xvcu
->dev
, "failed to enable pll_ref clock source\n");
328 refclk
= clk_get_rate(xvcu
->pll_ref
);
331 * The divide-by-2 should be always enabled (==1)
332 * to meet the timing in the design.
333 * Otherwise, it's an error
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");
343 for (i
= ARRAY_SIZE(xvcu_pll_cfg
) - 1; i
>= 0; i
--) {
344 const struct xvcu_pll_cfg
*cfg
= &xvcu_pll_cfg
[i
];
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)
351 mod
= pll_clk
% coreclk
;
353 divisor_core
= pll_clk
/ coreclk
;
354 } else if (coreclk
- mod
< LIMIT
) {
355 divisor_core
= pll_clk
/ coreclk
;
360 if (divisor_core
>= DIVISOR_MIN
&&
361 divisor_core
<= DIVISOR_MAX
) {
363 divisor_mcu
= pll_clk
/ mcuclk
;
364 mod
= pll_clk
% mcuclk
;
365 if (mcuclk
- mod
< LIMIT
)
373 dev_err(xvcu
->dev
, "Invalid clock combination.\n");
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
);
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
);
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
);
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
);
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
);
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
);
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
);
439 * xvcu_set_pll - PLL init sequence
440 * @xvcu: Pointer to the xvcu_device structure
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.
445 * Return: Returns status, either success or error+reason
447 static int xvcu_set_pll(struct xvcu_device
*xvcu
)
450 unsigned long timeout
;
453 ret
= xvcu_set_vcu_pll_info(xvcu
);
455 dev_err(xvcu
->dev
, "failed to set pll info\n");
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
);
469 * Defined the timeout for the max time to wait the
470 * PLL_STATUS to be locked.
472 timeout
= jiffies
+ msecs_to_jiffies(2000);
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
);
481 } while (!time_after(jiffies
, timeout
));
483 /* PLL is not locked even after the timeout of the 2sec */
484 dev_err(xvcu
->dev
, "PLL is not locked\n");
489 * xvcu_probe - Probe existence of the logicoreIP
492 * @pdev: Pointer to the platform_device structure
494 * Return: Returns 0 on success
495 * Negative error code otherwise
497 static int xvcu_probe(struct platform_device
*pdev
)
499 struct resource
*res
;
500 struct xvcu_device
*xvcu
;
503 xvcu
= devm_kzalloc(&pdev
->dev
, sizeof(*xvcu
), GFP_KERNEL
);
507 xvcu
->dev
= &pdev
->dev
;
508 res
= platform_get_resource_byname(pdev
, IORESOURCE_MEM
, "vcu_slcr");
510 dev_err(&pdev
->dev
, "get vcu_slcr memory resource failed.\n");
514 xvcu
->vcu_slcr_ba
= devm_ioremap(&pdev
->dev
, res
->start
,
516 if (!xvcu
->vcu_slcr_ba
) {
517 dev_err(&pdev
->dev
, "vcu_slcr register mapping failed.\n");
521 res
= platform_get_resource_byname(pdev
, IORESOURCE_MEM
, "logicore");
523 dev_err(&pdev
->dev
, "get logicore memory resource failed.\n");
527 xvcu
->logicore_reg_ba
= devm_ioremap(&pdev
->dev
, res
->start
,
529 if (!xvcu
->logicore_reg_ba
) {
530 dev_err(&pdev
->dev
, "logicore register mapping failed.\n");
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
);
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
);
546 ret
= clk_prepare_enable(xvcu
->aclk
);
548 dev_err(&pdev
->dev
, "aclk clock enable failed\n");
552 ret
= clk_prepare_enable(xvcu
->pll_ref
);
554 dev_err(&pdev
->dev
, "pll_ref clock enable failed\n");
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
563 xvcu_write(xvcu
->logicore_reg_ba
, VCU_GASKET_INIT
, VCU_GASKET_VALUE
);
565 /* Do the PLL Settings based on the ref clk,core and mcu clk freq */
566 ret
= xvcu_set_pll(xvcu
);
568 dev_err(&pdev
->dev
, "Failed to set the pll\n");
572 dev_set_drvdata(&pdev
->dev
, xvcu
);
574 dev_info(&pdev
->dev
, "%s: Probed successfully\n", __func__
);
579 clk_disable_unprepare(xvcu
->pll_ref
);
581 clk_disable_unprepare(xvcu
->aclk
);
586 * xvcu_remove - Insert gasket isolation
587 * and disable the clock
588 * @pdev: Pointer to the platform_device structure
590 * Return: Returns 0 on success
591 * Negative error code otherwise
593 static int xvcu_remove(struct platform_device
*pdev
)
595 struct xvcu_device
*xvcu
;
597 xvcu
= platform_get_drvdata(pdev
);
601 /* Add the the Gasket isolation and put the VCU in reset. */
602 xvcu_write(xvcu
->logicore_reg_ba
, VCU_GASKET_INIT
, 0);
604 clk_disable_unprepare(xvcu
->pll_ref
);
605 clk_disable_unprepare(xvcu
->aclk
);
610 static const struct of_device_id xvcu_of_id_table
[] = {
611 { .compatible
= "xlnx,vcu" },
612 { .compatible
= "xlnx,vcu-logicoreip-1.0" },
615 MODULE_DEVICE_TABLE(of
, xvcu_of_id_table
);
617 static struct platform_driver xvcu_driver
= {
619 .name
= "xilinx-vcu",
620 .of_match_table
= xvcu_of_id_table
,
623 .remove
= xvcu_remove
,
626 module_platform_driver(xvcu_driver
);
628 MODULE_AUTHOR("Dhaval Shah <dshah@xilinx.com>");
629 MODULE_DESCRIPTION("Xilinx VCU init Driver");
630 MODULE_LICENSE("GPL v2");