dp_power.c (9701B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. 4 */ 5 6#define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__ 7 8#include <linux/clk.h> 9#include <linux/clk-provider.h> 10#include <linux/regulator/consumer.h> 11#include <linux/pm_opp.h> 12#include "dp_power.h" 13#include "msm_drv.h" 14 15struct dp_power_private { 16 struct dp_parser *parser; 17 struct platform_device *pdev; 18 struct device *dev; 19 struct drm_device *drm_dev; 20 struct clk *link_clk_src; 21 struct clk *pixel_provider; 22 struct clk *link_provider; 23 struct regulator_bulk_data supplies[DP_DEV_REGULATOR_MAX]; 24 25 struct dp_power dp_power; 26}; 27 28static void dp_power_regulator_disable(struct dp_power_private *power) 29{ 30 struct regulator_bulk_data *s = power->supplies; 31 const struct dp_reg_entry *regs = power->parser->regulator_cfg->regs; 32 int num = power->parser->regulator_cfg->num; 33 int i; 34 35 DBG(""); 36 for (i = num - 1; i >= 0; i--) 37 if (regs[i].disable_load >= 0) 38 regulator_set_load(s[i].consumer, 39 regs[i].disable_load); 40 41 regulator_bulk_disable(num, s); 42} 43 44static int dp_power_regulator_enable(struct dp_power_private *power) 45{ 46 struct regulator_bulk_data *s = power->supplies; 47 const struct dp_reg_entry *regs = power->parser->regulator_cfg->regs; 48 int num = power->parser->regulator_cfg->num; 49 int ret, i; 50 51 DBG(""); 52 for (i = 0; i < num; i++) { 53 if (regs[i].enable_load >= 0) { 54 ret = regulator_set_load(s[i].consumer, 55 regs[i].enable_load); 56 if (ret < 0) { 57 pr_err("regulator %d set op mode failed, %d\n", 58 i, ret); 59 goto fail; 60 } 61 } 62 } 63 64 ret = regulator_bulk_enable(num, s); 65 if (ret < 0) { 66 pr_err("regulator enable failed, %d\n", ret); 67 goto fail; 68 } 69 70 return 0; 71 72fail: 73 for (i--; i >= 0; i--) 74 regulator_set_load(s[i].consumer, regs[i].disable_load); 75 return ret; 76} 77 78static int dp_power_regulator_init(struct dp_power_private *power) 79{ 80 struct regulator_bulk_data *s = power->supplies; 81 const struct dp_reg_entry *regs = power->parser->regulator_cfg->regs; 82 struct platform_device *pdev = power->pdev; 83 int num = power->parser->regulator_cfg->num; 84 int i, ret; 85 86 for (i = 0; i < num; i++) 87 s[i].supply = regs[i].name; 88 89 ret = devm_regulator_bulk_get(&pdev->dev, num, s); 90 if (ret < 0) { 91 pr_err("%s: failed to init regulator, ret=%d\n", 92 __func__, ret); 93 return ret; 94 } 95 96 return 0; 97} 98 99static int dp_power_clk_init(struct dp_power_private *power) 100{ 101 int rc = 0; 102 struct dss_module_power *core, *ctrl, *stream; 103 struct device *dev = &power->pdev->dev; 104 105 core = &power->parser->mp[DP_CORE_PM]; 106 ctrl = &power->parser->mp[DP_CTRL_PM]; 107 stream = &power->parser->mp[DP_STREAM_PM]; 108 109 rc = msm_dss_get_clk(dev, core->clk_config, core->num_clk); 110 if (rc) { 111 DRM_ERROR("failed to get %s clk. err=%d\n", 112 dp_parser_pm_name(DP_CORE_PM), rc); 113 return rc; 114 } 115 116 rc = msm_dss_get_clk(dev, ctrl->clk_config, ctrl->num_clk); 117 if (rc) { 118 DRM_ERROR("failed to get %s clk. err=%d\n", 119 dp_parser_pm_name(DP_CTRL_PM), rc); 120 msm_dss_put_clk(core->clk_config, core->num_clk); 121 return -ENODEV; 122 } 123 124 rc = msm_dss_get_clk(dev, stream->clk_config, stream->num_clk); 125 if (rc) { 126 DRM_ERROR("failed to get %s clk. err=%d\n", 127 dp_parser_pm_name(DP_CTRL_PM), rc); 128 msm_dss_put_clk(core->clk_config, core->num_clk); 129 return -ENODEV; 130 } 131 132 return 0; 133} 134 135static int dp_power_clk_deinit(struct dp_power_private *power) 136{ 137 struct dss_module_power *core, *ctrl, *stream; 138 139 core = &power->parser->mp[DP_CORE_PM]; 140 ctrl = &power->parser->mp[DP_CTRL_PM]; 141 stream = &power->parser->mp[DP_STREAM_PM]; 142 143 if (!core || !ctrl || !stream) { 144 DRM_ERROR("invalid power_data\n"); 145 return -EINVAL; 146 } 147 148 msm_dss_put_clk(ctrl->clk_config, ctrl->num_clk); 149 msm_dss_put_clk(core->clk_config, core->num_clk); 150 msm_dss_put_clk(stream->clk_config, stream->num_clk); 151 return 0; 152} 153 154static int dp_power_clk_set_link_rate(struct dp_power_private *power, 155 struct dss_clk *clk_arry, int num_clk, int enable) 156{ 157 u32 rate; 158 int i, rc = 0; 159 160 for (i = 0; i < num_clk; i++) { 161 if (clk_arry[i].clk) { 162 if (clk_arry[i].type == DSS_CLK_PCLK) { 163 if (enable) 164 rate = clk_arry[i].rate; 165 else 166 rate = 0; 167 168 rc = dev_pm_opp_set_rate(power->dev, rate); 169 if (rc) 170 break; 171 } 172 173 } 174 } 175 return rc; 176} 177 178static int dp_power_clk_set_rate(struct dp_power_private *power, 179 enum dp_pm_type module, bool enable) 180{ 181 int rc = 0; 182 struct dss_module_power *mp = &power->parser->mp[module]; 183 184 if (module == DP_CTRL_PM) { 185 rc = dp_power_clk_set_link_rate(power, mp->clk_config, mp->num_clk, enable); 186 if (rc) { 187 DRM_ERROR("failed to set link clks rate\n"); 188 return rc; 189 } 190 } else { 191 192 if (enable) { 193 rc = msm_dss_clk_set_rate(mp->clk_config, mp->num_clk); 194 if (rc) { 195 DRM_ERROR("failed to set clks rate\n"); 196 return rc; 197 } 198 } 199 } 200 201 rc = msm_dss_enable_clk(mp->clk_config, mp->num_clk, enable); 202 if (rc) { 203 DRM_ERROR("failed to %d clks, err: %d\n", enable, rc); 204 return rc; 205 } 206 207 return 0; 208} 209 210int dp_power_clk_status(struct dp_power *dp_power, enum dp_pm_type pm_type) 211{ 212 struct dp_power_private *power; 213 214 power = container_of(dp_power, struct dp_power_private, dp_power); 215 216 drm_dbg_dp(power->drm_dev, 217 "core_clk_on=%d link_clk_on=%d stream_clk_on=%d\n", 218 dp_power->core_clks_on, dp_power->link_clks_on, dp_power->stream_clks_on); 219 220 if (pm_type == DP_CORE_PM) 221 return dp_power->core_clks_on; 222 223 if (pm_type == DP_CTRL_PM) 224 return dp_power->link_clks_on; 225 226 if (pm_type == DP_STREAM_PM) 227 return dp_power->stream_clks_on; 228 229 return 0; 230} 231 232int dp_power_clk_enable(struct dp_power *dp_power, 233 enum dp_pm_type pm_type, bool enable) 234{ 235 int rc = 0; 236 struct dp_power_private *power; 237 238 power = container_of(dp_power, struct dp_power_private, dp_power); 239 240 if (pm_type != DP_CORE_PM && pm_type != DP_CTRL_PM && 241 pm_type != DP_STREAM_PM) { 242 DRM_ERROR("unsupported power module: %s\n", 243 dp_parser_pm_name(pm_type)); 244 return -EINVAL; 245 } 246 247 if (enable) { 248 if (pm_type == DP_CORE_PM && dp_power->core_clks_on) { 249 drm_dbg_dp(power->drm_dev, 250 "core clks already enabled\n"); 251 return 0; 252 } 253 254 if (pm_type == DP_CTRL_PM && dp_power->link_clks_on) { 255 drm_dbg_dp(power->drm_dev, 256 "links clks already enabled\n"); 257 return 0; 258 } 259 260 if (pm_type == DP_STREAM_PM && dp_power->stream_clks_on) { 261 drm_dbg_dp(power->drm_dev, 262 "pixel clks already enabled\n"); 263 return 0; 264 } 265 266 if ((pm_type == DP_CTRL_PM) && (!dp_power->core_clks_on)) { 267 drm_dbg_dp(power->drm_dev, 268 "Enable core clks before link clks\n"); 269 270 rc = dp_power_clk_set_rate(power, DP_CORE_PM, enable); 271 if (rc) { 272 DRM_ERROR("fail to enable clks: %s. err=%d\n", 273 dp_parser_pm_name(DP_CORE_PM), rc); 274 return rc; 275 } 276 dp_power->core_clks_on = true; 277 } 278 } 279 280 rc = dp_power_clk_set_rate(power, pm_type, enable); 281 if (rc) { 282 DRM_ERROR("failed to '%s' clks for: %s. err=%d\n", 283 enable ? "enable" : "disable", 284 dp_parser_pm_name(pm_type), rc); 285 return rc; 286 } 287 288 if (pm_type == DP_CORE_PM) 289 dp_power->core_clks_on = enable; 290 else if (pm_type == DP_STREAM_PM) 291 dp_power->stream_clks_on = enable; 292 else 293 dp_power->link_clks_on = enable; 294 295 drm_dbg_dp(power->drm_dev, "%s clocks for %s\n", 296 enable ? "enable" : "disable", 297 dp_parser_pm_name(pm_type)); 298 drm_dbg_dp(power->drm_dev, 299 "strem_clks:%s link_clks:%s core_clks:%s\n", 300 dp_power->stream_clks_on ? "on" : "off", 301 dp_power->link_clks_on ? "on" : "off", 302 dp_power->core_clks_on ? "on" : "off"); 303 304 return 0; 305} 306 307int dp_power_client_init(struct dp_power *dp_power) 308{ 309 int rc = 0; 310 struct dp_power_private *power; 311 312 if (!dp_power) { 313 DRM_ERROR("invalid power data\n"); 314 return -EINVAL; 315 } 316 317 power = container_of(dp_power, struct dp_power_private, dp_power); 318 319 pm_runtime_enable(&power->pdev->dev); 320 321 rc = dp_power_regulator_init(power); 322 if (rc) { 323 DRM_ERROR("failed to init regulators %d\n", rc); 324 goto error; 325 } 326 327 rc = dp_power_clk_init(power); 328 if (rc) { 329 DRM_ERROR("failed to init clocks %d\n", rc); 330 goto error; 331 } 332 return 0; 333 334error: 335 pm_runtime_disable(&power->pdev->dev); 336 return rc; 337} 338 339void dp_power_client_deinit(struct dp_power *dp_power) 340{ 341 struct dp_power_private *power; 342 343 if (!dp_power) { 344 DRM_ERROR("invalid power data\n"); 345 return; 346 } 347 348 power = container_of(dp_power, struct dp_power_private, dp_power); 349 350 dp_power_clk_deinit(power); 351 pm_runtime_disable(&power->pdev->dev); 352 353} 354 355int dp_power_init(struct dp_power *dp_power, bool flip) 356{ 357 int rc = 0; 358 struct dp_power_private *power = NULL; 359 360 if (!dp_power) { 361 DRM_ERROR("invalid power data\n"); 362 return -EINVAL; 363 } 364 365 power = container_of(dp_power, struct dp_power_private, dp_power); 366 367 pm_runtime_get_sync(&power->pdev->dev); 368 rc = dp_power_regulator_enable(power); 369 if (rc) { 370 DRM_ERROR("failed to enable regulators, %d\n", rc); 371 goto exit; 372 } 373 374 rc = dp_power_clk_enable(dp_power, DP_CORE_PM, true); 375 if (rc) { 376 DRM_ERROR("failed to enable DP core clocks, %d\n", rc); 377 goto err_clk; 378 } 379 380 return 0; 381 382err_clk: 383 dp_power_regulator_disable(power); 384exit: 385 pm_runtime_put_sync(&power->pdev->dev); 386 return rc; 387} 388 389int dp_power_deinit(struct dp_power *dp_power) 390{ 391 struct dp_power_private *power; 392 393 power = container_of(dp_power, struct dp_power_private, dp_power); 394 395 dp_power_clk_enable(dp_power, DP_CORE_PM, false); 396 dp_power_regulator_disable(power); 397 pm_runtime_put_sync(&power->pdev->dev); 398 return 0; 399} 400 401struct dp_power *dp_power_get(struct device *dev, struct dp_parser *parser) 402{ 403 struct dp_power_private *power; 404 struct dp_power *dp_power; 405 406 if (!parser) { 407 DRM_ERROR("invalid input\n"); 408 return ERR_PTR(-EINVAL); 409 } 410 411 power = devm_kzalloc(&parser->pdev->dev, sizeof(*power), GFP_KERNEL); 412 if (!power) 413 return ERR_PTR(-ENOMEM); 414 415 power->parser = parser; 416 power->pdev = parser->pdev; 417 power->dev = dev; 418 419 dp_power = &power->dp_power; 420 421 return dp_power; 422}