aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/soc/rockchip/pm_domains.c105
1 files changed, 102 insertions, 3 deletions
diff --git a/drivers/soc/rockchip/pm_domains.c b/drivers/soc/rockchip/pm_domains.c
index ac729fe42cc9..44842a205e4b 100644
--- a/drivers/soc/rockchip/pm_domains.c
+++ b/drivers/soc/rockchip/pm_domains.c
@@ -46,10 +46,20 @@ struct rockchip_pmu_info {
46 const struct rockchip_domain_info *domain_info; 46 const struct rockchip_domain_info *domain_info;
47}; 47};
48 48
49#define MAX_QOS_REGS_NUM 5
50#define QOS_PRIORITY 0x08
51#define QOS_MODE 0x0c
52#define QOS_BANDWIDTH 0x10
53#define QOS_SATURATION 0x14
54#define QOS_EXTCONTROL 0x18
55
49struct rockchip_pm_domain { 56struct rockchip_pm_domain {
50 struct generic_pm_domain genpd; 57 struct generic_pm_domain genpd;
51 const struct rockchip_domain_info *info; 58 const struct rockchip_domain_info *info;
52 struct rockchip_pmu *pmu; 59 struct rockchip_pmu *pmu;
60 int num_qos;
61 struct regmap **qos_regmap;
62 u32 *qos_save_regs[MAX_QOS_REGS_NUM];
53 int num_clks; 63 int num_clks;
54 struct clk *clks[]; 64 struct clk *clks[];
55}; 65};
@@ -118,6 +128,55 @@ static int rockchip_pmu_set_idle_request(struct rockchip_pm_domain *pd,
118 return 0; 128 return 0;
119} 129}
120 130
131static int rockchip_pmu_save_qos(struct rockchip_pm_domain *pd)
132{
133 int i;
134
135 for (i = 0; i < pd->num_qos; i++) {
136 regmap_read(pd->qos_regmap[i],
137 QOS_PRIORITY,
138 &pd->qos_save_regs[0][i]);
139 regmap_read(pd->qos_regmap[i],
140 QOS_MODE,
141 &pd->qos_save_regs[1][i]);
142 regmap_read(pd->qos_regmap[i],
143 QOS_BANDWIDTH,
144 &pd->qos_save_regs[2][i]);
145 regmap_read(pd->qos_regmap[i],
146 QOS_SATURATION,
147 &pd->qos_save_regs[3][i]);
148 regmap_read(pd->qos_regmap[i],
149 QOS_EXTCONTROL,
150 &pd->qos_save_regs[4][i]);
151 }
152 return 0;
153}
154
155static int rockchip_pmu_restore_qos(struct rockchip_pm_domain *pd)
156{
157 int i;
158
159 for (i = 0; i < pd->num_qos; i++) {
160 regmap_write(pd->qos_regmap[i],
161 QOS_PRIORITY,
162 pd->qos_save_regs[0][i]);
163 regmap_write(pd->qos_regmap[i],
164 QOS_MODE,
165 pd->qos_save_regs[1][i]);
166 regmap_write(pd->qos_regmap[i],
167 QOS_BANDWIDTH,
168 pd->qos_save_regs[2][i]);
169 regmap_write(pd->qos_regmap[i],
170 QOS_SATURATION,
171 pd->qos_save_regs[3][i]);
172 regmap_write(pd->qos_regmap[i],
173 QOS_EXTCONTROL,
174 pd->qos_save_regs[4][i]);
175 }
176
177 return 0;
178}
179
121static bool rockchip_pmu_domain_is_on(struct rockchip_pm_domain *pd) 180static bool rockchip_pmu_domain_is_on(struct rockchip_pm_domain *pd)
122{ 181{
123 struct rockchip_pmu *pmu = pd->pmu; 182 struct rockchip_pmu *pmu = pd->pmu;
@@ -161,7 +220,7 @@ static int rockchip_pd_power(struct rockchip_pm_domain *pd, bool power_on)
161 clk_enable(pd->clks[i]); 220 clk_enable(pd->clks[i]);
162 221
163 if (!power_on) { 222 if (!power_on) {
164 /* FIXME: add code to save AXI_QOS */ 223 rockchip_pmu_save_qos(pd);
165 224
166 /* if powering down, idle request to NIU first */ 225 /* if powering down, idle request to NIU first */
167 rockchip_pmu_set_idle_request(pd, true); 226 rockchip_pmu_set_idle_request(pd, true);
@@ -173,7 +232,7 @@ static int rockchip_pd_power(struct rockchip_pm_domain *pd, bool power_on)
173 /* if powering up, leave idle mode */ 232 /* if powering up, leave idle mode */
174 rockchip_pmu_set_idle_request(pd, false); 233 rockchip_pmu_set_idle_request(pd, false);
175 234
176 /* FIXME: add code to restore AXI_QOS */ 235 rockchip_pmu_restore_qos(pd);
177 } 236 }
178 237
179 for (i = pd->num_clks - 1; i >= 0; i--) 238 for (i = pd->num_clks - 1; i >= 0; i--)
@@ -241,9 +300,10 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
241{ 300{
242 const struct rockchip_domain_info *pd_info; 301 const struct rockchip_domain_info *pd_info;
243 struct rockchip_pm_domain *pd; 302 struct rockchip_pm_domain *pd;
303 struct device_node *qos_node;
244 struct clk *clk; 304 struct clk *clk;
245 int clk_cnt; 305 int clk_cnt;
246 int i; 306 int i, j;
247 u32 id; 307 u32 id;
248 int error; 308 int error;
249 309
@@ -303,6 +363,45 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
303 clk, node->name); 363 clk, node->name);
304 } 364 }
305 365
366 pd->num_qos = of_count_phandle_with_args(node, "pm_qos",
367 NULL);
368
369 if (pd->num_qos > 0) {
370 pd->qos_regmap = devm_kcalloc(pmu->dev, pd->num_qos,
371 sizeof(*pd->qos_regmap),
372 GFP_KERNEL);
373 if (!pd->qos_regmap) {
374 error = -ENOMEM;
375 goto err_out;
376 }
377
378 for (j = 0; j < MAX_QOS_REGS_NUM; j++) {
379 pd->qos_save_regs[j] = devm_kcalloc(pmu->dev,
380 pd->num_qos,
381 sizeof(u32),
382 GFP_KERNEL);
383 if (!pd->qos_save_regs[j]) {
384 error = -ENOMEM;
385 goto err_out;
386 }
387 }
388
389 for (j = 0; j < pd->num_qos; j++) {
390 qos_node = of_parse_phandle(node, "pm_qos", j);
391 if (!qos_node) {
392 error = -ENODEV;
393 goto err_out;
394 }
395 pd->qos_regmap[j] = syscon_node_to_regmap(qos_node);
396 if (IS_ERR(pd->qos_regmap[j])) {
397 error = -ENODEV;
398 of_node_put(qos_node);
399 goto err_out;
400 }
401 of_node_put(qos_node);
402 }
403 }
404
306 error = rockchip_pd_power(pd, true); 405 error = rockchip_pd_power(pd, true);
307 if (error) { 406 if (error) {
308 dev_err(pmu->dev, 407 dev_err(pmu->dev,