• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 Linaro Ltd.
3  *
4  * Author: Jun Nie <jun.nie@linaro.org>
5  * License terms: GNU General Public License (GPL) version 2
6  */
7 #include <linux/delay.h>
8 #include <linux/err.h>
9 #include <linux/io.h>
10 #include <linux/of.h>
11 #include <linux/platform_device.h>
12 #include <linux/pm_domain.h>
13 #include <linux/slab.h>
14 
15 #define PCU_DM_CLKEN        0x18
16 #define PCU_DM_RSTEN        0x1C
17 #define PCU_DM_ISOEN        0x20
18 #define PCU_DM_PWRDN        0x24
19 #define PCU_DM_ACK_SYNC     0x28
20 
21 enum {
22 	PCU_DM_NEON0 = 0,
23 	PCU_DM_NEON1,
24 	PCU_DM_GPU,
25 	PCU_DM_DECPPU,
26 	PCU_DM_VOU,
27 	PCU_DM_R2D,
28 	PCU_DM_TOP,
29 };
30 
31 static void __iomem *pcubase;
32 
33 struct zx_pm_domain {
34 	struct generic_pm_domain dm;
35 	unsigned int bit;
36 };
37 
normal_power_off(struct generic_pm_domain * domain)38 static int normal_power_off(struct generic_pm_domain *domain)
39 {
40 	struct zx_pm_domain *zpd = (struct zx_pm_domain *)domain;
41 	unsigned long loop = 1000;
42 	u32 tmp;
43 
44 	tmp = readl_relaxed(pcubase + PCU_DM_CLKEN);
45 	tmp &= ~BIT(zpd->bit);
46 	writel_relaxed(tmp, pcubase + PCU_DM_CLKEN);
47 	udelay(5);
48 
49 	tmp = readl_relaxed(pcubase + PCU_DM_ISOEN);
50 	tmp &= ~BIT(zpd->bit);
51 	writel_relaxed(tmp | BIT(zpd->bit), pcubase + PCU_DM_ISOEN);
52 	udelay(5);
53 
54 	tmp = readl_relaxed(pcubase + PCU_DM_RSTEN);
55 	tmp &= ~BIT(zpd->bit);
56 	writel_relaxed(tmp, pcubase + PCU_DM_RSTEN);
57 	udelay(5);
58 
59 	tmp = readl_relaxed(pcubase + PCU_DM_PWRDN);
60 	tmp &= ~BIT(zpd->bit);
61 	writel_relaxed(tmp | BIT(zpd->bit), pcubase + PCU_DM_PWRDN);
62 	do {
63 		tmp = readl_relaxed(pcubase + PCU_DM_ACK_SYNC) & BIT(zpd->bit);
64 	} while (--loop && !tmp);
65 
66 	if (!loop) {
67 		pr_err("Error: %s %s fail\n", __func__, domain->name);
68 		return -EIO;
69 	}
70 
71 	return 0;
72 }
73 
normal_power_on(struct generic_pm_domain * domain)74 static int normal_power_on(struct generic_pm_domain *domain)
75 {
76 	struct zx_pm_domain *zpd = (struct zx_pm_domain *)domain;
77 	unsigned long loop = 10000;
78 	u32 tmp;
79 
80 	tmp = readl_relaxed(pcubase + PCU_DM_PWRDN);
81 	tmp &= ~BIT(zpd->bit);
82 	writel_relaxed(tmp, pcubase + PCU_DM_PWRDN);
83 	do {
84 		tmp = readl_relaxed(pcubase + PCU_DM_ACK_SYNC) & BIT(zpd->bit);
85 	} while (--loop && tmp);
86 
87 	if (!loop) {
88 		pr_err("Error: %s %s fail\n", __func__, domain->name);
89 		return -EIO;
90 	}
91 
92 	tmp = readl_relaxed(pcubase + PCU_DM_RSTEN);
93 	tmp &= ~BIT(zpd->bit);
94 	writel_relaxed(tmp | BIT(zpd->bit), pcubase + PCU_DM_RSTEN);
95 	udelay(5);
96 
97 	tmp = readl_relaxed(pcubase + PCU_DM_ISOEN);
98 	tmp &= ~BIT(zpd->bit);
99 	writel_relaxed(tmp, pcubase + PCU_DM_ISOEN);
100 	udelay(5);
101 
102 	tmp = readl_relaxed(pcubase + PCU_DM_CLKEN);
103 	tmp &= ~BIT(zpd->bit);
104 	writel_relaxed(tmp | BIT(zpd->bit), pcubase + PCU_DM_CLKEN);
105 	udelay(5);
106 	return 0;
107 }
108 
109 static struct zx_pm_domain gpu_domain = {
110 	.dm = {
111 		.name		= "gpu_domain",
112 		.power_off	= normal_power_off,
113 		.power_on	= normal_power_on,
114 	},
115 	.bit = PCU_DM_GPU,
116 };
117 
118 static struct zx_pm_domain decppu_domain = {
119 	.dm = {
120 		.name		= "decppu_domain",
121 		.power_off	= normal_power_off,
122 		.power_on	= normal_power_on,
123 	},
124 	.bit = PCU_DM_DECPPU,
125 };
126 
127 static struct zx_pm_domain vou_domain = {
128 	.dm = {
129 		.name		= "vou_domain",
130 		.power_off	= normal_power_off,
131 		.power_on	= normal_power_on,
132 	},
133 	.bit = PCU_DM_VOU,
134 };
135 
136 static struct zx_pm_domain r2d_domain = {
137 	.dm = {
138 		.name		= "r2d_domain",
139 		.power_off	= normal_power_off,
140 		.power_on	= normal_power_on,
141 	},
142 	.bit = PCU_DM_R2D,
143 };
144 
145 static struct generic_pm_domain *zx296702_pm_domains[] = {
146 	&vou_domain.dm,
147 	&gpu_domain.dm,
148 	&decppu_domain.dm,
149 	&r2d_domain.dm,
150 };
151 
zx296702_pd_probe(struct platform_device * pdev)152 static int zx296702_pd_probe(struct platform_device *pdev)
153 {
154 	struct genpd_onecell_data *genpd_data;
155 	struct resource *res;
156 	int i;
157 
158 	genpd_data = devm_kzalloc(&pdev->dev, sizeof(*genpd_data), GFP_KERNEL);
159 	if (!genpd_data)
160 		return -ENOMEM;
161 
162 	genpd_data->domains = zx296702_pm_domains;
163 	genpd_data->num_domains = ARRAY_SIZE(zx296702_pm_domains);
164 
165 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
166 	if (!res) {
167 		dev_err(&pdev->dev, "no memory resource defined\n");
168 		return -ENODEV;
169 	}
170 
171 	pcubase = devm_ioremap_resource(&pdev->dev, res);
172 	if (!pcubase) {
173 		dev_err(&pdev->dev, "ioremap fail.\n");
174 		return -EIO;
175 	}
176 
177 	for (i = 0; i < ARRAY_SIZE(zx296702_pm_domains); ++i)
178 		pm_genpd_init(zx296702_pm_domains[i], NULL, false);
179 
180 	of_genpd_add_provider_onecell(pdev->dev.of_node, genpd_data);
181 	return 0;
182 }
183 
184 static const struct of_device_id zx296702_pm_domain_matches[] __initconst = {
185 	{ .compatible = "zte,zx296702-pcu", },
186 	{ },
187 };
188 
189 static struct platform_driver zx296702_pd_driver __initdata = {
190 	.driver = {
191 		.name = "zx-powerdomain",
192 		.owner = THIS_MODULE,
193 		.of_match_table = zx296702_pm_domain_matches,
194 	},
195 	.probe = zx296702_pd_probe,
196 };
197 
zx296702_pd_init(void)198 static int __init zx296702_pd_init(void)
199 {
200 	return platform_driver_register(&zx296702_pd_driver);
201 }
202 subsys_initcall(zx296702_pd_init);
203