forked from ~ljy/RK356X_SDK_RELEASE

hc
2023-12-06 08f87f769b595151be1afeff53e144f543faa614
kernel/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
....@@ -5,11 +5,12 @@
55
66 #include <linux/component.h>
77 #include <linux/module.h>
8
+#include <linux/of_device.h>
89 #include <linux/platform_device.h>
910
10
-#include <drm/drm_of.h>
11
-#include <drm/drmP.h>
1211 #include <drm/drm_crtc_helper.h>
12
+#include <drm/drm_of.h>
13
+#include <drm/drm_simple_kms_helper.h>
1314
1415 #include "sun8i_dw_hdmi.h"
1516 #include "sun8i_tcon_top.h"
....@@ -28,15 +29,27 @@
2829 .mode_set = sun8i_dw_hdmi_encoder_mode_set,
2930 };
3031
31
-static const struct drm_encoder_funcs sun8i_dw_hdmi_encoder_funcs = {
32
- .destroy = drm_encoder_cleanup,
33
-};
34
-
3532 static enum drm_mode_status
36
-sun8i_dw_hdmi_mode_valid(struct drm_connector *connector,
37
- const struct drm_display_mode *mode)
33
+sun8i_dw_hdmi_mode_valid_a83t(struct dw_hdmi *hdmi, void *data,
34
+ const struct drm_display_info *info,
35
+ const struct drm_display_mode *mode)
3836 {
3937 if (mode->clock > 297000)
38
+ return MODE_CLOCK_HIGH;
39
+
40
+ return MODE_OK;
41
+}
42
+
43
+static enum drm_mode_status
44
+sun8i_dw_hdmi_mode_valid_h6(struct dw_hdmi *hdmi, void *data,
45
+ const struct drm_display_info *info,
46
+ const struct drm_display_mode *mode)
47
+{
48
+ /*
49
+ * Controller support maximum of 594 MHz, which correlates to
50
+ * 4K@60Hz 4:4:4 or RGB.
51
+ */
52
+ if (mode->clock > 594000)
4053 return MODE_CLOCK_HIGH;
4154
4255 return MODE_OK;
....@@ -80,10 +93,34 @@
8093 return crtcs;
8194 }
8295
96
+static int sun8i_dw_hdmi_find_connector_pdev(struct device *dev,
97
+ struct platform_device **pdev_out)
98
+{
99
+ struct platform_device *pdev;
100
+ struct device_node *remote;
101
+
102
+ remote = of_graph_get_remote_node(dev->of_node, 1, -1);
103
+ if (!remote)
104
+ return -ENODEV;
105
+
106
+ if (!of_device_is_compatible(remote, "hdmi-connector")) {
107
+ of_node_put(remote);
108
+ return -ENODEV;
109
+ }
110
+
111
+ pdev = of_find_device_by_node(remote);
112
+ of_node_put(remote);
113
+ if (!pdev)
114
+ return -ENODEV;
115
+
116
+ *pdev_out = pdev;
117
+ return 0;
118
+}
119
+
83120 static int sun8i_dw_hdmi_bind(struct device *dev, struct device *master,
84121 void *data)
85122 {
86
- struct platform_device *pdev = to_platform_device(dev);
123
+ struct platform_device *pdev = to_platform_device(dev), *connector_pdev;
87124 struct dw_hdmi_plat_data *plat_data;
88125 struct drm_device *drm = data;
89126 struct device_node *phy_node;
....@@ -101,6 +138,8 @@
101138 plat_data = &hdmi->plat_data;
102139 hdmi->dev = &pdev->dev;
103140 encoder = &hdmi->encoder;
141
+
142
+ hdmi->quirks = of_device_get_match_data(dev);
104143
105144 encoder->possible_crtcs =
106145 sun8i_dw_hdmi_find_possible_crtcs(drm, dev->of_node);
....@@ -125,10 +164,36 @@
125164 return PTR_ERR(hdmi->clk_tmds);
126165 }
127166
167
+ hdmi->regulator = devm_regulator_get(dev, "hvcc");
168
+ if (IS_ERR(hdmi->regulator)) {
169
+ dev_err(dev, "Couldn't get regulator\n");
170
+ return PTR_ERR(hdmi->regulator);
171
+ }
172
+
173
+ ret = sun8i_dw_hdmi_find_connector_pdev(dev, &connector_pdev);
174
+ if (!ret) {
175
+ hdmi->ddc_en = gpiod_get_optional(&connector_pdev->dev,
176
+ "ddc-en", GPIOD_OUT_HIGH);
177
+ platform_device_put(connector_pdev);
178
+
179
+ if (IS_ERR(hdmi->ddc_en)) {
180
+ dev_err(dev, "Couldn't get ddc-en gpio\n");
181
+ return PTR_ERR(hdmi->ddc_en);
182
+ }
183
+ }
184
+
185
+ ret = regulator_enable(hdmi->regulator);
186
+ if (ret) {
187
+ dev_err(dev, "Failed to enable regulator\n");
188
+ goto err_unref_ddc_en;
189
+ }
190
+
191
+ gpiod_set_value(hdmi->ddc_en, 1);
192
+
128193 ret = reset_control_deassert(hdmi->rst_ctrl);
129194 if (ret) {
130195 dev_err(dev, "Could not deassert ctrl reset control\n");
131
- return ret;
196
+ goto err_disable_ddc_en;
132197 }
133198
134199 ret = clk_prepare_enable(hdmi->clk_tmds);
....@@ -144,23 +209,23 @@
144209 goto err_disable_clk_tmds;
145210 }
146211
147
- ret = sun8i_hdmi_phy_probe(hdmi, phy_node);
212
+ ret = sun8i_hdmi_phy_get(hdmi, phy_node);
148213 of_node_put(phy_node);
149214 if (ret) {
150215 dev_err(dev, "Couldn't get the HDMI PHY\n");
151216 goto err_disable_clk_tmds;
152217 }
153218
219
+ ret = sun8i_hdmi_phy_init(hdmi->phy);
220
+ if (ret)
221
+ goto err_disable_clk_tmds;
222
+
154223 drm_encoder_helper_add(encoder, &sun8i_dw_hdmi_encoder_helper_funcs);
155
- drm_encoder_init(drm, encoder, &sun8i_dw_hdmi_encoder_funcs,
156
- DRM_MODE_ENCODER_TMDS, NULL);
224
+ drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
157225
158
- sun8i_hdmi_phy_init(hdmi->phy);
159
-
160
- plat_data->mode_valid = &sun8i_dw_hdmi_mode_valid;
161
- plat_data->phy_ops = sun8i_hdmi_phy_get_ops();
162
- plat_data->phy_name = "sun8i_dw_hdmi_phy";
163
- plat_data->phy_data = hdmi->phy;
226
+ plat_data->mode_valid = hdmi->quirks->mode_valid;
227
+ plat_data->use_drm_infoframe = hdmi->quirks->use_drm_infoframe;
228
+ sun8i_hdmi_phy_set_ops(hdmi->phy, plat_data);
164229
165230 platform_set_drvdata(pdev, hdmi);
166231
....@@ -179,11 +244,16 @@
179244
180245 cleanup_encoder:
181246 drm_encoder_cleanup(encoder);
182
- sun8i_hdmi_phy_remove(hdmi);
183247 err_disable_clk_tmds:
184248 clk_disable_unprepare(hdmi->clk_tmds);
185249 err_assert_ctrl_reset:
186250 reset_control_assert(hdmi->rst_ctrl);
251
+err_disable_ddc_en:
252
+ gpiod_set_value(hdmi->ddc_en, 0);
253
+ regulator_disable(hdmi->regulator);
254
+err_unref_ddc_en:
255
+ if (hdmi->ddc_en)
256
+ gpiod_put(hdmi->ddc_en);
187257
188258 return ret;
189259 }
....@@ -194,9 +264,14 @@
194264 struct sun8i_dw_hdmi *hdmi = dev_get_drvdata(dev);
195265
196266 dw_hdmi_unbind(hdmi->hdmi);
197
- sun8i_hdmi_phy_remove(hdmi);
267
+ sun8i_hdmi_phy_deinit(hdmi->phy);
198268 clk_disable_unprepare(hdmi->clk_tmds);
199269 reset_control_assert(hdmi->rst_ctrl);
270
+ gpiod_set_value(hdmi->ddc_en, 0);
271
+ regulator_disable(hdmi->regulator);
272
+
273
+ if (hdmi->ddc_en)
274
+ gpiod_put(hdmi->ddc_en);
200275 }
201276
202277 static const struct component_ops sun8i_dw_hdmi_ops = {
....@@ -216,8 +291,24 @@
216291 return 0;
217292 }
218293
294
+static const struct sun8i_dw_hdmi_quirks sun8i_a83t_quirks = {
295
+ .mode_valid = sun8i_dw_hdmi_mode_valid_a83t,
296
+};
297
+
298
+static const struct sun8i_dw_hdmi_quirks sun50i_h6_quirks = {
299
+ .mode_valid = sun8i_dw_hdmi_mode_valid_h6,
300
+ .use_drm_infoframe = true,
301
+};
302
+
219303 static const struct of_device_id sun8i_dw_hdmi_dt_ids[] = {
220
- { .compatible = "allwinner,sun8i-a83t-dw-hdmi" },
304
+ {
305
+ .compatible = "allwinner,sun8i-a83t-dw-hdmi",
306
+ .data = &sun8i_a83t_quirks,
307
+ },
308
+ {
309
+ .compatible = "allwinner,sun50i-h6-dw-hdmi",
310
+ .data = &sun50i_h6_quirks,
311
+ },
221312 { /* sentinel */ },
222313 };
223314 MODULE_DEVICE_TABLE(of, sun8i_dw_hdmi_dt_ids);
....@@ -230,7 +321,32 @@
230321 .of_match_table = sun8i_dw_hdmi_dt_ids,
231322 },
232323 };
233
-module_platform_driver(sun8i_dw_hdmi_pltfm_driver);
324
+
325
+static int __init sun8i_dw_hdmi_init(void)
326
+{
327
+ int ret;
328
+
329
+ ret = platform_driver_register(&sun8i_dw_hdmi_pltfm_driver);
330
+ if (ret)
331
+ return ret;
332
+
333
+ ret = platform_driver_register(&sun8i_hdmi_phy_driver);
334
+ if (ret) {
335
+ platform_driver_unregister(&sun8i_dw_hdmi_pltfm_driver);
336
+ return ret;
337
+ }
338
+
339
+ return ret;
340
+}
341
+
342
+static void __exit sun8i_dw_hdmi_exit(void)
343
+{
344
+ platform_driver_unregister(&sun8i_dw_hdmi_pltfm_driver);
345
+ platform_driver_unregister(&sun8i_hdmi_phy_driver);
346
+}
347
+
348
+module_init(sun8i_dw_hdmi_init);
349
+module_exit(sun8i_dw_hdmi_exit);
234350
235351 MODULE_AUTHOR("Jernej Skrabec <jernej.skrabec@siol.net>");
236352 MODULE_DESCRIPTION("Allwinner DW HDMI bridge");