blob: 612660ce89f9a90d02cf2434d55bd8563019d626 [file] [log] [blame]
Neil Armstrong32edad52018-08-06 14:49:19 +02001// 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>
Simon Glass0f2af882020-05-10 11:40:05 -060011#include <log.h>
Simon Glass9bc15642020-02-03 07:36:16 -070012#include <malloc.h>
Neil Armstrong32edad52018-08-06 14:49:19 +020013#include <power-domain-uclass.h>
14#include <regmap.h>
15#include <syscon.h>
16#include <reset.h>
17#include <clk.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -060018#include <linux/bitops.h>
Simon Glassdbd79542020-05-10 11:40:11 -060019#include <linux/delay.h>
Simon Glassd66c5f72020-02-03 07:36:15 -070020#include <linux/err.h>
Neil Armstrong32edad52018-08-06 14:49:19 +020021
Neil Armstrong108f0af2019-08-30 14:09:21 +020022enum {
23 VPU_PWRC_COMPATIBLE_GX = 0,
24 VPU_PWRC_COMPATIBLE_G12A = 1,
25};
26
Neil Armstrong32edad52018-08-06 14:49:19 +020027/* 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)
Neil Armstrong108f0af2019-08-30 14:09:21 +020039#define HHI_VPU_MEM_PD_REG2 (0x4d << 2)
Neil Armstrong32edad52018-08-06 14:49:19 +020040
41struct 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
Neil Armstrong32edad52018-08-06 14:49:19 +020048static int meson_gx_pwrc_vpu_on(struct power_domain *power_domain)
49{
50 struct meson_gx_pwrc_vpu_priv *priv = dev_get_priv(power_domain->dev);
51 int i, ret;
52
53 regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
54 GEN_PWR_VPU_HDMI, 0);
55 udelay(20);
56
57 /* Power Up Memories */
58 for (i = 0; i < 32; i += 2) {
59 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG0,
60 0x3 << i, 0);
61 udelay(5);
62 }
63
64 for (i = 0; i < 32; i += 2) {
65 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG1,
66 0x3 << i, 0);
67 udelay(5);
68 }
69
Neil Armstrong108f0af2019-08-30 14:09:21 +020070 for (i = 8; i < 16; i++) {
71 regmap_update_bits(priv->regmap_hhi, HHI_MEM_PD_REG0,
72 BIT(i), 0);
73 udelay(5);
74 }
75 udelay(20);
76
77 ret = reset_assert_bulk(&priv->resets);
78 if (ret)
79 return ret;
80
81 regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
82 GEN_PWR_VPU_HDMI_ISO, 0);
83
84 ret = reset_deassert_bulk(&priv->resets);
85 if (ret)
86 return ret;
87
88 ret = clk_enable_bulk(&priv->clks);
89 if (ret)
90 return ret;
91
92 return 0;
93}
94
95static int meson_g12a_pwrc_vpu_on(struct power_domain *power_domain)
96{
97 struct meson_gx_pwrc_vpu_priv *priv = dev_get_priv(power_domain->dev);
98 int i, ret;
99
100 regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
101 GEN_PWR_VPU_HDMI, 0);
102 udelay(20);
103
104 /* Power Up Memories */
105 for (i = 0; i < 32; i += 2) {
106 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG0,
107 0x3 << i, 0);
108 udelay(5);
109 }
110
111 for (i = 0; i < 32; i += 2) {
112 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG1,
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_REG2,
119 0x3 << i, 0);
120 udelay(5);
121 }
122
Neil Armstrong32edad52018-08-06 14:49:19 +0200123 for (i = 8; i < 16; i++) {
124 regmap_update_bits(priv->regmap_hhi, HHI_MEM_PD_REG0,
125 BIT(i), 0);
126 udelay(5);
127 }
128 udelay(20);
129
130 ret = reset_assert_bulk(&priv->resets);
131 if (ret)
132 return ret;
133
134 regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
135 GEN_PWR_VPU_HDMI_ISO, 0);
136
137 ret = reset_deassert_bulk(&priv->resets);
138 if (ret)
139 return ret;
140
141 ret = clk_enable_bulk(&priv->clks);
142 if (ret)
143 return ret;
144
145 return 0;
146}
147
Neil Armstrong108f0af2019-08-30 14:09:21 +0200148static int meson_pwrc_vpu_on(struct power_domain *power_domain)
149{
150 unsigned int compat = dev_get_driver_data(power_domain->dev);
151
152 switch (compat) {
153 case VPU_PWRC_COMPATIBLE_GX:
154 return meson_gx_pwrc_vpu_on(power_domain);
155 case VPU_PWRC_COMPATIBLE_G12A:
156 return meson_g12a_pwrc_vpu_on(power_domain);
157 }
158
159 return -EINVAL;
160}
161
Neil Armstrong32edad52018-08-06 14:49:19 +0200162static int meson_gx_pwrc_vpu_off(struct power_domain *power_domain)
163{
164 struct meson_gx_pwrc_vpu_priv *priv = dev_get_priv(power_domain->dev);
165 int i;
166
167 regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
168 GEN_PWR_VPU_HDMI_ISO, GEN_PWR_VPU_HDMI_ISO);
169 udelay(20);
170
171 /* Power Down Memories */
172 for (i = 0; i < 32; i += 2) {
173 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG0,
174 0x3 << i, 0x3 << i);
175 udelay(5);
176 }
177 for (i = 0; i < 32; i += 2) {
178 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG1,
179 0x3 << i, 0x3 << i);
180 udelay(5);
181 }
Neil Armstrong108f0af2019-08-30 14:09:21 +0200182 for (i = 8; i < 16; i++) {
183 regmap_update_bits(priv->regmap_hhi, HHI_MEM_PD_REG0,
184 BIT(i), BIT(i));
185 udelay(5);
186 }
187 udelay(20);
188
189 regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
190 GEN_PWR_VPU_HDMI, GEN_PWR_VPU_HDMI);
191 mdelay(20);
192
193 clk_disable_bulk(&priv->clks);
194
195 return 0;
196}
197
198static int meson_g12a_pwrc_vpu_off(struct power_domain *power_domain)
199{
200 struct meson_gx_pwrc_vpu_priv *priv = dev_get_priv(power_domain->dev);
201 int i;
202
203 regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
204 GEN_PWR_VPU_HDMI_ISO, GEN_PWR_VPU_HDMI_ISO);
205 udelay(20);
206
207 /* Power Down Memories */
208 for (i = 0; i < 32; i += 2) {
209 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG0,
210 0x3 << i, 0x3 << i);
211 udelay(5);
212 }
213 for (i = 0; i < 32; i += 2) {
214 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG1,
215 0x3 << i, 0x3 << i);
216 udelay(5);
217 }
218 for (i = 0; i < 32; i += 2) {
219 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG2,
220 0x3 << i, 0x3 << i);
221 udelay(5);
222 }
Neil Armstrong32edad52018-08-06 14:49:19 +0200223 for (i = 8; i < 16; i++) {
224 regmap_update_bits(priv->regmap_hhi, HHI_MEM_PD_REG0,
225 BIT(i), BIT(i));
226 udelay(5);
227 }
228 udelay(20);
229
230 regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
231 GEN_PWR_VPU_HDMI, GEN_PWR_VPU_HDMI);
232 mdelay(20);
233
234 clk_disable_bulk(&priv->clks);
235
236 return 0;
237}
238
Neil Armstrong108f0af2019-08-30 14:09:21 +0200239static int meson_pwrc_vpu_off(struct power_domain *power_domain)
240{
241 unsigned int compat = dev_get_driver_data(power_domain->dev);
242
243 switch (compat) {
244 case VPU_PWRC_COMPATIBLE_GX:
245 return meson_gx_pwrc_vpu_off(power_domain);
246 case VPU_PWRC_COMPATIBLE_G12A:
247 return meson_g12a_pwrc_vpu_off(power_domain);
248 }
249
250 return -EINVAL;
251}
252
253static int meson_pwrc_vpu_of_xlate(struct power_domain *power_domain,
254 struct ofnode_phandle_args *args)
Neil Armstrong32edad52018-08-06 14:49:19 +0200255{
256 /* #power-domain-cells is 0 */
257
258 if (args->args_count != 0) {
259 debug("Invalid args_count: %d\n", args->args_count);
260 return -EINVAL;
261 }
262
263 return 0;
264}
265
266struct power_domain_ops meson_gx_pwrc_vpu_ops = {
Neil Armstrong108f0af2019-08-30 14:09:21 +0200267 .off = meson_pwrc_vpu_off,
268 .on = meson_pwrc_vpu_on,
Neil Armstrong108f0af2019-08-30 14:09:21 +0200269 .of_xlate = meson_pwrc_vpu_of_xlate,
Neil Armstrong32edad52018-08-06 14:49:19 +0200270};
271
272static const struct udevice_id meson_gx_pwrc_vpu_ids[] = {
Neil Armstrong108f0af2019-08-30 14:09:21 +0200273 {
274 .compatible = "amlogic,meson-gx-pwrc-vpu",
275 .data = VPU_PWRC_COMPATIBLE_GX,
276 },
277 {
278 .compatible = "amlogic,meson-g12a-pwrc-vpu",
279 .data = VPU_PWRC_COMPATIBLE_G12A,
280 },
Neil Armstrong32edad52018-08-06 14:49:19 +0200281 { }
282};
283
284static int meson_gx_pwrc_vpu_probe(struct udevice *dev)
285{
286 struct meson_gx_pwrc_vpu_priv *priv = dev_get_priv(dev);
287 u32 hhi_phandle;
288 ofnode hhi_node;
289 int ret;
290
Simon Glassa7ece582020-12-19 10:40:14 -0700291 priv->regmap_ao = syscon_node_to_regmap(dev_ofnode(dev_get_parent(dev)));
Neil Armstrong32edad52018-08-06 14:49:19 +0200292 if (IS_ERR(priv->regmap_ao))
293 return PTR_ERR(priv->regmap_ao);
294
Simon Glassa7ece582020-12-19 10:40:14 -0700295 ret = ofnode_read_u32(dev_ofnode(dev), "amlogic,hhi-sysctrl",
Neil Armstrong32edad52018-08-06 14:49:19 +0200296 &hhi_phandle);
297 if (ret)
298 return ret;
299
300 hhi_node = ofnode_get_by_phandle(hhi_phandle);
301 if (!ofnode_valid(hhi_node))
302 return -EINVAL;
303
304 priv->regmap_hhi = syscon_node_to_regmap(hhi_node);
305 if (IS_ERR(priv->regmap_hhi))
306 return PTR_ERR(priv->regmap_hhi);
307
308 ret = reset_get_bulk(dev, &priv->resets);
309 if (ret)
310 return ret;
311
312 ret = clk_get_bulk(dev, &priv->clks);
313 if (ret)
314 return ret;
315
316 return 0;
317}
318
319U_BOOT_DRIVER(meson_gx_pwrc_vpu) = {
320 .name = "meson_gx_pwrc_vpu",
321 .id = UCLASS_POWER_DOMAIN,
322 .of_match = meson_gx_pwrc_vpu_ids,
323 .probe = meson_gx_pwrc_vpu_probe,
324 .ops = &meson_gx_pwrc_vpu_ops,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700325 .priv_auto = sizeof(struct meson_gx_pwrc_vpu_priv),
Neil Armstrong32edad52018-08-06 14:49:19 +0200326};