hc
2024-05-10 cde9070d9970eef1f7ec2360586c802a16230ad8
kernel/drivers/gpu/drm/omapdrm/omap_encoder.c
....@@ -1,24 +1,14 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
34 * Author: Rob Clark <rob@ti.com>
4
- *
5
- * This program is free software; you can redistribute it and/or modify it
6
- * under the terms of the GNU General Public License version 2 as published by
7
- * the Free Software Foundation.
8
- *
9
- * This program is distributed in the hope that it will be useful, but WITHOUT
10
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12
- * more details.
13
- *
14
- * You should have received a copy of the GNU General Public License along with
15
- * this program. If not, see <http://www.gnu.org/licenses/>.
165 */
176
187 #include <linux/list.h>
198
9
+#include <drm/drm_bridge.h>
2010 #include <drm/drm_crtc.h>
21
-#include <drm/drm_crtc_helper.h>
11
+#include <drm/drm_modeset_helper_vtables.h>
2212 #include <drm/drm_edid.h>
2313
2414 #include "omap_drv.h"
....@@ -36,15 +26,8 @@
3626 */
3727 struct omap_encoder {
3828 struct drm_encoder base;
39
- struct omap_dss_device *dssdev;
29
+ struct omap_dss_device *output;
4030 };
41
-
42
-struct omap_dss_device *omap_encoder_get_dssdev(struct drm_encoder *encoder)
43
-{
44
- struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
45
-
46
- return omap_encoder->dssdev;
47
-}
4831
4932 static void omap_encoder_destroy(struct drm_encoder *encoder)
5033 {
....@@ -58,102 +41,129 @@
5841 .destroy = omap_encoder_destroy,
5942 };
6043
61
-static void omap_encoder_mode_set(struct drm_encoder *encoder,
62
- struct drm_display_mode *mode,
63
- struct drm_display_mode *adjusted_mode)
44
+static void omap_encoder_update_videomode_flags(struct videomode *vm,
45
+ u32 bus_flags)
6446 {
65
- struct drm_device *dev = encoder->dev;
47
+ if (!(vm->flags & (DISPLAY_FLAGS_DE_LOW |
48
+ DISPLAY_FLAGS_DE_HIGH))) {
49
+ if (bus_flags & DRM_BUS_FLAG_DE_LOW)
50
+ vm->flags |= DISPLAY_FLAGS_DE_LOW;
51
+ else if (bus_flags & DRM_BUS_FLAG_DE_HIGH)
52
+ vm->flags |= DISPLAY_FLAGS_DE_HIGH;
53
+ }
54
+
55
+ if (!(vm->flags & (DISPLAY_FLAGS_PIXDATA_POSEDGE |
56
+ DISPLAY_FLAGS_PIXDATA_NEGEDGE))) {
57
+ if (bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE)
58
+ vm->flags |= DISPLAY_FLAGS_PIXDATA_POSEDGE;
59
+ else if (bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE)
60
+ vm->flags |= DISPLAY_FLAGS_PIXDATA_NEGEDGE;
61
+ }
62
+
63
+ if (!(vm->flags & (DISPLAY_FLAGS_SYNC_POSEDGE |
64
+ DISPLAY_FLAGS_SYNC_NEGEDGE))) {
65
+ if (bus_flags & DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE)
66
+ vm->flags |= DISPLAY_FLAGS_SYNC_POSEDGE;
67
+ else if (bus_flags & DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE)
68
+ vm->flags |= DISPLAY_FLAGS_SYNC_NEGEDGE;
69
+ }
70
+}
71
+
72
+static void omap_encoder_mode_set(struct drm_encoder *encoder,
73
+ struct drm_display_mode *mode,
74
+ struct drm_display_mode *adjusted_mode)
75
+{
6676 struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
67
- struct omap_dss_device *dssdev = omap_encoder->dssdev;
77
+ struct omap_dss_device *output = omap_encoder->output;
78
+ struct omap_dss_device *dssdev;
79
+ struct drm_device *dev = encoder->dev;
6880 struct drm_connector *connector;
69
- bool hdmi_mode;
70
- int r;
81
+ struct drm_bridge *bridge;
82
+ struct videomode vm = { 0 };
83
+ u32 bus_flags;
7184
72
- hdmi_mode = false;
7385 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
74
- if (connector->encoder == encoder) {
75
- hdmi_mode = omap_connector_get_hdmi_mode(connector);
86
+ if (connector->encoder == encoder)
7687 break;
77
- }
7888 }
7989
80
- if (dssdev->driver->set_hdmi_mode)
81
- dssdev->driver->set_hdmi_mode(dssdev, hdmi_mode);
90
+ drm_display_mode_to_videomode(adjusted_mode, &vm);
8291
83
- if (hdmi_mode && dssdev->driver->set_hdmi_infoframe) {
84
- struct hdmi_avi_infoframe avi;
92
+ /*
93
+ * HACK: This fixes the vm flags.
94
+ * struct drm_display_mode does not contain the VSYNC/HSYNC/DE flags and
95
+ * they get lost when converting back and forth between struct
96
+ * drm_display_mode and struct videomode. The hack below goes and
97
+ * fetches the missing flags.
98
+ *
99
+ * A better solution is to use DRM's bus-flags through the whole driver.
100
+ */
101
+ for (dssdev = output; dssdev; dssdev = dssdev->next)
102
+ omap_encoder_update_videomode_flags(&vm, dssdev->bus_flags);
85103
86
- r = drm_hdmi_avi_infoframe_from_display_mode(&avi, adjusted_mode,
87
- false);
88
- if (r == 0)
89
- dssdev->driver->set_hdmi_infoframe(dssdev, &avi);
104
+ for (bridge = output->bridge; bridge;
105
+ bridge = drm_bridge_get_next_bridge(bridge)) {
106
+ if (!bridge->timings)
107
+ continue;
108
+
109
+ bus_flags = bridge->timings->input_bus_flags;
110
+ omap_encoder_update_videomode_flags(&vm, bus_flags);
90111 }
112
+
113
+ bus_flags = connector->display_info.bus_flags;
114
+ omap_encoder_update_videomode_flags(&vm, bus_flags);
115
+
116
+ /* Set timings for the dss manager. */
117
+ dss_mgr_set_timings(output, &vm);
91118 }
92119
93120 static void omap_encoder_disable(struct drm_encoder *encoder)
94121 {
95122 struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
96
- struct omap_dss_device *dssdev = omap_encoder->dssdev;
97
- struct omap_dss_driver *dssdrv = dssdev->driver;
98
-
99
- dssdrv->disable(dssdev);
100
-}
101
-
102
-static int omap_encoder_update(struct drm_encoder *encoder,
103
- enum omap_channel channel,
104
- struct videomode *vm)
105
-{
123
+ struct omap_dss_device *dssdev = omap_encoder->output;
106124 struct drm_device *dev = encoder->dev;
107
- struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
108
- struct omap_dss_device *dssdev = omap_encoder->dssdev;
109
- struct omap_dss_driver *dssdrv = dssdev->driver;
110
- int ret;
111125
112
- if (dssdrv->check_timings) {
113
- ret = dssdrv->check_timings(dssdev, vm);
114
- } else {
115
- struct videomode t = {0};
126
+ dev_dbg(dev->dev, "disable(%s)\n", dssdev->name);
116127
117
- dssdrv->get_timings(dssdev, &t);
118
-
119
- if (memcmp(vm, &t, sizeof(*vm)))
120
- ret = -EINVAL;
121
- else
122
- ret = 0;
123
- }
124
-
125
- if (ret) {
126
- dev_err(dev->dev, "could not set timings: %d\n", ret);
127
- return ret;
128
- }
129
-
130
- if (dssdrv->set_timings)
131
- dssdrv->set_timings(dssdev, vm);
132
-
133
- return 0;
128
+ /*
129
+ * Disable the chain of external devices, starting at the one at the
130
+ * internal encoder's output. This is used for DSI outputs only, as
131
+ * dssdev->next is NULL for all other outputs.
132
+ */
133
+ omapdss_device_disable(dssdev->next);
134134 }
135135
136136 static void omap_encoder_enable(struct drm_encoder *encoder)
137137 {
138138 struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
139
- struct omap_dss_device *dssdev = omap_encoder->dssdev;
140
- struct omap_dss_driver *dssdrv = dssdev->driver;
141
- int r;
139
+ struct omap_dss_device *dssdev = omap_encoder->output;
140
+ struct drm_device *dev = encoder->dev;
142141
143
- omap_encoder_update(encoder, omap_crtc_channel(encoder->crtc),
144
- omap_crtc_timings(encoder->crtc));
142
+ dev_dbg(dev->dev, "enable(%s)\n", dssdev->name);
145143
146
- r = dssdrv->enable(dssdev);
147
- if (r)
148
- dev_err(encoder->dev->dev,
149
- "Failed to enable display '%s': %d\n",
150
- dssdev->name, r);
144
+ /*
145
+ * Enable the chain of external devices, starting at the one at the
146
+ * internal encoder's output. This is used for DSI outputs only, as
147
+ * dssdev->next is NULL for all other outputs.
148
+ */
149
+ omapdss_device_enable(dssdev->next);
151150 }
152151
153152 static int omap_encoder_atomic_check(struct drm_encoder *encoder,
154153 struct drm_crtc_state *crtc_state,
155154 struct drm_connector_state *conn_state)
156155 {
156
+ struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
157
+ enum drm_mode_status status;
158
+
159
+ status = omap_connector_mode_fixup(omap_encoder->output,
160
+ &crtc_state->mode,
161
+ &crtc_state->adjusted_mode);
162
+ if (status != MODE_OK) {
163
+ dev_err(encoder->dev->dev, "invalid timings: %d\n", status);
164
+ return -EINVAL;
165
+ }
166
+
157167 return 0;
158168 }
159169
....@@ -166,7 +176,7 @@
166176
167177 /* initialize encoder */
168178 struct drm_encoder *omap_encoder_init(struct drm_device *dev,
169
- struct omap_dss_device *dssdev)
179
+ struct omap_dss_device *output)
170180 {
171181 struct drm_encoder *encoder = NULL;
172182 struct omap_encoder *omap_encoder;
....@@ -175,7 +185,7 @@
175185 if (!omap_encoder)
176186 goto fail;
177187
178
- omap_encoder->dssdev = dssdev;
188
+ omap_encoder->output = output;
179189
180190 encoder = &omap_encoder->base;
181191