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 drm_device *drm_dev; 20 struct clk *link_clk_src; 21 struct clk *pixel_provider; 22 struct clk *link_provider; 23 24 struct dp_power dp_power; 25 }; 26 27 static int dp_power_clk_init(struct dp_power_private *power) 28 { 29 int rc = 0; 30 struct dss_module_power *core, *ctrl, *stream; 31 struct device *dev = &power->pdev->dev; 32 33 core = &power->parser->mp[DP_CORE_PM]; 34 ctrl = &power->parser->mp[DP_CTRL_PM]; 35 stream = &power->parser->mp[DP_STREAM_PM]; 36 37 rc = devm_clk_bulk_get(dev, core->num_clk, core->clocks); 38 if (rc) { 39 DRM_ERROR("failed to get %s clk. err=%d\n", 40 dp_parser_pm_name(DP_CORE_PM), rc); 41 return rc; 42 } 43 44 rc = devm_clk_bulk_get(dev, ctrl->num_clk, ctrl->clocks); 45 if (rc) { 46 DRM_ERROR("failed to get %s clk. err=%d\n", 47 dp_parser_pm_name(DP_CTRL_PM), rc); 48 return -ENODEV; 49 } 50 51 rc = devm_clk_bulk_get(dev, stream->num_clk, stream->clocks); 52 if (rc) { 53 DRM_ERROR("failed to get %s clk. err=%d\n", 54 dp_parser_pm_name(DP_CTRL_PM), rc); 55 return -ENODEV; 56 } 57 58 return 0; 59 } 60 61 int dp_power_clk_status(struct dp_power *dp_power, enum dp_pm_type pm_type) 62 { 63 struct dp_power_private *power; 64 65 power = container_of(dp_power, struct dp_power_private, dp_power); 66 67 drm_dbg_dp(power->drm_dev, 68 "core_clk_on=%d link_clk_on=%d stream_clk_on=%d\n", 69 dp_power->core_clks_on, dp_power->link_clks_on, dp_power->stream_clks_on); 70 71 if (pm_type == DP_CORE_PM) 72 return dp_power->core_clks_on; 73 74 if (pm_type == DP_CTRL_PM) 75 return dp_power->link_clks_on; 76 77 if (pm_type == DP_STREAM_PM) 78 return dp_power->stream_clks_on; 79 80 return 0; 81 } 82 83 int dp_power_clk_enable(struct dp_power *dp_power, 84 enum dp_pm_type pm_type, bool enable) 85 { 86 int rc = 0; 87 struct dp_power_private *power; 88 struct dss_module_power *mp; 89 90 power = container_of(dp_power, struct dp_power_private, dp_power); 91 92 if (pm_type != DP_CORE_PM && pm_type != DP_CTRL_PM && 93 pm_type != DP_STREAM_PM) { 94 DRM_ERROR("unsupported power module: %s\n", 95 dp_parser_pm_name(pm_type)); 96 return -EINVAL; 97 } 98 99 if (enable) { 100 if (pm_type == DP_CORE_PM && dp_power->core_clks_on) { 101 drm_dbg_dp(power->drm_dev, 102 "core clks already enabled\n"); 103 return 0; 104 } 105 106 if (pm_type == DP_CTRL_PM && dp_power->link_clks_on) { 107 drm_dbg_dp(power->drm_dev, 108 "links clks already enabled\n"); 109 return 0; 110 } 111 112 if (pm_type == DP_STREAM_PM && dp_power->stream_clks_on) { 113 drm_dbg_dp(power->drm_dev, 114 "pixel clks already enabled\n"); 115 return 0; 116 } 117 118 if ((pm_type == DP_CTRL_PM) && (!dp_power->core_clks_on)) { 119 drm_dbg_dp(power->drm_dev, 120 "Enable core clks before link clks\n"); 121 mp = &power->parser->mp[DP_CORE_PM]; 122 123 rc = clk_bulk_prepare_enable(mp->num_clk, mp->clocks); 124 if (rc) { 125 DRM_ERROR("fail to enable clks: %s. err=%d\n", 126 dp_parser_pm_name(DP_CORE_PM), rc); 127 return rc; 128 } 129 dp_power->core_clks_on = true; 130 } 131 } 132 133 mp = &power->parser->mp[pm_type]; 134 if (enable) { 135 rc = clk_bulk_prepare_enable(mp->num_clk, mp->clocks); 136 if (rc) { 137 DRM_ERROR("failed to enable clks, err: %d\n", rc); 138 return rc; 139 } 140 } else { 141 clk_bulk_disable_unprepare(mp->num_clk, mp->clocks); 142 } 143 144 if (pm_type == DP_CORE_PM) 145 dp_power->core_clks_on = enable; 146 else if (pm_type == DP_STREAM_PM) 147 dp_power->stream_clks_on = enable; 148 else 149 dp_power->link_clks_on = enable; 150 151 drm_dbg_dp(power->drm_dev, "%s clocks for %s\n", 152 enable ? "enable" : "disable", 153 dp_parser_pm_name(pm_type)); 154 drm_dbg_dp(power->drm_dev, 155 "strem_clks:%s link_clks:%s core_clks:%s\n", 156 dp_power->stream_clks_on ? "on" : "off", 157 dp_power->link_clks_on ? "on" : "off", 158 dp_power->core_clks_on ? "on" : "off"); 159 160 return 0; 161 } 162 163 int dp_power_client_init(struct dp_power *dp_power) 164 { 165 int rc = 0; 166 struct dp_power_private *power; 167 168 if (!dp_power) { 169 DRM_ERROR("invalid power data\n"); 170 return -EINVAL; 171 } 172 173 power = container_of(dp_power, struct dp_power_private, dp_power); 174 175 pm_runtime_enable(&power->pdev->dev); 176 177 rc = dp_power_clk_init(power); 178 if (rc) 179 DRM_ERROR("failed to init clocks %d\n", rc); 180 181 return rc; 182 } 183 184 void dp_power_client_deinit(struct dp_power *dp_power) 185 { 186 struct dp_power_private *power; 187 188 if (!dp_power) { 189 DRM_ERROR("invalid power data\n"); 190 return; 191 } 192 193 power = container_of(dp_power, struct dp_power_private, dp_power); 194 195 pm_runtime_disable(&power->pdev->dev); 196 } 197 198 int dp_power_init(struct dp_power *dp_power, bool flip) 199 { 200 int rc = 0; 201 struct dp_power_private *power = NULL; 202 203 if (!dp_power) { 204 DRM_ERROR("invalid power data\n"); 205 return -EINVAL; 206 } 207 208 power = container_of(dp_power, struct dp_power_private, dp_power); 209 210 pm_runtime_get_sync(&power->pdev->dev); 211 212 rc = dp_power_clk_enable(dp_power, DP_CORE_PM, true); 213 if (rc) { 214 DRM_ERROR("failed to enable DP core clocks, %d\n", rc); 215 goto exit; 216 } 217 218 return 0; 219 220 exit: 221 pm_runtime_put_sync(&power->pdev->dev); 222 return rc; 223 } 224 225 int dp_power_deinit(struct dp_power *dp_power) 226 { 227 struct dp_power_private *power; 228 229 power = container_of(dp_power, struct dp_power_private, dp_power); 230 231 dp_power_clk_enable(dp_power, DP_CORE_PM, false); 232 pm_runtime_put_sync(&power->pdev->dev); 233 return 0; 234 } 235 236 struct dp_power *dp_power_get(struct device *dev, struct dp_parser *parser) 237 { 238 struct dp_power_private *power; 239 struct dp_power *dp_power; 240 241 if (!parser) { 242 DRM_ERROR("invalid input\n"); 243 return ERR_PTR(-EINVAL); 244 } 245 246 power = devm_kzalloc(&parser->pdev->dev, sizeof(*power), GFP_KERNEL); 247 if (!power) 248 return ERR_PTR(-ENOMEM); 249 250 power->parser = parser; 251 power->pdev = parser->pdev; 252 power->dev = dev; 253 254 dp_power = &power->dp_power; 255 256 return dp_power; 257 } 258