]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/gpu/drm/omapdrm/omap_crtc.c
3a5e68a06af3a8e0f25ccf09c8ee1fb86cf8917c
[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 static void omap_crtc_complete_page_flip(struct drm_crtc *crtc)
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         spin_lock_irqsave(&dev->event_lock, flags);
265
266         event = omap_crtc->event;
267         omap_crtc->event = NULL;
268
269         if (event) {
270                 list_del(&event->base.link);
271
272                 /*
273                  * Queue the event for delivery if it's still linked to a file
274                  * handle, otherwise just destroy it.
275                  */
276                 if (event->base.file_priv)
277                         drm_crtc_send_vblank_event(crtc, event);
278                 else
279                         event->base.destroy(&event->base);
280
281                 wake_up(&omap_crtc->flip_wait);
282                 drm_crtc_vblank_put(crtc);
283         }
284
285         spin_unlock_irqrestore(&dev->event_lock, flags);
286 }
287
288 static bool omap_crtc_page_flip_pending(struct drm_crtc *crtc)
289 {
290         struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
291         struct drm_device *dev = crtc->dev;
292         unsigned long flags;
293         bool pending;
294
295         spin_lock_irqsave(&dev->event_lock, flags);
296         pending = omap_crtc->event != NULL;
297         spin_unlock_irqrestore(&dev->event_lock, flags);
298
299         return pending;
300 }
301
302 static void omap_crtc_wait_page_flip(struct drm_crtc *crtc)
303 {
304         struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
305
306         if (wait_event_timeout(omap_crtc->flip_wait,
307                                !omap_crtc_page_flip_pending(crtc),
308                                msecs_to_jiffies(50)))
309                 return;
310
311         dev_warn(crtc->dev->dev, "page flip timeout!\n");
312
313         omap_crtc_complete_page_flip(crtc);
314 }
315
316 static void omap_crtc_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
317 {
318         struct omap_crtc *omap_crtc =
319                         container_of(irq, struct omap_crtc, error_irq);
320
321         if (omap_crtc->ignore_digit_sync_lost) {
322                 irqstatus &= ~DISPC_IRQ_SYNC_LOST_DIGIT;
323                 if (!irqstatus)
324                         return;
325         }
326
327         DRM_ERROR_RATELIMITED("%s: errors: %08x\n", omap_crtc->name, irqstatus);
328 }
329
330 static void omap_crtc_vblank_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
331 {
332         struct omap_crtc *omap_crtc =
333                         container_of(irq, struct omap_crtc, vblank_irq);
334         struct drm_device *dev = omap_crtc->base.dev;
335
336         if (dispc_mgr_go_busy(omap_crtc->channel))
337                 return;
338
339         DBG("%s: apply done", omap_crtc->name);
340         __omap_irq_unregister(dev, &omap_crtc->vblank_irq);
341
342         /* wakeup userspace */
343         omap_crtc_complete_page_flip(&omap_crtc->base);
344
345         complete(&omap_crtc->completion);
346 }
347
348 static int omap_crtc_flush(struct drm_crtc *crtc)
349 {
350         struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
351
352         DBG("%s: GO", omap_crtc->name);
353
354         WARN_ON(omap_crtc->vblank_irq.registered);
355
356         if (dispc_mgr_is_enabled(omap_crtc->channel)) {
357                 dispc_mgr_go(omap_crtc->channel);
358                 omap_irq_register(crtc->dev, &omap_crtc->vblank_irq);
359
360                 WARN_ON(!wait_for_completion_timeout(&omap_crtc->completion,
361                                                      msecs_to_jiffies(100)));
362                 reinit_completion(&omap_crtc->completion);
363         }
364
365         return 0;
366 }
367
368 static void omap_crtc_encoder_setup(struct drm_crtc *crtc, bool enable)
369 {
370         struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
371         struct omap_drm_private *priv = crtc->dev->dev_private;
372         struct drm_encoder *encoder = NULL;
373         unsigned int i;
374
375         DBG("%s: enable=%d", omap_crtc->name, enable);
376
377         for (i = 0; i < priv->num_encoders; i++) {
378                 if (priv->encoders[i]->crtc == crtc) {
379                         encoder = priv->encoders[i];
380                         break;
381                 }
382         }
383
384         if (omap_crtc->current_encoder && encoder != omap_crtc->current_encoder)
385                 omap_encoder_set_enabled(omap_crtc->current_encoder, false);
386
387         omap_crtc->current_encoder = encoder;
388
389         if (encoder) {
390                 omap_encoder_set_enabled(encoder, false);
391                 if (enable) {
392                         omap_encoder_update(encoder, omap_crtc->mgr,
393                                             &omap_crtc->timings);
394                         omap_encoder_set_enabled(encoder, true);
395                 }
396         }
397 }
398
399 /* -----------------------------------------------------------------------------
400  * CRTC Functions
401  */
402
403 static void omap_crtc_destroy(struct drm_crtc *crtc)
404 {
405         struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
406
407         DBG("%s", omap_crtc->name);
408
409         WARN_ON(omap_crtc->vblank_irq.registered);
410         omap_irq_unregister(crtc->dev, &omap_crtc->error_irq);
411
412         drm_crtc_cleanup(crtc);
413
414         kfree(omap_crtc);
415 }
416
417 static bool omap_crtc_mode_fixup(struct drm_crtc *crtc,
418                 const struct drm_display_mode *mode,
419                 struct drm_display_mode *adjusted_mode)
420 {
421         return true;
422 }
423
424 static void omap_crtc_enable(struct drm_crtc *crtc)
425 {
426         struct omap_drm_private *priv = crtc->dev->dev_private;
427         struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
428         unsigned int i;
429
430         DBG("%s", omap_crtc->name);
431
432         /* Enable all planes associated with the CRTC. */
433         for (i = 0; i < priv->num_planes; i++) {
434                 struct drm_plane *plane = priv->planes[i];
435
436                 if (plane->crtc == crtc)
437                         WARN_ON(omap_plane_setup(plane));
438         }
439
440         omap_crtc_encoder_setup(crtc, true);
441         omap_crtc_flush(crtc);
442
443         drm_crtc_vblank_on(crtc);
444 }
445
446 static void omap_crtc_disable(struct drm_crtc *crtc)
447 {
448         struct omap_drm_private *priv = crtc->dev->dev_private;
449         struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
450         unsigned int i;
451
452         DBG("%s", omap_crtc->name);
453
454         omap_crtc_wait_page_flip(crtc);
455         drm_crtc_vblank_off(crtc);
456
457         /* Disable 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, false);
466         omap_crtc_flush(crtc);
467 }
468
469 static void omap_crtc_mode_set_nofb(struct drm_crtc *crtc)
470 {
471         struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
472         struct drm_display_mode *mode = &crtc->state->adjusted_mode;
473
474         DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
475             omap_crtc->name, mode->base.id, mode->name,
476             mode->vrefresh, mode->clock,
477             mode->hdisplay, mode->hsync_start, mode->hsync_end, mode->htotal,
478             mode->vdisplay, mode->vsync_start, mode->vsync_end, mode->vtotal,
479             mode->type, mode->flags);
480
481         copy_timings_drm_to_omap(&omap_crtc->timings, mode);
482 }
483
484 static void omap_crtc_atomic_begin(struct drm_crtc *crtc)
485 {
486         struct drm_pending_vblank_event *event = crtc->state->event;
487         struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
488         struct drm_device *dev = crtc->dev;
489         unsigned long flags;
490
491         if (event) {
492                 WARN_ON(omap_crtc->event);
493                 WARN_ON(drm_crtc_vblank_get(crtc) != 0);
494
495                 spin_lock_irqsave(&dev->event_lock, flags);
496                 omap_crtc->event = event;
497                 spin_unlock_irqrestore(&dev->event_lock, flags);
498         }
499 }
500
501 static void omap_crtc_atomic_flush(struct drm_crtc *crtc)
502 {
503         omap_crtc_flush(crtc);
504
505         crtc->invert_dimensions = !!(crtc->primary->state->rotation &
506                                     (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270)));
507 }
508
509 static int omap_crtc_atomic_set_property(struct drm_crtc *crtc,
510                                          struct drm_crtc_state *state,
511                                          struct drm_property *property,
512                                          uint64_t val)
513 {
514         struct drm_plane_state *plane_state;
515         struct drm_plane *plane = crtc->primary;
516
517         /*
518          * Delegate property set to the primary plane. Get the plane state and
519          * set the property directly.
520          */
521
522         plane_state = drm_atomic_get_plane_state(state->state, plane);
523         if (!plane_state)
524                 return -EINVAL;
525
526         return drm_atomic_plane_set_property(plane, plane_state, property, val);
527 }
528
529 static int omap_crtc_atomic_get_property(struct drm_crtc *crtc,
530                                          const struct drm_crtc_state *state,
531                                          struct drm_property *property,
532                                          uint64_t *val)
533 {
534         /*
535          * Delegate property get to the primary plane. The
536          * drm_atomic_plane_get_property() function isn't exported, but can be
537          * called through drm_object_property_get_value() as that will call
538          * drm_atomic_get_property() for atomic drivers.
539          */
540         return drm_object_property_get_value(&crtc->primary->base, property,
541                                              val);
542 }
543
544 static const struct drm_crtc_funcs omap_crtc_funcs = {
545         .reset = drm_atomic_helper_crtc_reset,
546         .set_config = drm_atomic_helper_set_config,
547         .destroy = omap_crtc_destroy,
548         .page_flip = drm_atomic_helper_page_flip,
549         .set_property = drm_atomic_helper_crtc_set_property,
550         .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
551         .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
552         .atomic_set_property = omap_crtc_atomic_set_property,
553         .atomic_get_property = omap_crtc_atomic_get_property,
554 };
555
556 static const struct drm_crtc_helper_funcs omap_crtc_helper_funcs = {
557         .mode_fixup = omap_crtc_mode_fixup,
558         .mode_set_nofb = omap_crtc_mode_set_nofb,
559         .disable = omap_crtc_disable,
560         .enable = omap_crtc_enable,
561         .atomic_begin = omap_crtc_atomic_begin,
562         .atomic_flush = omap_crtc_atomic_flush,
563 };
564
565 /* -----------------------------------------------------------------------------
566  * Init and Cleanup
567  */
568
569 static const char *channel_names[] = {
570         [OMAP_DSS_CHANNEL_LCD] = "lcd",
571         [OMAP_DSS_CHANNEL_DIGIT] = "tv",
572         [OMAP_DSS_CHANNEL_LCD2] = "lcd2",
573         [OMAP_DSS_CHANNEL_LCD3] = "lcd3",
574 };
575
576 void omap_crtc_pre_init(void)
577 {
578         dss_install_mgr_ops(&mgr_ops);
579 }
580
581 void omap_crtc_pre_uninit(void)
582 {
583         dss_uninstall_mgr_ops();
584 }
585
586 /* initialize crtc */
587 struct drm_crtc *omap_crtc_init(struct drm_device *dev,
588                 struct drm_plane *plane, enum omap_channel channel, int id)
589 {
590         struct drm_crtc *crtc = NULL;
591         struct omap_crtc *omap_crtc;
592         int ret;
593
594         DBG("%s", channel_names[channel]);
595
596         omap_crtc = kzalloc(sizeof(*omap_crtc), GFP_KERNEL);
597         if (!omap_crtc)
598                 return NULL;
599
600         crtc = &omap_crtc->base;
601
602         init_waitqueue_head(&omap_crtc->flip_wait);
603         init_completion(&omap_crtc->completion);
604
605         omap_crtc->channel = channel;
606         omap_crtc->name = channel_names[channel];
607
608         omap_crtc->vblank_irq.irqmask = pipe2vbl(crtc);
609         omap_crtc->vblank_irq.irq = omap_crtc_vblank_irq;
610
611         omap_crtc->error_irq.irqmask =
612                         dispc_mgr_get_sync_lost_irq(channel);
613         omap_crtc->error_irq.irq = omap_crtc_error_irq;
614         omap_irq_register(dev, &omap_crtc->error_irq);
615
616         /* temporary: */
617         omap_crtc->mgr = omap_dss_get_overlay_manager(channel);
618
619         ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL,
620                                         &omap_crtc_funcs);
621         if (ret < 0) {
622                 kfree(omap_crtc);
623                 return NULL;
624         }
625
626         drm_crtc_helper_add(crtc, &omap_crtc_helper_funcs);
627
628         omap_plane_install_properties(crtc->primary, &crtc->base);
629
630         omap_crtcs[channel] = omap_crtc;
631
632         return crtc;
633 }