diff options
author | Olof Johansson <olof@lixom.net> | 2016-04-13 18:25:31 -0400 |
---|---|---|
committer | Olof Johansson <olof@lixom.net> | 2016-04-13 18:25:31 -0400 |
commit | a961bf24ba7137a223475c24a5b222112a1f1b88 (patch) | |
tree | 881ef99103f6b861967d98162584e09a1fe4dd18 | |
parent | 41f81a5100292fcdef113f54105d0dee01dedf87 (diff) | |
parent | 4506697d9f8537a8d33e9e002f8efceb32d10757 (diff) |
Merge tag 'v4.7-rockchip-drivers-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip into next/drivers
Rockchip soc-specific driver changes containing support for the
rk3399 powerdomains and necessary infrastructure changes to
accomodate them - like supporting nested powerdomains here.
* tag 'v4.7-rockchip-drivers-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip:
soc: rockchip: power-domain: check the existing of regmap
soc: rockchip: power-domain: Modify power domain driver for rk3399
dt-bindings: add binding for rk3399 power domains
dt-bindings: add power-domain header for RK3399 SoCs
soc: rockchip: power-domain: add support for sub-power domains
soc: rockchip: power-domain: allow domains only handling idle requests
soc: rockchip: power-domain: make idle handling optional
Signed-off-by: Olof Johansson <olof@lixom.net>
-rw-r--r-- | Documentation/devicetree/bindings/soc/rockchip/power_domain.txt | 37 | ||||
-rw-r--r-- | drivers/soc/rockchip/pm_domains.c | 142 | ||||
-rw-r--r-- | include/dt-bindings/power/rk3399-power.h | 53 |
3 files changed, 227 insertions, 5 deletions
diff --git a/Documentation/devicetree/bindings/soc/rockchip/power_domain.txt b/Documentation/devicetree/bindings/soc/rockchip/power_domain.txt index 13dc6a3fdb4a..98085c888d65 100644 --- a/Documentation/devicetree/bindings/soc/rockchip/power_domain.txt +++ b/Documentation/devicetree/bindings/soc/rockchip/power_domain.txt | |||
@@ -7,6 +7,7 @@ Required properties for power domain controller: | |||
7 | - compatible: Should be one of the following. | 7 | - compatible: Should be one of the following. |
8 | "rockchip,rk3288-power-controller" - for RK3288 SoCs. | 8 | "rockchip,rk3288-power-controller" - for RK3288 SoCs. |
9 | "rockchip,rk3368-power-controller" - for RK3368 SoCs. | 9 | "rockchip,rk3368-power-controller" - for RK3368 SoCs. |
10 | "rockchip,rk3399-power-controller" - for RK3399 SoCs. | ||
10 | - #power-domain-cells: Number of cells in a power-domain specifier. | 11 | - #power-domain-cells: Number of cells in a power-domain specifier. |
11 | Should be 1 for multiple PM domains. | 12 | Should be 1 for multiple PM domains. |
12 | - #address-cells: Should be 1. | 13 | - #address-cells: Should be 1. |
@@ -16,6 +17,7 @@ Required properties for power domain sub nodes: | |||
16 | - reg: index of the power domain, should use macros in: | 17 | - reg: index of the power domain, should use macros in: |
17 | "include/dt-bindings/power/rk3288-power.h" - for RK3288 type power domain. | 18 | "include/dt-bindings/power/rk3288-power.h" - for RK3288 type power domain. |
18 | "include/dt-bindings/power/rk3368-power.h" - for RK3368 type power domain. | 19 | "include/dt-bindings/power/rk3368-power.h" - for RK3368 type power domain. |
20 | "include/dt-bindings/power/rk3399-power.h" - for RK3399 type power domain. | ||
19 | - clocks (optional): phandles to clocks which need to be enabled while power domain | 21 | - clocks (optional): phandles to clocks which need to be enabled while power domain |
20 | switches state. | 22 | switches state. |
21 | 23 | ||
@@ -45,12 +47,41 @@ Example: | |||
45 | }; | 47 | }; |
46 | }; | 48 | }; |
47 | 49 | ||
50 | Example 2: | ||
51 | power: power-controller { | ||
52 | compatible = "rockchip,rk3399-power-controller"; | ||
53 | #power-domain-cells = <1>; | ||
54 | #address-cells = <1>; | ||
55 | #size-cells = <0>; | ||
56 | |||
57 | pd_vio { | ||
58 | #address-cells = <1>; | ||
59 | #size-cells = <0>; | ||
60 | reg = <RK3399_PD_VIO>; | ||
61 | |||
62 | pd_vo { | ||
63 | #address-cells = <1>; | ||
64 | #size-cells = <0>; | ||
65 | reg = <RK3399_PD_VO>; | ||
66 | |||
67 | pd_vopb { | ||
68 | reg = <RK3399_PD_VOPB>; | ||
69 | }; | ||
70 | |||
71 | pd_vopl { | ||
72 | reg = <RK3399_PD_VOPL>; | ||
73 | }; | ||
74 | }; | ||
75 | }; | ||
76 | }; | ||
77 | |||
48 | Node of a device using power domains must have a power-domains property, | 78 | Node of a device using power domains must have a power-domains property, |
49 | containing a phandle to the power device node and an index specifying which | 79 | containing a phandle to the power device node and an index specifying which |
50 | power domain to use. | 80 | power domain to use. |
51 | The index should use macros in: | 81 | The index should use macros in: |
52 | "include/dt-bindings/power/rk3288-power.h" - for rk3288 type power domain. | 82 | "include/dt-bindings/power/rk3288-power.h" - for rk3288 type power domain. |
53 | "include/dt-bindings/power/rk3368-power.h" - for rk3368 type power domain. | 83 | "include/dt-bindings/power/rk3368-power.h" - for rk3368 type power domain. |
84 | "include/dt-bindings/power/rk3399-power.h" - for rk3399 type power domain. | ||
54 | 85 | ||
55 | Example of the node using power domain: | 86 | Example of the node using power domain: |
56 | 87 | ||
@@ -65,3 +96,9 @@ Example of the node using power domain: | |||
65 | power-domains = <&power RK3368_PD_GPU_1>; | 96 | power-domains = <&power RK3368_PD_GPU_1>; |
66 | /* ... */ | 97 | /* ... */ |
67 | }; | 98 | }; |
99 | |||
100 | node { | ||
101 | /* ... */ | ||
102 | power-domains = <&power RK3399_PD_VOPB>; | ||
103 | /* ... */ | ||
104 | }; | ||
diff --git a/drivers/soc/rockchip/pm_domains.c b/drivers/soc/rockchip/pm_domains.c index 43155e1f97b9..ac729fe42cc9 100644 --- a/drivers/soc/rockchip/pm_domains.c +++ b/drivers/soc/rockchip/pm_domains.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/mfd/syscon.h> | 19 | #include <linux/mfd/syscon.h> |
20 | #include <dt-bindings/power/rk3288-power.h> | 20 | #include <dt-bindings/power/rk3288-power.h> |
21 | #include <dt-bindings/power/rk3368-power.h> | 21 | #include <dt-bindings/power/rk3368-power.h> |
22 | #include <dt-bindings/power/rk3399-power.h> | ||
22 | 23 | ||
23 | struct rockchip_domain_info { | 24 | struct rockchip_domain_info { |
24 | int pwr_mask; | 25 | int pwr_mask; |
@@ -66,11 +67,11 @@ struct rockchip_pmu { | |||
66 | 67 | ||
67 | #define DOMAIN(pwr, status, req, idle, ack) \ | 68 | #define DOMAIN(pwr, status, req, idle, ack) \ |
68 | { \ | 69 | { \ |
69 | .pwr_mask = BIT(pwr), \ | 70 | .pwr_mask = (pwr >= 0) ? BIT(pwr) : 0, \ |
70 | .status_mask = BIT(status), \ | 71 | .status_mask = (status >= 0) ? BIT(status) : 0, \ |
71 | .req_mask = BIT(req), \ | 72 | .req_mask = (req >= 0) ? BIT(req) : 0, \ |
72 | .idle_mask = BIT(idle), \ | 73 | .idle_mask = (idle >= 0) ? BIT(idle) : 0, \ |
73 | .ack_mask = BIT(ack), \ | 74 | .ack_mask = (ack >= 0) ? BIT(ack) : 0, \ |
74 | } | 75 | } |
75 | 76 | ||
76 | #define DOMAIN_RK3288(pwr, status, req) \ | 77 | #define DOMAIN_RK3288(pwr, status, req) \ |
@@ -79,6 +80,9 @@ struct rockchip_pmu { | |||
79 | #define DOMAIN_RK3368(pwr, status, req) \ | 80 | #define DOMAIN_RK3368(pwr, status, req) \ |
80 | DOMAIN(pwr, status, req, (req) + 16, req) | 81 | DOMAIN(pwr, status, req, (req) + 16, req) |
81 | 82 | ||
83 | #define DOMAIN_RK3399(pwr, status, req) \ | ||
84 | DOMAIN(pwr, status, req, req, req) | ||
85 | |||
82 | static bool rockchip_pmu_domain_is_idle(struct rockchip_pm_domain *pd) | 86 | static bool rockchip_pmu_domain_is_idle(struct rockchip_pm_domain *pd) |
83 | { | 87 | { |
84 | struct rockchip_pmu *pmu = pd->pmu; | 88 | struct rockchip_pmu *pmu = pd->pmu; |
@@ -96,6 +100,9 @@ static int rockchip_pmu_set_idle_request(struct rockchip_pm_domain *pd, | |||
96 | struct rockchip_pmu *pmu = pd->pmu; | 100 | struct rockchip_pmu *pmu = pd->pmu; |
97 | unsigned int val; | 101 | unsigned int val; |
98 | 102 | ||
103 | if (pd_info->req_mask == 0) | ||
104 | return 0; | ||
105 | |||
99 | regmap_update_bits(pmu->regmap, pmu->info->req_offset, | 106 | regmap_update_bits(pmu->regmap, pmu->info->req_offset, |
100 | pd_info->req_mask, idle ? -1U : 0); | 107 | pd_info->req_mask, idle ? -1U : 0); |
101 | 108 | ||
@@ -116,6 +123,10 @@ static bool rockchip_pmu_domain_is_on(struct rockchip_pm_domain *pd) | |||
116 | struct rockchip_pmu *pmu = pd->pmu; | 123 | struct rockchip_pmu *pmu = pd->pmu; |
117 | unsigned int val; | 124 | unsigned int val; |
118 | 125 | ||
126 | /* check idle status for idle-only domains */ | ||
127 | if (pd->info->status_mask == 0) | ||
128 | return !rockchip_pmu_domain_is_idle(pd); | ||
129 | |||
119 | regmap_read(pmu->regmap, pmu->info->status_offset, &val); | 130 | regmap_read(pmu->regmap, pmu->info->status_offset, &val); |
120 | 131 | ||
121 | /* 1'b0: power on, 1'b1: power off */ | 132 | /* 1'b0: power on, 1'b1: power off */ |
@@ -127,6 +138,9 @@ static void rockchip_do_pmu_set_power_domain(struct rockchip_pm_domain *pd, | |||
127 | { | 138 | { |
128 | struct rockchip_pmu *pmu = pd->pmu; | 139 | struct rockchip_pmu *pmu = pd->pmu; |
129 | 140 | ||
141 | if (pd->info->pwr_mask == 0) | ||
142 | return; | ||
143 | |||
130 | regmap_update_bits(pmu->regmap, pmu->info->pwr_offset, | 144 | regmap_update_bits(pmu->regmap, pmu->info->pwr_offset, |
131 | pd->info->pwr_mask, on ? 0 : -1U); | 145 | pd->info->pwr_mask, on ? 0 : -1U); |
132 | 146 | ||
@@ -360,6 +374,61 @@ static void rockchip_configure_pd_cnt(struct rockchip_pmu *pmu, | |||
360 | regmap_write(pmu->regmap, domain_reg_offset + 4, count); | 374 | regmap_write(pmu->regmap, domain_reg_offset + 4, count); |
361 | } | 375 | } |
362 | 376 | ||
377 | static int rockchip_pm_add_subdomain(struct rockchip_pmu *pmu, | ||
378 | struct device_node *parent) | ||
379 | { | ||
380 | struct device_node *np; | ||
381 | struct generic_pm_domain *child_domain, *parent_domain; | ||
382 | int error; | ||
383 | |||
384 | for_each_child_of_node(parent, np) { | ||
385 | u32 idx; | ||
386 | |||
387 | error = of_property_read_u32(parent, "reg", &idx); | ||
388 | if (error) { | ||
389 | dev_err(pmu->dev, | ||
390 | "%s: failed to retrieve domain id (reg): %d\n", | ||
391 | parent->name, error); | ||
392 | goto err_out; | ||
393 | } | ||
394 | parent_domain = pmu->genpd_data.domains[idx]; | ||
395 | |||
396 | error = rockchip_pm_add_one_domain(pmu, np); | ||
397 | if (error) { | ||
398 | dev_err(pmu->dev, "failed to handle node %s: %d\n", | ||
399 | np->name, error); | ||
400 | goto err_out; | ||
401 | } | ||
402 | |||
403 | error = of_property_read_u32(np, "reg", &idx); | ||
404 | if (error) { | ||
405 | dev_err(pmu->dev, | ||
406 | "%s: failed to retrieve domain id (reg): %d\n", | ||
407 | np->name, error); | ||
408 | goto err_out; | ||
409 | } | ||
410 | child_domain = pmu->genpd_data.domains[idx]; | ||
411 | |||
412 | error = pm_genpd_add_subdomain(parent_domain, child_domain); | ||
413 | if (error) { | ||
414 | dev_err(pmu->dev, "%s failed to add subdomain %s: %d\n", | ||
415 | parent_domain->name, child_domain->name, error); | ||
416 | goto err_out; | ||
417 | } else { | ||
418 | dev_dbg(pmu->dev, "%s add subdomain: %s\n", | ||
419 | parent_domain->name, child_domain->name); | ||
420 | } | ||
421 | |||
422 | rockchip_pm_add_subdomain(pmu, np); | ||
423 | } | ||
424 | |||
425 | return 0; | ||
426 | |||
427 | err_out: | ||
428 | of_node_put(np); | ||
429 | return error; | ||
430 | } | ||
431 | |||
363 | static int rockchip_pm_domain_probe(struct platform_device *pdev) | 432 | static int rockchip_pm_domain_probe(struct platform_device *pdev) |
364 | { | 433 | { |
365 | struct device *dev = &pdev->dev; | 434 | struct device *dev = &pdev->dev; |
@@ -406,6 +475,10 @@ static int rockchip_pm_domain_probe(struct platform_device *pdev) | |||
406 | } | 475 | } |
407 | 476 | ||
408 | pmu->regmap = syscon_node_to_regmap(parent->of_node); | 477 | pmu->regmap = syscon_node_to_regmap(parent->of_node); |
478 | if (IS_ERR(pmu->regmap)) { | ||
479 | dev_err(dev, "no regmap available\n"); | ||
480 | return PTR_ERR(pmu->regmap); | ||
481 | } | ||
409 | 482 | ||
410 | /* | 483 | /* |
411 | * Configure power up and down transition delays for CORE | 484 | * Configure power up and down transition delays for CORE |
@@ -426,6 +499,14 @@ static int rockchip_pm_domain_probe(struct platform_device *pdev) | |||
426 | of_node_put(node); | 499 | of_node_put(node); |
427 | goto err_out; | 500 | goto err_out; |
428 | } | 501 | } |
502 | |||
503 | error = rockchip_pm_add_subdomain(pmu, node); | ||
504 | if (error < 0) { | ||
505 | dev_err(dev, "failed to handle subdomain node %s: %d\n", | ||
506 | node->name, error); | ||
507 | of_node_put(node); | ||
508 | goto err_out; | ||
509 | } | ||
429 | } | 510 | } |
430 | 511 | ||
431 | if (error) { | 512 | if (error) { |
@@ -457,6 +538,36 @@ static const struct rockchip_domain_info rk3368_pm_domains[] = { | |||
457 | [RK3368_PD_GPU_1] = DOMAIN_RK3368(17, 16, 2), | 538 | [RK3368_PD_GPU_1] = DOMAIN_RK3368(17, 16, 2), |
458 | }; | 539 | }; |
459 | 540 | ||
541 | static const struct rockchip_domain_info rk3399_pm_domains[] = { | ||
542 | [RK3399_PD_TCPD0] = DOMAIN_RK3399(8, 8, -1), | ||
543 | [RK3399_PD_TCPD1] = DOMAIN_RK3399(9, 9, -1), | ||
544 | [RK3399_PD_CCI] = DOMAIN_RK3399(10, 10, -1), | ||
545 | [RK3399_PD_CCI0] = DOMAIN_RK3399(-1, -1, 15), | ||
546 | [RK3399_PD_CCI1] = DOMAIN_RK3399(-1, -1, 16), | ||
547 | [RK3399_PD_PERILP] = DOMAIN_RK3399(11, 11, 1), | ||
548 | [RK3399_PD_PERIHP] = DOMAIN_RK3399(12, 12, 2), | ||
549 | [RK3399_PD_CENTER] = DOMAIN_RK3399(13, 13, 14), | ||
550 | [RK3399_PD_VIO] = DOMAIN_RK3399(14, 14, 17), | ||
551 | [RK3399_PD_GPU] = DOMAIN_RK3399(15, 15, 0), | ||
552 | [RK3399_PD_VCODEC] = DOMAIN_RK3399(16, 16, 3), | ||
553 | [RK3399_PD_VDU] = DOMAIN_RK3399(17, 17, 4), | ||
554 | [RK3399_PD_RGA] = DOMAIN_RK3399(18, 18, 5), | ||
555 | [RK3399_PD_IEP] = DOMAIN_RK3399(19, 19, 6), | ||
556 | [RK3399_PD_VO] = DOMAIN_RK3399(20, 20, -1), | ||
557 | [RK3399_PD_VOPB] = DOMAIN_RK3399(-1, -1, 7), | ||
558 | [RK3399_PD_VOPL] = DOMAIN_RK3399(-1, -1, 8), | ||
559 | [RK3399_PD_ISP0] = DOMAIN_RK3399(22, 22, 9), | ||
560 | [RK3399_PD_ISP1] = DOMAIN_RK3399(23, 23, 10), | ||
561 | [RK3399_PD_HDCP] = DOMAIN_RK3399(24, 24, 11), | ||
562 | [RK3399_PD_GMAC] = DOMAIN_RK3399(25, 25, 23), | ||
563 | [RK3399_PD_EMMC] = DOMAIN_RK3399(26, 26, 24), | ||
564 | [RK3399_PD_USB3] = DOMAIN_RK3399(27, 27, 12), | ||
565 | [RK3399_PD_EDP] = DOMAIN_RK3399(28, 28, 22), | ||
566 | [RK3399_PD_GIC] = DOMAIN_RK3399(29, 29, 27), | ||
567 | [RK3399_PD_SD] = DOMAIN_RK3399(30, 30, 28), | ||
568 | [RK3399_PD_SDIOAUDIO] = DOMAIN_RK3399(31, 31, 29), | ||
569 | }; | ||
570 | |||
460 | static const struct rockchip_pmu_info rk3288_pmu = { | 571 | static const struct rockchip_pmu_info rk3288_pmu = { |
461 | .pwr_offset = 0x08, | 572 | .pwr_offset = 0x08, |
462 | .status_offset = 0x0c, | 573 | .status_offset = 0x0c, |
@@ -491,6 +602,23 @@ static const struct rockchip_pmu_info rk3368_pmu = { | |||
491 | .domain_info = rk3368_pm_domains, | 602 | .domain_info = rk3368_pm_domains, |
492 | }; | 603 | }; |
493 | 604 | ||
605 | static const struct rockchip_pmu_info rk3399_pmu = { | ||
606 | .pwr_offset = 0x14, | ||
607 | .status_offset = 0x18, | ||
608 | .req_offset = 0x60, | ||
609 | .idle_offset = 0x64, | ||
610 | .ack_offset = 0x68, | ||
611 | |||
612 | .core_pwrcnt_offset = 0x9c, | ||
613 | .gpu_pwrcnt_offset = 0xa4, | ||
614 | |||
615 | .core_power_transition_time = 24, | ||
616 | .gpu_power_transition_time = 24, | ||
617 | |||
618 | .num_domains = ARRAY_SIZE(rk3399_pm_domains), | ||
619 | .domain_info = rk3399_pm_domains, | ||
620 | }; | ||
621 | |||
494 | static const struct of_device_id rockchip_pm_domain_dt_match[] = { | 622 | static const struct of_device_id rockchip_pm_domain_dt_match[] = { |
495 | { | 623 | { |
496 | .compatible = "rockchip,rk3288-power-controller", | 624 | .compatible = "rockchip,rk3288-power-controller", |
@@ -500,6 +628,10 @@ static const struct of_device_id rockchip_pm_domain_dt_match[] = { | |||
500 | .compatible = "rockchip,rk3368-power-controller", | 628 | .compatible = "rockchip,rk3368-power-controller", |
501 | .data = (void *)&rk3368_pmu, | 629 | .data = (void *)&rk3368_pmu, |
502 | }, | 630 | }, |
631 | { | ||
632 | .compatible = "rockchip,rk3399-power-controller", | ||
633 | .data = (void *)&rk3399_pmu, | ||
634 | }, | ||
503 | { /* sentinel */ }, | 635 | { /* sentinel */ }, |
504 | }; | 636 | }; |
505 | 637 | ||
diff --git a/include/dt-bindings/power/rk3399-power.h b/include/dt-bindings/power/rk3399-power.h new file mode 100644 index 000000000000..168b3bfbd6f5 --- /dev/null +++ b/include/dt-bindings/power/rk3399-power.h | |||
@@ -0,0 +1,53 @@ | |||
1 | #ifndef __DT_BINDINGS_POWER_RK3399_POWER_H__ | ||
2 | #define __DT_BINDINGS_POWER_RK3399_POWER_H__ | ||
3 | |||
4 | /* VD_CORE_L */ | ||
5 | #define RK3399_PD_A53_L0 0 | ||
6 | #define RK3399_PD_A53_L1 1 | ||
7 | #define RK3399_PD_A53_L2 2 | ||
8 | #define RK3399_PD_A53_L3 3 | ||
9 | #define RK3399_PD_SCU_L 4 | ||
10 | |||
11 | /* VD_CORE_B */ | ||
12 | #define RK3399_PD_A72_B0 5 | ||
13 | #define RK3399_PD_A72_B1 6 | ||
14 | #define RK3399_PD_SCU_B 7 | ||
15 | |||
16 | /* VD_LOGIC */ | ||
17 | #define RK3399_PD_TCPD0 8 | ||
18 | #define RK3399_PD_TCPD1 9 | ||
19 | #define RK3399_PD_CCI 10 | ||
20 | #define RK3399_PD_CCI0 11 | ||
21 | #define RK3399_PD_CCI1 12 | ||
22 | #define RK3399_PD_PERILP 13 | ||
23 | #define RK3399_PD_PERIHP 14 | ||
24 | #define RK3399_PD_VIO 15 | ||
25 | #define RK3399_PD_VO 16 | ||
26 | #define RK3399_PD_VOPB 17 | ||
27 | #define RK3399_PD_VOPL 18 | ||
28 | #define RK3399_PD_ISP0 19 | ||
29 | #define RK3399_PD_ISP1 20 | ||
30 | #define RK3399_PD_HDCP 21 | ||
31 | #define RK3399_PD_GMAC 22 | ||
32 | #define RK3399_PD_EMMC 23 | ||
33 | #define RK3399_PD_USB3 24 | ||
34 | #define RK3399_PD_EDP 25 | ||
35 | #define RK3399_PD_GIC 26 | ||
36 | #define RK3399_PD_SD 27 | ||
37 | #define RK3399_PD_SDIOAUDIO 28 | ||
38 | #define RK3399_PD_ALIVE 29 | ||
39 | |||
40 | /* VD_CENTER */ | ||
41 | #define RK3399_PD_CENTER 30 | ||
42 | #define RK3399_PD_VCODEC 31 | ||
43 | #define RK3399_PD_VDU 32 | ||
44 | #define RK3399_PD_RGA 33 | ||
45 | #define RK3399_PD_IEP 34 | ||
46 | |||
47 | /* VD_GPU */ | ||
48 | #define RK3399_PD_GPU 35 | ||
49 | |||
50 | /* VD_PMU */ | ||
51 | #define RK3399_PD_PMU 36 | ||
52 | |||
53 | #endif | ||