]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/gpu/drm/omapdrm/omap_crtc.c
drm: omapdrm: Make the omap_crtc_flush function static
[karo-tx-linux.git] / drivers / gpu / drm / omapdrm / omap_crtc.c
1 /*
2  * drivers/gpu/drm/omapdrm/omap_crtc.c
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
20 #include <linux/completion.h>
21
22 #include <drm/drm_atomic.h>
23 #include <drm/drm_atomic_helper.h>
24 #include <drm/drm_crtc.h>
25 #include <drm/drm_crtc_helper.h>
26 #include <drm/drm_mode.h>
27 #include <drm/drm_plane_helper.h>
28
29 #include "omap_drv.h"
30
31 #define to_omap_crtc(x) container_of(x, struct omap_crtc, base)
32
33 struct omap_crtc {
34         struct drm_crtc base;
35
36         const char *name;
37         enum omap_channel channel;
38         struct drm_encoder *current_encoder;
39
40         /*
41          * Temporary: eventually this will go away, but it is needed
42          * for now to keep the output's happy.  (They only need
43          * mgr->id.)  Eventually this will be replaced w/ something
44          * more common-panel-framework-y
45          */
46         struct omap_overlay_manager *mgr;
47
48         struct omap_video_timings timings;
49
50         struct omap_drm_irq vblank_irq;
51         struct omap_drm_irq error_irq;
52
53         /* pending event */
54         struct drm_pending_vblank_event *event;
55         wait_queue_head_t flip_wait;
56
57         struct completion completion;
58
59         bool ignore_digit_sync_lost;
60 };
61
62 /* -----------------------------------------------------------------------------
63  * Helper Functions
64  */
65
66 uint32_t pipe2vbl(struct drm_crtc *crtc)
67 {
68         struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
69
70         return dispc_mgr_get_vsync_irq(omap_crtc->channel);
71 }
72
73 const struct omap_video_timings *omap_crtc_timings(struct drm_crtc *crtc)
74 {
75         struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
76         return &omap_crtc->timings;
77 }
78
79 enum omap_channel omap_crtc_channel(struct drm_crtc *crtc)
80 {
81         struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
82         return omap_crtc->channel;
83 }
84
85 /* -----------------------------------------------------------------------------
86  * DSS Manager Functions
87  */
88
89 /*
90  * Manager-ops, callbacks from output when they need to configure
91  * the upstream part of the video pipe.
92  *
93  * Most of these we can ignore until we add support for command-mode
94  * panels.. for video-mode the crtc-helpers already do an adequate
95  * job of sequencing the setup of the video pipe in the proper order
96  */
97
98 /* ovl-mgr-id -> crtc */
99 static struct omap_crtc *omap_crtcs[8];
100
101 /* we can probably ignore these until we support command-mode panels: */
102 static int omap_crtc_dss_connect(struct omap_overlay_manager *mgr,
103                 struct omap_dss_device *dst)
104 {
105         if (mgr->output)
106                 return -EINVAL;
107
108         if ((mgr->supported_outputs & dst->id) == 0)
109                 return -EINVAL;
110
111         dst->manager = mgr;
112         mgr->output = dst;
113
114         return 0;
115 }
116
117 static void omap_crtc_dss_disconnect(struct omap_overlay_manager *mgr,
118                 struct omap_dss_device *dst)
119 {
120         mgr->output->manager = NULL;
121         mgr->output = NULL;
122 }
123
124 static void omap_crtc_dss_start_update(struct omap_overlay_manager *mgr)
125 {
126 }
127
128 /* Called only from omap_crtc_encoder_setup and suspend/resume handlers. */
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
138         if (dispc_mgr_is_enabled(channel) == enable)
139                 return;
140
141         if (omap_crtc->channel == OMAP_DSS_CHANNEL_DIGIT) {
142                 /*
143                  * Digit output produces some sync lost interrupts during the
144                  * first frame when enabling, so we need to ignore those.
145                  */
146                 omap_crtc->ignore_digit_sync_lost = true;
147         }
148
149         framedone_irq = dispc_mgr_get_framedone_irq(channel);
150         vsync_irq = dispc_mgr_get_vsync_irq(channel);
151
152         if (enable) {
153                 wait = omap_irq_wait_init(dev, vsync_irq, 1);
154         } else {
155                 /*
156                  * When we disable the digit output, we need to wait for
157                  * FRAMEDONE to know that DISPC has finished with the output.
158                  *
159                  * OMAP2/3 does not have FRAMEDONE irq for digit output, and in
160                  * that case we need to use vsync interrupt, and wait for both
161                  * even and odd frames.
162                  */
163
164                 if (framedone_irq)
165                         wait = omap_irq_wait_init(dev, framedone_irq, 1);
166                 else
167                         wait = omap_irq_wait_init(dev, vsync_irq, 2);
168         }
169
170         dispc_mgr_enable(channel, enable);
171
172         ret = omap_irq_wait(dev, wait, msecs_to_jiffies(100));
173         if (ret) {
174                 dev_err(dev->dev, "%s: timeout waiting for %s\n",
175                                 omap_crtc->name, enable ? "enable" : "disable");
176         }
177
178         if (omap_crtc->channel == OMAP_DSS_CHANNEL_DIGIT) {
179                 omap_crtc->ignore_digit_sync_lost = false;
180                 /* make sure the irq handler sees the value above */
181                 mb();
182         }
183 }
184
185
186 static int omap_crtc_dss_enable(struct omap_overlay_manager *mgr)
187 {
188         struct omap_crtc *omap_crtc = omap_crtcs[mgr->id];
189         struct omap_overlay_manager_info info;
190
191         memset(&info, 0, sizeof(info));
192         info.default_color = 0x00000000;
193         info.trans_key = 0x00000000;
194         info.trans_key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
195         info.trans_enabled = false;
196
197         dispc_mgr_setup(omap_crtc->channel, &info);
198         dispc_mgr_set_timings(omap_crtc->channel,
199                         &omap_crtc->timings);
200         omap_crtc_set_enabled(&omap_crtc->base, true);
201
202         return 0;
203 }
204
205 static void omap_crtc_dss_disable(struct omap_overlay_manager *mgr)
206 {
207         struct omap_crtc *omap_crtc = omap_crtcs[mgr->id];
208
209         omap_crtc_set_enabled(&omap_crtc->base, false);
210 }
211
212 static void omap_crtc_dss_set_timings(struct omap_overlay_manager *mgr,
213                 const struct omap_video_timings *timings)
214 {
215         struct omap_crtc *omap_crtc = omap_crtcs[mgr->id];
216         DBG("%s", omap_crtc->name);
217         omap_crtc->timings = *timings;
218 }
219
220 static void omap_crtc_dss_set_lcd_config(struct omap_overlay_manager *mgr,
221                 const struct dss_lcd_mgr_config *config)
222 {
223         struct omap_crtc *omap_crtc = omap_crtcs[mgr->id];
224         DBG("%s", omap_crtc->name);
225         dispc_mgr_set_lcd_config(omap_crtc->channel, config);
226 }
227
228 static int omap_crtc_dss_register_framedone(
229                 struct omap_overlay_manager *mgr,
230                 void (*handler)(void *), void *data)
231 {
232         return 0;
233 }
234
235 static void omap_crtc_dss_unregister_framedone(
236                 struct omap_overlay_manager *mgr,
237                 void (*handler)(void *), void *data)
238 {
239 }
240
241 static const struct dss_mgr_ops mgr_ops = {
242         .connect = omap_crtc_dss_connect,
243         .disconnect = omap_crtc_dss_disconnect,
244         .start_update = omap_crtc_dss_start_update,
245         .enable = omap_crtc_dss_enable,
246         .disable = omap_crtc_dss_disable,
247         .set_timings = omap_crtc_dss_set_timings,
248         .set_lcd_config = omap_crtc_dss_set_lcd_config,
249         .register_framedone_handler = omap_crtc_dss_register_framedone,
250         .unregister_framedone_handler = omap_crtc_dss_unregister_framedone,
251 };
252
253 /* -----------------------------------------------------------------------------
254  * Setup, Flush and Page Flip
255  */
256
257 void omap_crtc_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file)
258 {
259         struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
260         struct drm_pending_vblank_event *event;
261         struct drm_device *dev = crtc->dev;
262         unsigned long flags;
263
264         /* Destroy the pending vertical blanking event associated with the
265          * pending page flip, if any, and disable vertical blanking interrupts.
266          */
267
268         spin_lock_irqsave(&dev->event_lock, flags);
269
270         event = omap_crtc->event;
271         omap_crtc->event = NULL;
272
273         if (event && event->base.file_priv == file) {
274                 event->base.destroy(&event->base);
275                 drm_crtc_vblank_put(crtc);
276         }
277
278         spin_unlock_irqrestore(&dev->event_lock, flags);
279 }
280
281 static void omap_crtc_complete_page_flip(struct drm_crtc *crtc)
282 {
283         struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
284         struct drm_pending_vblank_event *event;
285         struct drm_device *dev = crtc->dev;
286         unsigned long flags;
287
288         spin_lock_irqsave(&dev->event_lock, flags);
289
290         event = omap_crtc->event;
291         omap_crtc->event = NULL;
292
293         if (event) {
294                 drm_crtc_send_vblank_event(crtc, event);
295                 wake_up(&omap_crtc->flip_wait);
296                 drm_crtc_vblank_put(crtc);
297         }
298
299         spin_unlock_irqrestore(&dev->event_lock, flags);
300 }
301
302 static bool omap_crtc_page_flip_pending(struct drm_crtc *crtc)
303 {
304         struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
305         struct drm_device *dev = crtc->dev;
306         unsigned long flags;
307         bool pending;
308
309         spin_lock_irqsave(&dev->event_lock, flags);
310         pending = omap_crtc->event != NULL;
311         spin_unlock_irqrestore(&dev->event_lock, flags);
312
313         return pending;
314 }
315
316 static void omap_crtc_wait_page_flip(struct drm_crtc *crtc)
317 {
318         struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
319
320         if (wait_event_timeout(omap_crtc->flip_wait,
321                                !omap_crtc_page_flip_pending(crtc),
322                                msecs_to_jiffies(50)))
323                 return;
324
325         dev_warn(crtc->dev->dev, "page flip timeout!\n");
326
327         omap_crtc_complete_page_flip(crtc);
328 }
329
330 static void omap_crtc_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
331 {
332         struct omap_crtc *omap_crtc =
333                         container_of(irq, struct omap_crtc, error_irq);
334
335         if (omap_crtc->ignore_digit_sync_lost) {
336                 irqstatus &= ~DISPC_IRQ_SYNC_LOST_DIGIT;
337                 if (!irqstatus)
338                         return;
339         }
340
341         DRM_ERROR_RATELIMITED("%s: errors: %08x\n", omap_crtc->name, irqstatus);
342 }
343
344 static void omap_crtc_vblank_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
345 {
346         struct omap_crtc *omap_crtc =
347                         container_of(irq, struct omap_crtc, vblank_irq);
348         struct drm_device *dev = omap_crtc->base.dev;
349
350         if (dispc_mgr_go_busy(omap_crtc->channel))
351                 return;
352
353         DBG("%s: apply done", omap_crtc->name);
354         __omap_irq_unregister(dev, &omap_crtc->vblank_irq);
355
356         /* wakeup userspace */
357         omap_crtc_complete_page_flip(&omap_crtc->base);
358
359         complete(&omap_crtc->completion);
360 }
361
362 static int omap_crtc_flush(struct drm_crtc *crtc)
363 {
364         struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
365
366         DBG("%s: GO", omap_crtc->name);
367
368         WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
369         WARN_ON(omap_crtc->vblank_irq.registered);
370
371         dispc_runtime_get();
372
373         if (dispc_mgr_is_enabled(omap_crtc->channel)) {
374                 dispc_mgr_go(omap_crtc->channel);
375                 omap_irq_register(crtc->dev, &omap_crtc->vblank_irq);
376
377                 WARN_ON(!wait_for_completion_timeout(&omap_crtc->completion,
378                                                      msecs_to_jiffies(100)));
379                 reinit_completion(&omap_crtc->completion);
380         }
381
382         dispc_runtime_put();
383
384         return 0;
385 }
386
387 static void omap_crtc_encoder_setup(struct drm_crtc *crtc, bool enable)
388 {
389         struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
390         struct omap_drm_private *priv = crtc->dev->dev_private;
391         struct drm_encoder *encoder = NULL;
392         unsigned int i;
393
394         DBG("%s: enable=%d", omap_crtc->name, enable);
395
396         dispc_runtime_get();
397
398         for (i = 0; i < priv->num_encoders; i++) {
399                 if (priv->encoders[i]->crtc == crtc) {
400                         encoder = priv->encoders[i];
401                         break;
402                 }
403         }
404
405         if (omap_crtc->current_encoder && encoder != omap_crtc->current_encoder)
406                 omap_encoder_set_enabled(omap_crtc->current_encoder, false);
407
408         omap_crtc->current_encoder = encoder;
409
410         if (encoder) {
411                 omap_encoder_set_enabled(encoder, false);
412                 if (enable) {
413                         omap_encoder_update(encoder, omap_crtc->mgr,
414                                             &omap_crtc->timings);
415                         omap_encoder_set_enabled(encoder, true);
416                 }
417         }
418
419         dispc_runtime_put();
420 }
421
422 /* -----------------------------------------------------------------------------
423  * CRTC Functions
424  */
425
426 static void omap_crtc_destroy(struct drm_crtc *crtc)
427 {
428         struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
429
430         DBG("%s", omap_crtc->name);
431
432         WARN_ON(omap_crtc->vblank_irq.registered);
433         omap_irq_unregister(crtc->dev, &omap_crtc->error_irq);
434
435         drm_crtc_cleanup(crtc);
436
437         kfree(omap_crtc);
438 }
439
440 static bool omap_crtc_mode_fixup(struct drm_crtc *crtc,
441                 const struct drm_display_mode *mode,
442                 struct drm_display_mode *adjusted_mode)
443 {
444         return true;
445 }
446
447 static void omap_crtc_enable(struct drm_crtc *crtc)
448 {
449         struct omap_drm_private *priv = crtc->dev->dev_private;
450         struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
451         unsigned int i;
452
453         DBG("%s", omap_crtc->name);
454
455         dispc_runtime_get();
456
457         /* Enable all planes associated with the CRTC. */
458         for (i = 0; i < priv->num_planes; i++) {
459                 struct drm_plane *plane = priv->planes[i];
460
461                 if (plane->crtc == crtc)
462                         WARN_ON(omap_plane_setup(plane));
463         }
464
465         omap_crtc_encoder_setup(crtc, true);
466         omap_crtc_flush(crtc);
467
468         drm_crtc_vblank_on(crtc);
469
470         dispc_runtime_put();
471 }
472
473 static void omap_crtc_disable(struct drm_crtc *crtc)
474 {
475         struct omap_drm_private *priv = crtc->dev->dev_private;
476         struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
477         unsigned int i;
478
479         DBG("%s", omap_crtc->name);
480
481         omap_crtc_wait_page_flip(crtc);
482         dispc_runtime_get();
483         drm_crtc_vblank_off(crtc);
484
485         /* Disable all planes associated with the CRTC. */
486         for (i = 0; i < priv->num_planes; i++) {
487                 struct drm_plane *plane = priv->planes[i];
488
489                 if (plane->crtc == crtc)
490                         WARN_ON(omap_plane_setup(plane));
491         }
492
493         omap_crtc_encoder_setup(crtc, false);
494         omap_crtc_flush(crtc);
495
496         dispc_runtime_put();
497 }
498
499 static void omap_crtc_mode_set_nofb(struct drm_crtc *crtc)
500 {
501         struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
502         struct drm_display_mode *mode = &crtc->state->adjusted_mode;
503
504         DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
505             omap_crtc->name, mode->base.id, mode->name,
506             mode->vrefresh, mode->clock,
507             mode->hdisplay, mode->hsync_start, mode->hsync_end, mode->htotal,
508             mode->vdisplay, mode->vsync_start, mode->vsync_end, mode->vtotal,
509             mode->type, mode->flags);
510
511         copy_timings_drm_to_omap(&omap_crtc->timings, mode);
512 }
513
514 static void omap_crtc_atomic_begin(struct drm_crtc *crtc)
515 {
516         struct drm_pending_vblank_event *event = crtc->state->event;
517         struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
518         struct drm_device *dev = crtc->dev;
519         unsigned long flags;
520
521         dispc_runtime_get();
522
523         if (event) {
524                 WARN_ON(omap_crtc->event);
525                 WARN_ON(drm_crtc_vblank_get(crtc) != 0);
526
527                 spin_lock_irqsave(&dev->event_lock, flags);
528                 omap_crtc->event = event;
529                 spin_unlock_irqrestore(&dev->event_lock, flags);
530         }
531 }
532
533 static void omap_crtc_atomic_flush(struct drm_crtc *crtc)
534 {
535         omap_crtc_flush(crtc);
536
537         dispc_runtime_put();
538
539         crtc->invert_dimensions = !!(crtc->primary->state->rotation &
540                                     (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270)));
541 }
542
543 static int omap_crtc_atomic_set_property(struct drm_crtc *crtc,
544                                          struct drm_crtc_state *state,
545                                          struct drm_property *property,
546                                          uint64_t val)
547 {
548         struct drm_plane_state *plane_state;
549         struct drm_plane *plane = crtc->primary;
550
551         /*
552          * Delegate property set to the primary plane. Get the plane state and
553          * set the property directly.
554          */
555
556         plane_state = drm_atomic_get_plane_state(state->state, plane);
557         if (!plane_state)
558                 return -EINVAL;
559
560         return drm_atomic_plane_set_property(plane, plane_state, property, val);
561 }
562
563 static int omap_crtc_atomic_get_property(struct drm_crtc *crtc,
564                                          const struct drm_crtc_state *state,
565                                          struct drm_property *property,
566                                          uint64_t *val)
567 {
568         /*
569          * Delegate property get to the primary plane. The
570          * drm_atomic_plane_get_property() function isn't exported, but can be
571          * called through drm_object_property_get_value() as that will call
572          * drm_atomic_get_property() for atomic drivers.
573          */
574         return drm_object_property_get_value(&crtc->primary->base, property,
575                                              val);
576 }
577
578 static const struct drm_crtc_funcs omap_crtc_funcs = {
579         .reset = drm_atomic_helper_crtc_reset,
580         .set_config = drm_atomic_helper_set_config,
581         .destroy = omap_crtc_destroy,
582         .page_flip = drm_atomic_helper_page_flip,
583         .set_property = drm_atomic_helper_crtc_set_property,
584         .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
585         .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
586         .atomic_set_property = omap_crtc_atomic_set_property,
587         .atomic_get_property = omap_crtc_atomic_get_property,
588 };
589
590 static const struct drm_crtc_helper_funcs omap_crtc_helper_funcs = {
591         .mode_fixup = omap_crtc_mode_fixup,
592         .mode_set_nofb = omap_crtc_mode_set_nofb,
593         .disable = omap_crtc_disable,
594         .enable = omap_crtc_enable,
595         .atomic_begin = omap_crtc_atomic_begin,
596         .atomic_flush = omap_crtc_atomic_flush,
597 };
598
599 /* -----------------------------------------------------------------------------
600  * Init and Cleanup
601  */
602
603 static const char *channel_names[] = {
604         [OMAP_DSS_CHANNEL_LCD] = "lcd",
605         [OMAP_DSS_CHANNEL_DIGIT] = "tv",
606         [OMAP_DSS_CHANNEL_LCD2] = "lcd2",
607         [OMAP_DSS_CHANNEL_LCD3] = "lcd3",
608 };
609
610 void omap_crtc_pre_init(void)
611 {
612         dss_install_mgr_ops(&mgr_ops);
613 }
614
615 void omap_crtc_pre_uninit(void)
616 {
617         dss_uninstall_mgr_ops();
618 }
619
620 /* initialize crtc */
621 struct drm_crtc *omap_crtc_init(struct drm_device *dev,
622                 struct drm_plane *plane, enum omap_channel channel, int id)
623 {
624         struct drm_crtc *crtc = NULL;
625         struct omap_crtc *omap_crtc;
626         int ret;
627
628         DBG("%s", channel_names[channel]);
629
630         omap_crtc = kzalloc(sizeof(*omap_crtc), GFP_KERNEL);
631         if (!omap_crtc)
632                 return NULL;
633
634         crtc = &omap_crtc->base;
635
636         init_waitqueue_head(&omap_crtc->flip_wait);
637         init_completion(&omap_crtc->completion);
638
639         omap_crtc->channel = channel;
640         omap_crtc->name = channel_names[channel];
641
642         omap_crtc->vblank_irq.irqmask = pipe2vbl(crtc);
643         omap_crtc->vblank_irq.irq = omap_crtc_vblank_irq;
644
645         omap_crtc->error_irq.irqmask =
646                         dispc_mgr_get_sync_lost_irq(channel);
647         omap_crtc->error_irq.irq = omap_crtc_error_irq;
648         omap_irq_register(dev, &omap_crtc->error_irq);
649
650         /* temporary: */
651         omap_crtc->mgr = omap_dss_get_overlay_manager(channel);
652
653         ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL,
654                                         &omap_crtc_funcs);
655         if (ret < 0) {
656                 kfree(omap_crtc);
657                 return NULL;
658         }
659
660         drm_crtc_helper_add(crtc, &omap_crtc_helper_funcs);
661
662         omap_plane_install_properties(crtc->primary, &crtc->base);
663
664         omap_crtcs[channel] = omap_crtc;
665
666         return crtc;
667 }