hc
2024-10-22 8ac6c7a54ed1b98d142dce24b11c6de6a1e239a5
kernel/drivers/gpu/drm/tegra/output.c
....@@ -1,14 +1,13 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * Copyright (C) 2012 Avionic Design GmbH
34 * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
4
- *
5
- * This program is free software; you can redistribute it and/or modify
6
- * it under the terms of the GNU General Public License version 2 as
7
- * published by the Free Software Foundation.
85 */
96
107 #include <drm/drm_atomic_helper.h>
8
+#include <drm/drm_of.h>
119 #include <drm/drm_panel.h>
10
+#include <drm/drm_simple_kms_helper.h>
1211
1312 #include "drm.h"
1413 #include "dc.h"
....@@ -26,7 +25,7 @@
2625 * ignore any other means of obtaining a mode.
2726 */
2827 if (output->panel) {
29
- err = output->panel->funcs->get_modes(output->panel);
28
+ err = drm_panel_get_modes(output->panel, connector);
3029 if (err > 0)
3130 return err;
3231 }
....@@ -36,7 +35,7 @@
3635 else if (output->ddc)
3736 edid = drm_get_edid(connector, output->ddc);
3837
39
- cec_notifier_set_phys_addr_from_edid(output->notifier, edid);
38
+ cec_notifier_set_phys_addr_from_edid(output->cec, edid);
4039 drm_connector_update_edid_property(connector, edid);
4140
4241 if (edid) {
....@@ -53,18 +52,11 @@
5352 struct tegra_output *output = connector_to_output(connector);
5453 enum drm_connector_status status = connector_status_unknown;
5554
56
- if (gpio_is_valid(output->hpd_gpio)) {
57
- if (output->hpd_gpio_flags & OF_GPIO_ACTIVE_LOW) {
58
- if (gpio_get_value(output->hpd_gpio) != 0)
59
- status = connector_status_disconnected;
60
- else
61
- status = connector_status_connected;
62
- } else {
63
- if (gpio_get_value(output->hpd_gpio) == 0)
64
- status = connector_status_disconnected;
65
- else
66
- status = connector_status_connected;
67
- }
55
+ if (output->hpd_gpio) {
56
+ if (gpiod_get_value(output->hpd_gpio) == 0)
57
+ status = connector_status_disconnected;
58
+ else
59
+ status = connector_status_connected;
6860 } else {
6961 if (!output->panel)
7062 status = connector_status_disconnected;
....@@ -73,20 +65,20 @@
7365 }
7466
7567 if (status != connector_status_connected)
76
- cec_notifier_phys_addr_invalidate(output->notifier);
68
+ cec_notifier_phys_addr_invalidate(output->cec);
7769
7870 return status;
7971 }
8072
8173 void tegra_output_connector_destroy(struct drm_connector *connector)
8274 {
75
+ struct tegra_output *output = connector_to_output(connector);
76
+
77
+ if (output->cec)
78
+ cec_notifier_conn_unregister(output->cec);
79
+
8380 drm_connector_unregister(connector);
8481 drm_connector_cleanup(connector);
85
-}
86
-
87
-void tegra_output_encoder_destroy(struct drm_encoder *encoder)
88
-{
89
- drm_encoder_cleanup(encoder);
9082 }
9183
9284 static irqreturn_t hpd_irq(int irq, void *data)
....@@ -102,51 +94,61 @@
10294 int tegra_output_probe(struct tegra_output *output)
10395 {
10496 struct device_node *ddc, *panel;
97
+ unsigned long flags;
10598 int err, size;
10699
107100 if (!output->of_node)
108101 output->of_node = output->dev->of_node;
109102
103
+ err = drm_of_find_panel_or_bridge(output->of_node, -1, -1,
104
+ &output->panel, &output->bridge);
105
+ if (err && err != -ENODEV)
106
+ return err;
107
+
110108 panel = of_parse_phandle(output->of_node, "nvidia,panel", 0);
111109 if (panel) {
110
+ /*
111
+ * Don't mix nvidia,panel phandle with the graph in a
112
+ * device-tree.
113
+ */
114
+ WARN_ON(output->panel || output->bridge);
115
+
112116 output->panel = of_drm_find_panel(panel);
117
+ of_node_put(panel);
118
+
113119 if (IS_ERR(output->panel))
114120 return PTR_ERR(output->panel);
115
-
116
- of_node_put(panel);
117121 }
118122
119123 output->edid = of_get_property(output->of_node, "nvidia,edid", &size);
120124
121125 ddc = of_parse_phandle(output->of_node, "nvidia,ddc-i2c-bus", 0);
122126 if (ddc) {
123
- output->ddc = of_find_i2c_adapter_by_node(ddc);
127
+ output->ddc = of_get_i2c_adapter_by_node(ddc);
128
+ of_node_put(ddc);
129
+
124130 if (!output->ddc) {
125131 err = -EPROBE_DEFER;
126
- of_node_put(ddc);
127132 return err;
128133 }
129
-
130
- of_node_put(ddc);
131134 }
132135
133
- output->hpd_gpio = of_get_named_gpio_flags(output->of_node,
134
- "nvidia,hpd-gpio", 0,
135
- &output->hpd_gpio_flags);
136
- if (gpio_is_valid(output->hpd_gpio)) {
137
- unsigned long flags;
136
+ output->hpd_gpio = devm_gpiod_get_from_of_node(output->dev,
137
+ output->of_node,
138
+ "nvidia,hpd-gpio", 0,
139
+ GPIOD_IN,
140
+ "HDMI hotplug detect");
141
+ if (IS_ERR(output->hpd_gpio)) {
142
+ if (PTR_ERR(output->hpd_gpio) != -ENOENT)
143
+ return PTR_ERR(output->hpd_gpio);
138144
139
- err = gpio_request_one(output->hpd_gpio, GPIOF_DIR_IN,
140
- "HDMI hotplug detect");
141
- if (err < 0) {
142
- dev_err(output->dev, "gpio_request_one(): %d\n", err);
143
- return err;
144
- }
145
+ output->hpd_gpio = NULL;
146
+ }
145147
146
- err = gpio_to_irq(output->hpd_gpio);
148
+ if (output->hpd_gpio) {
149
+ err = gpiod_to_irq(output->hpd_gpio);
147150 if (err < 0) {
148
- dev_err(output->dev, "gpio_to_irq(): %d\n", err);
149
- gpio_free(output->hpd_gpio);
151
+ dev_err(output->dev, "gpiod_to_irq(): %d\n", err);
150152 return err;
151153 }
152154
....@@ -160,7 +162,6 @@
160162 if (err < 0) {
161163 dev_err(output->dev, "failed to request IRQ#%u: %d\n",
162164 output->hpd_irq, err);
163
- gpio_free(output->hpd_gpio);
164165 return err;
165166 }
166167
....@@ -179,31 +180,38 @@
179180
180181 void tegra_output_remove(struct tegra_output *output)
181182 {
182
- if (gpio_is_valid(output->hpd_gpio)) {
183
+ if (output->hpd_gpio)
183184 free_irq(output->hpd_irq, output);
184
- gpio_free(output->hpd_gpio);
185
- }
186185
187186 if (output->ddc)
188
- put_device(&output->ddc->dev);
187
+ i2c_put_adapter(output->ddc);
189188 }
190189
191190 int tegra_output_init(struct drm_device *drm, struct tegra_output *output)
192191 {
193
- int err;
194
-
195
- if (output->panel) {
196
- err = drm_panel_attach(output->panel, &output->connector);
197
- if (err < 0)
198
- return err;
199
- }
192
+ int connector_type;
200193
201194 /*
202195 * The connector is now registered and ready to receive hotplug events
203196 * so the hotplug interrupt can be enabled.
204197 */
205
- if (gpio_is_valid(output->hpd_gpio))
198
+ if (output->hpd_gpio)
206199 enable_irq(output->hpd_irq);
200
+
201
+ connector_type = output->connector.connector_type;
202
+ /*
203
+ * Create a CEC notifier for HDMI connector.
204
+ */
205
+ if (connector_type == DRM_MODE_CONNECTOR_HDMIA ||
206
+ connector_type == DRM_MODE_CONNECTOR_HDMIB) {
207
+ struct cec_connector_info conn_info;
208
+
209
+ cec_fill_conn_info_from_drm(&conn_info, &output->connector);
210
+ output->cec = cec_notifier_conn_register(output->dev, NULL,
211
+ &conn_info);
212
+ if (!output->cec)
213
+ return -ENOMEM;
214
+ }
207215
208216 return 0;
209217 }
....@@ -214,11 +222,8 @@
214222 * The connector is going away, so the interrupt must be disabled to
215223 * prevent the hotplug interrupt handler from potentially crashing.
216224 */
217
- if (gpio_is_valid(output->hpd_gpio))
225
+ if (output->hpd_gpio)
218226 disable_irq(output->hpd_irq);
219
-
220
- if (output->panel)
221
- drm_panel_detach(output->panel);
222227 }
223228
224229 void tegra_output_find_possible_crtcs(struct tegra_output *output,
....@@ -242,3 +247,19 @@
242247
243248 output->encoder.possible_crtcs = mask;
244249 }
250
+
251
+int tegra_output_suspend(struct tegra_output *output)
252
+{
253
+ if (output->hpd_irq)
254
+ disable_irq(output->hpd_irq);
255
+
256
+ return 0;
257
+}
258
+
259
+int tegra_output_resume(struct tegra_output *output)
260
+{
261
+ if (output->hpd_irq)
262
+ enable_irq(output->hpd_irq);
263
+
264
+ return 0;
265
+}