Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
0004  */
0005 
0006 #define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__
0007 
0008 #include <linux/clk.h>
0009 #include <linux/clk-provider.h>
0010 #include <linux/regulator/consumer.h>
0011 #include <linux/pm_opp.h>
0012 #include "dp_power.h"
0013 #include "msm_drv.h"
0014 
0015 struct dp_power_private {
0016     struct dp_parser *parser;
0017     struct platform_device *pdev;
0018     struct device *dev;
0019     struct drm_device *drm_dev;
0020     struct clk *link_clk_src;
0021     struct clk *pixel_provider;
0022     struct clk *link_provider;
0023 
0024     struct dp_power dp_power;
0025 };
0026 
0027 static int dp_power_clk_init(struct dp_power_private *power)
0028 {
0029     int rc = 0;
0030     struct dss_module_power *core, *ctrl, *stream;
0031     struct device *dev = &power->pdev->dev;
0032 
0033     core = &power->parser->mp[DP_CORE_PM];
0034     ctrl = &power->parser->mp[DP_CTRL_PM];
0035     stream = &power->parser->mp[DP_STREAM_PM];
0036 
0037     rc = devm_clk_bulk_get(dev, core->num_clk, core->clocks);
0038     if (rc) {
0039         DRM_ERROR("failed to get %s clk. err=%d\n",
0040             dp_parser_pm_name(DP_CORE_PM), rc);
0041         return rc;
0042     }
0043 
0044     rc = devm_clk_bulk_get(dev, ctrl->num_clk, ctrl->clocks);
0045     if (rc) {
0046         DRM_ERROR("failed to get %s clk. err=%d\n",
0047             dp_parser_pm_name(DP_CTRL_PM), rc);
0048         return -ENODEV;
0049     }
0050 
0051     rc = devm_clk_bulk_get(dev, stream->num_clk, stream->clocks);
0052     if (rc) {
0053         DRM_ERROR("failed to get %s clk. err=%d\n",
0054             dp_parser_pm_name(DP_CTRL_PM), rc);
0055         return -ENODEV;
0056     }
0057 
0058     return 0;
0059 }
0060 
0061 int dp_power_clk_status(struct dp_power *dp_power, enum dp_pm_type pm_type)
0062 {
0063     struct dp_power_private *power;
0064 
0065     power = container_of(dp_power, struct dp_power_private, dp_power);
0066 
0067     drm_dbg_dp(power->drm_dev,
0068         "core_clk_on=%d link_clk_on=%d stream_clk_on=%d\n",
0069         dp_power->core_clks_on, dp_power->link_clks_on, dp_power->stream_clks_on);
0070 
0071     if (pm_type == DP_CORE_PM)
0072         return dp_power->core_clks_on;
0073 
0074     if (pm_type == DP_CTRL_PM)
0075         return dp_power->link_clks_on;
0076 
0077     if (pm_type == DP_STREAM_PM)
0078         return dp_power->stream_clks_on;
0079 
0080     return 0;
0081 }
0082 
0083 int dp_power_clk_enable(struct dp_power *dp_power,
0084         enum dp_pm_type pm_type, bool enable)
0085 {
0086     int rc = 0;
0087     struct dp_power_private *power;
0088     struct dss_module_power *mp;
0089 
0090     power = container_of(dp_power, struct dp_power_private, dp_power);
0091 
0092     if (pm_type != DP_CORE_PM && pm_type != DP_CTRL_PM &&
0093             pm_type != DP_STREAM_PM) {
0094         DRM_ERROR("unsupported power module: %s\n",
0095                 dp_parser_pm_name(pm_type));
0096         return -EINVAL;
0097     }
0098 
0099     if (enable) {
0100         if (pm_type == DP_CORE_PM && dp_power->core_clks_on) {
0101             drm_dbg_dp(power->drm_dev,
0102                     "core clks already enabled\n");
0103             return 0;
0104         }
0105 
0106         if (pm_type == DP_CTRL_PM && dp_power->link_clks_on) {
0107             drm_dbg_dp(power->drm_dev,
0108                     "links clks already enabled\n");
0109             return 0;
0110         }
0111 
0112         if (pm_type == DP_STREAM_PM && dp_power->stream_clks_on) {
0113             drm_dbg_dp(power->drm_dev,
0114                     "pixel clks already enabled\n");
0115             return 0;
0116         }
0117 
0118         if ((pm_type == DP_CTRL_PM) && (!dp_power->core_clks_on)) {
0119             drm_dbg_dp(power->drm_dev,
0120                     "Enable core clks before link clks\n");
0121             mp = &power->parser->mp[DP_CORE_PM];
0122 
0123             rc = clk_bulk_prepare_enable(mp->num_clk, mp->clocks);
0124             if (rc) {
0125                 DRM_ERROR("fail to enable clks: %s. err=%d\n",
0126                     dp_parser_pm_name(DP_CORE_PM), rc);
0127                 return rc;
0128             }
0129             dp_power->core_clks_on = true;
0130         }
0131     }
0132 
0133     mp = &power->parser->mp[pm_type];
0134     if (enable) {
0135         rc = clk_bulk_prepare_enable(mp->num_clk, mp->clocks);
0136         if (rc) {
0137             DRM_ERROR("failed to enable clks, err: %d\n", rc);
0138             return rc;
0139         }
0140     } else {
0141         clk_bulk_disable_unprepare(mp->num_clk, mp->clocks);
0142     }
0143 
0144     if (pm_type == DP_CORE_PM)
0145         dp_power->core_clks_on = enable;
0146     else if (pm_type == DP_STREAM_PM)
0147         dp_power->stream_clks_on = enable;
0148     else
0149         dp_power->link_clks_on = enable;
0150 
0151     drm_dbg_dp(power->drm_dev, "%s clocks for %s\n",
0152             enable ? "enable" : "disable",
0153             dp_parser_pm_name(pm_type));
0154     drm_dbg_dp(power->drm_dev,
0155         "strem_clks:%s link_clks:%s core_clks:%s\n",
0156         dp_power->stream_clks_on ? "on" : "off",
0157         dp_power->link_clks_on ? "on" : "off",
0158         dp_power->core_clks_on ? "on" : "off");
0159 
0160     return 0;
0161 }
0162 
0163 int dp_power_client_init(struct dp_power *dp_power)
0164 {
0165     int rc = 0;
0166     struct dp_power_private *power;
0167 
0168     if (!dp_power) {
0169         DRM_ERROR("invalid power data\n");
0170         return -EINVAL;
0171     }
0172 
0173     power = container_of(dp_power, struct dp_power_private, dp_power);
0174 
0175     pm_runtime_enable(&power->pdev->dev);
0176 
0177     rc = dp_power_clk_init(power);
0178     if (rc)
0179         DRM_ERROR("failed to init clocks %d\n", rc);
0180 
0181     return rc;
0182 }
0183 
0184 void dp_power_client_deinit(struct dp_power *dp_power)
0185 {
0186     struct dp_power_private *power;
0187 
0188     if (!dp_power) {
0189         DRM_ERROR("invalid power data\n");
0190         return;
0191     }
0192 
0193     power = container_of(dp_power, struct dp_power_private, dp_power);
0194 
0195     pm_runtime_disable(&power->pdev->dev);
0196 }
0197 
0198 int dp_power_init(struct dp_power *dp_power, bool flip)
0199 {
0200     int rc = 0;
0201     struct dp_power_private *power = NULL;
0202 
0203     if (!dp_power) {
0204         DRM_ERROR("invalid power data\n");
0205         return -EINVAL;
0206     }
0207 
0208     power = container_of(dp_power, struct dp_power_private, dp_power);
0209 
0210     pm_runtime_get_sync(&power->pdev->dev);
0211 
0212     rc = dp_power_clk_enable(dp_power, DP_CORE_PM, true);
0213     if (rc) {
0214         DRM_ERROR("failed to enable DP core clocks, %d\n", rc);
0215         goto exit;
0216     }
0217 
0218     return 0;
0219 
0220 exit:
0221     pm_runtime_put_sync(&power->pdev->dev);
0222     return rc;
0223 }
0224 
0225 int dp_power_deinit(struct dp_power *dp_power)
0226 {
0227     struct dp_power_private *power;
0228 
0229     power = container_of(dp_power, struct dp_power_private, dp_power);
0230 
0231     dp_power_clk_enable(dp_power, DP_CORE_PM, false);
0232     pm_runtime_put_sync(&power->pdev->dev);
0233     return 0;
0234 }
0235 
0236 struct dp_power *dp_power_get(struct device *dev, struct dp_parser *parser)
0237 {
0238     struct dp_power_private *power;
0239     struct dp_power *dp_power;
0240 
0241     if (!parser) {
0242         DRM_ERROR("invalid input\n");
0243         return ERR_PTR(-EINVAL);
0244     }
0245 
0246     power = devm_kzalloc(&parser->pdev->dev, sizeof(*power), GFP_KERNEL);
0247     if (!power)
0248         return ERR_PTR(-ENOMEM);
0249 
0250     power->parser = parser;
0251     power->pdev = parser->pdev;
0252     power->dev = dev;
0253 
0254     dp_power = &power->dp_power;
0255 
0256     return dp_power;
0257 }