2019-05-27 09:55:01 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2011-10-04 14:19:01 +04:00
/* exynos_drm_crtc.c
*
* Copyright ( c ) 2011 Samsung Electronics Co . , Ltd .
* Authors :
* Inki Dae < inki . dae @ samsung . com >
* Joonyoung Shim < jy0922 . shim @ samsung . com >
* Seung - Woo Kim < sw0312 . kim @ samsung . com >
*/
2015-06-01 18:04:44 +03:00
# include <drm/drm_atomic.h>
# include <drm/drm_atomic_helper.h>
2017-08-24 16:33:51 +03:00
# include <drm/drm_encoder.h>
2019-01-18 00:03:34 +03:00
# include <drm/drm_probe_helper.h>
2019-06-24 16:06:28 +03:00
# include <drm/drm_vblank.h>
2011-10-04 14:19:01 +04:00
2013-08-13 03:46:40 +04:00
# include "exynos_drm_crtc.h"
2011-10-04 14:19:01 +04:00
# include "exynos_drm_drv.h"
2012-06-27 09:27:04 +04:00
# include "exynos_drm_plane.h"
2011-10-04 14:19:01 +04:00
2017-06-30 12:36:44 +03:00
static void exynos_drm_crtc_atomic_enable ( struct drm_crtc * crtc ,
drm/atomic: Pass the full state to CRTC atomic enable/disable
If the CRTC driver ever needs to access the full DRM state, it can't do so
at atomic_enable / atomic_disable time since drm_atomic_helper_swap_state
will have cleared the pointer from the struct drm_crtc_state to the struct
drm_atomic_state before calling those hooks.
In order to allow that, let's pass the full DRM state to atomic_enable and
atomic_disable. The conversion was done using the coccinelle script below,
built tested on all the drivers and actually tested on vc4.
virtual report
@@
struct drm_crtc_helper_funcs *FUNCS;
identifier dev, state;
identifier crtc, crtc_state;
@@
disable_outputs(struct drm_device *dev, struct drm_atomic_state *state)
{
<...
- FUNCS->atomic_disable(crtc, crtc_state);
+ FUNCS->atomic_disable(crtc, state);
...>
}
@@
struct drm_crtc_helper_funcs *FUNCS;
identifier dev, state;
identifier crtc, crtc_state;
@@
drm_atomic_helper_commit_modeset_enables(struct drm_device *dev, struct drm_atomic_state *state)
{
<...
- FUNCS->atomic_enable(crtc, crtc_state);
+ FUNCS->atomic_enable(crtc, state);
...>
}
@@
identifier crtc, old_state;
@@
struct drm_crtc_helper_funcs {
...
- void (*atomic_enable)(struct drm_crtc *crtc, struct drm_crtc_state *old_state);
+ void (*atomic_enable)(struct drm_crtc *crtc, struct drm_atomic_state *state);
...
- void (*atomic_disable)(struct drm_crtc *crtc, struct drm_crtc_state *old_state);
+ void (*atomic_disable)(struct drm_crtc *crtc, struct drm_atomic_state *state);
...
}
@ crtc_atomic_func @
identifier helpers;
identifier func;
@@
(
static struct drm_crtc_helper_funcs helpers = {
...,
.atomic_enable = func,
...,
};
|
static struct drm_crtc_helper_funcs helpers = {
...,
.atomic_disable = func,
...,
};
)
@ ignores_old_state @
identifier crtc_atomic_func.func;
identifier crtc, old_state;
@@
void func(struct drm_crtc *crtc,
struct drm_crtc_state *old_state)
{
... when != old_state
}
@ adds_old_state depends on crtc_atomic_func && !ignores_old_state @
identifier crtc_atomic_func.func;
identifier crtc, old_state;
@@
void func(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
{
+ struct drm_crtc_state *old_state = drm_atomic_get_old_crtc_state(state, crtc);
...
}
@ depends on crtc_atomic_func @
identifier crtc_atomic_func.func;
expression E;
type T;
@@
void func(...)
{
...
- T state = E;
+ T crtc_state = E;
<+...
- state
+ crtc_state
...+>
}
@ depends on crtc_atomic_func @
identifier crtc_atomic_func.func;
type T;
@@
void func(...)
{
...
- T state;
+ T crtc_state;
<+...
- state
+ crtc_state
...+>
}
@ depends on crtc_atomic_func @
identifier crtc_atomic_func.func;
identifier old_state;
identifier crtc;
@@
void func(struct drm_crtc *crtc,
- struct drm_crtc_state *old_state
+ struct drm_atomic_state *state
)
{ ... }
@ include depends on adds_old_state @
@@
#include <drm/drm_atomic.h>
@ no_include depends on !include && adds_old_state @
@@
+ #include <drm/drm_atomic.h>
#include <drm/...>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: https://patchwork.freedesktop.org/patch/msgid/845aa10ef171fc0ea060495efef142a0c13f7870.1602161031.git-series.maxime@cerno.tech
2020-10-08 15:44:08 +03:00
struct drm_atomic_state * state )
2011-10-04 14:19:01 +04:00
{
2011-11-04 12:04:45 +04:00
struct exynos_drm_crtc * exynos_crtc = to_exynos_crtc ( crtc ) ;
2011-10-04 14:19:01 +04:00
2019-12-19 05:07:53 +03:00
if ( exynos_crtc - > ops - > atomic_enable )
exynos_crtc - > ops - > atomic_enable ( exynos_crtc ) ;
2014-02-19 16:02:55 +04:00
2015-06-01 18:04:53 +03:00
drm_crtc_vblank_on ( crtc ) ;
2011-10-04 14:19:01 +04:00
}
2017-06-30 12:36:45 +03:00
static void exynos_drm_crtc_atomic_disable ( struct drm_crtc * crtc ,
drm/atomic: Pass the full state to CRTC atomic enable/disable
If the CRTC driver ever needs to access the full DRM state, it can't do so
at atomic_enable / atomic_disable time since drm_atomic_helper_swap_state
will have cleared the pointer from the struct drm_crtc_state to the struct
drm_atomic_state before calling those hooks.
In order to allow that, let's pass the full DRM state to atomic_enable and
atomic_disable. The conversion was done using the coccinelle script below,
built tested on all the drivers and actually tested on vc4.
virtual report
@@
struct drm_crtc_helper_funcs *FUNCS;
identifier dev, state;
identifier crtc, crtc_state;
@@
disable_outputs(struct drm_device *dev, struct drm_atomic_state *state)
{
<...
- FUNCS->atomic_disable(crtc, crtc_state);
+ FUNCS->atomic_disable(crtc, state);
...>
}
@@
struct drm_crtc_helper_funcs *FUNCS;
identifier dev, state;
identifier crtc, crtc_state;
@@
drm_atomic_helper_commit_modeset_enables(struct drm_device *dev, struct drm_atomic_state *state)
{
<...
- FUNCS->atomic_enable(crtc, crtc_state);
+ FUNCS->atomic_enable(crtc, state);
...>
}
@@
identifier crtc, old_state;
@@
struct drm_crtc_helper_funcs {
...
- void (*atomic_enable)(struct drm_crtc *crtc, struct drm_crtc_state *old_state);
+ void (*atomic_enable)(struct drm_crtc *crtc, struct drm_atomic_state *state);
...
- void (*atomic_disable)(struct drm_crtc *crtc, struct drm_crtc_state *old_state);
+ void (*atomic_disable)(struct drm_crtc *crtc, struct drm_atomic_state *state);
...
}
@ crtc_atomic_func @
identifier helpers;
identifier func;
@@
(
static struct drm_crtc_helper_funcs helpers = {
...,
.atomic_enable = func,
...,
};
|
static struct drm_crtc_helper_funcs helpers = {
...,
.atomic_disable = func,
...,
};
)
@ ignores_old_state @
identifier crtc_atomic_func.func;
identifier crtc, old_state;
@@
void func(struct drm_crtc *crtc,
struct drm_crtc_state *old_state)
{
... when != old_state
}
@ adds_old_state depends on crtc_atomic_func && !ignores_old_state @
identifier crtc_atomic_func.func;
identifier crtc, old_state;
@@
void func(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
{
+ struct drm_crtc_state *old_state = drm_atomic_get_old_crtc_state(state, crtc);
...
}
@ depends on crtc_atomic_func @
identifier crtc_atomic_func.func;
expression E;
type T;
@@
void func(...)
{
...
- T state = E;
+ T crtc_state = E;
<+...
- state
+ crtc_state
...+>
}
@ depends on crtc_atomic_func @
identifier crtc_atomic_func.func;
type T;
@@
void func(...)
{
...
- T state;
+ T crtc_state;
<+...
- state
+ crtc_state
...+>
}
@ depends on crtc_atomic_func @
identifier crtc_atomic_func.func;
identifier old_state;
identifier crtc;
@@
void func(struct drm_crtc *crtc,
- struct drm_crtc_state *old_state
+ struct drm_atomic_state *state
)
{ ... }
@ include depends on adds_old_state @
@@
#include <drm/drm_atomic.h>
@ no_include depends on !include && adds_old_state @
@@
+ #include <drm/drm_atomic.h>
#include <drm/...>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: https://patchwork.freedesktop.org/patch/msgid/845aa10ef171fc0ea060495efef142a0c13f7870.1602161031.git-series.maxime@cerno.tech
2020-10-08 15:44:08 +03:00
struct drm_atomic_state * state )
2015-06-01 18:04:51 +03:00
{
2015-06-01 18:04:53 +03:00
struct exynos_drm_crtc * exynos_crtc = to_exynos_crtc ( crtc ) ;
2015-06-01 18:04:51 +03:00
2015-06-01 18:04:53 +03:00
drm_crtc_vblank_off ( crtc ) ;
2019-12-19 05:07:53 +03:00
if ( exynos_crtc - > ops - > atomic_disable )
exynos_crtc - > ops - > atomic_disable ( exynos_crtc ) ;
2017-01-20 06:51:41 +03:00
if ( crtc - > state - > event & & ! crtc - > state - > active ) {
spin_lock_irq ( & crtc - > dev - > event_lock ) ;
drm_crtc_send_vblank_event ( crtc , crtc - > state - > event ) ;
spin_unlock_irq ( & crtc - > dev - > event_lock ) ;
crtc - > state - > event = NULL ;
}
2015-06-01 18:04:51 +03:00
}
2015-10-26 15:03:39 +03:00
static int exynos_crtc_atomic_check ( struct drm_crtc * crtc ,
struct drm_crtc_state * state )
{
struct exynos_drm_crtc * exynos_crtc = to_exynos_crtc ( crtc ) ;
2015-11-27 09:57:31 +03:00
if ( ! state - > enable )
return 0 ;
2015-10-26 15:03:39 +03:00
if ( exynos_crtc - > ops - > atomic_check )
return exynos_crtc - > ops - > atomic_check ( exynos_crtc , state ) ;
return 0 ;
}
2015-07-21 14:28:58 +03:00
static void exynos_crtc_atomic_begin ( struct drm_crtc * crtc ,
struct drm_crtc_state * old_crtc_state )
2015-06-01 18:04:48 +03:00
{
struct exynos_drm_crtc * exynos_crtc = to_exynos_crtc ( crtc ) ;
2016-01-05 15:52:51 +03:00
if ( exynos_crtc - > ops - > atomic_begin )
exynos_crtc - > ops - > atomic_begin ( exynos_crtc ) ;
2015-06-01 18:04:48 +03:00
}
2015-07-21 14:28:58 +03:00
static void exynos_crtc_atomic_flush ( struct drm_crtc * crtc ,
struct drm_crtc_state * old_crtc_state )
2015-06-01 18:04:48 +03:00
{
2015-08-24 14:36:59 +03:00
struct exynos_drm_crtc * exynos_crtc = to_exynos_crtc ( crtc ) ;
2016-01-05 15:52:51 +03:00
if ( exynos_crtc - > ops - > atomic_flush )
exynos_crtc - > ops - > atomic_flush ( exynos_crtc ) ;
2017-03-14 11:27:56 +03:00
}
2017-08-24 16:33:56 +03:00
static enum drm_mode_status exynos_crtc_mode_valid ( struct drm_crtc * crtc ,
const struct drm_display_mode * mode )
{
struct exynos_drm_crtc * exynos_crtc = to_exynos_crtc ( crtc ) ;
if ( exynos_crtc - > ops - > mode_valid )
return exynos_crtc - > ops - > mode_valid ( exynos_crtc , mode ) ;
return MODE_OK ;
}
2017-09-29 13:05:38 +03:00
static bool exynos_crtc_mode_fixup ( struct drm_crtc * crtc ,
const struct drm_display_mode * mode ,
struct drm_display_mode * adjusted_mode )
{
struct exynos_drm_crtc * exynos_crtc = to_exynos_crtc ( crtc ) ;
if ( exynos_crtc - > ops - > mode_fixup )
return exynos_crtc - > ops - > mode_fixup ( exynos_crtc , mode ,
adjusted_mode ) ;
return true ;
}
2017-03-14 11:27:56 +03:00
static const struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = {
2017-08-24 16:33:56 +03:00
. mode_valid = exynos_crtc_mode_valid ,
2017-09-29 13:05:38 +03:00
. mode_fixup = exynos_crtc_mode_fixup ,
2017-03-14 11:27:56 +03:00
. atomic_check = exynos_crtc_atomic_check ,
. atomic_begin = exynos_crtc_atomic_begin ,
. atomic_flush = exynos_crtc_atomic_flush ,
2017-06-30 12:36:44 +03:00
. atomic_enable = exynos_drm_crtc_atomic_enable ,
2017-06-30 12:36:45 +03:00
. atomic_disable = exynos_drm_crtc_atomic_disable ,
2017-03-14 11:27:56 +03:00
} ;
void exynos_crtc_handle_event ( struct exynos_drm_crtc * exynos_crtc )
{
struct drm_crtc * crtc = & exynos_crtc - > base ;
struct drm_pending_vblank_event * event = crtc - > state - > event ;
unsigned long flags ;
2016-09-23 16:21:38 +03:00
2017-03-15 17:41:01 +03:00
if ( ! event )
return ;
crtc - > state - > event = NULL ;
WARN_ON ( drm_crtc_vblank_get ( crtc ) ! = 0 ) ;
2016-09-23 16:21:38 +03:00
2017-03-15 17:41:01 +03:00
spin_lock_irqsave ( & crtc - > dev - > event_lock , flags ) ;
drm_crtc_arm_vblank_event ( crtc , event ) ;
spin_unlock_irqrestore ( & crtc - > dev - > event_lock , flags ) ;
2015-06-01 18:04:48 +03:00
}
2011-10-04 14:19:01 +04:00
static void exynos_drm_crtc_destroy ( struct drm_crtc * crtc )
{
struct exynos_drm_crtc * exynos_crtc = to_exynos_crtc ( crtc ) ;
drm_crtc_cleanup ( crtc ) ;
kfree ( exynos_crtc ) ;
}
2017-02-07 12:16:20 +03:00
static int exynos_drm_crtc_enable_vblank ( struct drm_crtc * crtc )
{
struct exynos_drm_crtc * exynos_crtc = to_exynos_crtc ( crtc ) ;
if ( exynos_crtc - > ops - > enable_vblank )
return exynos_crtc - > ops - > enable_vblank ( exynos_crtc ) ;
return 0 ;
}
static void exynos_drm_crtc_disable_vblank ( struct drm_crtc * crtc )
{
struct exynos_drm_crtc * exynos_crtc = to_exynos_crtc ( crtc ) ;
if ( exynos_crtc - > ops - > disable_vblank )
exynos_crtc - > ops - > disable_vblank ( exynos_crtc ) ;
}
2015-12-15 14:21:06 +03:00
static const struct drm_crtc_funcs exynos_crtc_funcs = {
2015-06-01 18:04:47 +03:00
. set_config = drm_atomic_helper_set_config ,
2015-06-01 18:04:48 +03:00
. page_flip = drm_atomic_helper_page_flip ,
2011-10-04 14:19:01 +04:00
. destroy = exynos_drm_crtc_destroy ,
2015-06-01 18:04:44 +03:00
. reset = drm_atomic_helper_crtc_reset ,
. atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state ,
. atomic_destroy_state = drm_atomic_helper_crtc_destroy_state ,
2017-02-07 12:16:20 +03:00
. enable_vblank = exynos_drm_crtc_enable_vblank ,
. disable_vblank = exynos_drm_crtc_disable_vblank ,
2011-10-04 14:19:01 +04:00
} ;
2015-01-18 12:16:23 +03:00
struct exynos_drm_crtc * exynos_drm_crtc_create ( struct drm_device * drm_dev ,
2015-05-07 03:04:45 +03:00
struct drm_plane * plane ,
enum exynos_drm_output_type type ,
const struct exynos_drm_crtc_ops * ops ,
void * ctx )
2011-10-04 14:19:01 +04:00
{
struct exynos_drm_crtc * exynos_crtc ;
struct drm_crtc * crtc ;
2014-09-19 16:58:53 +04:00
int ret ;
2011-10-04 14:19:01 +04:00
exynos_crtc = kzalloc ( sizeof ( * exynos_crtc ) , GFP_KERNEL ) ;
2013-08-19 14:04:55 +04:00
if ( ! exynos_crtc )
2015-01-18 12:16:23 +03:00
return ERR_PTR ( - ENOMEM ) ;
2011-10-04 14:19:01 +04:00
2014-11-06 00:51:35 +03:00
exynos_crtc - > type = type ;
2015-01-18 12:16:23 +03:00
exynos_crtc - > ops = ops ;
exynos_crtc - > ctx = ctx ;
2012-06-27 09:27:04 +04:00
2014-11-03 23:20:29 +03:00
crtc = & exynos_crtc - > base ;
2011-10-04 14:19:01 +04:00
2014-11-26 21:43:27 +03:00
ret = drm_crtc_init_with_planes ( drm_dev , crtc , plane , NULL ,
drm: Pass 'name' to drm_crtc_init_with_planes()
Done with coccinelle for the most part. However, it thinks '...' is
part of the semantic patch, so I put an 'int DOTDOTDOT' placeholder
in its place and got rid of it with sed afterwards.
I didn't convert drm_crtc_init() since passing the varargs through
would mean either cpp macros or va_list, and I figured we don't
care about these legacy functions enough to warrant the extra pain.
@@
identifier dev, crtc, primary, cursor, funcs;
@@
int drm_crtc_init_with_planes(struct drm_device *dev,
struct drm_crtc *crtc,
struct drm_plane *primary, struct drm_plane *cursor,
const struct drm_crtc_funcs *funcs
+ ,const char *name, int DOTDOTDOT
)
{ ... }
@@
identifier dev, crtc, primary, cursor, funcs;
@@
int drm_crtc_init_with_planes(struct drm_device *dev,
struct drm_crtc *crtc,
struct drm_plane *primary, struct drm_plane *cursor,
const struct drm_crtc_funcs *funcs
+ ,const char *name, int DOTDOTDOT
);
@@
expression E1, E2, E3, E4, E5;
@@
drm_crtc_init_with_planes(E1, E2, E3, E4, E5
+ ,NULL
)
v2: Split crtc and plane changes apart
Pass NULL for no-name instead of ""
Leave drm_crtc_init() alone
v3: Add ', or NULL...' to @name kernel doc (Jani)
Annotate the function with __printf() attribute (Jani)
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/1449670771-2751-1-git-send-email-ville.syrjala@linux.intel.com
2015-12-09 17:19:31 +03:00
& exynos_crtc_funcs , NULL ) ;
2014-09-19 16:58:53 +04:00
if ( ret < 0 )
goto err_crtc ;
2011-10-04 14:19:01 +04:00
drm_crtc_helper_add ( crtc , & exynos_crtc_helper_funcs ) ;
2015-01-18 12:16:23 +03:00
return exynos_crtc ;
2014-09-19 16:58:53 +04:00
err_crtc :
plane - > funcs - > destroy ( plane ) ;
kfree ( exynos_crtc ) ;
2015-01-18 12:16:23 +03:00
return ERR_PTR ( ret ) ;
2011-10-04 14:19:01 +04:00
}
2017-08-24 16:33:51 +03:00
struct exynos_drm_crtc * exynos_drm_crtc_get_by_type ( struct drm_device * drm_dev ,
2015-08-11 11:38:06 +03:00
enum exynos_drm_output_type out_type )
2014-05-09 09:25:20 +04:00
{
struct drm_crtc * crtc ;
2017-05-29 04:05:25 +03:00
drm_for_each_crtc ( crtc , drm_dev )
if ( to_exynos_crtc ( crtc ) - > type = = out_type )
2017-08-24 16:33:51 +03:00
return to_exynos_crtc ( crtc ) ;
2014-05-09 09:25:20 +04:00
2017-12-12 15:01:15 +03:00
return ERR_PTR ( - ENODEV ) ;
2017-08-24 16:33:51 +03:00
}
int exynos_drm_set_possible_crtcs ( struct drm_encoder * encoder ,
enum exynos_drm_output_type out_type )
{
struct exynos_drm_crtc * crtc = exynos_drm_crtc_get_by_type ( encoder - > dev ,
out_type ) ;
if ( IS_ERR ( crtc ) )
return PTR_ERR ( crtc ) ;
encoder - > possible_crtcs = drm_crtc_mask ( & crtc - > base ) ;
return 0 ;
2014-05-09 09:25:20 +04:00
}
2014-07-17 13:01:19 +04:00
void exynos_drm_crtc_te_handler ( struct drm_crtc * crtc )
{
2015-01-18 12:16:23 +03:00
struct exynos_drm_crtc * exynos_crtc = to_exynos_crtc ( crtc ) ;
2014-07-17 13:01:19 +04:00
2015-01-18 12:16:23 +03:00
if ( exynos_crtc - > ops - > te_handler )
exynos_crtc - > ops - > te_handler ( exynos_crtc ) ;
2014-07-17 13:01:19 +04:00
}