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