diff options
| -rw-r--r-- | drivers/soc/rockchip/pm_domains.c | 105 |
1 files changed, 102 insertions, 3 deletions
diff --git a/drivers/soc/rockchip/pm_domains.c b/drivers/soc/rockchip/pm_domains.c index ac729fe42cc9..44842a205e4b 100644 --- a/drivers/soc/rockchip/pm_domains.c +++ b/drivers/soc/rockchip/pm_domains.c | |||
| @@ -46,10 +46,20 @@ struct rockchip_pmu_info { | |||
| 46 | const struct rockchip_domain_info *domain_info; | 46 | const struct rockchip_domain_info *domain_info; |
| 47 | }; | 47 | }; |
| 48 | 48 | ||
| 49 | #define MAX_QOS_REGS_NUM 5 | ||
| 50 | #define QOS_PRIORITY 0x08 | ||
| 51 | #define QOS_MODE 0x0c | ||
| 52 | #define QOS_BANDWIDTH 0x10 | ||
| 53 | #define QOS_SATURATION 0x14 | ||
| 54 | #define QOS_EXTCONTROL 0x18 | ||
| 55 | |||
| 49 | struct rockchip_pm_domain { | 56 | struct rockchip_pm_domain { |
| 50 | struct generic_pm_domain genpd; | 57 | struct generic_pm_domain genpd; |
| 51 | const struct rockchip_domain_info *info; | 58 | const struct rockchip_domain_info *info; |
| 52 | struct rockchip_pmu *pmu; | 59 | struct rockchip_pmu *pmu; |
| 60 | int num_qos; | ||
| 61 | struct regmap **qos_regmap; | ||
| 62 | u32 *qos_save_regs[MAX_QOS_REGS_NUM]; | ||
| 53 | int num_clks; | 63 | int num_clks; |
| 54 | struct clk *clks[]; | 64 | struct clk *clks[]; |
| 55 | }; | 65 | }; |
| @@ -118,6 +128,55 @@ static int rockchip_pmu_set_idle_request(struct rockchip_pm_domain *pd, | |||
| 118 | return 0; | 128 | return 0; |
| 119 | } | 129 | } |
| 120 | 130 | ||
| 131 | static int rockchip_pmu_save_qos(struct rockchip_pm_domain *pd) | ||
| 132 | { | ||
| 133 | int i; | ||
| 134 | |||
| 135 | for (i = 0; i < pd->num_qos; i++) { | ||
| 136 | regmap_read(pd->qos_regmap[i], | ||
| 137 | QOS_PRIORITY, | ||
| 138 | &pd->qos_save_regs[0][i]); | ||
| 139 | regmap_read(pd->qos_regmap[i], | ||
| 140 | QOS_MODE, | ||
| 141 | &pd->qos_save_regs[1][i]); | ||
| 142 | regmap_read(pd->qos_regmap[i], | ||
| 143 | QOS_BANDWIDTH, | ||
| 144 | &pd->qos_save_regs[2][i]); | ||
| 145 | regmap_read(pd->qos_regmap[i], | ||
| 146 | QOS_SATURATION, | ||
| 147 | &pd->qos_save_regs[3][i]); | ||
| 148 | regmap_read(pd->qos_regmap[i], | ||
| 149 | QOS_EXTCONTROL, | ||
| 150 | &pd->qos_save_regs[4][i]); | ||
| 151 | } | ||
| 152 | return 0; | ||
| 153 | } | ||
| 154 | |||
| 155 | static int rockchip_pmu_restore_qos(struct rockchip_pm_domain *pd) | ||
| 156 | { | ||
| 157 | int i; | ||
| 158 | |||
| 159 | for (i = 0; i < pd->num_qos; i++) { | ||
| 160 | regmap_write(pd->qos_regmap[i], | ||
| 161 | QOS_PRIORITY, | ||
| 162 | pd->qos_save_regs[0][i]); | ||
| 163 | regmap_write(pd->qos_regmap[i], | ||
| 164 | QOS_MODE, | ||
| 165 | pd->qos_save_regs[1][i]); | ||
| 166 | regmap_write(pd->qos_regmap[i], | ||
| 167 | QOS_BANDWIDTH, | ||
| 168 | pd->qos_save_regs[2][i]); | ||
| 169 | regmap_write(pd->qos_regmap[i], | ||
| 170 | QOS_SATURATION, | ||
| 171 | pd->qos_save_regs[3][i]); | ||
| 172 | regmap_write(pd->qos_regmap[i], | ||
| 173 | QOS_EXTCONTROL, | ||
| 174 | pd->qos_save_regs[4][i]); | ||
| 175 | } | ||
| 176 | |||
| 177 | return 0; | ||
| 178 | } | ||
| 179 | |||
| 121 | static bool rockchip_pmu_domain_is_on(struct rockchip_pm_domain *pd) | 180 | static bool rockchip_pmu_domain_is_on(struct rockchip_pm_domain *pd) |
| 122 | { | 181 | { |
| 123 | struct rockchip_pmu *pmu = pd->pmu; | 182 | struct rockchip_pmu *pmu = pd->pmu; |
| @@ -161,7 +220,7 @@ static int rockchip_pd_power(struct rockchip_pm_domain *pd, bool power_on) | |||
| 161 | clk_enable(pd->clks[i]); | 220 | clk_enable(pd->clks[i]); |
| 162 | 221 | ||
| 163 | if (!power_on) { | 222 | if (!power_on) { |
| 164 | /* FIXME: add code to save AXI_QOS */ | 223 | rockchip_pmu_save_qos(pd); |
| 165 | 224 | ||
| 166 | /* if powering down, idle request to NIU first */ | 225 | /* if powering down, idle request to NIU first */ |
| 167 | rockchip_pmu_set_idle_request(pd, true); | 226 | rockchip_pmu_set_idle_request(pd, true); |
| @@ -173,7 +232,7 @@ static int rockchip_pd_power(struct rockchip_pm_domain *pd, bool power_on) | |||
| 173 | /* if powering up, leave idle mode */ | 232 | /* if powering up, leave idle mode */ |
| 174 | rockchip_pmu_set_idle_request(pd, false); | 233 | rockchip_pmu_set_idle_request(pd, false); |
| 175 | 234 | ||
| 176 | /* FIXME: add code to restore AXI_QOS */ | 235 | rockchip_pmu_restore_qos(pd); |
| 177 | } | 236 | } |
| 178 | 237 | ||
| 179 | for (i = pd->num_clks - 1; i >= 0; i--) | 238 | for (i = pd->num_clks - 1; i >= 0; i--) |
| @@ -241,9 +300,10 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu, | |||
| 241 | { | 300 | { |
| 242 | const struct rockchip_domain_info *pd_info; | 301 | const struct rockchip_domain_info *pd_info; |
| 243 | struct rockchip_pm_domain *pd; | 302 | struct rockchip_pm_domain *pd; |
| 303 | struct device_node *qos_node; | ||
| 244 | struct clk *clk; | 304 | struct clk *clk; |
| 245 | int clk_cnt; | 305 | int clk_cnt; |
| 246 | int i; | 306 | int i, j; |
| 247 | u32 id; | 307 | u32 id; |
| 248 | int error; | 308 | int error; |
| 249 | 309 | ||
| @@ -303,6 +363,45 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu, | |||
| 303 | clk, node->name); | 363 | clk, node->name); |
| 304 | } | 364 | } |
| 305 | 365 | ||
| 366 | pd->num_qos = of_count_phandle_with_args(node, "pm_qos", | ||
| 367 | NULL); | ||
| 368 | |||
| 369 | if (pd->num_qos > 0) { | ||
| 370 | pd->qos_regmap = devm_kcalloc(pmu->dev, pd->num_qos, | ||
| 371 | sizeof(*pd->qos_regmap), | ||
| 372 | GFP_KERNEL); | ||
| 373 | if (!pd->qos_regmap) { | ||
| 374 | error = -ENOMEM; | ||
| 375 | goto err_out; | ||
| 376 | } | ||
| 377 | |||
| 378 | for (j = 0; j < MAX_QOS_REGS_NUM; j++) { | ||
| 379 | pd->qos_save_regs[j] = devm_kcalloc(pmu->dev, | ||
| 380 | pd->num_qos, | ||
| 381 | sizeof(u32), | ||
| 382 | GFP_KERNEL); | ||
| 383 | if (!pd->qos_save_regs[j]) { | ||
| 384 | error = -ENOMEM; | ||
| 385 | goto err_out; | ||
| 386 | } | ||
| 387 | } | ||
| 388 | |||
| 389 | for (j = 0; j < pd->num_qos; j++) { | ||
| 390 | qos_node = of_parse_phandle(node, "pm_qos", j); | ||
| 391 | if (!qos_node) { | ||
| 392 | error = -ENODEV; | ||
| 393 | goto err_out; | ||
| 394 | } | ||
| 395 | pd->qos_regmap[j] = syscon_node_to_regmap(qos_node); | ||
| 396 | if (IS_ERR(pd->qos_regmap[j])) { | ||
| 397 | error = -ENODEV; | ||
| 398 | of_node_put(qos_node); | ||
| 399 | goto err_out; | ||
| 400 | } | ||
| 401 | of_node_put(qos_node); | ||
| 402 | } | ||
| 403 | } | ||
| 404 | |||
| 306 | error = rockchip_pd_power(pd, true); | 405 | error = rockchip_pd_power(pd, true); |
| 307 | if (error) { | 406 | if (error) { |
| 308 | dev_err(pmu->dev, | 407 | dev_err(pmu->dev, |
