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