1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
6 #define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__
9 #include <linux/clk-provider.h>
10 #include <linux/regulator/consumer.h>
11 #include <linux/pm_opp.h>
15 struct dp_power_private {
16 struct dp_parser *parser;
18 struct drm_device *drm_dev;
19 struct clk *link_clk_src;
20 struct clk *pixel_provider;
21 struct clk *link_provider;
23 struct dp_power dp_power;
26 static int dp_power_clk_init(struct dp_power_private *power)
29 struct dss_module_power *core, *ctrl, *stream;
30 struct device *dev = power->dev;
32 core = &power->parser->mp[DP_CORE_PM];
33 ctrl = &power->parser->mp[DP_CTRL_PM];
34 stream = &power->parser->mp[DP_STREAM_PM];
36 rc = devm_clk_bulk_get(dev, core->num_clk, core->clocks);
40 rc = devm_clk_bulk_get(dev, ctrl->num_clk, ctrl->clocks);
44 rc = devm_clk_bulk_get(dev, stream->num_clk, stream->clocks);
51 int dp_power_clk_status(struct dp_power *dp_power, enum dp_pm_type pm_type)
53 struct dp_power_private *power;
55 power = container_of(dp_power, struct dp_power_private, dp_power);
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);
61 if (pm_type == DP_CORE_PM)
62 return dp_power->core_clks_on;
64 if (pm_type == DP_CTRL_PM)
65 return dp_power->link_clks_on;
67 if (pm_type == DP_STREAM_PM)
68 return dp_power->stream_clks_on;
73 int dp_power_clk_enable(struct dp_power *dp_power,
74 enum dp_pm_type pm_type, bool enable)
77 struct dp_power_private *power;
78 struct dss_module_power *mp;
80 power = container_of(dp_power, struct dp_power_private, dp_power);
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));
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");
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");
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");
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];
113 rc = clk_bulk_prepare_enable(mp->num_clk, mp->clocks);
117 dp_power->core_clks_on = true;
121 mp = &power->parser->mp[pm_type];
123 rc = clk_bulk_prepare_enable(mp->num_clk, mp->clocks);
127 clk_bulk_disable_unprepare(mp->num_clk, mp->clocks);
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;
135 dp_power->link_clks_on = enable;
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");
149 int dp_power_client_init(struct dp_power *dp_power)
151 struct dp_power_private *power;
153 power = container_of(dp_power, struct dp_power_private, dp_power);
155 pm_runtime_enable(power->dev);
157 return dp_power_clk_init(power);
160 void dp_power_client_deinit(struct dp_power *dp_power)
162 struct dp_power_private *power;
164 power = container_of(dp_power, struct dp_power_private, dp_power);
166 pm_runtime_disable(power->dev);
169 int dp_power_init(struct dp_power *dp_power)
172 struct dp_power_private *power = NULL;
174 power = container_of(dp_power, struct dp_power_private, dp_power);
176 pm_runtime_get_sync(power->dev);
178 rc = dp_power_clk_enable(dp_power, DP_CORE_PM, true);
180 pm_runtime_put_sync(power->dev);
185 int dp_power_deinit(struct dp_power *dp_power)
187 struct dp_power_private *power;
189 power = container_of(dp_power, struct dp_power_private, dp_power);
191 dp_power_clk_enable(dp_power, DP_CORE_PM, false);
192 pm_runtime_put_sync(power->dev);
196 struct dp_power *dp_power_get(struct device *dev, struct dp_parser *parser)
198 struct dp_power_private *power;
199 struct dp_power *dp_power;
201 power = devm_kzalloc(dev, sizeof(*power), GFP_KERNEL);
203 return ERR_PTR(-ENOMEM);
205 power->parser = parser;
208 dp_power = &power->dp_power;