2 * drivers/gpu/drm/omapdrm/omap_crtc.c
4 * Copyright (C) 2011 Texas Instruments
5 * Author: Rob Clark <rob@ti.com>
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.
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
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/>.
20 #include <drm/drm_atomic.h>
21 #include <drm/drm_atomic_helper.h>
22 #include <drm/drm_crtc.h>
23 #include <drm/drm_crtc_helper.h>
24 #include <drm/drm_mode.h>
25 #include <drm/drm_plane_helper.h>
29 #define to_omap_crtc(x) container_of(x, struct omap_crtc, base)
35 enum omap_channel channel
;
39 bool ignore_digit_sync_lost
;
43 wait_queue_head_t pending_wait
;
44 struct drm_pending_vblank_event
*event
;
47 /* -----------------------------------------------------------------------------
51 struct videomode
*omap_crtc_timings(struct drm_crtc
*crtc
)
53 struct omap_crtc
*omap_crtc
= to_omap_crtc(crtc
);
54 return &omap_crtc
->vm
;
57 enum omap_channel
omap_crtc_channel(struct drm_crtc
*crtc
)
59 struct omap_crtc
*omap_crtc
= to_omap_crtc(crtc
);
60 return omap_crtc
->channel
;
63 static bool omap_crtc_is_pending(struct drm_crtc
*crtc
)
65 struct omap_crtc
*omap_crtc
= to_omap_crtc(crtc
);
69 spin_lock_irqsave(&crtc
->dev
->event_lock
, flags
);
70 pending
= omap_crtc
->pending
;
71 spin_unlock_irqrestore(&crtc
->dev
->event_lock
, flags
);
76 int omap_crtc_wait_pending(struct drm_crtc
*crtc
)
78 struct omap_crtc
*omap_crtc
= to_omap_crtc(crtc
);
81 * Timeout is set to a "sufficiently" high value, which should cover
82 * a single frame refresh even on slower displays.
84 return wait_event_timeout(omap_crtc
->pending_wait
,
85 !omap_crtc_is_pending(crtc
),
86 msecs_to_jiffies(250));
89 /* -----------------------------------------------------------------------------
90 * DSS Manager Functions
94 * Manager-ops, callbacks from output when they need to configure
95 * the upstream part of the video pipe.
97 * Most of these we can ignore until we add support for command-mode
98 * panels.. for video-mode the crtc-helpers already do an adequate
99 * job of sequencing the setup of the video pipe in the proper order
102 /* ovl-mgr-id -> crtc */
103 static struct omap_crtc
*omap_crtcs
[8];
104 static struct omap_dss_device
*omap_crtc_output
[8];
106 /* we can probably ignore these until we support command-mode panels: */
107 static int omap_crtc_dss_connect(enum omap_channel channel
,
108 struct omap_dss_device
*dst
)
110 if (omap_crtc_output
[channel
])
113 if ((dispc_mgr_get_supported_outputs(channel
) & dst
->id
) == 0)
116 omap_crtc_output
[channel
] = dst
;
117 dst
->dispc_channel_connected
= true;
122 static void omap_crtc_dss_disconnect(enum omap_channel channel
,
123 struct omap_dss_device
*dst
)
125 omap_crtc_output
[channel
] = NULL
;
126 dst
->dispc_channel_connected
= false;
129 static void omap_crtc_dss_start_update(enum omap_channel channel
)
133 /* Called only from the encoder enable/disable and suspend/resume handlers. */
134 static void omap_crtc_set_enabled(struct drm_crtc
*crtc
, bool enable
)
136 struct drm_device
*dev
= crtc
->dev
;
137 struct omap_crtc
*omap_crtc
= to_omap_crtc(crtc
);
138 enum omap_channel channel
= omap_crtc
->channel
;
139 struct omap_irq_wait
*wait
;
140 u32 framedone_irq
, vsync_irq
;
143 if (WARN_ON(omap_crtc
->enabled
== enable
))
146 if (omap_crtc_output
[channel
]->output_type
== OMAP_DISPLAY_TYPE_HDMI
) {
147 dispc_mgr_enable(channel
, enable
);
148 omap_crtc
->enabled
= enable
;
152 if (omap_crtc
->channel
== OMAP_DSS_CHANNEL_DIGIT
) {
154 * Digit output produces some sync lost interrupts during the
155 * first frame when enabling, so we need to ignore those.
157 omap_crtc
->ignore_digit_sync_lost
= true;
160 framedone_irq
= dispc_mgr_get_framedone_irq(channel
);
161 vsync_irq
= dispc_mgr_get_vsync_irq(channel
);
164 wait
= omap_irq_wait_init(dev
, vsync_irq
, 1);
167 * When we disable the digit output, we need to wait for
168 * FRAMEDONE to know that DISPC has finished with the output.
170 * OMAP2/3 does not have FRAMEDONE irq for digit output, and in
171 * that case we need to use vsync interrupt, and wait for both
172 * even and odd frames.
176 wait
= omap_irq_wait_init(dev
, framedone_irq
, 1);
178 wait
= omap_irq_wait_init(dev
, vsync_irq
, 2);
181 dispc_mgr_enable(channel
, enable
);
182 omap_crtc
->enabled
= enable
;
184 ret
= omap_irq_wait(dev
, wait
, msecs_to_jiffies(100));
186 dev_err(dev
->dev
, "%s: timeout waiting for %s\n",
187 omap_crtc
->name
, enable
? "enable" : "disable");
190 if (omap_crtc
->channel
== OMAP_DSS_CHANNEL_DIGIT
) {
191 omap_crtc
->ignore_digit_sync_lost
= false;
192 /* make sure the irq handler sees the value above */
198 static int omap_crtc_dss_enable(enum omap_channel channel
)
200 struct omap_crtc
*omap_crtc
= omap_crtcs
[channel
];
201 struct omap_overlay_manager_info info
;
203 memset(&info
, 0, sizeof(info
));
204 info
.default_color
= 0x00000000;
205 info
.trans_key
= 0x00000000;
206 info
.trans_key_type
= OMAP_DSS_COLOR_KEY_GFX_DST
;
207 info
.trans_enabled
= false;
209 dispc_mgr_setup(omap_crtc
->channel
, &info
);
210 dispc_mgr_set_timings(omap_crtc
->channel
,
212 omap_crtc_set_enabled(&omap_crtc
->base
, true);
217 static void omap_crtc_dss_disable(enum omap_channel channel
)
219 struct omap_crtc
*omap_crtc
= omap_crtcs
[channel
];
221 omap_crtc_set_enabled(&omap_crtc
->base
, false);
224 static void omap_crtc_dss_set_timings(enum omap_channel channel
,
225 const struct videomode
*vm
)
227 struct omap_crtc
*omap_crtc
= omap_crtcs
[channel
];
228 DBG("%s", omap_crtc
->name
);
232 static void omap_crtc_dss_set_lcd_config(enum omap_channel channel
,
233 const struct dss_lcd_mgr_config
*config
)
235 struct omap_crtc
*omap_crtc
= omap_crtcs
[channel
];
236 DBG("%s", omap_crtc
->name
);
237 dispc_mgr_set_lcd_config(omap_crtc
->channel
, config
);
240 static int omap_crtc_dss_register_framedone(
241 enum omap_channel channel
,
242 void (*handler
)(void *), void *data
)
247 static void omap_crtc_dss_unregister_framedone(
248 enum omap_channel channel
,
249 void (*handler
)(void *), void *data
)
253 static const struct dss_mgr_ops mgr_ops
= {
254 .connect
= omap_crtc_dss_connect
,
255 .disconnect
= omap_crtc_dss_disconnect
,
256 .start_update
= omap_crtc_dss_start_update
,
257 .enable
= omap_crtc_dss_enable
,
258 .disable
= omap_crtc_dss_disable
,
259 .set_timings
= omap_crtc_dss_set_timings
,
260 .set_lcd_config
= omap_crtc_dss_set_lcd_config
,
261 .register_framedone_handler
= omap_crtc_dss_register_framedone
,
262 .unregister_framedone_handler
= omap_crtc_dss_unregister_framedone
,
265 /* -----------------------------------------------------------------------------
266 * Setup, Flush and Page Flip
269 void omap_crtc_error_irq(struct drm_crtc
*crtc
, uint32_t irqstatus
)
271 struct omap_crtc
*omap_crtc
= to_omap_crtc(crtc
);
273 if (omap_crtc
->ignore_digit_sync_lost
) {
274 irqstatus
&= ~DISPC_IRQ_SYNC_LOST_DIGIT
;
279 DRM_ERROR_RATELIMITED("%s: errors: %08x\n", omap_crtc
->name
, irqstatus
);
282 void omap_crtc_vblank_irq(struct drm_crtc
*crtc
)
284 struct omap_crtc
*omap_crtc
= to_omap_crtc(crtc
);
287 spin_lock(&crtc
->dev
->event_lock
);
289 * If the dispc is busy we're racing the flush operation. Try again on
290 * the next vblank interrupt.
292 if (dispc_mgr_go_busy(omap_crtc
->channel
)) {
293 spin_unlock(&crtc
->dev
->event_lock
);
297 /* Send the vblank event if one has been requested. */
298 if (omap_crtc
->event
) {
299 drm_crtc_send_vblank_event(crtc
, omap_crtc
->event
);
300 omap_crtc
->event
= NULL
;
303 pending
= omap_crtc
->pending
;
304 omap_crtc
->pending
= false;
305 spin_unlock(&crtc
->dev
->event_lock
);
308 drm_crtc_vblank_put(crtc
);
310 /* Wake up omap_atomic_complete. */
311 wake_up(&omap_crtc
->pending_wait
);
313 DBG("%s: apply done", omap_crtc
->name
);
316 /* -----------------------------------------------------------------------------
320 static void omap_crtc_destroy(struct drm_crtc
*crtc
)
322 struct omap_crtc
*omap_crtc
= to_omap_crtc(crtc
);
324 DBG("%s", omap_crtc
->name
);
326 drm_crtc_cleanup(crtc
);
331 static void omap_crtc_enable(struct drm_crtc
*crtc
)
333 struct omap_crtc
*omap_crtc
= to_omap_crtc(crtc
);
336 DBG("%s", omap_crtc
->name
);
338 spin_lock_irq(&crtc
->dev
->event_lock
);
339 drm_crtc_vblank_on(crtc
);
340 ret
= drm_crtc_vblank_get(crtc
);
343 WARN_ON(omap_crtc
->pending
);
344 omap_crtc
->pending
= true;
345 spin_unlock_irq(&crtc
->dev
->event_lock
);
348 static void omap_crtc_disable(struct drm_crtc
*crtc
)
350 struct omap_crtc
*omap_crtc
= to_omap_crtc(crtc
);
352 DBG("%s", omap_crtc
->name
);
354 drm_crtc_vblank_off(crtc
);
357 static void omap_crtc_mode_set_nofb(struct drm_crtc
*crtc
)
359 struct omap_crtc
*omap_crtc
= to_omap_crtc(crtc
);
360 struct drm_display_mode
*mode
= &crtc
->state
->adjusted_mode
;
362 DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
363 omap_crtc
->name
, mode
->base
.id
, mode
->name
,
364 mode
->vrefresh
, mode
->clock
,
365 mode
->hdisplay
, mode
->hsync_start
, mode
->hsync_end
, mode
->htotal
,
366 mode
->vdisplay
, mode
->vsync_start
, mode
->vsync_end
, mode
->vtotal
,
367 mode
->type
, mode
->flags
);
369 drm_display_mode_to_videomode(mode
, &omap_crtc
->vm
);
370 omap_crtc
->vm
.flags
|= DISPLAY_FLAGS_DE_HIGH
|
371 DISPLAY_FLAGS_PIXDATA_POSEDGE
|
372 DISPLAY_FLAGS_SYNC_NEGEDGE
;
375 static int omap_crtc_atomic_check(struct drm_crtc
*crtc
,
376 struct drm_crtc_state
*state
)
378 if (state
->color_mgmt_changed
&& state
->gamma_lut
) {
379 uint length
= state
->gamma_lut
->length
/
380 sizeof(struct drm_color_lut
);
389 static void omap_crtc_atomic_begin(struct drm_crtc
*crtc
,
390 struct drm_crtc_state
*old_crtc_state
)
394 static void omap_crtc_atomic_flush(struct drm_crtc
*crtc
,
395 struct drm_crtc_state
*old_crtc_state
)
397 struct omap_crtc
*omap_crtc
= to_omap_crtc(crtc
);
400 if (crtc
->state
->color_mgmt_changed
) {
401 struct drm_color_lut
*lut
= NULL
;
404 if (crtc
->state
->gamma_lut
) {
405 lut
= (struct drm_color_lut
*)
406 crtc
->state
->gamma_lut
->data
;
407 length
= crtc
->state
->gamma_lut
->length
/
410 dispc_mgr_set_gamma(omap_crtc
->channel
, lut
, length
);
413 /* Only flush the CRTC if it is currently enabled. */
414 if (!omap_crtc
->enabled
)
417 DBG("%s: GO", omap_crtc
->name
);
419 ret
= drm_crtc_vblank_get(crtc
);
422 spin_lock_irq(&crtc
->dev
->event_lock
);
423 dispc_mgr_go(omap_crtc
->channel
);
425 WARN_ON(omap_crtc
->pending
);
426 omap_crtc
->pending
= true;
428 if (crtc
->state
->event
)
429 omap_crtc
->event
= crtc
->state
->event
;
430 spin_unlock_irq(&crtc
->dev
->event_lock
);
433 static bool omap_crtc_is_plane_prop(struct drm_crtc
*crtc
,
434 struct drm_property
*property
)
436 struct drm_device
*dev
= crtc
->dev
;
437 struct omap_drm_private
*priv
= dev
->dev_private
;
439 return property
== priv
->zorder_prop
||
440 property
== crtc
->primary
->rotation_property
;
443 static int omap_crtc_atomic_set_property(struct drm_crtc
*crtc
,
444 struct drm_crtc_state
*state
,
445 struct drm_property
*property
,
448 if (omap_crtc_is_plane_prop(crtc
, property
)) {
449 struct drm_plane_state
*plane_state
;
450 struct drm_plane
*plane
= crtc
->primary
;
453 * Delegate property set to the primary plane. Get the plane
454 * state and set the property directly.
457 plane_state
= drm_atomic_get_plane_state(state
->state
, plane
);
458 if (IS_ERR(plane_state
))
459 return PTR_ERR(plane_state
);
461 return drm_atomic_plane_set_property(plane
, plane_state
,
468 static int omap_crtc_atomic_get_property(struct drm_crtc
*crtc
,
469 const struct drm_crtc_state
*state
,
470 struct drm_property
*property
,
473 if (omap_crtc_is_plane_prop(crtc
, property
)) {
475 * Delegate property get to the primary plane. The
476 * drm_atomic_plane_get_property() function isn't exported, but
477 * can be called through drm_object_property_get_value() as that
478 * will call drm_atomic_get_property() for atomic drivers.
480 return drm_object_property_get_value(&crtc
->primary
->base
,
487 static const struct drm_crtc_funcs omap_crtc_funcs
= {
488 .reset
= drm_atomic_helper_crtc_reset
,
489 .set_config
= drm_atomic_helper_set_config
,
490 .destroy
= omap_crtc_destroy
,
491 .page_flip
= drm_atomic_helper_page_flip
,
492 .gamma_set
= drm_atomic_helper_legacy_gamma_set
,
493 .set_property
= drm_atomic_helper_crtc_set_property
,
494 .atomic_duplicate_state
= drm_atomic_helper_crtc_duplicate_state
,
495 .atomic_destroy_state
= drm_atomic_helper_crtc_destroy_state
,
496 .atomic_set_property
= omap_crtc_atomic_set_property
,
497 .atomic_get_property
= omap_crtc_atomic_get_property
,
498 .enable_vblank
= omap_irq_enable_vblank
,
499 .disable_vblank
= omap_irq_disable_vblank
,
502 static const struct drm_crtc_helper_funcs omap_crtc_helper_funcs
= {
503 .mode_set_nofb
= omap_crtc_mode_set_nofb
,
504 .disable
= omap_crtc_disable
,
505 .enable
= omap_crtc_enable
,
506 .atomic_check
= omap_crtc_atomic_check
,
507 .atomic_begin
= omap_crtc_atomic_begin
,
508 .atomic_flush
= omap_crtc_atomic_flush
,
511 /* -----------------------------------------------------------------------------
515 static const char *channel_names
[] = {
516 [OMAP_DSS_CHANNEL_LCD
] = "lcd",
517 [OMAP_DSS_CHANNEL_DIGIT
] = "tv",
518 [OMAP_DSS_CHANNEL_LCD2
] = "lcd2",
519 [OMAP_DSS_CHANNEL_LCD3
] = "lcd3",
522 void omap_crtc_pre_init(void)
524 dss_install_mgr_ops(&mgr_ops
);
527 void omap_crtc_pre_uninit(void)
529 dss_uninstall_mgr_ops();
532 /* initialize crtc */
533 struct drm_crtc
*omap_crtc_init(struct drm_device
*dev
,
534 struct drm_plane
*plane
, enum omap_channel channel
, int id
)
536 struct drm_crtc
*crtc
= NULL
;
537 struct omap_crtc
*omap_crtc
;
540 DBG("%s", channel_names
[channel
]);
542 omap_crtc
= kzalloc(sizeof(*omap_crtc
), GFP_KERNEL
);
546 crtc
= &omap_crtc
->base
;
548 init_waitqueue_head(&omap_crtc
->pending_wait
);
550 omap_crtc
->channel
= channel
;
551 omap_crtc
->name
= channel_names
[channel
];
553 ret
= drm_crtc_init_with_planes(dev
, crtc
, plane
, NULL
,
554 &omap_crtc_funcs
, NULL
);
560 drm_crtc_helper_add(crtc
, &omap_crtc_helper_funcs
);
562 /* The dispc API adapts to what ever size, but the HW supports
563 * 256 element gamma table for LCDs and 1024 element table for
564 * OMAP_DSS_CHANNEL_DIGIT. X server assumes 256 element gamma
565 * tables so lets use that. Size of HW gamma table can be
566 * extracted with dispc_mgr_gamma_size(). If it returns 0
567 * gamma table is not supprted.
569 if (dispc_mgr_gamma_size(channel
)) {
570 uint gamma_lut_size
= 256;
572 drm_crtc_enable_color_mgmt(crtc
, 0, false, gamma_lut_size
);
573 drm_mode_crtc_set_gamma_size(crtc
, gamma_lut_size
);
576 omap_plane_install_properties(crtc
->primary
, &crtc
->base
);
578 omap_crtcs
[channel
] = omap_crtc
;