GNU Linux-libre 4.19.264-gnu1
[releases.git] / arch / arm / mach-zx / zx296702-pm-domain.c
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
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
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
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 (IS_ERR(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
198 static int __init zx296702_pd_init(void)
199 {
200         return platform_driver_register(&zx296702_pd_driver);
201 }
202 subsys_initcall(zx296702_pd_init);