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>
13 #include <power-domain-uclass.h>
18 #include <linux/delay.h>
19 #include <linux/err.h>
22 VPU_PWRC_COMPATIBLE_GX = 0,
23 VPU_PWRC_COMPATIBLE_G12A = 1,
28 #define AO_RTI_GEN_PWR_SLEEP0 (0x3a << 2)
30 #define GEN_PWR_VPU_HDMI BIT(8)
31 #define GEN_PWR_VPU_HDMI_ISO BIT(9)
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)
38 #define HHI_VPU_MEM_PD_REG2 (0x4d << 2)
40 struct meson_gx_pwrc_vpu_priv {
41 struct regmap *regmap_ao;
42 struct regmap *regmap_hhi;
43 struct reset_ctl_bulk resets;
47 static int meson_pwrc_vpu_request(struct power_domain *power_domain)
52 static int meson_pwrc_vpu_free(struct power_domain *power_domain)
57 static int meson_gx_pwrc_vpu_on(struct power_domain *power_domain)
59 struct meson_gx_pwrc_vpu_priv *priv = dev_get_priv(power_domain->dev);
62 regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
66 /* Power Up Memories */
67 for (i = 0; i < 32; i += 2) {
68 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG0,
73 for (i = 0; i < 32; i += 2) {
74 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG1,
79 for (i = 8; i < 16; i++) {
80 regmap_update_bits(priv->regmap_hhi, HHI_MEM_PD_REG0,
86 ret = reset_assert_bulk(&priv->resets);
90 regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
91 GEN_PWR_VPU_HDMI_ISO, 0);
93 ret = reset_deassert_bulk(&priv->resets);
97 ret = clk_enable_bulk(&priv->clks);
104 static int meson_g12a_pwrc_vpu_on(struct power_domain *power_domain)
106 struct meson_gx_pwrc_vpu_priv *priv = dev_get_priv(power_domain->dev);
109 regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
110 GEN_PWR_VPU_HDMI, 0);
113 /* Power Up Memories */
114 for (i = 0; i < 32; i += 2) {
115 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG0,
120 for (i = 0; i < 32; i += 2) {
121 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG1,
126 for (i = 0; i < 32; i += 2) {
127 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG2,
132 for (i = 8; i < 16; i++) {
133 regmap_update_bits(priv->regmap_hhi, HHI_MEM_PD_REG0,
139 ret = reset_assert_bulk(&priv->resets);
143 regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
144 GEN_PWR_VPU_HDMI_ISO, 0);
146 ret = reset_deassert_bulk(&priv->resets);
150 ret = clk_enable_bulk(&priv->clks);
157 static int meson_pwrc_vpu_on(struct power_domain *power_domain)
159 unsigned int compat = dev_get_driver_data(power_domain->dev);
162 case VPU_PWRC_COMPATIBLE_GX:
163 return meson_gx_pwrc_vpu_on(power_domain);
164 case VPU_PWRC_COMPATIBLE_G12A:
165 return meson_g12a_pwrc_vpu_on(power_domain);
171 static int meson_gx_pwrc_vpu_off(struct power_domain *power_domain)
173 struct meson_gx_pwrc_vpu_priv *priv = dev_get_priv(power_domain->dev);
176 regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
177 GEN_PWR_VPU_HDMI_ISO, GEN_PWR_VPU_HDMI_ISO);
180 /* Power Down Memories */
181 for (i = 0; i < 32; i += 2) {
182 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG0,
186 for (i = 0; i < 32; i += 2) {
187 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG1,
191 for (i = 8; i < 16; i++) {
192 regmap_update_bits(priv->regmap_hhi, HHI_MEM_PD_REG0,
198 regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
199 GEN_PWR_VPU_HDMI, GEN_PWR_VPU_HDMI);
202 clk_disable_bulk(&priv->clks);
207 static int meson_g12a_pwrc_vpu_off(struct power_domain *power_domain)
209 struct meson_gx_pwrc_vpu_priv *priv = dev_get_priv(power_domain->dev);
212 regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
213 GEN_PWR_VPU_HDMI_ISO, GEN_PWR_VPU_HDMI_ISO);
216 /* Power Down Memories */
217 for (i = 0; i < 32; i += 2) {
218 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG0,
222 for (i = 0; i < 32; i += 2) {
223 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG1,
227 for (i = 0; i < 32; i += 2) {
228 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG2,
232 for (i = 8; i < 16; i++) {
233 regmap_update_bits(priv->regmap_hhi, HHI_MEM_PD_REG0,
239 regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
240 GEN_PWR_VPU_HDMI, GEN_PWR_VPU_HDMI);
243 clk_disable_bulk(&priv->clks);
248 static int meson_pwrc_vpu_off(struct power_domain *power_domain)
250 unsigned int compat = dev_get_driver_data(power_domain->dev);
253 case VPU_PWRC_COMPATIBLE_GX:
254 return meson_gx_pwrc_vpu_off(power_domain);
255 case VPU_PWRC_COMPATIBLE_G12A:
256 return meson_g12a_pwrc_vpu_off(power_domain);
262 static int meson_pwrc_vpu_of_xlate(struct power_domain *power_domain,
263 struct ofnode_phandle_args *args)
265 /* #power-domain-cells is 0 */
267 if (args->args_count != 0) {
268 debug("Invalid args_count: %d\n", args->args_count);
275 struct power_domain_ops meson_gx_pwrc_vpu_ops = {
276 .rfree = meson_pwrc_vpu_free,
277 .off = meson_pwrc_vpu_off,
278 .on = meson_pwrc_vpu_on,
279 .request = meson_pwrc_vpu_request,
280 .of_xlate = meson_pwrc_vpu_of_xlate,
283 static const struct udevice_id meson_gx_pwrc_vpu_ids[] = {
285 .compatible = "amlogic,meson-gx-pwrc-vpu",
286 .data = VPU_PWRC_COMPATIBLE_GX,
289 .compatible = "amlogic,meson-g12a-pwrc-vpu",
290 .data = VPU_PWRC_COMPATIBLE_G12A,
295 static int meson_gx_pwrc_vpu_probe(struct udevice *dev)
297 struct meson_gx_pwrc_vpu_priv *priv = dev_get_priv(dev);
302 priv->regmap_ao = syscon_node_to_regmap(dev_get_parent(dev)->node);
303 if (IS_ERR(priv->regmap_ao))
304 return PTR_ERR(priv->regmap_ao);
306 ret = ofnode_read_u32(dev->node, "amlogic,hhi-sysctrl",
311 hhi_node = ofnode_get_by_phandle(hhi_phandle);
312 if (!ofnode_valid(hhi_node))
315 priv->regmap_hhi = syscon_node_to_regmap(hhi_node);
316 if (IS_ERR(priv->regmap_hhi))
317 return PTR_ERR(priv->regmap_hhi);
319 ret = reset_get_bulk(dev, &priv->resets);
323 ret = clk_get_bulk(dev, &priv->clks);
330 U_BOOT_DRIVER(meson_gx_pwrc_vpu) = {
331 .name = "meson_gx_pwrc_vpu",
332 .id = UCLASS_POWER_DOMAIN,
333 .of_match = meson_gx_pwrc_vpu_ids,
334 .probe = meson_gx_pwrc_vpu_probe,
335 .ops = &meson_gx_pwrc_vpu_ops,
336 .priv_auto_alloc_size = sizeof(struct meson_gx_pwrc_vpu_priv),