1*8d5579ceSNeil Armstrong // SPDX-License-Identifier: GPL-2.0
2*8d5579ceSNeil Armstrong /*
3*8d5579ceSNeil Armstrong  * Amlogic Meson VPU Power Domain Controller driver
4*8d5579ceSNeil Armstrong  *
5*8d5579ceSNeil Armstrong  * Copyright (c) 2018 BayLibre, SAS.
6*8d5579ceSNeil Armstrong  * Author: Neil Armstrong <narmstrong@baylibre.com>
7*8d5579ceSNeil Armstrong  */
8*8d5579ceSNeil Armstrong 
9*8d5579ceSNeil Armstrong #include <common.h>
10*8d5579ceSNeil Armstrong #include <dm.h>
11*8d5579ceSNeil Armstrong #include <power-domain-uclass.h>
12*8d5579ceSNeil Armstrong #include <regmap.h>
13*8d5579ceSNeil Armstrong #include <syscon.h>
14*8d5579ceSNeil Armstrong #include <reset.h>
15*8d5579ceSNeil Armstrong #include <clk.h>
16*8d5579ceSNeil Armstrong 
17*8d5579ceSNeil Armstrong /* AO Offsets */
18*8d5579ceSNeil Armstrong 
19*8d5579ceSNeil Armstrong #define AO_RTI_GEN_PWR_SLEEP0		(0x3a << 2)
20*8d5579ceSNeil Armstrong 
21*8d5579ceSNeil Armstrong #define GEN_PWR_VPU_HDMI		BIT(8)
22*8d5579ceSNeil Armstrong #define GEN_PWR_VPU_HDMI_ISO		BIT(9)
23*8d5579ceSNeil Armstrong 
24*8d5579ceSNeil Armstrong /* HHI Offsets */
25*8d5579ceSNeil Armstrong 
26*8d5579ceSNeil Armstrong #define HHI_MEM_PD_REG0			(0x40 << 2)
27*8d5579ceSNeil Armstrong #define HHI_VPU_MEM_PD_REG0		(0x41 << 2)
28*8d5579ceSNeil Armstrong #define HHI_VPU_MEM_PD_REG1		(0x42 << 2)
29*8d5579ceSNeil Armstrong 
30*8d5579ceSNeil Armstrong struct meson_gx_pwrc_vpu_priv {
31*8d5579ceSNeil Armstrong 	struct regmap *regmap_ao;
32*8d5579ceSNeil Armstrong 	struct regmap *regmap_hhi;
33*8d5579ceSNeil Armstrong 	struct reset_ctl_bulk resets;
34*8d5579ceSNeil Armstrong 	struct clk_bulk clks;
35*8d5579ceSNeil Armstrong };
36*8d5579ceSNeil Armstrong 
meson_gx_pwrc_vpu_request(struct power_domain * power_domain)37*8d5579ceSNeil Armstrong static int meson_gx_pwrc_vpu_request(struct power_domain *power_domain)
38*8d5579ceSNeil Armstrong {
39*8d5579ceSNeil Armstrong 	return 0;
40*8d5579ceSNeil Armstrong }
41*8d5579ceSNeil Armstrong 
meson_gx_pwrc_vpu_free(struct power_domain * power_domain)42*8d5579ceSNeil Armstrong static int meson_gx_pwrc_vpu_free(struct power_domain *power_domain)
43*8d5579ceSNeil Armstrong {
44*8d5579ceSNeil Armstrong 	return 0;
45*8d5579ceSNeil Armstrong }
46*8d5579ceSNeil Armstrong 
meson_gx_pwrc_vpu_on(struct power_domain * power_domain)47*8d5579ceSNeil Armstrong static int meson_gx_pwrc_vpu_on(struct power_domain *power_domain)
48*8d5579ceSNeil Armstrong {
49*8d5579ceSNeil Armstrong 	struct meson_gx_pwrc_vpu_priv *priv = dev_get_priv(power_domain->dev);
50*8d5579ceSNeil Armstrong 	int i, ret;
51*8d5579ceSNeil Armstrong 
52*8d5579ceSNeil Armstrong 	regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
53*8d5579ceSNeil Armstrong 			   GEN_PWR_VPU_HDMI, 0);
54*8d5579ceSNeil Armstrong 	udelay(20);
55*8d5579ceSNeil Armstrong 
56*8d5579ceSNeil Armstrong 	/* Power Up Memories */
57*8d5579ceSNeil Armstrong 	for (i = 0; i < 32; i += 2) {
58*8d5579ceSNeil Armstrong 		regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG0,
59*8d5579ceSNeil Armstrong 				   0x3 << i, 0);
60*8d5579ceSNeil Armstrong 		udelay(5);
61*8d5579ceSNeil Armstrong 	}
62*8d5579ceSNeil Armstrong 
63*8d5579ceSNeil Armstrong 	for (i = 0; i < 32; i += 2) {
64*8d5579ceSNeil Armstrong 		regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG1,
65*8d5579ceSNeil Armstrong 				   0x3 << i, 0);
66*8d5579ceSNeil Armstrong 		udelay(5);
67*8d5579ceSNeil Armstrong 	}
68*8d5579ceSNeil Armstrong 
69*8d5579ceSNeil Armstrong 	for (i = 8; i < 16; i++) {
70*8d5579ceSNeil Armstrong 		regmap_update_bits(priv->regmap_hhi, HHI_MEM_PD_REG0,
71*8d5579ceSNeil Armstrong 				   BIT(i), 0);
72*8d5579ceSNeil Armstrong 		udelay(5);
73*8d5579ceSNeil Armstrong 	}
74*8d5579ceSNeil Armstrong 	udelay(20);
75*8d5579ceSNeil Armstrong 
76*8d5579ceSNeil Armstrong 	ret = reset_assert_bulk(&priv->resets);
77*8d5579ceSNeil Armstrong 	if (ret)
78*8d5579ceSNeil Armstrong 		return ret;
79*8d5579ceSNeil Armstrong 
80*8d5579ceSNeil Armstrong 	regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
81*8d5579ceSNeil Armstrong 			   GEN_PWR_VPU_HDMI_ISO, 0);
82*8d5579ceSNeil Armstrong 
83*8d5579ceSNeil Armstrong 	ret = reset_deassert_bulk(&priv->resets);
84*8d5579ceSNeil Armstrong 	if (ret)
85*8d5579ceSNeil Armstrong 		return ret;
86*8d5579ceSNeil Armstrong 
87*8d5579ceSNeil Armstrong 	ret = clk_enable_bulk(&priv->clks);
88*8d5579ceSNeil Armstrong 	if (ret)
89*8d5579ceSNeil Armstrong 		return ret;
90*8d5579ceSNeil Armstrong 
91*8d5579ceSNeil Armstrong 	return 0;
92*8d5579ceSNeil Armstrong }
93*8d5579ceSNeil Armstrong 
meson_gx_pwrc_vpu_off(struct power_domain * power_domain)94*8d5579ceSNeil Armstrong static int meson_gx_pwrc_vpu_off(struct power_domain *power_domain)
95*8d5579ceSNeil Armstrong {
96*8d5579ceSNeil Armstrong 	struct meson_gx_pwrc_vpu_priv *priv = dev_get_priv(power_domain->dev);
97*8d5579ceSNeil Armstrong 	int i;
98*8d5579ceSNeil Armstrong 
99*8d5579ceSNeil Armstrong 	regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
100*8d5579ceSNeil Armstrong 			   GEN_PWR_VPU_HDMI_ISO, GEN_PWR_VPU_HDMI_ISO);
101*8d5579ceSNeil Armstrong 	udelay(20);
102*8d5579ceSNeil Armstrong 
103*8d5579ceSNeil Armstrong 	/* Power Down Memories */
104*8d5579ceSNeil Armstrong 	for (i = 0; i < 32; i += 2) {
105*8d5579ceSNeil Armstrong 		regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG0,
106*8d5579ceSNeil Armstrong 				   0x3 << i, 0x3 << i);
107*8d5579ceSNeil Armstrong 		udelay(5);
108*8d5579ceSNeil Armstrong 	}
109*8d5579ceSNeil Armstrong 	for (i = 0; i < 32; i += 2) {
110*8d5579ceSNeil Armstrong 		regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG1,
111*8d5579ceSNeil Armstrong 				   0x3 << i, 0x3 << i);
112*8d5579ceSNeil Armstrong 		udelay(5);
113*8d5579ceSNeil Armstrong 	}
114*8d5579ceSNeil Armstrong 	for (i = 8; i < 16; i++) {
115*8d5579ceSNeil Armstrong 		regmap_update_bits(priv->regmap_hhi, HHI_MEM_PD_REG0,
116*8d5579ceSNeil Armstrong 				   BIT(i), BIT(i));
117*8d5579ceSNeil Armstrong 		udelay(5);
118*8d5579ceSNeil Armstrong 	}
119*8d5579ceSNeil Armstrong 	udelay(20);
120*8d5579ceSNeil Armstrong 
121*8d5579ceSNeil Armstrong 	regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
122*8d5579ceSNeil Armstrong 			   GEN_PWR_VPU_HDMI, GEN_PWR_VPU_HDMI);
123*8d5579ceSNeil Armstrong 	mdelay(20);
124*8d5579ceSNeil Armstrong 
125*8d5579ceSNeil Armstrong 	clk_disable_bulk(&priv->clks);
126*8d5579ceSNeil Armstrong 
127*8d5579ceSNeil Armstrong 	return 0;
128*8d5579ceSNeil Armstrong }
129*8d5579ceSNeil Armstrong 
meson_gx_pwrc_vpu_of_xlate(struct power_domain * power_domain,struct ofnode_phandle_args * args)130*8d5579ceSNeil Armstrong static int meson_gx_pwrc_vpu_of_xlate(struct power_domain *power_domain,
131*8d5579ceSNeil Armstrong 				      struct ofnode_phandle_args *args)
132*8d5579ceSNeil Armstrong {
133*8d5579ceSNeil Armstrong 	/* #power-domain-cells is 0 */
134*8d5579ceSNeil Armstrong 
135*8d5579ceSNeil Armstrong 	if (args->args_count != 0) {
136*8d5579ceSNeil Armstrong 		debug("Invalid args_count: %d\n", args->args_count);
137*8d5579ceSNeil Armstrong 		return -EINVAL;
138*8d5579ceSNeil Armstrong 	}
139*8d5579ceSNeil Armstrong 
140*8d5579ceSNeil Armstrong 	return 0;
141*8d5579ceSNeil Armstrong }
142*8d5579ceSNeil Armstrong 
143*8d5579ceSNeil Armstrong struct power_domain_ops meson_gx_pwrc_vpu_ops = {
144*8d5579ceSNeil Armstrong 	.free = meson_gx_pwrc_vpu_free,
145*8d5579ceSNeil Armstrong 	.off = meson_gx_pwrc_vpu_off,
146*8d5579ceSNeil Armstrong 	.on = meson_gx_pwrc_vpu_on,
147*8d5579ceSNeil Armstrong 	.request = meson_gx_pwrc_vpu_request,
148*8d5579ceSNeil Armstrong 	.of_xlate = meson_gx_pwrc_vpu_of_xlate,
149*8d5579ceSNeil Armstrong };
150*8d5579ceSNeil Armstrong 
151*8d5579ceSNeil Armstrong static const struct udevice_id meson_gx_pwrc_vpu_ids[] = {
152*8d5579ceSNeil Armstrong 	{ .compatible = "amlogic,meson-gx-pwrc-vpu" },
153*8d5579ceSNeil Armstrong 	{ }
154*8d5579ceSNeil Armstrong };
155*8d5579ceSNeil Armstrong 
meson_gx_pwrc_vpu_probe(struct udevice * dev)156*8d5579ceSNeil Armstrong static int meson_gx_pwrc_vpu_probe(struct udevice *dev)
157*8d5579ceSNeil Armstrong {
158*8d5579ceSNeil Armstrong 	struct meson_gx_pwrc_vpu_priv *priv = dev_get_priv(dev);
159*8d5579ceSNeil Armstrong 	u32 hhi_phandle;
160*8d5579ceSNeil Armstrong 	ofnode hhi_node;
161*8d5579ceSNeil Armstrong 	int ret;
162*8d5579ceSNeil Armstrong 
163*8d5579ceSNeil Armstrong 	priv->regmap_ao = syscon_node_to_regmap(dev_get_parent(dev)->node);
164*8d5579ceSNeil Armstrong 	if (IS_ERR(priv->regmap_ao))
165*8d5579ceSNeil Armstrong 		return PTR_ERR(priv->regmap_ao);
166*8d5579ceSNeil Armstrong 
167*8d5579ceSNeil Armstrong 	ret = ofnode_read_u32(dev->node, "amlogic,hhi-sysctrl",
168*8d5579ceSNeil Armstrong 			      &hhi_phandle);
169*8d5579ceSNeil Armstrong 	if (ret)
170*8d5579ceSNeil Armstrong 		return ret;
171*8d5579ceSNeil Armstrong 
172*8d5579ceSNeil Armstrong 	hhi_node = ofnode_get_by_phandle(hhi_phandle);
173*8d5579ceSNeil Armstrong 	if (!ofnode_valid(hhi_node))
174*8d5579ceSNeil Armstrong 		return -EINVAL;
175*8d5579ceSNeil Armstrong 
176*8d5579ceSNeil Armstrong 	priv->regmap_hhi = syscon_node_to_regmap(hhi_node);
177*8d5579ceSNeil Armstrong 	if (IS_ERR(priv->regmap_hhi))
178*8d5579ceSNeil Armstrong 		return PTR_ERR(priv->regmap_hhi);
179*8d5579ceSNeil Armstrong 
180*8d5579ceSNeil Armstrong 	ret = reset_get_bulk(dev, &priv->resets);
181*8d5579ceSNeil Armstrong 	if (ret)
182*8d5579ceSNeil Armstrong 		return ret;
183*8d5579ceSNeil Armstrong 
184*8d5579ceSNeil Armstrong 	ret = clk_get_bulk(dev, &priv->clks);
185*8d5579ceSNeil Armstrong 	if (ret)
186*8d5579ceSNeil Armstrong 		return ret;
187*8d5579ceSNeil Armstrong 
188*8d5579ceSNeil Armstrong 	return 0;
189*8d5579ceSNeil Armstrong }
190*8d5579ceSNeil Armstrong 
191*8d5579ceSNeil Armstrong U_BOOT_DRIVER(meson_gx_pwrc_vpu) = {
192*8d5579ceSNeil Armstrong 	.name = "meson_gx_pwrc_vpu",
193*8d5579ceSNeil Armstrong 	.id = UCLASS_POWER_DOMAIN,
194*8d5579ceSNeil Armstrong 	.of_match = meson_gx_pwrc_vpu_ids,
195*8d5579ceSNeil Armstrong 	.probe = meson_gx_pwrc_vpu_probe,
196*8d5579ceSNeil Armstrong 	.ops = &meson_gx_pwrc_vpu_ops,
197*8d5579ceSNeil Armstrong 	.priv_auto_alloc_size = sizeof(struct meson_gx_pwrc_vpu_priv),
198*8d5579ceSNeil Armstrong };
199