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