.. | .. |
---|
93 | 93 | #define QOS_SATURATION 0x14 |
---|
94 | 94 | #define QOS_EXTCONTROL 0x18 |
---|
95 | 95 | |
---|
| 96 | +#define SHAPING_NBPKTMAX0 0x0 |
---|
| 97 | + |
---|
96 | 98 | struct rockchip_pm_domain { |
---|
97 | 99 | struct generic_pm_domain genpd; |
---|
98 | 100 | const struct rockchip_domain_info *info; |
---|
99 | 101 | struct rockchip_pmu *pmu; |
---|
100 | 102 | int num_qos; |
---|
| 103 | + int num_shaping; |
---|
101 | 104 | struct regmap **qos_regmap; |
---|
| 105 | + struct regmap **shaping_regmap; |
---|
102 | 106 | u32 *qos_save_regs[MAX_QOS_REGS_NUM]; |
---|
| 107 | + u32 *shaping_save_regs; |
---|
103 | 108 | bool *qos_is_need_init[MAX_QOS_REGS_NUM]; |
---|
| 109 | + bool *shaping_is_need_init; |
---|
104 | 110 | int num_clks; |
---|
105 | 111 | struct clk_bulk_data *clks; |
---|
106 | 112 | bool is_ignore_pwr; |
---|
107 | 113 | bool is_qos_saved; |
---|
108 | 114 | bool is_qos_need_init; |
---|
| 115 | + bool is_shaping_need_init; |
---|
109 | 116 | struct regulator *supply; |
---|
110 | 117 | }; |
---|
111 | 118 | |
---|
.. | .. |
---|
124 | 131 | module_param_named(always_on, pm_domain_always_on, bool, 0644); |
---|
125 | 132 | MODULE_PARM_DESC(always_on, |
---|
126 | 133 | "Always keep pm domains power on except for system suspend."); |
---|
127 | | - |
---|
128 | | -#ifdef MODULE |
---|
129 | | -static bool keepon_startup = true; |
---|
130 | | -static void rockchip_pd_keepon_do_release(void); |
---|
131 | | - |
---|
132 | | -static int pd_param_set_keepon_startup(const char *val, |
---|
133 | | - const struct kernel_param *kp) |
---|
134 | | -{ |
---|
135 | | - int ret; |
---|
136 | | - |
---|
137 | | - ret = param_set_bool(val, kp); |
---|
138 | | - if (ret) |
---|
139 | | - return ret; |
---|
140 | | - |
---|
141 | | - if (!keepon_startup) |
---|
142 | | - rockchip_pd_keepon_do_release(); |
---|
143 | | - |
---|
144 | | - return 0; |
---|
145 | | -} |
---|
146 | | - |
---|
147 | | -static const struct kernel_param_ops pd_keepon_startup_ops = { |
---|
148 | | - .set = pd_param_set_keepon_startup, |
---|
149 | | - .get = param_get_bool, |
---|
150 | | -}; |
---|
151 | | - |
---|
152 | | -module_param_cb(keepon_startup, &pd_keepon_startup_ops, &keepon_startup, 0644); |
---|
153 | | -MODULE_PARM_DESC(keepon_startup, |
---|
154 | | - "Keep pm domains power on during system startup."); |
---|
155 | | -#endif |
---|
156 | 134 | |
---|
157 | 135 | static void rockchip_pmu_lock(struct rockchip_pm_domain *pd) |
---|
158 | 136 | { |
---|
.. | .. |
---|
459 | 437 | } |
---|
460 | 438 | EXPORT_SYMBOL(rockchip_pmu_idle_request); |
---|
461 | 439 | |
---|
| 440 | +static int rockchip_pmu_save_shaping(struct rockchip_pm_domain *pd) |
---|
| 441 | +{ |
---|
| 442 | + int i; |
---|
| 443 | + |
---|
| 444 | + for (i = 0; i < pd->num_shaping; i++) |
---|
| 445 | + regmap_read(pd->shaping_regmap[i], SHAPING_NBPKTMAX0, |
---|
| 446 | + &pd->shaping_save_regs[i]); |
---|
| 447 | + |
---|
| 448 | + return 0; |
---|
| 449 | +} |
---|
| 450 | + |
---|
| 451 | +static int rockchip_pmu_restore_shaping(struct rockchip_pm_domain *pd) |
---|
| 452 | +{ |
---|
| 453 | + int i; |
---|
| 454 | + |
---|
| 455 | + for (i = 0; i < pd->num_shaping; i++) |
---|
| 456 | + regmap_write(pd->shaping_regmap[i], SHAPING_NBPKTMAX0, |
---|
| 457 | + pd->shaping_save_regs[i]); |
---|
| 458 | + |
---|
| 459 | + return 0; |
---|
| 460 | +} |
---|
| 461 | + |
---|
| 462 | +static void rockchip_pmu_init_shaping(struct rockchip_pm_domain *pd) |
---|
| 463 | +{ |
---|
| 464 | + int i; |
---|
| 465 | + |
---|
| 466 | + if (!pd->is_shaping_need_init) |
---|
| 467 | + return; |
---|
| 468 | + |
---|
| 469 | + for (i = 0; i < pd->num_shaping; i++) |
---|
| 470 | + if (pd->shaping_is_need_init[i]) |
---|
| 471 | + regmap_write(pd->shaping_regmap[i], SHAPING_NBPKTMAX0, |
---|
| 472 | + pd->shaping_save_regs[i]); |
---|
| 473 | + |
---|
| 474 | + kfree(pd->shaping_is_need_init); |
---|
| 475 | + pd->shaping_is_need_init = NULL; |
---|
| 476 | + pd->is_shaping_need_init = false; |
---|
| 477 | +} |
---|
| 478 | + |
---|
462 | 479 | static int rockchip_pmu_save_qos(struct rockchip_pm_domain *pd) |
---|
463 | 480 | { |
---|
464 | 481 | int i; |
---|
.. | .. |
---|
480 | 497 | QOS_EXTCONTROL, |
---|
481 | 498 | &pd->qos_save_regs[4][i]); |
---|
482 | 499 | } |
---|
483 | | - return 0; |
---|
| 500 | + |
---|
| 501 | + return rockchip_pmu_save_shaping(pd); |
---|
484 | 502 | } |
---|
485 | 503 | |
---|
486 | 504 | static int rockchip_pmu_restore_qos(struct rockchip_pm_domain *pd) |
---|
.. | .. |
---|
505 | 523 | pd->qos_save_regs[4][i]); |
---|
506 | 524 | } |
---|
507 | 525 | |
---|
508 | | - return 0; |
---|
| 526 | + return rockchip_pmu_restore_shaping(pd); |
---|
509 | 527 | } |
---|
510 | 528 | |
---|
511 | 529 | static void rockchip_pmu_init_qos(struct rockchip_pm_domain *pd) |
---|
512 | 530 | { |
---|
513 | 531 | int i; |
---|
| 532 | + |
---|
| 533 | + rockchip_pmu_init_shaping(pd); |
---|
514 | 534 | |
---|
515 | 535 | if (!pd->is_qos_need_init) |
---|
516 | 536 | return; |
---|
.. | .. |
---|
809 | 829 | |
---|
810 | 830 | if (pd->is_qos_saved) |
---|
811 | 831 | rockchip_pmu_restore_qos(pd); |
---|
812 | | - if (pd->is_qos_need_init) |
---|
| 832 | + if (pd->is_qos_need_init || pd->is_shaping_need_init) |
---|
813 | 833 | rockchip_pmu_init_qos(pd); |
---|
814 | 834 | } |
---|
815 | 835 | |
---|
.. | .. |
---|
949 | 969 | if (!pd->is_qos_need_init) { |
---|
950 | 970 | kfree(pd->qos_is_need_init[0]); |
---|
951 | 971 | pd->qos_is_need_init[0] = NULL; |
---|
952 | | - return; |
---|
953 | 972 | } |
---|
| 973 | + if (!pd->is_shaping_need_init) { |
---|
| 974 | + kfree(pd->shaping_is_need_init); |
---|
| 975 | + pd->shaping_is_need_init = NULL; |
---|
| 976 | + } |
---|
| 977 | + if (!pd->is_qos_need_init && !pd->is_shaping_need_init) |
---|
| 978 | + return; |
---|
954 | 979 | |
---|
955 | 980 | is_pd_on = rockchip_pmu_domain_is_on(pd); |
---|
956 | 981 | if (is_pd_on) { |
---|
.. | .. |
---|
982 | 1007 | } |
---|
983 | 1008 | |
---|
984 | 1009 | return 0; |
---|
| 1010 | +} |
---|
| 1011 | + |
---|
| 1012 | +static int rockchip_pd_of_get_shaping(struct rockchip_pm_domain *pd, |
---|
| 1013 | + struct device_node *node) |
---|
| 1014 | +{ |
---|
| 1015 | + struct rockchip_pmu *pmu = pd->pmu; |
---|
| 1016 | + struct device_node *shaping_node; |
---|
| 1017 | + int num_shaping = 0, num_shaping_reg = 0; |
---|
| 1018 | + int error, i; |
---|
| 1019 | + u32 val; |
---|
| 1020 | + |
---|
| 1021 | + num_shaping = of_count_phandle_with_args(node, "pm_shaping", NULL); |
---|
| 1022 | + |
---|
| 1023 | + for (i = 0; i < num_shaping; i++) { |
---|
| 1024 | + shaping_node = of_parse_phandle(node, "pm_shaping", i); |
---|
| 1025 | + if (shaping_node && of_device_is_available(shaping_node)) |
---|
| 1026 | + pd->num_shaping++; |
---|
| 1027 | + of_node_put(shaping_node); |
---|
| 1028 | + } |
---|
| 1029 | + |
---|
| 1030 | + if (pd->num_shaping > 0) { |
---|
| 1031 | + pd->shaping_regmap = devm_kcalloc(pmu->dev, pd->num_shaping, |
---|
| 1032 | + sizeof(*pd->shaping_regmap), |
---|
| 1033 | + GFP_KERNEL); |
---|
| 1034 | + if (!pd->shaping_regmap) |
---|
| 1035 | + return -ENOMEM; |
---|
| 1036 | + pd->shaping_save_regs = devm_kmalloc(pmu->dev, sizeof(u32) * |
---|
| 1037 | + pd->num_shaping, |
---|
| 1038 | + GFP_KERNEL); |
---|
| 1039 | + if (!pd->shaping_save_regs) |
---|
| 1040 | + return -ENOMEM; |
---|
| 1041 | + pd->shaping_is_need_init = kcalloc(pd->num_shaping, sizeof(bool), |
---|
| 1042 | + GFP_KERNEL); |
---|
| 1043 | + if (!pd->shaping_is_need_init) |
---|
| 1044 | + return -ENOMEM; |
---|
| 1045 | + for (i = 0; i < num_shaping; i++) { |
---|
| 1046 | + shaping_node = of_parse_phandle(node, "pm_shaping", i); |
---|
| 1047 | + if (!shaping_node) { |
---|
| 1048 | + error = -ENODEV; |
---|
| 1049 | + goto err_free_init; |
---|
| 1050 | + } |
---|
| 1051 | + if (of_device_is_available(shaping_node)) { |
---|
| 1052 | + pd->shaping_regmap[num_shaping_reg] = |
---|
| 1053 | + syscon_node_to_regmap(shaping_node); |
---|
| 1054 | + if (IS_ERR(pd->shaping_regmap[num_shaping_reg])) { |
---|
| 1055 | + of_node_put(shaping_node); |
---|
| 1056 | + error = -ENODEV; |
---|
| 1057 | + goto err_free_init; |
---|
| 1058 | + } |
---|
| 1059 | + if (!of_property_read_u32(shaping_node, |
---|
| 1060 | + "shaping-init", |
---|
| 1061 | + &val)) { |
---|
| 1062 | + pd->shaping_save_regs[i] = val; |
---|
| 1063 | + pd->shaping_is_need_init[i] = true; |
---|
| 1064 | + pd->is_shaping_need_init = true; |
---|
| 1065 | + } |
---|
| 1066 | + num_shaping_reg++; |
---|
| 1067 | + } |
---|
| 1068 | + of_node_put(shaping_node); |
---|
| 1069 | + if (num_shaping_reg > pd->num_shaping) { |
---|
| 1070 | + error = -EINVAL; |
---|
| 1071 | + goto err_free_init; |
---|
| 1072 | + } |
---|
| 1073 | + } |
---|
| 1074 | + } |
---|
| 1075 | + |
---|
| 1076 | + return 0; |
---|
| 1077 | + |
---|
| 1078 | +err_free_init: |
---|
| 1079 | + kfree(pd->shaping_is_need_init); |
---|
| 1080 | + pd->shaping_is_need_init = NULL; |
---|
| 1081 | + |
---|
| 1082 | + return error; |
---|
985 | 1083 | } |
---|
986 | 1084 | |
---|
987 | 1085 | static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu, |
---|
.. | .. |
---|
1160 | 1258 | } |
---|
1161 | 1259 | } |
---|
1162 | 1260 | |
---|
| 1261 | + error = rockchip_pd_of_get_shaping(pd, node); |
---|
| 1262 | + if (error) |
---|
| 1263 | + goto err_unprepare_clocks; |
---|
| 1264 | + |
---|
1163 | 1265 | if (pd->info->name) |
---|
1164 | 1266 | pd->genpd.name = pd->info->name; |
---|
1165 | 1267 | else |
---|
.. | .. |
---|
1309 | 1411 | return error; |
---|
1310 | 1412 | } |
---|
1311 | 1413 | |
---|
| 1414 | +#ifdef MODULE |
---|
| 1415 | +void rockchip_pd_disable_unused(void) |
---|
| 1416 | +{ |
---|
| 1417 | + struct generic_pm_domain *genpd; |
---|
| 1418 | + struct rockchip_pm_domain *pd; |
---|
| 1419 | + int i; |
---|
| 1420 | + |
---|
| 1421 | + if (!g_pmu) |
---|
| 1422 | + return; |
---|
| 1423 | + |
---|
| 1424 | + for (i = 0; i < g_pmu->genpd_data.num_domains; i++) { |
---|
| 1425 | + genpd = g_pmu->genpd_data.domains[i]; |
---|
| 1426 | + if (genpd) { |
---|
| 1427 | + pd = to_rockchip_pd(genpd); |
---|
| 1428 | + if (pd->info->always_on) |
---|
| 1429 | + continue; |
---|
| 1430 | + if (pd->info->keepon_startup && |
---|
| 1431 | + (genpd->flags & GENPD_FLAG_ALWAYS_ON)) |
---|
| 1432 | + genpd->flags &= (~GENPD_FLAG_ALWAYS_ON); |
---|
| 1433 | + queue_work(pm_wq, &genpd->power_off_work); |
---|
| 1434 | + } |
---|
| 1435 | + } |
---|
| 1436 | +} |
---|
| 1437 | +EXPORT_SYMBOL_GPL(rockchip_pd_disable_unused); |
---|
| 1438 | +#else |
---|
1312 | 1439 | static void rockchip_pd_keepon_do_release(void) |
---|
1313 | 1440 | { |
---|
1314 | 1441 | struct generic_pm_domain *genpd; |
---|
.. | .. |
---|
1334 | 1461 | } |
---|
1335 | 1462 | } |
---|
1336 | 1463 | |
---|
1337 | | -#ifndef MODULE |
---|
1338 | 1464 | static int __init rockchip_pd_keepon_release(void) |
---|
1339 | 1465 | { |
---|
1340 | 1466 | rockchip_pd_keepon_do_release(); |
---|