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