drm/msm/dp: return correct Colorimetry for DP_TEST_DYNAMIC_RANGE_CEA case
[platform/kernel/linux-starfive.git] / drivers / gpu / drm / msm / dp / dp_power.c
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 }