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