| .. | .. |
|---|
| 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(); |
|---|