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/err.h>
21 VPU_PWRC_COMPATIBLE_GX = 0,
22 VPU_PWRC_COMPATIBLE_G12A = 1,
27 #define AO_RTI_GEN_PWR_SLEEP0 (0x3a << 2)
29 #define GEN_PWR_VPU_HDMI BIT(8)
30 #define GEN_PWR_VPU_HDMI_ISO BIT(9)
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)
37 #define HHI_VPU_MEM_PD_REG2 (0x4d << 2)
39 struct meson_gx_pwrc_vpu_priv {
40 struct regmap *regmap_ao;
41 struct regmap *regmap_hhi;
42 struct reset_ctl_bulk resets;
46 static int meson_pwrc_vpu_request(struct power_domain *power_domain)
51 static int meson_pwrc_vpu_free(struct power_domain *power_domain)
56 static int meson_gx_pwrc_vpu_on(struct power_domain *power_domain)
58 struct meson_gx_pwrc_vpu_priv *priv = dev_get_priv(power_domain->dev);
61 regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
65 /* Power Up Memories */
66 for (i = 0; i < 32; i += 2) {
67 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG0,
72 for (i = 0; i < 32; i += 2) {
73 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG1,
78 for (i = 8; i < 16; i++) {
79 regmap_update_bits(priv->regmap_hhi, HHI_MEM_PD_REG0,
85 ret = reset_assert_bulk(&priv->resets);
89 regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
90 GEN_PWR_VPU_HDMI_ISO, 0);
92 ret = reset_deassert_bulk(&priv->resets);
96 ret = clk_enable_bulk(&priv->clks);
103 static int meson_g12a_pwrc_vpu_on(struct power_domain *power_domain)
105 struct meson_gx_pwrc_vpu_priv *priv = dev_get_priv(power_domain->dev);
108 regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
109 GEN_PWR_VPU_HDMI, 0);
112 /* Power Up Memories */
113 for (i = 0; i < 32; i += 2) {
114 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG0,
119 for (i = 0; i < 32; i += 2) {
120 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG1,
125 for (i = 0; i < 32; i += 2) {
126 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG2,
131 for (i = 8; i < 16; i++) {
132 regmap_update_bits(priv->regmap_hhi, HHI_MEM_PD_REG0,
138 ret = reset_assert_bulk(&priv->resets);
142 regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
143 GEN_PWR_VPU_HDMI_ISO, 0);
145 ret = reset_deassert_bulk(&priv->resets);
149 ret = clk_enable_bulk(&priv->clks);
156 static int meson_pwrc_vpu_on(struct power_domain *power_domain)
158 unsigned int compat = dev_get_driver_data(power_domain->dev);
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);
170 static int meson_gx_pwrc_vpu_off(struct power_domain *power_domain)
172 struct meson_gx_pwrc_vpu_priv *priv = dev_get_priv(power_domain->dev);
175 regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
176 GEN_PWR_VPU_HDMI_ISO, GEN_PWR_VPU_HDMI_ISO);
179 /* Power Down Memories */
180 for (i = 0; i < 32; i += 2) {
181 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG0,
185 for (i = 0; i < 32; i += 2) {
186 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG1,
190 for (i = 8; i < 16; i++) {
191 regmap_update_bits(priv->regmap_hhi, HHI_MEM_PD_REG0,
197 regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
198 GEN_PWR_VPU_HDMI, GEN_PWR_VPU_HDMI);
201 clk_disable_bulk(&priv->clks);
206 static int meson_g12a_pwrc_vpu_off(struct power_domain *power_domain)
208 struct meson_gx_pwrc_vpu_priv *priv = dev_get_priv(power_domain->dev);
211 regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
212 GEN_PWR_VPU_HDMI_ISO, GEN_PWR_VPU_HDMI_ISO);
215 /* Power Down Memories */
216 for (i = 0; i < 32; i += 2) {
217 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG0,
221 for (i = 0; i < 32; i += 2) {
222 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG1,
226 for (i = 0; i < 32; i += 2) {
227 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG2,
231 for (i = 8; i < 16; i++) {
232 regmap_update_bits(priv->regmap_hhi, HHI_MEM_PD_REG0,
238 regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
239 GEN_PWR_VPU_HDMI, GEN_PWR_VPU_HDMI);
242 clk_disable_bulk(&priv->clks);
247 static int meson_pwrc_vpu_off(struct power_domain *power_domain)
249 unsigned int compat = dev_get_driver_data(power_domain->dev);
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);
261 static int meson_pwrc_vpu_of_xlate(struct power_domain *power_domain,
262 struct ofnode_phandle_args *args)
264 /* #power-domain-cells is 0 */
266 if (args->args_count != 0) {
267 debug("Invalid args_count: %d\n", args->args_count);
274 struct power_domain_ops meson_gx_pwrc_vpu_ops = {
275 .rfree = meson_pwrc_vpu_free,
276 .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,
282 static const struct udevice_id meson_gx_pwrc_vpu_ids[] = {
284 .compatible = "amlogic,meson-gx-pwrc-vpu",
285 .data = VPU_PWRC_COMPATIBLE_GX,
288 .compatible = "amlogic,meson-g12a-pwrc-vpu",
289 .data = VPU_PWRC_COMPATIBLE_G12A,
294 static int meson_gx_pwrc_vpu_probe(struct udevice *dev)
296 struct meson_gx_pwrc_vpu_priv *priv = dev_get_priv(dev);
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);
305 ret = ofnode_read_u32(dev->node, "amlogic,hhi-sysctrl",
310 hhi_node = ofnode_get_by_phandle(hhi_phandle);
311 if (!ofnode_valid(hhi_node))
314 priv->regmap_hhi = syscon_node_to_regmap(hhi_node);
315 if (IS_ERR(priv->regmap_hhi))
316 return PTR_ERR(priv->regmap_hhi);
318 ret = reset_get_bulk(dev, &priv->resets);
322 ret = clk_get_bulk(dev, &priv->clks);
329 U_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),