aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/soc/rockchip/grf.c28
-rw-r--r--drivers/soc/rockchip/pm_domains.c95
2 files changed, 75 insertions, 48 deletions
diff --git a/drivers/soc/rockchip/grf.c b/drivers/soc/rockchip/grf.c
index 15e71fd6c513..96882ffde67e 100644
--- a/drivers/soc/rockchip/grf.c
+++ b/drivers/soc/rockchip/grf.c
@@ -43,6 +43,28 @@ static const struct rockchip_grf_info rk3036_grf __initconst = {
43 .num_values = ARRAY_SIZE(rk3036_defaults), 43 .num_values = ARRAY_SIZE(rk3036_defaults),
44}; 44};
45 45
46#define RK3128_GRF_SOC_CON0 0x140
47
48static const struct rockchip_grf_value rk3128_defaults[] __initconst = {
49 { "jtag switching", RK3128_GRF_SOC_CON0, HIWORD_UPDATE(0, 1, 8) },
50};
51
52static const struct rockchip_grf_info rk3128_grf __initconst = {
53 .values = rk3128_defaults,
54 .num_values = ARRAY_SIZE(rk3128_defaults),
55};
56
57#define RK3228_GRF_SOC_CON6 0x418
58
59static const struct rockchip_grf_value rk3228_defaults[] __initconst = {
60 { "jtag switching", RK3228_GRF_SOC_CON6, HIWORD_UPDATE(0, 1, 8) },
61};
62
63static const struct rockchip_grf_info rk3228_grf __initconst = {
64 .values = rk3228_defaults,
65 .num_values = ARRAY_SIZE(rk3228_defaults),
66};
67
46#define RK3288_GRF_SOC_CON0 0x244 68#define RK3288_GRF_SOC_CON0 0x244
47 69
48static const struct rockchip_grf_value rk3288_defaults[] __initconst = { 70static const struct rockchip_grf_value rk3288_defaults[] __initconst = {
@@ -92,6 +114,12 @@ static const struct of_device_id rockchip_grf_dt_match[] __initconst = {
92 .compatible = "rockchip,rk3036-grf", 114 .compatible = "rockchip,rk3036-grf",
93 .data = (void *)&rk3036_grf, 115 .data = (void *)&rk3036_grf,
94 }, { 116 }, {
117 .compatible = "rockchip,rk3128-grf",
118 .data = (void *)&rk3128_grf,
119 }, {
120 .compatible = "rockchip,rk3228-grf",
121 .data = (void *)&rk3228_grf,
122 }, {
95 .compatible = "rockchip,rk3288-grf", 123 .compatible = "rockchip,rk3288-grf",
96 .data = (void *)&rk3288_grf, 124 .data = (void *)&rk3288_grf,
97 }, { 125 }, {
diff --git a/drivers/soc/rockchip/pm_domains.c b/drivers/soc/rockchip/pm_domains.c
index 5c342167b9db..53efc386b1ad 100644
--- a/drivers/soc/rockchip/pm_domains.c
+++ b/drivers/soc/rockchip/pm_domains.c
@@ -67,7 +67,7 @@ struct rockchip_pm_domain {
67 struct regmap **qos_regmap; 67 struct regmap **qos_regmap;
68 u32 *qos_save_regs[MAX_QOS_REGS_NUM]; 68 u32 *qos_save_regs[MAX_QOS_REGS_NUM];
69 int num_clks; 69 int num_clks;
70 struct clk *clks[]; 70 struct clk_bulk_data *clks;
71}; 71};
72 72
73struct rockchip_pmu { 73struct rockchip_pmu {
@@ -274,13 +274,18 @@ static void rockchip_do_pmu_set_power_domain(struct rockchip_pm_domain *pd,
274 274
275static int rockchip_pd_power(struct rockchip_pm_domain *pd, bool power_on) 275static int rockchip_pd_power(struct rockchip_pm_domain *pd, bool power_on)
276{ 276{
277 int i; 277 struct rockchip_pmu *pmu = pd->pmu;
278 int ret;
278 279
279 mutex_lock(&pd->pmu->mutex); 280 mutex_lock(&pmu->mutex);
280 281
281 if (rockchip_pmu_domain_is_on(pd) != power_on) { 282 if (rockchip_pmu_domain_is_on(pd) != power_on) {
282 for (i = 0; i < pd->num_clks; i++) 283 ret = clk_bulk_enable(pd->num_clks, pd->clks);
283 clk_enable(pd->clks[i]); 284 if (ret < 0) {
285 dev_err(pmu->dev, "failed to enable clocks\n");
286 mutex_unlock(&pmu->mutex);
287 return ret;
288 }
284 289
285 if (!power_on) { 290 if (!power_on) {
286 rockchip_pmu_save_qos(pd); 291 rockchip_pmu_save_qos(pd);
@@ -298,11 +303,10 @@ static int rockchip_pd_power(struct rockchip_pm_domain *pd, bool power_on)
298 rockchip_pmu_restore_qos(pd); 303 rockchip_pmu_restore_qos(pd);
299 } 304 }
300 305
301 for (i = pd->num_clks - 1; i >= 0; i--) 306 clk_bulk_disable(pd->num_clks, pd->clks);
302 clk_disable(pd->clks[i]);
303 } 307 }
304 308
305 mutex_unlock(&pd->pmu->mutex); 309 mutex_unlock(&pmu->mutex);
306 return 0; 310 return 0;
307} 311}
308 312
@@ -364,8 +368,6 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
364 const struct rockchip_domain_info *pd_info; 368 const struct rockchip_domain_info *pd_info;
365 struct rockchip_pm_domain *pd; 369 struct rockchip_pm_domain *pd;
366 struct device_node *qos_node; 370 struct device_node *qos_node;
367 struct clk *clk;
368 int clk_cnt;
369 int i, j; 371 int i, j;
370 u32 id; 372 u32 id;
371 int error; 373 int error;
@@ -391,41 +393,41 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
391 return -EINVAL; 393 return -EINVAL;
392 } 394 }
393 395
394 clk_cnt = of_count_phandle_with_args(node, "clocks", "#clock-cells"); 396 pd = devm_kzalloc(pmu->dev, sizeof(*pd), GFP_KERNEL);
395 pd = devm_kzalloc(pmu->dev,
396 sizeof(*pd) + clk_cnt * sizeof(pd->clks[0]),
397 GFP_KERNEL);
398 if (!pd) 397 if (!pd)
399 return -ENOMEM; 398 return -ENOMEM;
400 399
401 pd->info = pd_info; 400 pd->info = pd_info;
402 pd->pmu = pmu; 401 pd->pmu = pmu;
403 402
404 for (i = 0; i < clk_cnt; i++) { 403 pd->num_clks = of_count_phandle_with_args(node, "clocks",
405 clk = of_clk_get(node, i); 404 "#clock-cells");
406 if (IS_ERR(clk)) { 405 if (pd->num_clks > 0) {
407 error = PTR_ERR(clk); 406 pd->clks = devm_kcalloc(pmu->dev, pd->num_clks,
407 sizeof(*pd->clks), GFP_KERNEL);
408 if (!pd->clks)
409 return -ENOMEM;
410 } else {
411 dev_dbg(pmu->dev, "%s: doesn't have clocks: %d\n",
412 node->name, pd->num_clks);
413 pd->num_clks = 0;
414 }
415
416 for (i = 0; i < pd->num_clks; i++) {
417 pd->clks[i].clk = of_clk_get(node, i);
418 if (IS_ERR(pd->clks[i].clk)) {
419 error = PTR_ERR(pd->clks[i].clk);
408 dev_err(pmu->dev, 420 dev_err(pmu->dev,
409 "%s: failed to get clk at index %d: %d\n", 421 "%s: failed to get clk at index %d: %d\n",
410 node->name, i, error); 422 node->name, i, error);
411 goto err_out; 423 return error;
412 }
413
414 error = clk_prepare(clk);
415 if (error) {
416 dev_err(pmu->dev,
417 "%s: failed to prepare clk %pC (index %d): %d\n",
418 node->name, clk, i, error);
419 clk_put(clk);
420 goto err_out;
421 } 424 }
422
423 pd->clks[pd->num_clks++] = clk;
424
425 dev_dbg(pmu->dev, "added clock '%pC' to domain '%s'\n",
426 clk, node->name);
427 } 425 }
428 426
427 error = clk_bulk_prepare(pd->num_clks, pd->clks);
428 if (error)
429 goto err_put_clocks;
430
429 pd->num_qos = of_count_phandle_with_args(node, "pm_qos", 431 pd->num_qos = of_count_phandle_with_args(node, "pm_qos",
430 NULL); 432 NULL);
431 433
@@ -435,7 +437,7 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
435 GFP_KERNEL); 437 GFP_KERNEL);
436 if (!pd->qos_regmap) { 438 if (!pd->qos_regmap) {
437 error = -ENOMEM; 439 error = -ENOMEM;
438 goto err_out; 440 goto err_unprepare_clocks;
439 } 441 }
440 442
441 for (j = 0; j < MAX_QOS_REGS_NUM; j++) { 443 for (j = 0; j < MAX_QOS_REGS_NUM; j++) {
@@ -445,7 +447,7 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
445 GFP_KERNEL); 447 GFP_KERNEL);
446 if (!pd->qos_save_regs[j]) { 448 if (!pd->qos_save_regs[j]) {
447 error = -ENOMEM; 449 error = -ENOMEM;
448 goto err_out; 450 goto err_unprepare_clocks;
449 } 451 }
450 } 452 }
451 453
@@ -453,13 +455,13 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
453 qos_node = of_parse_phandle(node, "pm_qos", j); 455 qos_node = of_parse_phandle(node, "pm_qos", j);
454 if (!qos_node) { 456 if (!qos_node) {
455 error = -ENODEV; 457 error = -ENODEV;
456 goto err_out; 458 goto err_unprepare_clocks;
457 } 459 }
458 pd->qos_regmap[j] = syscon_node_to_regmap(qos_node); 460 pd->qos_regmap[j] = syscon_node_to_regmap(qos_node);
459 if (IS_ERR(pd->qos_regmap[j])) { 461 if (IS_ERR(pd->qos_regmap[j])) {
460 error = -ENODEV; 462 error = -ENODEV;
461 of_node_put(qos_node); 463 of_node_put(qos_node);
462 goto err_out; 464 goto err_unprepare_clocks;
463 } 465 }
464 of_node_put(qos_node); 466 of_node_put(qos_node);
465 } 467 }
@@ -470,7 +472,7 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
470 dev_err(pmu->dev, 472 dev_err(pmu->dev,
471 "failed to power on domain '%s': %d\n", 473 "failed to power on domain '%s': %d\n",
472 node->name, error); 474 node->name, error);
473 goto err_out; 475 goto err_unprepare_clocks;
474 } 476 }
475 477
476 pd->genpd.name = node->name; 478 pd->genpd.name = node->name;
@@ -486,17 +488,16 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
486 pmu->genpd_data.domains[id] = &pd->genpd; 488 pmu->genpd_data.domains[id] = &pd->genpd;
487 return 0; 489 return 0;
488 490
489err_out: 491err_unprepare_clocks:
490 while (--i >= 0) { 492 clk_bulk_unprepare(pd->num_clks, pd->clks);
491 clk_unprepare(pd->clks[i]); 493err_put_clocks:
492 clk_put(pd->clks[i]); 494 clk_bulk_put(pd->num_clks, pd->clks);
493 }
494 return error; 495 return error;
495} 496}
496 497
497static void rockchip_pm_remove_one_domain(struct rockchip_pm_domain *pd) 498static void rockchip_pm_remove_one_domain(struct rockchip_pm_domain *pd)
498{ 499{
499 int i, ret; 500 int ret;
500 501
501 /* 502 /*
502 * We're in the error cleanup already, so we only complain, 503 * We're in the error cleanup already, so we only complain,
@@ -507,10 +508,8 @@ static void rockchip_pm_remove_one_domain(struct rockchip_pm_domain *pd)
507 dev_err(pd->pmu->dev, "failed to remove domain '%s' : %d - state may be inconsistent\n", 508 dev_err(pd->pmu->dev, "failed to remove domain '%s' : %d - state may be inconsistent\n",
508 pd->genpd.name, ret); 509 pd->genpd.name, ret);
509 510
510 for (i = 0; i < pd->num_clks; i++) { 511 clk_bulk_unprepare(pd->num_clks, pd->clks);
511 clk_unprepare(pd->clks[i]); 512 clk_bulk_put(pd->num_clks, pd->clks);
512 clk_put(pd->clks[i]);
513 }
514 513
515 /* protect the zeroing of pm->num_clks */ 514 /* protect the zeroing of pm->num_clks */
516 mutex_lock(&pd->pmu->mutex); 515 mutex_lock(&pd->pmu->mutex);