1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2015 Linaro Ltd.
5 * Author: Jun Nie <jun.nie@linaro.org>
7 #include <linux/delay.h>
11 #include <linux/platform_device.h>
12 #include <linux/pm_domain.h>
13 #include <linux/slab.h>
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
31 static void __iomem
*pcubase
;
34 struct generic_pm_domain dm
;
38 static int normal_power_off(struct generic_pm_domain
*domain
)
40 struct zx_pm_domain
*zpd
= (struct zx_pm_domain
*)domain
;
41 unsigned long loop
= 1000;
44 tmp
= readl_relaxed(pcubase
+ PCU_DM_CLKEN
);
45 tmp
&= ~BIT(zpd
->bit
);
46 writel_relaxed(tmp
, pcubase
+ PCU_DM_CLKEN
);
49 tmp
= readl_relaxed(pcubase
+ PCU_DM_ISOEN
);
50 tmp
&= ~BIT(zpd
->bit
);
51 writel_relaxed(tmp
| BIT(zpd
->bit
), pcubase
+ PCU_DM_ISOEN
);
54 tmp
= readl_relaxed(pcubase
+ PCU_DM_RSTEN
);
55 tmp
&= ~BIT(zpd
->bit
);
56 writel_relaxed(tmp
, pcubase
+ PCU_DM_RSTEN
);
59 tmp
= readl_relaxed(pcubase
+ PCU_DM_PWRDN
);
60 tmp
&= ~BIT(zpd
->bit
);
61 writel_relaxed(tmp
| BIT(zpd
->bit
), pcubase
+ PCU_DM_PWRDN
);
63 tmp
= readl_relaxed(pcubase
+ PCU_DM_ACK_SYNC
) & BIT(zpd
->bit
);
64 } while (--loop
&& !tmp
);
67 pr_err("Error: %s %s fail\n", __func__
, domain
->name
);
74 static int normal_power_on(struct generic_pm_domain
*domain
)
76 struct zx_pm_domain
*zpd
= (struct zx_pm_domain
*)domain
;
77 unsigned long loop
= 10000;
80 tmp
= readl_relaxed(pcubase
+ PCU_DM_PWRDN
);
81 tmp
&= ~BIT(zpd
->bit
);
82 writel_relaxed(tmp
, pcubase
+ PCU_DM_PWRDN
);
84 tmp
= readl_relaxed(pcubase
+ PCU_DM_ACK_SYNC
) & BIT(zpd
->bit
);
85 } while (--loop
&& tmp
);
88 pr_err("Error: %s %s fail\n", __func__
, domain
->name
);
92 tmp
= readl_relaxed(pcubase
+ PCU_DM_RSTEN
);
93 tmp
&= ~BIT(zpd
->bit
);
94 writel_relaxed(tmp
| BIT(zpd
->bit
), pcubase
+ PCU_DM_RSTEN
);
97 tmp
= readl_relaxed(pcubase
+ PCU_DM_ISOEN
);
98 tmp
&= ~BIT(zpd
->bit
);
99 writel_relaxed(tmp
, pcubase
+ PCU_DM_ISOEN
);
102 tmp
= readl_relaxed(pcubase
+ PCU_DM_CLKEN
);
103 tmp
&= ~BIT(zpd
->bit
);
104 writel_relaxed(tmp
| BIT(zpd
->bit
), pcubase
+ PCU_DM_CLKEN
);
109 static struct zx_pm_domain gpu_domain
= {
111 .name
= "gpu_domain",
112 .power_off
= normal_power_off
,
113 .power_on
= normal_power_on
,
118 static struct zx_pm_domain decppu_domain
= {
120 .name
= "decppu_domain",
121 .power_off
= normal_power_off
,
122 .power_on
= normal_power_on
,
124 .bit
= PCU_DM_DECPPU
,
127 static struct zx_pm_domain vou_domain
= {
129 .name
= "vou_domain",
130 .power_off
= normal_power_off
,
131 .power_on
= normal_power_on
,
136 static struct zx_pm_domain r2d_domain
= {
138 .name
= "r2d_domain",
139 .power_off
= normal_power_off
,
140 .power_on
= normal_power_on
,
145 static struct generic_pm_domain
*zx296702_pm_domains
[] = {
152 static int zx296702_pd_probe(struct platform_device
*pdev
)
154 struct genpd_onecell_data
*genpd_data
;
155 struct resource
*res
;
158 genpd_data
= devm_kzalloc(&pdev
->dev
, sizeof(*genpd_data
), GFP_KERNEL
);
162 genpd_data
->domains
= zx296702_pm_domains
;
163 genpd_data
->num_domains
= ARRAY_SIZE(zx296702_pm_domains
);
165 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
167 dev_err(&pdev
->dev
, "no memory resource defined\n");
171 pcubase
= devm_ioremap_resource(&pdev
->dev
, res
);
172 if (IS_ERR(pcubase
)) {
173 dev_err(&pdev
->dev
, "ioremap fail.\n");
177 for (i
= 0; i
< ARRAY_SIZE(zx296702_pm_domains
); ++i
)
178 pm_genpd_init(zx296702_pm_domains
[i
], NULL
, false);
180 of_genpd_add_provider_onecell(pdev
->dev
.of_node
, genpd_data
);
184 static const struct of_device_id zx296702_pm_domain_matches
[] __initconst
= {
185 { .compatible
= "zte,zx296702-pcu", },
189 static struct platform_driver zx296702_pd_driver __initdata
= {
191 .name
= "zx-powerdomain",
192 .owner
= THIS_MODULE
,
193 .of_match_table
= zx296702_pm_domain_matches
,
195 .probe
= zx296702_pd_probe
,
198 static int __init
zx296702_pd_init(void)
200 return platform_driver_register(&zx296702_pd_driver
);
202 subsys_initcall(zx296702_pd_init
);