GNU Linux-libre 6.8.7-gnu
[releases.git] / drivers / pmdomain / amlogic / meson-gx-pwrc-vpu.c
1 /*
2  * Copyright (c) 2017 BayLibre, SAS
3  * Author: Neil Armstrong <narmstrong@baylibre.com>
4  *
5  * SPDX-License-Identifier: GPL-2.0+
6  */
7
8 #include <linux/platform_device.h>
9 #include <linux/pm_domain.h>
10 #include <linux/bitfield.h>
11 #include <linux/regmap.h>
12 #include <linux/mfd/syscon.h>
13 #include <linux/of.h>
14 #include <linux/reset.h>
15 #include <linux/clk.h>
16 #include <linux/module.h>
17
18 /* AO Offsets */
19
20 #define AO_RTI_GEN_PWR_SLEEP0           (0x3a << 2)
21
22 #define GEN_PWR_VPU_HDMI                BIT(8)
23 #define GEN_PWR_VPU_HDMI_ISO            BIT(9)
24
25 /* HHI Offsets */
26
27 #define HHI_MEM_PD_REG0                 (0x40 << 2)
28 #define HHI_VPU_MEM_PD_REG0             (0x41 << 2)
29 #define HHI_VPU_MEM_PD_REG1             (0x42 << 2)
30 #define HHI_VPU_MEM_PD_REG2             (0x4d << 2)
31
32 struct meson_gx_pwrc_vpu {
33         struct generic_pm_domain genpd;
34         struct regmap *regmap_ao;
35         struct regmap *regmap_hhi;
36         struct reset_control *rstc;
37         struct clk *vpu_clk;
38         struct clk *vapb_clk;
39 };
40
41 static inline
42 struct meson_gx_pwrc_vpu *genpd_to_pd(struct generic_pm_domain *d)
43 {
44         return container_of(d, struct meson_gx_pwrc_vpu, genpd);
45 }
46
47 static int meson_gx_pwrc_vpu_power_off(struct generic_pm_domain *genpd)
48 {
49         struct meson_gx_pwrc_vpu *pd = genpd_to_pd(genpd);
50         int i;
51
52         regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
53                            GEN_PWR_VPU_HDMI_ISO, GEN_PWR_VPU_HDMI_ISO);
54         udelay(20);
55
56         /* Power Down Memories */
57         for (i = 0; i < 32; i += 2) {
58                 regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0,
59                                    0x3 << i, 0x3 << i);
60                 udelay(5);
61         }
62         for (i = 0; i < 32; i += 2) {
63                 regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1,
64                                    0x3 << i, 0x3 << i);
65                 udelay(5);
66         }
67         for (i = 8; i < 16; i++) {
68                 regmap_update_bits(pd->regmap_hhi, HHI_MEM_PD_REG0,
69                                    BIT(i), BIT(i));
70                 udelay(5);
71         }
72         udelay(20);
73
74         regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
75                            GEN_PWR_VPU_HDMI, GEN_PWR_VPU_HDMI);
76
77         msleep(20);
78
79         clk_disable_unprepare(pd->vpu_clk);
80         clk_disable_unprepare(pd->vapb_clk);
81
82         return 0;
83 }
84
85 static int meson_g12a_pwrc_vpu_power_off(struct generic_pm_domain *genpd)
86 {
87         struct meson_gx_pwrc_vpu *pd = genpd_to_pd(genpd);
88         int i;
89
90         regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
91                            GEN_PWR_VPU_HDMI_ISO, GEN_PWR_VPU_HDMI_ISO);
92         udelay(20);
93
94         /* Power Down Memories */
95         for (i = 0; i < 32; i += 2) {
96                 regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0,
97                                    0x3 << i, 0x3 << i);
98                 udelay(5);
99         }
100         for (i = 0; i < 32; i += 2) {
101                 regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1,
102                                    0x3 << i, 0x3 << i);
103                 udelay(5);
104         }
105         for (i = 0; i < 32; i += 2) {
106                 regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG2,
107                                    0x3 << i, 0x3 << i);
108                 udelay(5);
109         }
110         for (i = 8; i < 16; i++) {
111                 regmap_update_bits(pd->regmap_hhi, HHI_MEM_PD_REG0,
112                                    BIT(i), BIT(i));
113                 udelay(5);
114         }
115         udelay(20);
116
117         regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
118                            GEN_PWR_VPU_HDMI, GEN_PWR_VPU_HDMI);
119
120         msleep(20);
121
122         clk_disable_unprepare(pd->vpu_clk);
123         clk_disable_unprepare(pd->vapb_clk);
124
125         return 0;
126 }
127
128 static int meson_gx_pwrc_vpu_setup_clk(struct meson_gx_pwrc_vpu *pd)
129 {
130         int ret;
131
132         ret = clk_prepare_enable(pd->vpu_clk);
133         if (ret)
134                 return ret;
135
136         ret = clk_prepare_enable(pd->vapb_clk);
137         if (ret)
138                 clk_disable_unprepare(pd->vpu_clk);
139
140         return ret;
141 }
142
143 static int meson_gx_pwrc_vpu_power_on(struct generic_pm_domain *genpd)
144 {
145         struct meson_gx_pwrc_vpu *pd = genpd_to_pd(genpd);
146         int ret;
147         int i;
148
149         regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
150                            GEN_PWR_VPU_HDMI, 0);
151         udelay(20);
152
153         /* Power Up Memories */
154         for (i = 0; i < 32; i += 2) {
155                 regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0,
156                                    0x3 << i, 0);
157                 udelay(5);
158         }
159
160         for (i = 0; i < 32; i += 2) {
161                 regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1,
162                                    0x3 << i, 0);
163                 udelay(5);
164         }
165
166         for (i = 8; i < 16; i++) {
167                 regmap_update_bits(pd->regmap_hhi, HHI_MEM_PD_REG0,
168                                    BIT(i), 0);
169                 udelay(5);
170         }
171         udelay(20);
172
173         ret = reset_control_assert(pd->rstc);
174         if (ret)
175                 return ret;
176
177         regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
178                            GEN_PWR_VPU_HDMI_ISO, 0);
179
180         ret = reset_control_deassert(pd->rstc);
181         if (ret)
182                 return ret;
183
184         ret = meson_gx_pwrc_vpu_setup_clk(pd);
185         if (ret)
186                 return ret;
187
188         return 0;
189 }
190
191 static int meson_g12a_pwrc_vpu_power_on(struct generic_pm_domain *genpd)
192 {
193         struct meson_gx_pwrc_vpu *pd = genpd_to_pd(genpd);
194         int ret;
195         int i;
196
197         regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
198                            GEN_PWR_VPU_HDMI, 0);
199         udelay(20);
200
201         /* Power Up Memories */
202         for (i = 0; i < 32; i += 2) {
203                 regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0,
204                                    0x3 << i, 0);
205                 udelay(5);
206         }
207
208         for (i = 0; i < 32; i += 2) {
209                 regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1,
210                                    0x3 << i, 0);
211                 udelay(5);
212         }
213
214         for (i = 0; i < 32; i += 2) {
215                 regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG2,
216                                    0x3 << i, 0);
217                 udelay(5);
218         }
219
220         for (i = 8; i < 16; i++) {
221                 regmap_update_bits(pd->regmap_hhi, HHI_MEM_PD_REG0,
222                                    BIT(i), 0);
223                 udelay(5);
224         }
225         udelay(20);
226
227         ret = reset_control_assert(pd->rstc);
228         if (ret)
229                 return ret;
230
231         regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
232                            GEN_PWR_VPU_HDMI_ISO, 0);
233
234         ret = reset_control_deassert(pd->rstc);
235         if (ret)
236                 return ret;
237
238         ret = meson_gx_pwrc_vpu_setup_clk(pd);
239         if (ret)
240                 return ret;
241
242         return 0;
243 }
244
245 static bool meson_gx_pwrc_vpu_get_power(struct meson_gx_pwrc_vpu *pd)
246 {
247         u32 reg;
248
249         regmap_read(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, &reg);
250
251         return (reg & GEN_PWR_VPU_HDMI);
252 }
253
254 static struct meson_gx_pwrc_vpu vpu_hdmi_pd = {
255         .genpd = {
256                 .name = "vpu_hdmi",
257                 .power_off = meson_gx_pwrc_vpu_power_off,
258                 .power_on = meson_gx_pwrc_vpu_power_on,
259         },
260 };
261
262 static struct meson_gx_pwrc_vpu vpu_hdmi_pd_g12a = {
263         .genpd = {
264                 .name = "vpu_hdmi",
265                 .power_off = meson_g12a_pwrc_vpu_power_off,
266                 .power_on = meson_g12a_pwrc_vpu_power_on,
267         },
268 };
269
270 static int meson_gx_pwrc_vpu_probe(struct platform_device *pdev)
271 {
272         const struct meson_gx_pwrc_vpu *vpu_pd_match;
273         struct regmap *regmap_ao, *regmap_hhi;
274         struct meson_gx_pwrc_vpu *vpu_pd;
275         struct device_node *parent_np;
276         struct reset_control *rstc;
277         struct clk *vpu_clk;
278         struct clk *vapb_clk;
279         bool powered_off;
280         int ret;
281
282         vpu_pd_match = of_device_get_match_data(&pdev->dev);
283         if (!vpu_pd_match) {
284                 dev_err(&pdev->dev, "failed to get match data\n");
285                 return -ENODEV;
286         }
287
288         vpu_pd = devm_kzalloc(&pdev->dev, sizeof(*vpu_pd), GFP_KERNEL);
289         if (!vpu_pd)
290                 return -ENOMEM;
291
292         memcpy(vpu_pd, vpu_pd_match, sizeof(*vpu_pd));
293
294         parent_np = of_get_parent(pdev->dev.of_node);
295         regmap_ao = syscon_node_to_regmap(parent_np);
296         of_node_put(parent_np);
297         if (IS_ERR(regmap_ao)) {
298                 dev_err(&pdev->dev, "failed to get regmap\n");
299                 return PTR_ERR(regmap_ao);
300         }
301
302         regmap_hhi = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
303                                                      "amlogic,hhi-sysctrl");
304         if (IS_ERR(regmap_hhi)) {
305                 dev_err(&pdev->dev, "failed to get HHI regmap\n");
306                 return PTR_ERR(regmap_hhi);
307         }
308
309         rstc = devm_reset_control_array_get_exclusive(&pdev->dev);
310         if (IS_ERR(rstc))
311                 return dev_err_probe(&pdev->dev, PTR_ERR(rstc),
312                                      "failed to get reset lines\n");
313
314         vpu_clk = devm_clk_get(&pdev->dev, "vpu");
315         if (IS_ERR(vpu_clk)) {
316                 dev_err(&pdev->dev, "vpu clock request failed\n");
317                 return PTR_ERR(vpu_clk);
318         }
319
320         vapb_clk = devm_clk_get(&pdev->dev, "vapb");
321         if (IS_ERR(vapb_clk)) {
322                 dev_err(&pdev->dev, "vapb clock request failed\n");
323                 return PTR_ERR(vapb_clk);
324         }
325
326         vpu_pd->regmap_ao = regmap_ao;
327         vpu_pd->regmap_hhi = regmap_hhi;
328         vpu_pd->rstc = rstc;
329         vpu_pd->vpu_clk = vpu_clk;
330         vpu_pd->vapb_clk = vapb_clk;
331
332         platform_set_drvdata(pdev, vpu_pd);
333
334         powered_off = meson_gx_pwrc_vpu_get_power(vpu_pd);
335
336         /* If already powered, sync the clock states */
337         if (!powered_off) {
338                 ret = meson_gx_pwrc_vpu_setup_clk(vpu_pd);
339                 if (ret)
340                         return ret;
341         }
342
343         vpu_pd->genpd.flags = GENPD_FLAG_ALWAYS_ON;
344         pm_genpd_init(&vpu_pd->genpd, NULL, powered_off);
345
346         return of_genpd_add_provider_simple(pdev->dev.of_node,
347                                             &vpu_pd->genpd);
348 }
349
350 static void meson_gx_pwrc_vpu_shutdown(struct platform_device *pdev)
351 {
352         struct meson_gx_pwrc_vpu *vpu_pd = platform_get_drvdata(pdev);
353         bool powered_off;
354
355         powered_off = meson_gx_pwrc_vpu_get_power(vpu_pd);
356         if (!powered_off)
357                 vpu_pd->genpd.power_off(&vpu_pd->genpd);
358 }
359
360 static const struct of_device_id meson_gx_pwrc_vpu_match_table[] = {
361         { .compatible = "amlogic,meson-gx-pwrc-vpu", .data = &vpu_hdmi_pd },
362         {
363           .compatible = "amlogic,meson-g12a-pwrc-vpu",
364           .data = &vpu_hdmi_pd_g12a
365         },
366         { /* sentinel */ }
367 };
368 MODULE_DEVICE_TABLE(of, meson_gx_pwrc_vpu_match_table);
369
370 static struct platform_driver meson_gx_pwrc_vpu_driver = {
371         .probe  = meson_gx_pwrc_vpu_probe,
372         .shutdown = meson_gx_pwrc_vpu_shutdown,
373         .driver = {
374                 .name           = "meson_gx_pwrc_vpu",
375                 .of_match_table = meson_gx_pwrc_vpu_match_table,
376         },
377 };
378 module_platform_driver(meson_gx_pwrc_vpu_driver);
379 MODULE_LICENSE("GPL v2");