Commit | Line | Data |
---|---|---|
cd5351f4 | 1 | /* |
8bb0daff | 2 | * drivers/gpu/drm/omapdrm/omap_crtc.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 | ||
69a12263 LP |
20 | #include <drm/drm_atomic.h> |
21 | #include <drm/drm_atomic_helper.h> | |
2d278f54 LP |
22 | #include <drm/drm_crtc.h> |
23 | #include <drm/drm_crtc_helper.h> | |
b9ed9f0e | 24 | #include <drm/drm_mode.h> |
3cb9ae4f | 25 | #include <drm/drm_plane_helper.h> |
2d278f54 LP |
26 | |
27 | #include "omap_drv.h" | |
cd5351f4 RC |
28 | |
29 | #define to_omap_crtc(x) container_of(x, struct omap_crtc, base) | |
30 | ||
31 | struct omap_crtc { | |
32 | struct drm_crtc base; | |
f5f9454c | 33 | |
bb5c2d9a | 34 | const char *name; |
f5f9454c | 35 | enum omap_channel channel; |
f5f9454c | 36 | |
da11bbbb | 37 | struct videomode vm; |
f5f9454c | 38 | |
a42133a7 | 39 | struct omap_drm_irq vblank_irq; |
f5f9454c | 40 | |
a36af73f | 41 | bool ignore_digit_sync_lost; |
5f741b39 | 42 | |
f933a3a9 | 43 | bool enabled; |
5f741b39 TV |
44 | bool pending; |
45 | wait_queue_head_t pending_wait; | |
f5f9454c RC |
46 | }; |
47 | ||
971fb3e5 LP |
48 | /* ----------------------------------------------------------------------------- |
49 | * Helper Functions | |
50 | */ | |
51 | ||
0d8f371f AT |
52 | uint32_t pipe2vbl(struct drm_crtc *crtc) |
53 | { | |
54 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | |
55 | ||
56 | return dispc_mgr_get_vsync_irq(omap_crtc->channel); | |
57 | } | |
58 | ||
4520ff28 | 59 | struct videomode *omap_crtc_timings(struct drm_crtc *crtc) |
971fb3e5 LP |
60 | { |
61 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | |
da11bbbb | 62 | return &omap_crtc->vm; |
971fb3e5 LP |
63 | } |
64 | ||
65 | enum omap_channel omap_crtc_channel(struct drm_crtc *crtc) | |
66 | { | |
67 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | |
68 | return omap_crtc->channel; | |
69 | } | |
70 | ||
5f741b39 TV |
71 | int omap_crtc_wait_pending(struct drm_crtc *crtc) |
72 | { | |
73 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | |
74 | ||
61f3c40b TV |
75 | /* |
76 | * Timeout is set to a "sufficiently" high value, which should cover | |
77 | * a single frame refresh even on slower displays. | |
78 | */ | |
5f741b39 TV |
79 | return wait_event_timeout(omap_crtc->pending_wait, |
80 | !omap_crtc->pending, | |
61f3c40b | 81 | msecs_to_jiffies(250)); |
5f741b39 TV |
82 | } |
83 | ||
971fb3e5 LP |
84 | /* ----------------------------------------------------------------------------- |
85 | * DSS Manager Functions | |
86 | */ | |
87 | ||
f5f9454c RC |
88 | /* |
89 | * Manager-ops, callbacks from output when they need to configure | |
90 | * the upstream part of the video pipe. | |
91 | * | |
92 | * Most of these we can ignore until we add support for command-mode | |
93 | * panels.. for video-mode the crtc-helpers already do an adequate | |
94 | * job of sequencing the setup of the video pipe in the proper order | |
95 | */ | |
96 | ||
04b1fc02 TV |
97 | /* ovl-mgr-id -> crtc */ |
98 | static struct omap_crtc *omap_crtcs[8]; | |
3a924138 | 99 | static struct omap_dss_device *omap_crtc_output[8]; |
04b1fc02 | 100 | |
f5f9454c | 101 | /* we can probably ignore these until we support command-mode panels: */ |
e5cbb6e8 | 102 | static int omap_crtc_dss_connect(enum omap_channel channel, |
1f68d9c4 | 103 | struct omap_dss_device *dst) |
a7e71e7f | 104 | { |
e5cbb6e8 | 105 | if (omap_crtc_output[channel]) |
a7e71e7f TV |
106 | return -EINVAL; |
107 | ||
e5cbb6e8 | 108 | if ((dispc_mgr_get_supported_outputs(channel) & dst->id) == 0) |
a7e71e7f TV |
109 | return -EINVAL; |
110 | ||
e5cbb6e8 | 111 | omap_crtc_output[channel] = dst; |
49239503 | 112 | dst->dispc_channel_connected = true; |
a7e71e7f TV |
113 | |
114 | return 0; | |
115 | } | |
116 | ||
e5cbb6e8 | 117 | static void omap_crtc_dss_disconnect(enum omap_channel channel, |
1f68d9c4 | 118 | struct omap_dss_device *dst) |
a7e71e7f | 119 | { |
e5cbb6e8 | 120 | omap_crtc_output[channel] = NULL; |
49239503 | 121 | dst->dispc_channel_connected = false; |
a7e71e7f TV |
122 | } |
123 | ||
e5cbb6e8 | 124 | static void omap_crtc_dss_start_update(enum omap_channel channel) |
f5f9454c RC |
125 | { |
126 | } | |
127 | ||
4029755e | 128 | /* Called only from the encoder enable/disable and suspend/resume handlers. */ |
8472b570 LP |
129 | static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable) |
130 | { | |
131 | struct drm_device *dev = crtc->dev; | |
132 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | |
133 | enum omap_channel channel = omap_crtc->channel; | |
134 | struct omap_irq_wait *wait; | |
135 | u32 framedone_irq, vsync_irq; | |
136 | int ret; | |
137 | ||
3a924138 | 138 | if (omap_crtc_output[channel]->output_type == OMAP_DISPLAY_TYPE_HDMI) { |
4e4b53ce | 139 | dispc_mgr_enable(channel, enable); |
f933a3a9 | 140 | omap_crtc->enabled = enable; |
4e4b53ce TV |
141 | return; |
142 | } | |
143 | ||
8472b570 LP |
144 | if (dispc_mgr_is_enabled(channel) == enable) |
145 | return; | |
146 | ||
ef422283 TV |
147 | if (omap_crtc->channel == OMAP_DSS_CHANNEL_DIGIT) { |
148 | /* | |
149 | * Digit output produces some sync lost interrupts during the | |
150 | * first frame when enabling, so we need to ignore those. | |
151 | */ | |
152 | omap_crtc->ignore_digit_sync_lost = true; | |
153 | } | |
8472b570 LP |
154 | |
155 | framedone_irq = dispc_mgr_get_framedone_irq(channel); | |
156 | vsync_irq = dispc_mgr_get_vsync_irq(channel); | |
157 | ||
158 | if (enable) { | |
159 | wait = omap_irq_wait_init(dev, vsync_irq, 1); | |
160 | } else { | |
161 | /* | |
162 | * When we disable the digit output, we need to wait for | |
163 | * FRAMEDONE to know that DISPC has finished with the output. | |
164 | * | |
165 | * OMAP2/3 does not have FRAMEDONE irq for digit output, and in | |
166 | * that case we need to use vsync interrupt, and wait for both | |
167 | * even and odd frames. | |
168 | */ | |
169 | ||
170 | if (framedone_irq) | |
171 | wait = omap_irq_wait_init(dev, framedone_irq, 1); | |
172 | else | |
173 | wait = omap_irq_wait_init(dev, vsync_irq, 2); | |
174 | } | |
175 | ||
176 | dispc_mgr_enable(channel, enable); | |
f933a3a9 | 177 | omap_crtc->enabled = enable; |
8472b570 LP |
178 | |
179 | ret = omap_irq_wait(dev, wait, msecs_to_jiffies(100)); | |
180 | if (ret) { | |
181 | dev_err(dev->dev, "%s: timeout waiting for %s\n", | |
182 | omap_crtc->name, enable ? "enable" : "disable"); | |
183 | } | |
184 | ||
ef422283 TV |
185 | if (omap_crtc->channel == OMAP_DSS_CHANNEL_DIGIT) { |
186 | omap_crtc->ignore_digit_sync_lost = false; | |
187 | /* make sure the irq handler sees the value above */ | |
188 | mb(); | |
189 | } | |
8472b570 LP |
190 | } |
191 | ||
506096a1 | 192 | |
e5cbb6e8 | 193 | static int omap_crtc_dss_enable(enum omap_channel channel) |
f5f9454c | 194 | { |
e5cbb6e8 | 195 | struct omap_crtc *omap_crtc = omap_crtcs[channel]; |
dee8260d | 196 | struct omap_overlay_manager_info info; |
506096a1 | 197 | |
dee8260d LP |
198 | memset(&info, 0, sizeof(info)); |
199 | info.default_color = 0x00000000; | |
200 | info.trans_key = 0x00000000; | |
201 | info.trans_key_type = OMAP_DSS_COLOR_KEY_GFX_DST; | |
202 | info.trans_enabled = false; | |
203 | ||
204 | dispc_mgr_setup(omap_crtc->channel, &info); | |
506096a1 | 205 | dispc_mgr_set_timings(omap_crtc->channel, |
da11bbbb | 206 | &omap_crtc->vm); |
8472b570 | 207 | omap_crtc_set_enabled(&omap_crtc->base, true); |
506096a1 | 208 | |
f5f9454c RC |
209 | return 0; |
210 | } | |
211 | ||
e5cbb6e8 | 212 | static void omap_crtc_dss_disable(enum omap_channel channel) |
f5f9454c | 213 | { |
e5cbb6e8 | 214 | struct omap_crtc *omap_crtc = omap_crtcs[channel]; |
506096a1 | 215 | |
8472b570 | 216 | omap_crtc_set_enabled(&omap_crtc->base, false); |
f5f9454c RC |
217 | } |
218 | ||
e5cbb6e8 | 219 | static void omap_crtc_dss_set_timings(enum omap_channel channel, |
da11bbbb | 220 | const struct videomode *vm) |
f5f9454c | 221 | { |
e5cbb6e8 | 222 | struct omap_crtc *omap_crtc = omap_crtcs[channel]; |
f5f9454c | 223 | DBG("%s", omap_crtc->name); |
da11bbbb | 224 | omap_crtc->vm = *vm; |
f5f9454c RC |
225 | } |
226 | ||
e5cbb6e8 | 227 | static void omap_crtc_dss_set_lcd_config(enum omap_channel channel, |
f5f9454c RC |
228 | const struct dss_lcd_mgr_config *config) |
229 | { | |
e5cbb6e8 | 230 | struct omap_crtc *omap_crtc = omap_crtcs[channel]; |
f5f9454c RC |
231 | DBG("%s", omap_crtc->name); |
232 | dispc_mgr_set_lcd_config(omap_crtc->channel, config); | |
233 | } | |
234 | ||
4343f0f8 | 235 | static int omap_crtc_dss_register_framedone( |
e5cbb6e8 | 236 | enum omap_channel channel, |
f5f9454c RC |
237 | void (*handler)(void *), void *data) |
238 | { | |
239 | return 0; | |
240 | } | |
241 | ||
4343f0f8 | 242 | static void omap_crtc_dss_unregister_framedone( |
e5cbb6e8 | 243 | enum omap_channel channel, |
f5f9454c RC |
244 | void (*handler)(void *), void *data) |
245 | { | |
246 | } | |
247 | ||
248 | static const struct dss_mgr_ops mgr_ops = { | |
4343f0f8 LP |
249 | .connect = omap_crtc_dss_connect, |
250 | .disconnect = omap_crtc_dss_disconnect, | |
251 | .start_update = omap_crtc_dss_start_update, | |
252 | .enable = omap_crtc_dss_enable, | |
253 | .disable = omap_crtc_dss_disable, | |
254 | .set_timings = omap_crtc_dss_set_timings, | |
255 | .set_lcd_config = omap_crtc_dss_set_lcd_config, | |
256 | .register_framedone_handler = omap_crtc_dss_register_framedone, | |
257 | .unregister_framedone_handler = omap_crtc_dss_unregister_framedone, | |
cd5351f4 RC |
258 | }; |
259 | ||
971fb3e5 | 260 | /* ----------------------------------------------------------------------------- |
1d5e5ea1 | 261 | * Setup, Flush and Page Flip |
971fb3e5 LP |
262 | */ |
263 | ||
fa16d262 | 264 | static void omap_crtc_complete_page_flip(struct drm_crtc *crtc) |
15d02e92 | 265 | { |
fa16d262 | 266 | struct drm_pending_vblank_event *event; |
15d02e92 | 267 | struct drm_device *dev = crtc->dev; |
fa16d262 | 268 | unsigned long flags; |
15d02e92 | 269 | |
5f741b39 | 270 | event = crtc->state->event; |
c397cfd4 | 271 | |
5f741b39 TV |
272 | if (!event) |
273 | return; | |
c397cfd4 LP |
274 | |
275 | spin_lock_irqsave(&dev->event_lock, flags); | |
8c04fdee | 276 | drm_crtc_send_vblank_event(crtc, event); |
5f741b39 | 277 | spin_unlock_irqrestore(&dev->event_lock, flags); |
15d02e92 LP |
278 | } |
279 | ||
e0519af7 | 280 | void omap_crtc_error_irq(struct drm_crtc *crtc, uint32_t irqstatus) |
971fb3e5 | 281 | { |
e0519af7 | 282 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); |
a36af73f TV |
283 | |
284 | if (omap_crtc->ignore_digit_sync_lost) { | |
285 | irqstatus &= ~DISPC_IRQ_SYNC_LOST_DIGIT; | |
286 | if (!irqstatus) | |
287 | return; | |
288 | } | |
289 | ||
3b143fc8 | 290 | DRM_ERROR_RATELIMITED("%s: errors: %08x\n", omap_crtc->name, irqstatus); |
971fb3e5 LP |
291 | } |
292 | ||
a42133a7 | 293 | static void omap_crtc_vblank_irq(struct omap_drm_irq *irq, uint32_t irqstatus) |
971fb3e5 LP |
294 | { |
295 | struct omap_crtc *omap_crtc = | |
a42133a7 LP |
296 | container_of(irq, struct omap_crtc, vblank_irq); |
297 | struct drm_device *dev = omap_crtc->base.dev; | |
971fb3e5 | 298 | |
a42133a7 LP |
299 | if (dispc_mgr_go_busy(omap_crtc->channel)) |
300 | return; | |
301 | ||
302 | DBG("%s: apply done", omap_crtc->name); | |
5f741b39 | 303 | |
a42133a7 LP |
304 | __omap_irq_unregister(dev, &omap_crtc->vblank_irq); |
305 | ||
5f741b39 TV |
306 | rmb(); |
307 | WARN_ON(!omap_crtc->pending); | |
308 | omap_crtc->pending = false; | |
309 | wmb(); | |
310 | ||
311 | /* wake up userspace */ | |
fa16d262 | 312 | omap_crtc_complete_page_flip(&omap_crtc->base); |
a42133a7 | 313 | |
5f741b39 TV |
314 | /* wake up omap_atomic_complete */ |
315 | wake_up(&omap_crtc->pending_wait); | |
971fb3e5 LP |
316 | } |
317 | ||
971fb3e5 LP |
318 | /* ----------------------------------------------------------------------------- |
319 | * CRTC Functions | |
f5f9454c RC |
320 | */ |
321 | ||
cd5351f4 RC |
322 | static void omap_crtc_destroy(struct drm_crtc *crtc) |
323 | { | |
324 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | |
f5f9454c RC |
325 | |
326 | DBG("%s", omap_crtc->name); | |
327 | ||
a42133a7 | 328 | WARN_ON(omap_crtc->vblank_irq.registered); |
f5f9454c | 329 | |
cd5351f4 | 330 | drm_crtc_cleanup(crtc); |
f5f9454c | 331 | |
cd5351f4 RC |
332 | kfree(omap_crtc); |
333 | } | |
334 | ||
f1d57fb5 | 335 | static void omap_crtc_enable(struct drm_crtc *crtc) |
cd5351f4 RC |
336 | { |
337 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | |
338 | ||
f1d57fb5 | 339 | DBG("%s", omap_crtc->name); |
f5f9454c | 340 | |
5f741b39 TV |
341 | rmb(); |
342 | WARN_ON(omap_crtc->pending); | |
343 | omap_crtc->pending = true; | |
344 | wmb(); | |
345 | ||
346 | omap_irq_register(crtc->dev, &omap_crtc->vblank_irq); | |
347 | ||
f1d57fb5 | 348 | drm_crtc_vblank_on(crtc); |
cd5351f4 RC |
349 | } |
350 | ||
f1d57fb5 | 351 | static void omap_crtc_disable(struct drm_crtc *crtc) |
cd5351f4 | 352 | { |
f1d57fb5 | 353 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); |
f1d57fb5 LP |
354 | |
355 | DBG("%s", omap_crtc->name); | |
356 | ||
f1d57fb5 | 357 | drm_crtc_vblank_off(crtc); |
cd5351f4 RC |
358 | } |
359 | ||
f7a73b65 | 360 | static void omap_crtc_mode_set_nofb(struct drm_crtc *crtc) |
cd5351f4 RC |
361 | { |
362 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | |
f7a73b65 | 363 | struct drm_display_mode *mode = &crtc->state->adjusted_mode; |
f5f9454c RC |
364 | |
365 | DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", | |
f7a73b65 LP |
366 | omap_crtc->name, mode->base.id, mode->name, |
367 | mode->vrefresh, mode->clock, | |
368 | mode->hdisplay, mode->hsync_start, mode->hsync_end, mode->htotal, | |
369 | mode->vdisplay, mode->vsync_start, mode->vsync_end, mode->vtotal, | |
370 | mode->type, mode->flags); | |
f5f9454c | 371 | |
da11bbbb PU |
372 | drm_display_mode_to_videomode(mode, &omap_crtc->vm); |
373 | omap_crtc->vm.flags |= DISPLAY_FLAGS_DE_HIGH | | |
374 | DISPLAY_FLAGS_PIXDATA_POSEDGE | | |
375 | DISPLAY_FLAGS_SYNC_NEGEDGE; | |
cd5351f4 RC |
376 | } |
377 | ||
492a426a JS |
378 | static int omap_crtc_atomic_check(struct drm_crtc *crtc, |
379 | struct drm_crtc_state *state) | |
380 | { | |
381 | if (state->color_mgmt_changed && state->gamma_lut) { | |
382 | uint length = state->gamma_lut->length / | |
383 | sizeof(struct drm_color_lut); | |
384 | ||
385 | if (length < 2) | |
386 | return -EINVAL; | |
387 | } | |
388 | ||
389 | return 0; | |
390 | } | |
391 | ||
c201d00f DV |
392 | static void omap_crtc_atomic_begin(struct drm_crtc *crtc, |
393 | struct drm_crtc_state *old_crtc_state) | |
de8e4100 | 394 | { |
fa16d262 | 395 | } |
cd5351f4 | 396 | |
c201d00f DV |
397 | static void omap_crtc_atomic_flush(struct drm_crtc *crtc, |
398 | struct drm_crtc_state *old_crtc_state) | |
fa16d262 | 399 | { |
6646dfd0 TV |
400 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); |
401 | ||
402 | WARN_ON(omap_crtc->vblank_irq.registered); | |
403 | ||
492a426a JS |
404 | if (crtc->state->color_mgmt_changed) { |
405 | struct drm_color_lut *lut = NULL; | |
406 | uint length = 0; | |
407 | ||
408 | if (crtc->state->gamma_lut) { | |
409 | lut = (struct drm_color_lut *) | |
410 | crtc->state->gamma_lut->data; | |
411 | length = crtc->state->gamma_lut->length / | |
412 | sizeof(*lut); | |
413 | } | |
414 | dispc_mgr_set_gamma(omap_crtc->channel, lut, length); | |
415 | } | |
416 | ||
dadf4659 LP |
417 | /* |
418 | * Only flush the CRTC if it is currently enabled. CRTCs that require a | |
419 | * mode set are disabled prior plane updates and enabled afterwards. | |
420 | * They are thus not active (regardless of what their CRTC core state | |
421 | * reports) and the DRM core could thus call this function even though | |
422 | * the CRTC is currently disabled. Do nothing in that case. | |
423 | */ | |
f933a3a9 LP |
424 | if (!omap_crtc->enabled) |
425 | return; | |
5f741b39 | 426 | |
f933a3a9 | 427 | DBG("%s: GO", omap_crtc->name); |
6646dfd0 | 428 | |
f933a3a9 LP |
429 | rmb(); |
430 | WARN_ON(omap_crtc->pending); | |
431 | omap_crtc->pending = true; | |
432 | wmb(); | |
5f741b39 | 433 | |
f933a3a9 LP |
434 | dispc_mgr_go(omap_crtc->channel); |
435 | omap_irq_register(crtc->dev, &omap_crtc->vblank_irq); | |
cd5351f4 RC |
436 | } |
437 | ||
0da88db1 | 438 | static bool omap_crtc_is_plane_prop(struct drm_crtc *crtc, |
6bdad6cf TV |
439 | struct drm_property *property) |
440 | { | |
0da88db1 | 441 | struct drm_device *dev = crtc->dev; |
6bdad6cf TV |
442 | struct omap_drm_private *priv = dev->dev_private; |
443 | ||
444 | return property == priv->zorder_prop || | |
0da88db1 | 445 | property == crtc->primary->rotation_property; |
6bdad6cf TV |
446 | } |
447 | ||
afc34932 LP |
448 | static int omap_crtc_atomic_set_property(struct drm_crtc *crtc, |
449 | struct drm_crtc_state *state, | |
450 | struct drm_property *property, | |
451 | uint64_t val) | |
3c810c61 | 452 | { |
0da88db1 | 453 | if (omap_crtc_is_plane_prop(crtc, property)) { |
6bdad6cf TV |
454 | struct drm_plane_state *plane_state; |
455 | struct drm_plane *plane = crtc->primary; | |
afc34932 | 456 | |
6bdad6cf TV |
457 | /* |
458 | * Delegate property set to the primary plane. Get the plane | |
459 | * state and set the property directly. | |
460 | */ | |
afc34932 | 461 | |
6bdad6cf TV |
462 | plane_state = drm_atomic_get_plane_state(state->state, plane); |
463 | if (IS_ERR(plane_state)) | |
464 | return PTR_ERR(plane_state); | |
afc34932 | 465 | |
6bdad6cf TV |
466 | return drm_atomic_plane_set_property(plane, plane_state, |
467 | property, val); | |
468 | } | |
469 | ||
470 | return -EINVAL; | |
afc34932 | 471 | } |
1e0fdfc2 | 472 | |
afc34932 LP |
473 | static int omap_crtc_atomic_get_property(struct drm_crtc *crtc, |
474 | const struct drm_crtc_state *state, | |
475 | struct drm_property *property, | |
476 | uint64_t *val) | |
477 | { | |
0da88db1 | 478 | if (omap_crtc_is_plane_prop(crtc, property)) { |
6bdad6cf TV |
479 | /* |
480 | * Delegate property get to the primary plane. The | |
481 | * drm_atomic_plane_get_property() function isn't exported, but | |
482 | * can be called through drm_object_property_get_value() as that | |
483 | * will call drm_atomic_get_property() for atomic drivers. | |
484 | */ | |
485 | return drm_object_property_get_value(&crtc->primary->base, | |
486 | property, val); | |
487 | } | |
488 | ||
489 | return -EINVAL; | |
3c810c61 RC |
490 | } |
491 | ||
cd5351f4 | 492 | static const struct drm_crtc_funcs omap_crtc_funcs = { |
69a12263 | 493 | .reset = drm_atomic_helper_crtc_reset, |
9416c9df | 494 | .set_config = drm_atomic_helper_set_config, |
cd5351f4 | 495 | .destroy = omap_crtc_destroy, |
fa16d262 | 496 | .page_flip = drm_atomic_helper_page_flip, |
492a426a | 497 | .gamma_set = drm_atomic_helper_legacy_gamma_set, |
afc34932 | 498 | .set_property = drm_atomic_helper_crtc_set_property, |
69a12263 LP |
499 | .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, |
500 | .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, | |
afc34932 LP |
501 | .atomic_set_property = omap_crtc_atomic_set_property, |
502 | .atomic_get_property = omap_crtc_atomic_get_property, | |
cd5351f4 RC |
503 | }; |
504 | ||
505 | static const struct drm_crtc_helper_funcs omap_crtc_helper_funcs = { | |
f7a73b65 | 506 | .mode_set_nofb = omap_crtc_mode_set_nofb, |
f1d57fb5 LP |
507 | .disable = omap_crtc_disable, |
508 | .enable = omap_crtc_enable, | |
492a426a | 509 | .atomic_check = omap_crtc_atomic_check, |
de8e4100 LP |
510 | .atomic_begin = omap_crtc_atomic_begin, |
511 | .atomic_flush = omap_crtc_atomic_flush, | |
cd5351f4 RC |
512 | }; |
513 | ||
971fb3e5 LP |
514 | /* ----------------------------------------------------------------------------- |
515 | * Init and Cleanup | |
516 | */ | |
e2f8fd74 | 517 | |
f5f9454c | 518 | static const char *channel_names[] = { |
222025e4 LP |
519 | [OMAP_DSS_CHANNEL_LCD] = "lcd", |
520 | [OMAP_DSS_CHANNEL_DIGIT] = "tv", | |
521 | [OMAP_DSS_CHANNEL_LCD2] = "lcd2", | |
522 | [OMAP_DSS_CHANNEL_LCD3] = "lcd3", | |
f5f9454c RC |
523 | }; |
524 | ||
04b1fc02 TV |
525 | void omap_crtc_pre_init(void) |
526 | { | |
527 | dss_install_mgr_ops(&mgr_ops); | |
528 | } | |
529 | ||
3a01ab25 AT |
530 | void omap_crtc_pre_uninit(void) |
531 | { | |
532 | dss_uninstall_mgr_ops(); | |
533 | } | |
534 | ||
cd5351f4 RC |
535 | /* initialize crtc */ |
536 | struct drm_crtc *omap_crtc_init(struct drm_device *dev, | |
f5f9454c | 537 | struct drm_plane *plane, enum omap_channel channel, int id) |
cd5351f4 RC |
538 | { |
539 | struct drm_crtc *crtc = NULL; | |
f5f9454c | 540 | struct omap_crtc *omap_crtc; |
ef6b0e02 | 541 | int ret; |
f5f9454c RC |
542 | |
543 | DBG("%s", channel_names[channel]); | |
cd5351f4 | 544 | |
f5f9454c | 545 | omap_crtc = kzalloc(sizeof(*omap_crtc), GFP_KERNEL); |
78110bb8 | 546 | if (!omap_crtc) |
ef6b0e02 | 547 | return NULL; |
cd5351f4 | 548 | |
cd5351f4 | 549 | crtc = &omap_crtc->base; |
bb5c2d9a | 550 | |
5f741b39 | 551 | init_waitqueue_head(&omap_crtc->pending_wait); |
f5f9454c | 552 | |
0d8f371f | 553 | omap_crtc->channel = channel; |
0d8f371f | 554 | omap_crtc->name = channel_names[channel]; |
0d8f371f | 555 | |
a42133a7 LP |
556 | omap_crtc->vblank_irq.irqmask = pipe2vbl(crtc); |
557 | omap_crtc->vblank_irq.irq = omap_crtc_vblank_irq; | |
f5f9454c | 558 | |
ef6b0e02 | 559 | ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL, |
f9882876 | 560 | &omap_crtc_funcs, NULL); |
ef6b0e02 LP |
561 | if (ret < 0) { |
562 | kfree(omap_crtc); | |
563 | return NULL; | |
564 | } | |
565 | ||
cd5351f4 RC |
566 | drm_crtc_helper_add(crtc, &omap_crtc_helper_funcs); |
567 | ||
492a426a JS |
568 | /* The dispc API adapts to what ever size, but the HW supports |
569 | * 256 element gamma table for LCDs and 1024 element table for | |
570 | * OMAP_DSS_CHANNEL_DIGIT. X server assumes 256 element gamma | |
571 | * tables so lets use that. Size of HW gamma table can be | |
572 | * extracted with dispc_mgr_gamma_size(). If it returns 0 | |
573 | * gamma table is not supprted. | |
574 | */ | |
575 | if (dispc_mgr_gamma_size(channel)) { | |
576 | uint gamma_lut_size = 256; | |
577 | ||
578 | drm_crtc_enable_color_mgmt(crtc, 0, false, gamma_lut_size); | |
579 | drm_mode_crtc_set_gamma_size(crtc, gamma_lut_size); | |
580 | } | |
581 | ||
ef6b0e02 | 582 | omap_plane_install_properties(crtc->primary, &crtc->base); |
3c810c61 | 583 | |
04b1fc02 TV |
584 | omap_crtcs[channel] = omap_crtc; |
585 | ||
cd5351f4 | 586 | return crtc; |
cd5351f4 | 587 | } |