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/bitops.h>
19 #include <linux/delay.h>
20 #include <linux/err.h>
23 VPU_PWRC_COMPATIBLE_GX = 0,
24 VPU_PWRC_COMPATIBLE_G12A = 1,
29 #define AO_RTI_GEN_PWR_SLEEP0 (0x3a << 2)
31 #define GEN_PWR_VPU_HDMI BIT(8)
32 #define GEN_PWR_VPU_HDMI_ISO BIT(9)
36 #define HHI_MEM_PD_REG0 (0x40 << 2)
37 #define HHI_VPU_MEM_PD_REG0 (0x41 << 2)
38 #define HHI_VPU_MEM_PD_REG1 (0x42 << 2)
39 #define HHI_VPU_MEM_PD_REG2 (0x4d << 2)
41 struct meson_gx_pwrc_vpu_priv {
42 struct regmap *regmap_ao;
43 struct regmap *regmap_hhi;
44 struct reset_ctl_bulk resets;
48 static int meson_pwrc_vpu_request(struct power_domain *power_domain)
53 static int meson_pwrc_vpu_free(struct power_domain *power_domain)
58 static int meson_gx_pwrc_vpu_on(struct power_domain *power_domain)
60 struct meson_gx_pwrc_vpu_priv *priv = dev_get_priv(power_domain->dev);
63 regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
67 /* Power Up Memories */
68 for (i = 0; i < 32; i += 2) {
69 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG0,
74 for (i = 0; i < 32; i += 2) {
75 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG1,
80 for (i = 8; i < 16; i++) {
81 regmap_update_bits(priv->regmap_hhi, HHI_MEM_PD_REG0,
87 ret = reset_assert_bulk(&priv->resets);
91 regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
92 GEN_PWR_VPU_HDMI_ISO, 0);
94 ret = reset_deassert_bulk(&priv->resets);
98 ret = clk_enable_bulk(&priv->clks);
105 static int meson_g12a_pwrc_vpu_on(struct power_domain *power_domain)
107 struct meson_gx_pwrc_vpu_priv *priv = dev_get_priv(power_domain->dev);
110 regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
111 GEN_PWR_VPU_HDMI, 0);
114 /* Power Up Memories */
115 for (i = 0; i < 32; i += 2) {
116 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG0,
121 for (i = 0; i < 32; i += 2) {
122 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG1,
127 for (i = 0; i < 32; i += 2) {
128 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG2,
133 for (i = 8; i < 16; i++) {
134 regmap_update_bits(priv->regmap_hhi, HHI_MEM_PD_REG0,
140 ret = reset_assert_bulk(&priv->resets);
144 regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
145 GEN_PWR_VPU_HDMI_ISO, 0);
147 ret = reset_deassert_bulk(&priv->resets);
151 ret = clk_enable_bulk(&priv->clks);
158 static int meson_pwrc_vpu_on(struct power_domain *power_domain)
160 unsigned int compat = dev_get_driver_data(power_domain->dev);
163 case VPU_PWRC_COMPATIBLE_GX:
164 return meson_gx_pwrc_vpu_on(power_domain);
165 case VPU_PWRC_COMPATIBLE_G12A:
166 return meson_g12a_pwrc_vpu_on(power_domain);
172 static int meson_gx_pwrc_vpu_off(struct power_domain *power_domain)
174 struct meson_gx_pwrc_vpu_priv *priv = dev_get_priv(power_domain->dev);
177 regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
178 GEN_PWR_VPU_HDMI_ISO, GEN_PWR_VPU_HDMI_ISO);
181 /* Power Down Memories */
182 for (i = 0; i < 32; i += 2) {
183 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG0,
187 for (i = 0; i < 32; i += 2) {
188 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG1,
192 for (i = 8; i < 16; i++) {
193 regmap_update_bits(priv->regmap_hhi, HHI_MEM_PD_REG0,
199 regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
200 GEN_PWR_VPU_HDMI, GEN_PWR_VPU_HDMI);
203 clk_disable_bulk(&priv->clks);
208 static int meson_g12a_pwrc_vpu_off(struct power_domain *power_domain)
210 struct meson_gx_pwrc_vpu_priv *priv = dev_get_priv(power_domain->dev);
213 regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
214 GEN_PWR_VPU_HDMI_ISO, GEN_PWR_VPU_HDMI_ISO);
217 /* Power Down Memories */
218 for (i = 0; i < 32; i += 2) {
219 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG0,
223 for (i = 0; i < 32; i += 2) {
224 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG1,
228 for (i = 0; i < 32; i += 2) {
229 regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG2,
233 for (i = 8; i < 16; i++) {
234 regmap_update_bits(priv->regmap_hhi, HHI_MEM_PD_REG0,
240 regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
241 GEN_PWR_VPU_HDMI, GEN_PWR_VPU_HDMI);
244 clk_disable_bulk(&priv->clks);
249 static int meson_pwrc_vpu_off(struct power_domain *power_domain)
251 unsigned int compat = dev_get_driver_data(power_domain->dev);
254 case VPU_PWRC_COMPATIBLE_GX:
255 return meson_gx_pwrc_vpu_off(power_domain);
256 case VPU_PWRC_COMPATIBLE_G12A:
257 return meson_g12a_pwrc_vpu_off(power_domain);
263 static int meson_pwrc_vpu_of_xlate(struct power_domain *power_domain,
264 struct ofnode_phandle_args *args)
266 /* #power-domain-cells is 0 */
268 if (args->args_count != 0) {
269 debug("Invalid args_count: %d\n", args->args_count);
276 struct power_domain_ops meson_gx_pwrc_vpu_ops = {
277 .rfree = meson_pwrc_vpu_free,
278 .off = meson_pwrc_vpu_off,
279 .on = meson_pwrc_vpu_on,
280 .request = meson_pwrc_vpu_request,
281 .of_xlate = meson_pwrc_vpu_of_xlate,
284 static const struct udevice_id meson_gx_pwrc_vpu_ids[] = {
286 .compatible = "amlogic,meson-gx-pwrc-vpu",
287 .data = VPU_PWRC_COMPATIBLE_GX,
290 .compatible = "amlogic,meson-g12a-pwrc-vpu",
291 .data = VPU_PWRC_COMPATIBLE_G12A,
296 static int meson_gx_pwrc_vpu_probe(struct udevice *dev)
298 struct meson_gx_pwrc_vpu_priv *priv = dev_get_priv(dev);
303 priv->regmap_ao = syscon_node_to_regmap(dev_get_parent(dev)->node);
304 if (IS_ERR(priv->regmap_ao))
305 return PTR_ERR(priv->regmap_ao);
307 ret = ofnode_read_u32(dev->node, "amlogic,hhi-sysctrl",
312 hhi_node = ofnode_get_by_phandle(hhi_phandle);
313 if (!ofnode_valid(hhi_node))
316 priv->regmap_hhi = syscon_node_to_regmap(hhi_node);
317 if (IS_ERR(priv->regmap_hhi))
318 return PTR_ERR(priv->regmap_hhi);
320 ret = reset_get_bulk(dev, &priv->resets);
324 ret = clk_get_bulk(dev, &priv->clks);
331 U_BOOT_DRIVER(meson_gx_pwrc_vpu) = {
332 .name = "meson_gx_pwrc_vpu",
333 .id = UCLASS_POWER_DOMAIN,
334 .of_match = meson_gx_pwrc_vpu_ids,
335 .probe = meson_gx_pwrc_vpu_probe,
336 .ops = &meson_gx_pwrc_vpu_ops,
337 .priv_auto_alloc_size = sizeof(struct meson_gx_pwrc_vpu_priv),