Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.13.7.
  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
 21enum {
 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
 31static void __iomem *pcubase;
 32
 33struct zx_pm_domain {
 34	struct generic_pm_domain dm;
 35	unsigned int bit;
 36};
 37
 38static 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
 74static 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
109static 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
118static 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
127static 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
136static 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
145static 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
152static 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
184static const struct of_device_id zx296702_pm_domain_matches[] __initconst = {
185	{ .compatible = "zte,zx296702-pcu", },
186	{ },
187};
188
189static 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
198static int __init zx296702_pd_init(void)
199{
200	return platform_driver_register(&zx296702_pd_driver);
201}
202subsys_initcall(zx296702_pd_init);