diff options
-rw-r--r-- | drivers/soc/rockchip/grf.c | 28 | ||||
-rw-r--r-- | drivers/soc/rockchip/pm_domains.c | 95 |
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 | |||
48 | static const struct rockchip_grf_value rk3128_defaults[] __initconst = { | ||
49 | { "jtag switching", RK3128_GRF_SOC_CON0, HIWORD_UPDATE(0, 1, 8) }, | ||
50 | }; | ||
51 | |||
52 | static 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 | |||
59 | static const struct rockchip_grf_value rk3228_defaults[] __initconst = { | ||
60 | { "jtag switching", RK3228_GRF_SOC_CON6, HIWORD_UPDATE(0, 1, 8) }, | ||
61 | }; | ||
62 | |||
63 | static 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 | ||
48 | static const struct rockchip_grf_value rk3288_defaults[] __initconst = { | 70 | static 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 | ||
73 | struct rockchip_pmu { | 73 | struct rockchip_pmu { |
@@ -274,13 +274,18 @@ static void rockchip_do_pmu_set_power_domain(struct rockchip_pm_domain *pd, | |||
274 | 274 | ||
275 | static int rockchip_pd_power(struct rockchip_pm_domain *pd, bool power_on) | 275 | static 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 | ||
489 | err_out: | 491 | err_unprepare_clocks: |
490 | while (--i >= 0) { | 492 | clk_bulk_unprepare(pd->num_clks, pd->clks); |
491 | clk_unprepare(pd->clks[i]); | 493 | err_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 | ||
497 | static void rockchip_pm_remove_one_domain(struct rockchip_pm_domain *pd) | 498 | static 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); |