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