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