colibri_imx6: fix video stdout in default environment
[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/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
48 static int meson_pwrc_vpu_request(struct power_domain *power_domain)
49 {
50         return 0;
51 }
52
53 static int meson_pwrc_vpu_free(struct power_domain *power_domain)
54 {
55         return 0;
56 }
57
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
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
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
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
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
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
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
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_get_parent(dev)->node);
304         if (IS_ERR(priv->regmap_ao))
305                 return PTR_ERR(priv->regmap_ao);
306
307         ret = ofnode_read_u32(dev->node, "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_alloc_size = sizeof(struct meson_gx_pwrc_vpu_priv),
338 };