drm: omapdrm: Switch plane update to atomic helpers
[deliverable/linux.git] / drivers / gpu / drm / omapdrm / omap_crtc.c
CommitLineData
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
a42133a7
LP
20#include <linux/completion.h>
21
69a12263
LP
22#include <drm/drm_atomic.h>
23#include <drm/drm_atomic_helper.h>
2d278f54
LP
24#include <drm/drm_crtc.h>
25#include <drm/drm_crtc_helper.h>
b9ed9f0e 26#include <drm/drm_mode.h>
3cb9ae4f 27#include <drm/drm_plane_helper.h>
2d278f54
LP
28
29#include "omap_drv.h"
cd5351f4
RC
30
31#define to_omap_crtc(x) container_of(x, struct omap_crtc, base)
32
15d02e92
LP
33enum omap_page_flip_state {
34 OMAP_PAGE_FLIP_IDLE,
35 OMAP_PAGE_FLIP_WAIT,
36 OMAP_PAGE_FLIP_QUEUED,
37 OMAP_PAGE_FLIP_CANCELLED,
38};
39
cd5351f4
RC
40struct omap_crtc {
41 struct drm_crtc base;
f5f9454c 42
bb5c2d9a 43 const char *name;
f5f9454c
RC
44 int pipe;
45 enum omap_channel channel;
46 struct omap_overlay_manager_info info;
c7aef12f 47 struct drm_encoder *current_encoder;
f5f9454c
RC
48
49 /*
50 * Temporary: eventually this will go away, but it is needed
51 * for now to keep the output's happy. (They only need
52 * mgr->id.) Eventually this will be replaced w/ something
53 * more common-panel-framework-y
54 */
04b1fc02 55 struct omap_overlay_manager *mgr;
f5f9454c
RC
56
57 struct omap_video_timings timings;
58 bool enabled;
f5f9454c 59
a42133a7 60 struct omap_drm_irq vblank_irq;
f5f9454c
RC
61 struct omap_drm_irq error_irq;
62
a42133a7
LP
63 /* list of framebuffers to unpin */
64 struct list_head pending_unpins;
cd5351f4 65
42fb61cc 66 /*
15d02e92
LP
67 * flip_state flag indicates the current page flap state: IDLE if no
68 * page queue has been submitted, WAIT when waiting for GEM async
69 * completion, QUEUED when the page flip has been queued to the hardware
70 * or CANCELLED when the CRTC is turned off before the flip gets queued
0c19ac9d
LP
71 * to the hardware. The flip event, if any, is stored in flip_event, and
72 * the framebuffer queued for page flip is stored in flip_fb. The
15d02e92 73 * flip_wait wait queue is used to wait for page flip completion.
42fb61cc
LP
74 *
75 * The flip_work work queue handles page flip requests without caring
76 * about what context the GEM async callback is called from. Possibly we
77 * should just make omap_gem always call the cb from the worker so we
78 * don't have to care about this.
79 */
15d02e92 80 enum omap_page_flip_state flip_state;
42fb61cc 81 struct drm_pending_vblank_event *flip_event;
0c19ac9d 82 struct drm_framebuffer *flip_fb;
c397cfd4 83 wait_queue_head_t flip_wait;
42fb61cc 84 struct work_struct flip_work;
f5f9454c 85
a42133a7
LP
86 struct completion completion;
87
a36af73f 88 bool ignore_digit_sync_lost;
f5f9454c
RC
89};
90
a42133a7
LP
91struct omap_framebuffer_unpin {
92 struct list_head list;
93 struct drm_framebuffer *fb;
94};
95
971fb3e5
LP
96/* -----------------------------------------------------------------------------
97 * Helper Functions
98 */
99
0d8f371f
AT
100uint32_t pipe2vbl(struct drm_crtc *crtc)
101{
102 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
103
104 return dispc_mgr_get_vsync_irq(omap_crtc->channel);
105}
106
971fb3e5
LP
107const struct omap_video_timings *omap_crtc_timings(struct drm_crtc *crtc)
108{
109 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
110 return &omap_crtc->timings;
111}
112
113enum omap_channel omap_crtc_channel(struct drm_crtc *crtc)
114{
115 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
116 return omap_crtc->channel;
117}
118
119/* -----------------------------------------------------------------------------
120 * DSS Manager Functions
121 */
122
f5f9454c
RC
123/*
124 * Manager-ops, callbacks from output when they need to configure
125 * the upstream part of the video pipe.
126 *
127 * Most of these we can ignore until we add support for command-mode
128 * panels.. for video-mode the crtc-helpers already do an adequate
129 * job of sequencing the setup of the video pipe in the proper order
130 */
131
04b1fc02
TV
132/* ovl-mgr-id -> crtc */
133static struct omap_crtc *omap_crtcs[8];
134
f5f9454c 135/* we can probably ignore these until we support command-mode panels: */
4343f0f8 136static int omap_crtc_dss_connect(struct omap_overlay_manager *mgr,
1f68d9c4 137 struct omap_dss_device *dst)
a7e71e7f
TV
138{
139 if (mgr->output)
140 return -EINVAL;
141
142 if ((mgr->supported_outputs & dst->id) == 0)
143 return -EINVAL;
144
145 dst->manager = mgr;
146 mgr->output = dst;
147
148 return 0;
149}
150
4343f0f8 151static void omap_crtc_dss_disconnect(struct omap_overlay_manager *mgr,
1f68d9c4 152 struct omap_dss_device *dst)
a7e71e7f
TV
153{
154 mgr->output->manager = NULL;
155 mgr->output = NULL;
156}
157
4343f0f8 158static void omap_crtc_dss_start_update(struct omap_overlay_manager *mgr)
f5f9454c
RC
159{
160}
161
a42133a7 162/* Called only from omap_crtc_setup and suspend/resume handlers. */
8472b570
LP
163static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable)
164{
165 struct drm_device *dev = crtc->dev;
166 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
167 enum omap_channel channel = omap_crtc->channel;
168 struct omap_irq_wait *wait;
169 u32 framedone_irq, vsync_irq;
170 int ret;
171
172 if (dispc_mgr_is_enabled(channel) == enable)
173 return;
174
ef422283
TV
175 if (omap_crtc->channel == OMAP_DSS_CHANNEL_DIGIT) {
176 /*
177 * Digit output produces some sync lost interrupts during the
178 * first frame when enabling, so we need to ignore those.
179 */
180 omap_crtc->ignore_digit_sync_lost = true;
181 }
8472b570
LP
182
183 framedone_irq = dispc_mgr_get_framedone_irq(channel);
184 vsync_irq = dispc_mgr_get_vsync_irq(channel);
185
186 if (enable) {
187 wait = omap_irq_wait_init(dev, vsync_irq, 1);
188 } else {
189 /*
190 * When we disable the digit output, we need to wait for
191 * FRAMEDONE to know that DISPC has finished with the output.
192 *
193 * OMAP2/3 does not have FRAMEDONE irq for digit output, and in
194 * that case we need to use vsync interrupt, and wait for both
195 * even and odd frames.
196 */
197
198 if (framedone_irq)
199 wait = omap_irq_wait_init(dev, framedone_irq, 1);
200 else
201 wait = omap_irq_wait_init(dev, vsync_irq, 2);
202 }
203
204 dispc_mgr_enable(channel, enable);
205
206 ret = omap_irq_wait(dev, wait, msecs_to_jiffies(100));
207 if (ret) {
208 dev_err(dev->dev, "%s: timeout waiting for %s\n",
209 omap_crtc->name, enable ? "enable" : "disable");
210 }
211
ef422283
TV
212 if (omap_crtc->channel == OMAP_DSS_CHANNEL_DIGIT) {
213 omap_crtc->ignore_digit_sync_lost = false;
214 /* make sure the irq handler sees the value above */
215 mb();
216 }
8472b570
LP
217}
218
506096a1 219
4343f0f8 220static int omap_crtc_dss_enable(struct omap_overlay_manager *mgr)
f5f9454c 221{
506096a1
TV
222 struct omap_crtc *omap_crtc = omap_crtcs[mgr->id];
223
224 dispc_mgr_setup(omap_crtc->channel, &omap_crtc->info);
225 dispc_mgr_set_timings(omap_crtc->channel,
226 &omap_crtc->timings);
8472b570 227 omap_crtc_set_enabled(&omap_crtc->base, true);
506096a1 228
f5f9454c
RC
229 return 0;
230}
231
4343f0f8 232static void omap_crtc_dss_disable(struct omap_overlay_manager *mgr)
f5f9454c 233{
506096a1
TV
234 struct omap_crtc *omap_crtc = omap_crtcs[mgr->id];
235
8472b570 236 omap_crtc_set_enabled(&omap_crtc->base, false);
f5f9454c
RC
237}
238
4343f0f8 239static void omap_crtc_dss_set_timings(struct omap_overlay_manager *mgr,
f5f9454c
RC
240 const struct omap_video_timings *timings)
241{
04b1fc02 242 struct omap_crtc *omap_crtc = omap_crtcs[mgr->id];
f5f9454c
RC
243 DBG("%s", omap_crtc->name);
244 omap_crtc->timings = *timings;
f5f9454c
RC
245}
246
4343f0f8 247static void omap_crtc_dss_set_lcd_config(struct omap_overlay_manager *mgr,
f5f9454c
RC
248 const struct dss_lcd_mgr_config *config)
249{
04b1fc02 250 struct omap_crtc *omap_crtc = omap_crtcs[mgr->id];
f5f9454c
RC
251 DBG("%s", omap_crtc->name);
252 dispc_mgr_set_lcd_config(omap_crtc->channel, config);
253}
254
4343f0f8 255static int omap_crtc_dss_register_framedone(
f5f9454c
RC
256 struct omap_overlay_manager *mgr,
257 void (*handler)(void *), void *data)
258{
259 return 0;
260}
261
4343f0f8 262static void omap_crtc_dss_unregister_framedone(
f5f9454c
RC
263 struct omap_overlay_manager *mgr,
264 void (*handler)(void *), void *data)
265{
266}
267
268static const struct dss_mgr_ops mgr_ops = {
4343f0f8
LP
269 .connect = omap_crtc_dss_connect,
270 .disconnect = omap_crtc_dss_disconnect,
271 .start_update = omap_crtc_dss_start_update,
272 .enable = omap_crtc_dss_enable,
273 .disable = omap_crtc_dss_disable,
274 .set_timings = omap_crtc_dss_set_timings,
275 .set_lcd_config = omap_crtc_dss_set_lcd_config,
276 .register_framedone_handler = omap_crtc_dss_register_framedone,
277 .unregister_framedone_handler = omap_crtc_dss_unregister_framedone,
cd5351f4
RC
278};
279
971fb3e5 280/* -----------------------------------------------------------------------------
1d5e5ea1 281 * Setup, Flush and Page Flip
971fb3e5
LP
282 */
283
1d5e5ea1
LP
284void omap_crtc_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file)
285{
286 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
287 struct drm_device *dev = crtc->dev;
288 unsigned long flags;
289
290 spin_lock_irqsave(&dev->event_lock, flags);
291
292 /* Only complete events queued for our file handle. */
293 if (omap_crtc->flip_event &&
294 file == omap_crtc->flip_event->base.file_priv) {
295 drm_send_vblank_event(dev, omap_crtc->pipe,
296 omap_crtc->flip_event);
297 omap_crtc->flip_event = NULL;
298 }
299
300 spin_unlock_irqrestore(&dev->event_lock, flags);
301}
302
15d02e92
LP
303/* Must be called with dev->event_lock locked. */
304static void omap_crtc_complete_page_flip(struct drm_crtc *crtc,
305 enum omap_page_flip_state state)
306{
307 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
308 struct drm_device *dev = crtc->dev;
309
310 if (omap_crtc->flip_event) {
311 drm_send_vblank_event(dev, omap_crtc->pipe,
312 omap_crtc->flip_event);
313 omap_crtc->flip_event = NULL;
314 }
315
316 omap_crtc->flip_state = state;
c397cfd4
LP
317
318 if (state == OMAP_PAGE_FLIP_IDLE)
319 wake_up(&omap_crtc->flip_wait);
320}
321
322static bool omap_crtc_page_flip_pending(struct drm_crtc *crtc)
323{
324 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
325 struct drm_device *dev = crtc->dev;
326 unsigned long flags;
327 bool pending;
328
329 spin_lock_irqsave(&dev->event_lock, flags);
330 pending = omap_crtc->flip_state != OMAP_PAGE_FLIP_IDLE;
331 spin_unlock_irqrestore(&dev->event_lock, flags);
332
333 return pending;
334}
335
336static void omap_crtc_wait_page_flip(struct drm_crtc *crtc)
337{
338 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
339 struct drm_device *dev = crtc->dev;
340 bool cancelled = false;
341 unsigned long flags;
342
343 /*
344 * If we're still waiting for the GEM async operation to complete just
345 * cancel the page flip, as we're holding the CRTC mutex preventing the
346 * page flip work handler from queueing the page flip.
347 *
348 * We can't release the reference to the frame buffer here as the async
349 * operation doesn't keep its own reference to the buffer. We'll just
350 * let the page flip work queue handle that.
351 */
352 spin_lock_irqsave(&dev->event_lock, flags);
353 if (omap_crtc->flip_state == OMAP_PAGE_FLIP_WAIT) {
354 omap_crtc_complete_page_flip(crtc, OMAP_PAGE_FLIP_CANCELLED);
355 cancelled = true;
356 }
357 spin_unlock_irqrestore(&dev->event_lock, flags);
358
359 if (cancelled)
360 return;
361
362 if (wait_event_timeout(omap_crtc->flip_wait,
363 !omap_crtc_page_flip_pending(crtc),
364 msecs_to_jiffies(50)))
365 return;
366
367 dev_warn(crtc->dev->dev, "page flip timeout!\n");
368
369 spin_lock_irqsave(&dev->event_lock, flags);
370 omap_crtc_complete_page_flip(crtc, OMAP_PAGE_FLIP_IDLE);
371 spin_unlock_irqrestore(&dev->event_lock, flags);
15d02e92
LP
372}
373
971fb3e5
LP
374static void omap_crtc_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
375{
376 struct omap_crtc *omap_crtc =
377 container_of(irq, struct omap_crtc, error_irq);
a36af73f
TV
378
379 if (omap_crtc->ignore_digit_sync_lost) {
380 irqstatus &= ~DISPC_IRQ_SYNC_LOST_DIGIT;
381 if (!irqstatus)
382 return;
383 }
384
3b143fc8 385 DRM_ERROR_RATELIMITED("%s: errors: %08x\n", omap_crtc->name, irqstatus);
971fb3e5
LP
386}
387
a42133a7 388static void omap_crtc_vblank_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
971fb3e5
LP
389{
390 struct omap_crtc *omap_crtc =
a42133a7
LP
391 container_of(irq, struct omap_crtc, vblank_irq);
392 struct drm_device *dev = omap_crtc->base.dev;
393 unsigned long flags;
971fb3e5 394
a42133a7
LP
395 if (dispc_mgr_go_busy(omap_crtc->channel))
396 return;
397
398 DBG("%s: apply done", omap_crtc->name);
399 __omap_irq_unregister(dev, &omap_crtc->vblank_irq);
400
a42133a7 401 /* wakeup userspace */
15d02e92
LP
402 spin_lock_irqsave(&dev->event_lock, flags);
403 omap_crtc_complete_page_flip(&omap_crtc->base, OMAP_PAGE_FLIP_IDLE);
a42133a7
LP
404 spin_unlock_irqrestore(&dev->event_lock, flags);
405
406 complete(&omap_crtc->completion);
971fb3e5
LP
407}
408
a42133a7 409int omap_crtc_flush(struct drm_crtc *crtc)
971fb3e5 410{
a42133a7
LP
411 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
412 struct omap_framebuffer_unpin *fb, *next;
971fb3e5 413
a42133a7 414 DBG("%s: GO", omap_crtc->name);
971fb3e5 415
a42133a7
LP
416 WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
417 WARN_ON(omap_crtc->vblank_irq.registered);
971fb3e5 418
a42133a7 419 dispc_runtime_get();
971fb3e5 420
a42133a7
LP
421 if (dispc_mgr_is_enabled(omap_crtc->channel)) {
422 dispc_mgr_go(omap_crtc->channel);
423 omap_irq_register(crtc->dev, &omap_crtc->vblank_irq);
971fb3e5 424
a42133a7
LP
425 WARN_ON(!wait_for_completion_timeout(&omap_crtc->completion,
426 msecs_to_jiffies(100)));
427 reinit_completion(&omap_crtc->completion);
428 }
971fb3e5 429
a42133a7 430 dispc_runtime_put();
971fb3e5 431
a42133a7
LP
432 /* Unpin and unreference pending framebuffers. */
433 list_for_each_entry_safe(fb, next, &omap_crtc->pending_unpins, list) {
434 omap_framebuffer_unpin(fb->fb);
435 drm_framebuffer_unreference(fb->fb);
436 list_del(&fb->list);
437 kfree(fb);
971fb3e5
LP
438 }
439
a42133a7 440 return 0;
971fb3e5
LP
441}
442
a42133a7 443int omap_crtc_queue_unpin(struct drm_crtc *crtc, struct drm_framebuffer *fb)
971fb3e5
LP
444{
445 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
a42133a7 446 struct omap_framebuffer_unpin *unpin;
971fb3e5 447
a42133a7
LP
448 unpin = kzalloc(sizeof(*unpin), GFP_KERNEL);
449 if (!unpin)
450 return -ENOMEM;
971fb3e5 451
a42133a7
LP
452 unpin->fb = fb;
453 list_add_tail(&unpin->list, &omap_crtc->pending_unpins);
971fb3e5
LP
454
455 return 0;
456}
457
a42133a7 458static void omap_crtc_setup(struct drm_crtc *crtc)
971fb3e5 459{
a42133a7 460 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
971fb3e5
LP
461 struct omap_drm_private *priv = crtc->dev->dev_private;
462 struct drm_encoder *encoder = NULL;
463 unsigned int i;
464
465 DBG("%s: enabled=%d", omap_crtc->name, omap_crtc->enabled);
466
a42133a7
LP
467 dispc_runtime_get();
468
971fb3e5
LP
469 for (i = 0; i < priv->num_encoders; i++) {
470 if (priv->encoders[i]->crtc == crtc) {
471 encoder = priv->encoders[i];
472 break;
473 }
474 }
475
476 if (omap_crtc->current_encoder && encoder != omap_crtc->current_encoder)
477 omap_encoder_set_enabled(omap_crtc->current_encoder, false);
478
479 omap_crtc->current_encoder = encoder;
480
481 if (!omap_crtc->enabled) {
482 if (encoder)
483 omap_encoder_set_enabled(encoder, false);
484 } else {
485 if (encoder) {
486 omap_encoder_set_enabled(encoder, false);
487 omap_encoder_update(encoder, omap_crtc->mgr,
488 &omap_crtc->timings);
489 omap_encoder_set_enabled(encoder, true);
490 }
491 }
971fb3e5 492
a42133a7 493 dispc_runtime_put();
971fb3e5
LP
494}
495
496/* -----------------------------------------------------------------------------
497 * CRTC Functions
f5f9454c
RC
498 */
499
cd5351f4
RC
500static void omap_crtc_destroy(struct drm_crtc *crtc)
501{
502 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
f5f9454c
RC
503
504 DBG("%s", omap_crtc->name);
505
a42133a7 506 WARN_ON(omap_crtc->vblank_irq.registered);
f5f9454c
RC
507 omap_irq_unregister(crtc->dev, &omap_crtc->error_irq);
508
cd5351f4 509 drm_crtc_cleanup(crtc);
f5f9454c 510
cd5351f4
RC
511 kfree(omap_crtc);
512}
513
f1d57fb5
LP
514static bool omap_crtc_mode_fixup(struct drm_crtc *crtc,
515 const struct drm_display_mode *mode,
516 struct drm_display_mode *adjusted_mode)
517{
518 return true;
519}
520
521static void omap_crtc_enable(struct drm_crtc *crtc)
cd5351f4 522{
bb5c2d9a 523 struct omap_drm_private *priv = crtc->dev->dev_private;
cd5351f4 524 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
f1d57fb5 525 unsigned int i;
cd5351f4 526
f1d57fb5 527 DBG("%s", omap_crtc->name);
f5f9454c 528
f1d57fb5 529 if (omap_crtc->enabled)
a42133a7 530 return;
cd5351f4 531
f1d57fb5 532 /* Enable all planes associated with the CRTC. */
a42133a7
LP
533 for (i = 0; i < priv->num_planes; i++) {
534 struct drm_plane *plane = priv->planes[i];
535
536 if (plane->crtc == crtc)
f1d57fb5 537 WARN_ON(omap_plane_set_enable(plane, true));
cd5351f4 538 }
a42133a7 539
f1d57fb5 540 omap_crtc->enabled = true;
a42133a7
LP
541
542 omap_crtc_setup(crtc);
543 omap_crtc_flush(crtc);
c397cfd4 544
f1d57fb5
LP
545 dispc_runtime_get();
546 drm_crtc_vblank_on(crtc);
547 dispc_runtime_put();
cd5351f4
RC
548}
549
f1d57fb5 550static void omap_crtc_disable(struct drm_crtc *crtc)
cd5351f4 551{
f1d57fb5
LP
552 struct omap_drm_private *priv = crtc->dev->dev_private;
553 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
554 unsigned int i;
555
556 DBG("%s", omap_crtc->name);
557
558 if (!omap_crtc->enabled)
559 return;
560
561 omap_crtc_wait_page_flip(crtc);
562 dispc_runtime_get();
563 drm_crtc_vblank_off(crtc);
564 dispc_runtime_put();
565
566 /* Disable all planes associated with the CRTC. */
567 for (i = 0; i < priv->num_planes; i++) {
568 struct drm_plane *plane = priv->planes[i];
569
570 if (plane->crtc == crtc)
571 WARN_ON(omap_plane_set_enable(plane, false));
572 }
573
f7a73b65
LP
574 /*
575 * HACK: Unpin the primary plane frame buffer if we're disabled without
576 * going through full mode set.
577 * HACK: The legacy set config helper drm_crtc_helper_set_config() that
578 * we still use calls the .disable() operation directly when called with
579 * a NULL frame buffer (for instance from drm_fb_release()). As a result
580 * the CRTC is disabled without going through a full mode set, and the
581 * primary plane' framebuffer is kept pin. Unpin it manually here until
582 * we switch to the atomic set config helper.
583 */
584 if (crtc->primary->fb) {
585 const struct drm_plane_helper_funcs *funcs;
586
587 funcs = crtc->primary->helper_private;
588 funcs->cleanup_fb(crtc->primary, crtc->primary->fb, NULL);
589 }
590
f1d57fb5
LP
591 omap_crtc->enabled = false;
592
593 omap_crtc_setup(crtc);
594 omap_crtc_flush(crtc);
cd5351f4
RC
595}
596
f7a73b65 597static void omap_crtc_mode_set_nofb(struct drm_crtc *crtc)
cd5351f4
RC
598{
599 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
f7a73b65 600 struct drm_display_mode *mode = &crtc->state->adjusted_mode;
f5f9454c
RC
601
602 DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
f7a73b65
LP
603 omap_crtc->name, mode->base.id, mode->name,
604 mode->vrefresh, mode->clock,
605 mode->hdisplay, mode->hsync_start, mode->hsync_end, mode->htotal,
606 mode->vdisplay, mode->vsync_start, mode->vsync_end, mode->vtotal,
607 mode->type, mode->flags);
f5f9454c
RC
608
609 copy_timings_drm_to_omap(&omap_crtc->timings, mode);
cd5351f4
RC
610}
611
f1d57fb5
LP
612static void omap_crtc_dpms(struct drm_crtc *crtc, int mode)
613{
614 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
615 bool enable = (mode == DRM_MODE_DPMS_ON);
616
617 DBG("%s: %d", omap_crtc->name, mode);
618
619 if (enable)
620 omap_crtc_enable(crtc);
621 else
622 omap_crtc_disable(crtc);
623}
624
cd5351f4
RC
625static void omap_crtc_prepare(struct drm_crtc *crtc)
626{
627 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
bb5c2d9a 628 DBG("%s", omap_crtc->name);
cd5351f4
RC
629 omap_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
630}
631
632static void omap_crtc_commit(struct drm_crtc *crtc)
633{
634 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
bb5c2d9a 635 DBG("%s", omap_crtc->name);
cd5351f4
RC
636 omap_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
637}
638
de8e4100
LP
639static void omap_crtc_atomic_begin(struct drm_crtc *crtc)
640{
641 dispc_runtime_get();
642}
643
644static void omap_crtc_atomic_flush(struct drm_crtc *crtc)
645{
646 omap_crtc_flush(crtc);
647
648 dispc_runtime_put();
649}
650
f5f9454c 651static void page_flip_worker(struct work_struct *work)
72d0c336 652{
f5f9454c 653 struct omap_crtc *omap_crtc =
42fb61cc 654 container_of(work, struct omap_crtc, flip_work);
f5f9454c 655 struct drm_crtc *crtc = &omap_crtc->base;
f5f9454c 656 struct drm_display_mode *mode = &crtc->mode;
15d02e92
LP
657 struct drm_device *dev = crtc->dev;
658 struct drm_framebuffer *fb;
119c0814 659 struct drm_gem_object *bo;
15d02e92
LP
660 unsigned long flags;
661 bool queue_flip;
72d0c336 662
51fd371b 663 drm_modeset_lock(&crtc->mutex, NULL);
15d02e92
LP
664
665 spin_lock_irqsave(&dev->event_lock, flags);
0c19ac9d 666
15d02e92
LP
667 /*
668 * The page flip could have been cancelled while waiting for the GEM
669 * async operation to complete. Don't queue the flip in that case.
670 */
671 if (omap_crtc->flip_state == OMAP_PAGE_FLIP_WAIT) {
672 omap_crtc->flip_state = OMAP_PAGE_FLIP_QUEUED;
673 queue_flip = true;
674 } else {
675 omap_crtc->flip_state = OMAP_PAGE_FLIP_IDLE;
676 queue_flip = false;
677 }
15d02e92 678
0c19ac9d
LP
679 fb = omap_crtc->flip_fb;
680 omap_crtc->flip_fb = NULL;
681
682 spin_unlock_irqrestore(&dev->event_lock, flags);
15d02e92
LP
683
684 if (queue_flip) {
685 omap_plane_mode_set(crtc->primary, crtc, fb,
686 0, 0, mode->hdisplay, mode->vdisplay,
687 crtc->x, crtc->y, mode->hdisplay,
688 mode->vdisplay);
689 omap_crtc_flush(crtc);
690 }
691
51fd371b 692 drm_modeset_unlock(&crtc->mutex);
119c0814 693
15d02e92 694 bo = omap_framebuffer_bo(fb, 0);
119c0814 695 drm_gem_object_unreference_unlocked(bo);
0c19ac9d 696 drm_framebuffer_unreference(fb);
72d0c336
RC
697}
698
f5f9454c
RC
699static void page_flip_cb(void *arg)
700{
701 struct drm_crtc *crtc = arg;
702 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
703 struct omap_drm_private *priv = crtc->dev->dev_private;
704
705 /* avoid assumptions about what ctxt we are called from: */
42fb61cc 706 queue_work(priv->wq, &omap_crtc->flip_work);
f5f9454c
RC
707}
708
077db4da
LP
709static int omap_crtc_page_flip(struct drm_crtc *crtc,
710 struct drm_framebuffer *fb,
711 struct drm_pending_vblank_event *event,
712 uint32_t page_flip_flags)
cd5351f4
RC
713{
714 struct drm_device *dev = crtc->dev;
715 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
f4510a27 716 struct drm_plane *primary = crtc->primary;
119c0814 717 struct drm_gem_object *bo;
38e5597a 718 unsigned long flags;
cd5351f4 719
f4510a27 720 DBG("%d -> %d (event=%p)", primary->fb ? primary->fb->base.id : -1,
f5f9454c 721 fb->base.id, event);
cd5351f4 722
38e5597a
AT
723 spin_lock_irqsave(&dev->event_lock, flags);
724
15d02e92 725 if (omap_crtc->flip_state != OMAP_PAGE_FLIP_IDLE) {
38e5597a 726 spin_unlock_irqrestore(&dev->event_lock, flags);
cd5351f4 727 dev_err(dev->dev, "already a pending flip\n");
549a7549 728 return -EBUSY;
cd5351f4
RC
729 }
730
0c19ac9d
LP
731 /*
732 * Store a reference to the framebuffer queued for page flip in the CRTC
733 * private structure. We can't rely on crtc->primary->fb in the page
734 * flip worker, as a racing CRTC disable (due for instance to an
735 * explicit framebuffer deletion from userspace) would set that field to
736 * NULL before the worker gets a change to run.
737 */
738 drm_framebuffer_reference(fb);
739 omap_crtc->flip_fb = fb;
42fb61cc 740 omap_crtc->flip_event = event;
15d02e92 741 omap_crtc->flip_state = OMAP_PAGE_FLIP_WAIT;
0c19ac9d 742
69a12263 743 drm_atomic_set_fb_for_plane(primary->state, fb);
42fb61cc 744 primary->fb = fb;
cd5351f4 745
38e5597a
AT
746 spin_unlock_irqrestore(&dev->event_lock, flags);
747
119c0814
RC
748 /*
749 * Hold a reference temporarily until the crtc is updated
750 * and takes the reference to the bo. This avoids it
751 * getting freed from under us:
752 */
753 bo = omap_framebuffer_bo(fb, 0);
754 drm_gem_object_reference(bo);
755
756 omap_gem_op_async(bo, OMAP_GEM_READ, page_flip_cb, crtc);
cd5351f4
RC
757
758 return 0;
759}
760
3c810c61
RC
761static int omap_crtc_set_property(struct drm_crtc *crtc,
762 struct drm_property *property, uint64_t val)
763{
e2cd09b2 764 if (property == crtc->dev->mode_config.rotation_property) {
1e0fdfc2
RC
765 crtc->invert_dimensions =
766 !!(val & ((1LL << DRM_ROTATE_90) | (1LL << DRM_ROTATE_270)));
767 }
768
ef6b0e02 769 return omap_plane_set_property(crtc->primary, property, val);
3c810c61
RC
770}
771
cd5351f4 772static const struct drm_crtc_funcs omap_crtc_funcs = {
69a12263 773 .reset = drm_atomic_helper_crtc_reset,
cd5351f4
RC
774 .set_config = drm_crtc_helper_set_config,
775 .destroy = omap_crtc_destroy,
077db4da 776 .page_flip = omap_crtc_page_flip,
3c810c61 777 .set_property = omap_crtc_set_property,
69a12263
LP
778 .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
779 .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
cd5351f4
RC
780};
781
782static const struct drm_crtc_helper_funcs omap_crtc_helper_funcs = {
783 .dpms = omap_crtc_dpms,
784 .mode_fixup = omap_crtc_mode_fixup,
f7a73b65 785 .mode_set = drm_helper_crtc_mode_set,
cd5351f4
RC
786 .prepare = omap_crtc_prepare,
787 .commit = omap_crtc_commit,
f7a73b65
LP
788 .mode_set_nofb = omap_crtc_mode_set_nofb,
789 .mode_set_base = drm_helper_crtc_mode_set_base,
f1d57fb5
LP
790 .disable = omap_crtc_disable,
791 .enable = omap_crtc_enable,
de8e4100
LP
792 .atomic_begin = omap_crtc_atomic_begin,
793 .atomic_flush = omap_crtc_atomic_flush,
cd5351f4
RC
794};
795
971fb3e5
LP
796/* -----------------------------------------------------------------------------
797 * Init and Cleanup
798 */
e2f8fd74 799
f5f9454c 800static const char *channel_names[] = {
222025e4
LP
801 [OMAP_DSS_CHANNEL_LCD] = "lcd",
802 [OMAP_DSS_CHANNEL_DIGIT] = "tv",
803 [OMAP_DSS_CHANNEL_LCD2] = "lcd2",
804 [OMAP_DSS_CHANNEL_LCD3] = "lcd3",
f5f9454c
RC
805};
806
04b1fc02
TV
807void omap_crtc_pre_init(void)
808{
809 dss_install_mgr_ops(&mgr_ops);
810}
811
3a01ab25
AT
812void omap_crtc_pre_uninit(void)
813{
814 dss_uninstall_mgr_ops();
815}
816
cd5351f4
RC
817/* initialize crtc */
818struct drm_crtc *omap_crtc_init(struct drm_device *dev,
f5f9454c 819 struct drm_plane *plane, enum omap_channel channel, int id)
cd5351f4
RC
820{
821 struct drm_crtc *crtc = NULL;
f5f9454c
RC
822 struct omap_crtc *omap_crtc;
823 struct omap_overlay_manager_info *info;
ef6b0e02 824 int ret;
f5f9454c
RC
825
826 DBG("%s", channel_names[channel]);
cd5351f4 827
f5f9454c 828 omap_crtc = kzalloc(sizeof(*omap_crtc), GFP_KERNEL);
78110bb8 829 if (!omap_crtc)
ef6b0e02 830 return NULL;
cd5351f4 831
cd5351f4 832 crtc = &omap_crtc->base;
bb5c2d9a 833
42fb61cc 834 INIT_WORK(&omap_crtc->flip_work, page_flip_worker);
c397cfd4 835 init_waitqueue_head(&omap_crtc->flip_wait);
f5f9454c 836
a42133a7 837 INIT_LIST_HEAD(&omap_crtc->pending_unpins);
f5f9454c 838
a42133a7 839 init_completion(&omap_crtc->completion);
f5f9454c 840
0d8f371f 841 omap_crtc->channel = channel;
0d8f371f
AT
842 omap_crtc->name = channel_names[channel];
843 omap_crtc->pipe = id;
844
a42133a7
LP
845 omap_crtc->vblank_irq.irqmask = pipe2vbl(crtc);
846 omap_crtc->vblank_irq.irq = omap_crtc_vblank_irq;
f5f9454c
RC
847
848 omap_crtc->error_irq.irqmask =
849 dispc_mgr_get_sync_lost_irq(channel);
850 omap_crtc->error_irq.irq = omap_crtc_error_irq;
851 omap_irq_register(dev, &omap_crtc->error_irq);
852
f5f9454c 853 /* temporary: */
04b1fc02 854 omap_crtc->mgr = omap_dss_get_overlay_manager(channel);
f5f9454c
RC
855
856 /* TODO: fix hard-coded setup.. add properties! */
857 info = &omap_crtc->info;
858 info->default_color = 0x00000000;
859 info->trans_key = 0x00000000;
860 info->trans_key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
861 info->trans_enabled = false;
bb5c2d9a 862
ef6b0e02
LP
863 ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL,
864 &omap_crtc_funcs);
865 if (ret < 0) {
866 kfree(omap_crtc);
867 return NULL;
868 }
869
cd5351f4
RC
870 drm_crtc_helper_add(crtc, &omap_crtc_helper_funcs);
871
ef6b0e02 872 omap_plane_install_properties(crtc->primary, &crtc->base);
3c810c61 873
04b1fc02
TV
874 omap_crtcs[channel] = omap_crtc;
875
cd5351f4 876 return crtc;
cd5351f4 877}
This page took 0.272239 seconds and 5 git commands to generate.