Commit | Line | Data |
---|---|---|
cd5351f4 | 1 | /* |
8bb0daff | 2 | * drivers/gpu/drm/omapdrm/omap_encoder.c |
cd5351f4 RC |
3 | * |
4 | * Copyright (C) 2011 Texas Instruments | |
5 | * Author: Rob Clark <rob@ti.com> | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify it | |
8 | * under the terms of the GNU General Public License version 2 as published by | |
9 | * the Free Software Foundation. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, but WITHOUT | |
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
14 | * more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License along with | |
17 | * this program. If not, see <http://www.gnu.org/licenses/>. | |
18 | */ | |
19 | ||
2d278f54 LP |
20 | #include <linux/list.h> |
21 | ||
22 | #include <drm/drm_crtc.h> | |
23 | #include <drm/drm_crtc_helper.h> | |
4f930c0f TV |
24 | #include <drm/drm_edid.h> |
25 | ||
cd5351f4 RC |
26 | #include "omap_drv.h" |
27 | ||
cd5351f4 RC |
28 | /* |
29 | * encoder funcs | |
30 | */ | |
31 | ||
32 | #define to_omap_encoder(x) container_of(x, struct omap_encoder, base) | |
33 | ||
f5f9454c RC |
34 | /* The encoder and connector both map to same dssdev.. the encoder |
35 | * handles the 'active' parts, ie. anything the modifies the state | |
36 | * of the hw, and the connector handles the 'read-only' parts, like | |
37 | * detecting connection and reading edid. | |
38 | */ | |
cd5351f4 RC |
39 | struct omap_encoder { |
40 | struct drm_encoder base; | |
f5f9454c | 41 | struct omap_dss_device *dssdev; |
cd5351f4 RC |
42 | }; |
43 | ||
0d8f371f AT |
44 | struct omap_dss_device *omap_encoder_get_dssdev(struct drm_encoder *encoder) |
45 | { | |
46 | struct omap_encoder *omap_encoder = to_omap_encoder(encoder); | |
47 | ||
48 | return omap_encoder->dssdev; | |
49 | } | |
50 | ||
cd5351f4 RC |
51 | static void omap_encoder_destroy(struct drm_encoder *encoder) |
52 | { | |
53 | struct omap_encoder *omap_encoder = to_omap_encoder(encoder); | |
ec72a81e | 54 | |
cd5351f4 RC |
55 | drm_encoder_cleanup(encoder); |
56 | kfree(omap_encoder); | |
57 | } | |
58 | ||
f5f9454c RC |
59 | static const struct drm_encoder_funcs omap_encoder_funcs = { |
60 | .destroy = omap_encoder_destroy, | |
61 | }; | |
62 | ||
cd5351f4 RC |
63 | static void omap_encoder_mode_set(struct drm_encoder *encoder, |
64 | struct drm_display_mode *mode, | |
65 | struct drm_display_mode *adjusted_mode) | |
66 | { | |
4f930c0f TV |
67 | struct drm_device *dev = encoder->dev; |
68 | struct omap_encoder *omap_encoder = to_omap_encoder(encoder); | |
69 | struct omap_dss_device *dssdev = omap_encoder->dssdev; | |
70 | struct drm_connector *connector; | |
71 | bool hdmi_mode; | |
72 | int r; | |
73 | ||
74 | hdmi_mode = false; | |
75 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | |
76 | if (connector->encoder == encoder) { | |
77 | hdmi_mode = omap_connector_get_hdmi_mode(connector); | |
78 | break; | |
79 | } | |
80 | } | |
81 | ||
82 | if (dssdev->driver->set_hdmi_mode) | |
83 | dssdev->driver->set_hdmi_mode(dssdev, hdmi_mode); | |
84 | ||
85 | if (hdmi_mode && dssdev->driver->set_hdmi_infoframe) { | |
86 | struct hdmi_avi_infoframe avi; | |
87 | ||
88 | r = drm_hdmi_avi_infoframe_from_display_mode(&avi, adjusted_mode); | |
89 | if (r == 0) | |
90 | dssdev->driver->set_hdmi_infoframe(dssdev, &avi); | |
91 | } | |
cd5351f4 RC |
92 | } |
93 | ||
68dc0390 | 94 | static void omap_encoder_disable(struct drm_encoder *encoder) |
cd5351f4 RC |
95 | { |
96 | struct omap_encoder *omap_encoder = to_omap_encoder(encoder); | |
f5f9454c RC |
97 | struct omap_dss_device *dssdev = omap_encoder->dssdev; |
98 | struct omap_dss_driver *dssdrv = dssdev->driver; | |
99 | ||
4029755e | 100 | dssdrv->disable(dssdev); |
f5f9454c RC |
101 | } |
102 | ||
4029755e LP |
103 | static int omap_encoder_update(struct drm_encoder *encoder, |
104 | enum omap_channel channel, | |
105 | struct omap_video_timings *timings) | |
f5f9454c RC |
106 | { |
107 | struct drm_device *dev = encoder->dev; | |
108 | struct omap_encoder *omap_encoder = to_omap_encoder(encoder); | |
109 | struct omap_dss_device *dssdev = omap_encoder->dssdev; | |
110 | struct omap_dss_driver *dssdrv = dssdev->driver; | |
111 | int ret; | |
112 | ||
4029755e | 113 | dssdev->src->manager = omap_dss_get_overlay_manager(channel); |
f5f9454c | 114 | |
bddabbe1 AT |
115 | if (dssdrv->check_timings) { |
116 | ret = dssdrv->check_timings(dssdev, timings); | |
117 | } else { | |
118 | struct omap_video_timings t = {0}; | |
119 | ||
120 | dssdrv->get_timings(dssdev, &t); | |
121 | ||
122 | if (memcmp(timings, &t, sizeof(struct omap_video_timings))) | |
123 | ret = -EINVAL; | |
124 | else | |
125 | ret = 0; | |
126 | } | |
127 | ||
f5f9454c RC |
128 | if (ret) { |
129 | dev_err(dev->dev, "could not set timings: %d\n", ret); | |
130 | return ret; | |
131 | } | |
132 | ||
bddabbe1 AT |
133 | if (dssdrv->set_timings) |
134 | dssdrv->set_timings(dssdev, timings); | |
f5f9454c RC |
135 | |
136 | return 0; | |
cd5351f4 RC |
137 | } |
138 | ||
4029755e LP |
139 | static void omap_encoder_enable(struct drm_encoder *encoder) |
140 | { | |
141 | struct omap_encoder *omap_encoder = to_omap_encoder(encoder); | |
142 | struct omap_dss_device *dssdev = omap_encoder->dssdev; | |
143 | struct omap_dss_driver *dssdrv = dssdev->driver; | |
144 | ||
145 | omap_encoder_update(encoder, omap_crtc_channel(encoder->crtc), | |
146 | omap_crtc_timings(encoder->crtc)); | |
147 | ||
148 | dssdrv->enable(dssdev); | |
149 | } | |
150 | ||
151 | static int omap_encoder_atomic_check(struct drm_encoder *encoder, | |
152 | struct drm_crtc_state *crtc_state, | |
153 | struct drm_connector_state *conn_state) | |
154 | { | |
155 | return 0; | |
156 | } | |
157 | ||
158 | static const struct drm_encoder_helper_funcs omap_encoder_helper_funcs = { | |
159 | .mode_set = omap_encoder_mode_set, | |
160 | .disable = omap_encoder_disable, | |
161 | .enable = omap_encoder_enable, | |
162 | .atomic_check = omap_encoder_atomic_check, | |
163 | }; | |
164 | ||
cd5351f4 RC |
165 | /* initialize encoder */ |
166 | struct drm_encoder *omap_encoder_init(struct drm_device *dev, | |
f5f9454c | 167 | struct omap_dss_device *dssdev) |
cd5351f4 RC |
168 | { |
169 | struct drm_encoder *encoder = NULL; | |
170 | struct omap_encoder *omap_encoder; | |
cd5351f4 RC |
171 | |
172 | omap_encoder = kzalloc(sizeof(*omap_encoder), GFP_KERNEL); | |
78110bb8 | 173 | if (!omap_encoder) |
cd5351f4 | 174 | goto fail; |
cd5351f4 | 175 | |
f5f9454c RC |
176 | omap_encoder->dssdev = dssdev; |
177 | ||
cd5351f4 RC |
178 | encoder = &omap_encoder->base; |
179 | ||
180 | drm_encoder_init(dev, encoder, &omap_encoder_funcs, | |
13a3d91f | 181 | DRM_MODE_ENCODER_TMDS, NULL); |
cd5351f4 RC |
182 | drm_encoder_helper_add(encoder, &omap_encoder_helper_funcs); |
183 | ||
cd5351f4 RC |
184 | return encoder; |
185 | ||
186 | fail: | |
582bc28c | 187 | if (encoder) |
65b0bd06 | 188 | omap_encoder_destroy(encoder); |
cd5351f4 RC |
189 | |
190 | return NULL; | |
191 | } |