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