1 // SPDX-License-Identifier: GPL-2.0
3 * Amlogic Meson VPU Power Domain Controller driver
5 * Copyright (c) 2018 BayLibre, SAS.
6 * Author: Neil Armstrong <narmstrong@baylibre.com>
11 #include <power-domain-uclass.h>
16 #include <linux/err.h>
19 VPU_PWRC_COMPATIBLE_GX = 0,
20 VPU_PWRC_COMPATIBLE_G12A = 1,
25 #define AO_RTI_GEN_PWR_SLEEP0 (0x3a << 2)
27 #define GEN_PWR_VPU_HDMI BIT(8)
28 #define GEN_PWR_VPU_HDMI_ISO BIT(9)
32 #define HHI_MEM_PD_REG0 (0x40 << 2)
33 #define HHI_VPU_MEM_PD_REG0 (0x41 << 2)
34 #define HHI_VPU_MEM_PD_REG1 (0x42 << 2)
35 #define HHI_VPU_MEM_PD_REG2 (0x4d << 2)
37 struct meson_gx_pwrc_vpu_priv {
38 struct regmap *regmap_ao;
39 struct regmap *regmap_hhi;
40 struct reset_ctl_bulk resets;
44 static int meson_pwrc_vpu_request(struct power_domain *power_domain)
49 static int meson_pwrc_vpu_free(struct power_domain *power_domain)
54 static int meson_gx_pwrc_vpu_on(struct power_domain *power_domain)
56 struct meson_gx_pwrc_vpu_priv *priv = dev_get_priv(power_domain->dev);
59 regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
63 /* Power Up Memories */
64 for (i = 0; i < 32; i += 2) {
65 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG0,
70 for (i = 0; i < 32; i += 2) {
71 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG1,
76 for (i = 8; i < 16; i++) {
77 regmap_update_bits(priv->regmap_hhi, HHI_MEM_PD_REG0,
83 ret = reset_assert_bulk(&priv->resets);
87 regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
88 GEN_PWR_VPU_HDMI_ISO, 0);
90 ret = reset_deassert_bulk(&priv->resets);
94 ret = clk_enable_bulk(&priv->clks);
101 static int meson_g12a_pwrc_vpu_on(struct power_domain *power_domain)
103 struct meson_gx_pwrc_vpu_priv *priv = dev_get_priv(power_domain->dev);
106 regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
107 GEN_PWR_VPU_HDMI, 0);
110 /* Power Up Memories */
111 for (i = 0; i < 32; i += 2) {
112 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG0,
117 for (i = 0; i < 32; i += 2) {
118 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG1,
123 for (i = 0; i < 32; i += 2) {
124 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG2,
129 for (i = 8; i < 16; i++) {
130 regmap_update_bits(priv->regmap_hhi, HHI_MEM_PD_REG0,
136 ret = reset_assert_bulk(&priv->resets);
140 regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
141 GEN_PWR_VPU_HDMI_ISO, 0);
143 ret = reset_deassert_bulk(&priv->resets);
147 ret = clk_enable_bulk(&priv->clks);
154 static int meson_pwrc_vpu_on(struct power_domain *power_domain)
156 unsigned int compat = dev_get_driver_data(power_domain->dev);
159 case VPU_PWRC_COMPATIBLE_GX:
160 return meson_gx_pwrc_vpu_on(power_domain);
161 case VPU_PWRC_COMPATIBLE_G12A:
162 return meson_g12a_pwrc_vpu_on(power_domain);
168 static int meson_gx_pwrc_vpu_off(struct power_domain *power_domain)
170 struct meson_gx_pwrc_vpu_priv *priv = dev_get_priv(power_domain->dev);
173 regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
174 GEN_PWR_VPU_HDMI_ISO, GEN_PWR_VPU_HDMI_ISO);
177 /* Power Down Memories */
178 for (i = 0; i < 32; i += 2) {
179 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG0,
183 for (i = 0; i < 32; i += 2) {
184 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG1,
188 for (i = 8; i < 16; i++) {
189 regmap_update_bits(priv->regmap_hhi, HHI_MEM_PD_REG0,
195 regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
196 GEN_PWR_VPU_HDMI, GEN_PWR_VPU_HDMI);
199 clk_disable_bulk(&priv->clks);
204 static int meson_g12a_pwrc_vpu_off(struct power_domain *power_domain)
206 struct meson_gx_pwrc_vpu_priv *priv = dev_get_priv(power_domain->dev);
209 regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
210 GEN_PWR_VPU_HDMI_ISO, GEN_PWR_VPU_HDMI_ISO);
213 /* Power Down Memories */
214 for (i = 0; i < 32; i += 2) {
215 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG0,
219 for (i = 0; i < 32; i += 2) {
220 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG1,
224 for (i = 0; i < 32; i += 2) {
225 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG2,
229 for (i = 8; i < 16; i++) {
230 regmap_update_bits(priv->regmap_hhi, HHI_MEM_PD_REG0,
236 regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
237 GEN_PWR_VPU_HDMI, GEN_PWR_VPU_HDMI);
240 clk_disable_bulk(&priv->clks);
245 static int meson_pwrc_vpu_off(struct power_domain *power_domain)
247 unsigned int compat = dev_get_driver_data(power_domain->dev);
250 case VPU_PWRC_COMPATIBLE_GX:
251 return meson_gx_pwrc_vpu_off(power_domain);
252 case VPU_PWRC_COMPATIBLE_G12A:
253 return meson_g12a_pwrc_vpu_off(power_domain);
259 static int meson_pwrc_vpu_of_xlate(struct power_domain *power_domain,
260 struct ofnode_phandle_args *args)
262 /* #power-domain-cells is 0 */
264 if (args->args_count != 0) {
265 debug("Invalid args_count: %d\n", args->args_count);
272 struct power_domain_ops meson_gx_pwrc_vpu_ops = {
273 .rfree = meson_pwrc_vpu_free,
274 .off = meson_pwrc_vpu_off,
275 .on = meson_pwrc_vpu_on,
276 .request = meson_pwrc_vpu_request,
277 .of_xlate = meson_pwrc_vpu_of_xlate,
280 static const struct udevice_id meson_gx_pwrc_vpu_ids[] = {
282 .compatible = "amlogic,meson-gx-pwrc-vpu",
283 .data = VPU_PWRC_COMPATIBLE_GX,
286 .compatible = "amlogic,meson-g12a-pwrc-vpu",
287 .data = VPU_PWRC_COMPATIBLE_G12A,
292 static int meson_gx_pwrc_vpu_probe(struct udevice *dev)
294 struct meson_gx_pwrc_vpu_priv *priv = dev_get_priv(dev);
299 priv->regmap_ao = syscon_node_to_regmap(dev_get_parent(dev)->node);
300 if (IS_ERR(priv->regmap_ao))
301 return PTR_ERR(priv->regmap_ao);
303 ret = ofnode_read_u32(dev->node, "amlogic,hhi-sysctrl",
308 hhi_node = ofnode_get_by_phandle(hhi_phandle);
309 if (!ofnode_valid(hhi_node))
312 priv->regmap_hhi = syscon_node_to_regmap(hhi_node);
313 if (IS_ERR(priv->regmap_hhi))
314 return PTR_ERR(priv->regmap_hhi);
316 ret = reset_get_bulk(dev, &priv->resets);
320 ret = clk_get_bulk(dev, &priv->clks);
327 U_BOOT_DRIVER(meson_gx_pwrc_vpu) = {
328 .name = "meson_gx_pwrc_vpu",
329 .id = UCLASS_POWER_DOMAIN,
330 .of_match = meson_gx_pwrc_vpu_ids,
331 .probe = meson_gx_pwrc_vpu_probe,
332 .ops = &meson_gx_pwrc_vpu_ops,
333 .priv_auto_alloc_size = sizeof(struct meson_gx_pwrc_vpu_priv),