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