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