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