linux/drivers/gpu/drm/msm/dp/dp_power.c
<<
>>
Prefs
   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 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
  27static 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
  43static 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
  71fail:
  72        for (i--; i >= 0; i--)
  73                regulator_set_load(s[i].consumer, regs[i].disable_load);
  74        return ret;
  75}
  76
  77static 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
  98static 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
 134static 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
 153static 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
 177static 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
 209int 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
 226int 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
 296int 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
 323error:
 324        pm_runtime_disable(&power->pdev->dev);
 325        return rc;
 326}
 327
 328void 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
 344int 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
 371err_clk:
 372        dp_power_regulator_disable(power);
 373exit:
 374        pm_runtime_put_sync(&power->pdev->dev);
 375        return rc;
 376}
 377
 378int 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
 390struct 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