1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Amlogic Meson VPU Power Domain Controller driver
4  *
5  * Copyright (c) 2018 BayLibre, SAS.
6  * Author: Neil Armstrong <narmstrong@baylibre.com>
7  */
8 
9 #include <common.h>
10 #include <dm.h>
11 #include <log.h>
12 #include <malloc.h>
13 #include <power-domain-uclass.h>
14 #include <regmap.h>
15 #include <syscon.h>
16 #include <reset.h>
17 #include <clk.h>
18 #include <linux/bitops.h>
19 #include <linux/delay.h>
20 #include <linux/err.h>
21 
22 enum {
23 	VPU_PWRC_COMPATIBLE_GX		= 0,
24 	VPU_PWRC_COMPATIBLE_G12A	= 1,
25 };
26 
27 /* AO Offsets */
28 
29 #define AO_RTI_GEN_PWR_SLEEP0		(0x3a << 2)
30 
31 #define GEN_PWR_VPU_HDMI		BIT(8)
32 #define GEN_PWR_VPU_HDMI_ISO		BIT(9)
33 
34 /* HHI Offsets */
35 
36 #define HHI_MEM_PD_REG0			(0x40 << 2)
37 #define HHI_VPU_MEM_PD_REG0		(0x41 << 2)
38 #define HHI_VPU_MEM_PD_REG1		(0x42 << 2)
39 #define HHI_VPU_MEM_PD_REG2		(0x4d << 2)
40 
41 struct meson_gx_pwrc_vpu_priv {
42 	struct regmap *regmap_ao;
43 	struct regmap *regmap_hhi;
44 	struct reset_ctl_bulk resets;
45 	struct clk_bulk clks;
46 };
47 
meson_pwrc_vpu_request(struct power_domain * power_domain)48 static int meson_pwrc_vpu_request(struct power_domain *power_domain)
49 {
50 	return 0;
51 }
52 
meson_pwrc_vpu_free(struct power_domain * power_domain)53 static int meson_pwrc_vpu_free(struct power_domain *power_domain)
54 {
55 	return 0;
56 }
57 
meson_gx_pwrc_vpu_on(struct power_domain * power_domain)58 static int meson_gx_pwrc_vpu_on(struct power_domain *power_domain)
59 {
60 	struct meson_gx_pwrc_vpu_priv *priv = dev_get_priv(power_domain->dev);
61 	int i, ret;
62 
63 	regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
64 			   GEN_PWR_VPU_HDMI, 0);
65 	udelay(20);
66 
67 	/* Power Up Memories */
68 	for (i = 0; i < 32; i += 2) {
69 		regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG0,
70 				   0x3 << i, 0);
71 		udelay(5);
72 	}
73 
74 	for (i = 0; i < 32; i += 2) {
75 		regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG1,
76 				   0x3 << i, 0);
77 		udelay(5);
78 	}
79 
80 	for (i = 8; i < 16; i++) {
81 		regmap_update_bits(priv->regmap_hhi, HHI_MEM_PD_REG0,
82 				   BIT(i), 0);
83 		udelay(5);
84 	}
85 	udelay(20);
86 
87 	ret = reset_assert_bulk(&priv->resets);
88 	if (ret)
89 		return ret;
90 
91 	regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
92 			   GEN_PWR_VPU_HDMI_ISO, 0);
93 
94 	ret = reset_deassert_bulk(&priv->resets);
95 	if (ret)
96 		return ret;
97 
98 	ret = clk_enable_bulk(&priv->clks);
99 	if (ret)
100 		return ret;
101 
102 	return 0;
103 }
104 
meson_g12a_pwrc_vpu_on(struct power_domain * power_domain)105 static int meson_g12a_pwrc_vpu_on(struct power_domain *power_domain)
106 {
107 	struct meson_gx_pwrc_vpu_priv *priv = dev_get_priv(power_domain->dev);
108 	int i, ret;
109 
110 	regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
111 			   GEN_PWR_VPU_HDMI, 0);
112 	udelay(20);
113 
114 	/* Power Up Memories */
115 	for (i = 0; i < 32; i += 2) {
116 		regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG0,
117 				   0x3 << i, 0);
118 		udelay(5);
119 	}
120 
121 	for (i = 0; i < 32; i += 2) {
122 		regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG1,
123 				   0x3 << i, 0);
124 		udelay(5);
125 	}
126 
127 	for (i = 0; i < 32; i += 2) {
128 		regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG2,
129 				   0x3 << i, 0);
130 		udelay(5);
131 	}
132 
133 	for (i = 8; i < 16; i++) {
134 		regmap_update_bits(priv->regmap_hhi, HHI_MEM_PD_REG0,
135 				   BIT(i), 0);
136 		udelay(5);
137 	}
138 	udelay(20);
139 
140 	ret = reset_assert_bulk(&priv->resets);
141 	if (ret)
142 		return ret;
143 
144 	regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
145 			   GEN_PWR_VPU_HDMI_ISO, 0);
146 
147 	ret = reset_deassert_bulk(&priv->resets);
148 	if (ret)
149 		return ret;
150 
151 	ret = clk_enable_bulk(&priv->clks);
152 	if (ret)
153 		return ret;
154 
155 	return 0;
156 }
157 
meson_pwrc_vpu_on(struct power_domain * power_domain)158 static int meson_pwrc_vpu_on(struct power_domain *power_domain)
159 {
160 	unsigned int compat = dev_get_driver_data(power_domain->dev);
161 
162 	switch (compat) {
163 	case VPU_PWRC_COMPATIBLE_GX:
164 		return meson_gx_pwrc_vpu_on(power_domain);
165 	case VPU_PWRC_COMPATIBLE_G12A:
166 		return meson_g12a_pwrc_vpu_on(power_domain);
167 	}
168 
169 	return -EINVAL;
170 }
171 
meson_gx_pwrc_vpu_off(struct power_domain * power_domain)172 static int meson_gx_pwrc_vpu_off(struct power_domain *power_domain)
173 {
174 	struct meson_gx_pwrc_vpu_priv *priv = dev_get_priv(power_domain->dev);
175 	int i;
176 
177 	regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
178 			   GEN_PWR_VPU_HDMI_ISO, GEN_PWR_VPU_HDMI_ISO);
179 	udelay(20);
180 
181 	/* Power Down Memories */
182 	for (i = 0; i < 32; i += 2) {
183 		regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG0,
184 				   0x3 << i, 0x3 << i);
185 		udelay(5);
186 	}
187 	for (i = 0; i < 32; i += 2) {
188 		regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG1,
189 				   0x3 << i, 0x3 << i);
190 		udelay(5);
191 	}
192 	for (i = 8; i < 16; i++) {
193 		regmap_update_bits(priv->regmap_hhi, HHI_MEM_PD_REG0,
194 				   BIT(i), BIT(i));
195 		udelay(5);
196 	}
197 	udelay(20);
198 
199 	regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
200 			   GEN_PWR_VPU_HDMI, GEN_PWR_VPU_HDMI);
201 	mdelay(20);
202 
203 	clk_disable_bulk(&priv->clks);
204 
205 	return 0;
206 }
207 
meson_g12a_pwrc_vpu_off(struct power_domain * power_domain)208 static int meson_g12a_pwrc_vpu_off(struct power_domain *power_domain)
209 {
210 	struct meson_gx_pwrc_vpu_priv *priv = dev_get_priv(power_domain->dev);
211 	int i;
212 
213 	regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
214 			   GEN_PWR_VPU_HDMI_ISO, GEN_PWR_VPU_HDMI_ISO);
215 	udelay(20);
216 
217 	/* Power Down Memories */
218 	for (i = 0; i < 32; i += 2) {
219 		regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG0,
220 				   0x3 << i, 0x3 << i);
221 		udelay(5);
222 	}
223 	for (i = 0; i < 32; i += 2) {
224 		regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG1,
225 				   0x3 << i, 0x3 << i);
226 		udelay(5);
227 	}
228 	for (i = 0; i < 32; i += 2) {
229 		regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG2,
230 				   0x3 << i, 0x3 << i);
231 		udelay(5);
232 	}
233 	for (i = 8; i < 16; i++) {
234 		regmap_update_bits(priv->regmap_hhi, HHI_MEM_PD_REG0,
235 				   BIT(i), BIT(i));
236 		udelay(5);
237 	}
238 	udelay(20);
239 
240 	regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
241 			   GEN_PWR_VPU_HDMI, GEN_PWR_VPU_HDMI);
242 	mdelay(20);
243 
244 	clk_disable_bulk(&priv->clks);
245 
246 	return 0;
247 }
248 
meson_pwrc_vpu_off(struct power_domain * power_domain)249 static int meson_pwrc_vpu_off(struct power_domain *power_domain)
250 {
251 	unsigned int compat = dev_get_driver_data(power_domain->dev);
252 
253 	switch (compat) {
254 	case VPU_PWRC_COMPATIBLE_GX:
255 		return meson_gx_pwrc_vpu_off(power_domain);
256 	case VPU_PWRC_COMPATIBLE_G12A:
257 		return meson_g12a_pwrc_vpu_off(power_domain);
258 	}
259 
260 	return -EINVAL;
261 }
262 
meson_pwrc_vpu_of_xlate(struct power_domain * power_domain,struct ofnode_phandle_args * args)263 static int meson_pwrc_vpu_of_xlate(struct power_domain *power_domain,
264 				   struct ofnode_phandle_args *args)
265 {
266 	/* #power-domain-cells is 0 */
267 
268 	if (args->args_count != 0) {
269 		debug("Invalid args_count: %d\n", args->args_count);
270 		return -EINVAL;
271 	}
272 
273 	return 0;
274 }
275 
276 struct power_domain_ops meson_gx_pwrc_vpu_ops = {
277 	.rfree = meson_pwrc_vpu_free,
278 	.off = meson_pwrc_vpu_off,
279 	.on = meson_pwrc_vpu_on,
280 	.request = meson_pwrc_vpu_request,
281 	.of_xlate = meson_pwrc_vpu_of_xlate,
282 };
283 
284 static const struct udevice_id meson_gx_pwrc_vpu_ids[] = {
285 	{
286 		.compatible = "amlogic,meson-gx-pwrc-vpu",
287 		.data = VPU_PWRC_COMPATIBLE_GX,
288 	},
289 	{
290 		.compatible = "amlogic,meson-g12a-pwrc-vpu",
291 		.data = VPU_PWRC_COMPATIBLE_G12A,
292 	},
293 	{ }
294 };
295 
meson_gx_pwrc_vpu_probe(struct udevice * dev)296 static int meson_gx_pwrc_vpu_probe(struct udevice *dev)
297 {
298 	struct meson_gx_pwrc_vpu_priv *priv = dev_get_priv(dev);
299 	u32 hhi_phandle;
300 	ofnode hhi_node;
301 	int ret;
302 
303 	priv->regmap_ao = syscon_node_to_regmap(dev_ofnode(dev_get_parent(dev)));
304 	if (IS_ERR(priv->regmap_ao))
305 		return PTR_ERR(priv->regmap_ao);
306 
307 	ret = ofnode_read_u32(dev_ofnode(dev), "amlogic,hhi-sysctrl",
308 			      &hhi_phandle);
309 	if (ret)
310 		return ret;
311 
312 	hhi_node = ofnode_get_by_phandle(hhi_phandle);
313 	if (!ofnode_valid(hhi_node))
314 		return -EINVAL;
315 
316 	priv->regmap_hhi = syscon_node_to_regmap(hhi_node);
317 	if (IS_ERR(priv->regmap_hhi))
318 		return PTR_ERR(priv->regmap_hhi);
319 
320 	ret = reset_get_bulk(dev, &priv->resets);
321 	if (ret)
322 		return ret;
323 
324 	ret = clk_get_bulk(dev, &priv->clks);
325 	if (ret)
326 		return ret;
327 
328 	return 0;
329 }
330 
331 U_BOOT_DRIVER(meson_gx_pwrc_vpu) = {
332 	.name = "meson_gx_pwrc_vpu",
333 	.id = UCLASS_POWER_DOMAIN,
334 	.of_match = meson_gx_pwrc_vpu_ids,
335 	.probe = meson_gx_pwrc_vpu_probe,
336 	.ops = &meson_gx_pwrc_vpu_ops,
337 	.priv_auto	= sizeof(struct meson_gx_pwrc_vpu_priv),
338 };
339