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