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 if (pm_type == DP_CORE_PM) 212 return dp_power->core_clks_on; 213 214 if (pm_type == DP_CTRL_PM) 215 return dp_power->link_clks_on; 216 217 if (pm_type == DP_STREAM_PM) 218 return dp_power->stream_clks_on; 219 220 return 0; 221 } 222 223 int dp_power_clk_enable(struct dp_power *dp_power, 224 enum dp_pm_type pm_type, bool enable) 225 { 226 int rc = 0; 227 struct dp_power_private *power; 228 229 power = container_of(dp_power, struct dp_power_private, dp_power); 230 231 if (pm_type != DP_CORE_PM && pm_type != DP_CTRL_PM && 232 pm_type != DP_STREAM_PM) { 233 DRM_ERROR("unsupported power module: %s\n", 234 dp_parser_pm_name(pm_type)); 235 return -EINVAL; 236 } 237 238 if (enable) { 239 if (pm_type == DP_CORE_PM && dp_power->core_clks_on) { 240 DRM_DEBUG_DP("core clks already enabled\n"); 241 return 0; 242 } 243 244 if (pm_type == DP_CTRL_PM && dp_power->link_clks_on) { 245 DRM_DEBUG_DP("links clks already enabled\n"); 246 return 0; 247 } 248 249 if (pm_type == DP_STREAM_PM && dp_power->stream_clks_on) { 250 DRM_DEBUG_DP("pixel clks already enabled\n"); 251 return 0; 252 } 253 254 if ((pm_type == DP_CTRL_PM) && (!dp_power->core_clks_on)) { 255 DRM_DEBUG_DP("Enable core clks before link clks\n"); 256 257 rc = dp_power_clk_set_rate(power, DP_CORE_PM, enable); 258 if (rc) { 259 DRM_ERROR("fail to enable clks: %s. err=%d\n", 260 dp_parser_pm_name(DP_CORE_PM), rc); 261 return rc; 262 } 263 dp_power->core_clks_on = true; 264 } 265 } 266 267 rc = dp_power_clk_set_rate(power, pm_type, enable); 268 if (rc) { 269 DRM_ERROR("failed to '%s' clks for: %s. err=%d\n", 270 enable ? "enable" : "disable", 271 dp_parser_pm_name(pm_type), rc); 272 return rc; 273 } 274 275 if (pm_type == DP_CORE_PM) 276 dp_power->core_clks_on = enable; 277 else if (pm_type == DP_STREAM_PM) 278 dp_power->stream_clks_on = enable; 279 else 280 dp_power->link_clks_on = enable; 281 282 DRM_DEBUG_DP("%s clocks for %s\n", 283 enable ? "enable" : "disable", 284 dp_parser_pm_name(pm_type)); 285 DRM_DEBUG_DP("strem_clks:%s link_clks:%s core_clks:%s\n", 286 dp_power->stream_clks_on ? "on" : "off", 287 dp_power->link_clks_on ? "on" : "off", 288 dp_power->core_clks_on ? "on" : "off"); 289 290 return 0; 291 } 292 293 int dp_power_client_init(struct dp_power *dp_power) 294 { 295 int rc = 0; 296 struct dp_power_private *power; 297 298 if (!dp_power) { 299 DRM_ERROR("invalid power data\n"); 300 return -EINVAL; 301 } 302 303 power = container_of(dp_power, struct dp_power_private, dp_power); 304 305 pm_runtime_enable(&power->pdev->dev); 306 307 rc = dp_power_regulator_init(power); 308 if (rc) { 309 DRM_ERROR("failed to init regulators %d\n", rc); 310 goto error; 311 } 312 313 rc = dp_power_clk_init(power); 314 if (rc) { 315 DRM_ERROR("failed to init clocks %d\n", rc); 316 goto error; 317 } 318 return 0; 319 320 error: 321 pm_runtime_disable(&power->pdev->dev); 322 return rc; 323 } 324 325 void dp_power_client_deinit(struct dp_power *dp_power) 326 { 327 struct dp_power_private *power; 328 329 if (!dp_power) { 330 DRM_ERROR("invalid power data\n"); 331 return; 332 } 333 334 power = container_of(dp_power, struct dp_power_private, dp_power); 335 336 dp_power_clk_deinit(power); 337 pm_runtime_disable(&power->pdev->dev); 338 339 } 340 341 int dp_power_init(struct dp_power *dp_power, bool flip) 342 { 343 int rc = 0; 344 struct dp_power_private *power = NULL; 345 346 if (!dp_power) { 347 DRM_ERROR("invalid power data\n"); 348 return -EINVAL; 349 } 350 351 power = container_of(dp_power, struct dp_power_private, dp_power); 352 353 pm_runtime_get_sync(&power->pdev->dev); 354 rc = dp_power_regulator_enable(power); 355 if (rc) { 356 DRM_ERROR("failed to enable regulators, %d\n", rc); 357 goto exit; 358 } 359 360 rc = dp_power_clk_enable(dp_power, DP_CORE_PM, true); 361 if (rc) { 362 DRM_ERROR("failed to enable DP core clocks, %d\n", rc); 363 goto err_clk; 364 } 365 366 return 0; 367 368 err_clk: 369 dp_power_regulator_disable(power); 370 exit: 371 pm_runtime_put_sync(&power->pdev->dev); 372 return rc; 373 } 374 375 int dp_power_deinit(struct dp_power *dp_power) 376 { 377 struct dp_power_private *power; 378 379 power = container_of(dp_power, struct dp_power_private, dp_power); 380 381 dp_power_clk_enable(dp_power, DP_CORE_PM, false); 382 dp_power_regulator_disable(power); 383 pm_runtime_put_sync(&power->pdev->dev); 384 return 0; 385 } 386 387 struct dp_power *dp_power_get(struct device *dev, struct dp_parser *parser) 388 { 389 struct dp_power_private *power; 390 struct dp_power *dp_power; 391 392 if (!parser) { 393 DRM_ERROR("invalid input\n"); 394 return ERR_PTR(-EINVAL); 395 } 396 397 power = devm_kzalloc(&parser->pdev->dev, sizeof(*power), GFP_KERNEL); 398 if (!power) 399 return ERR_PTR(-ENOMEM); 400 401 power->parser = parser; 402 power->pdev = parser->pdev; 403 power->dev = dev; 404 405 dp_power = &power->dp_power; 406 407 return dp_power; 408 } 409