2018-09-28 16:13:25 -03:00
// SPDX-License-Identifier: GPL-2.0+
2012-09-21 10:07:50 +02:00
/*
* i . MX IPUv3 Graphics driver
*
* Copyright ( C ) 2011 Sascha Hauer , Pengutronix
*/
2019-07-16 08:42:18 +02:00
2019-01-17 22:03:34 +01:00
# include <linux/clk.h>
2013-11-03 11:23:34 +00:00
# include <linux/component.h>
2012-09-21 10:07:50 +02:00
# include <linux/device.h>
2019-07-16 08:42:18 +02:00
# include <linux/dma-mapping.h>
2019-01-17 22:03:34 +01:00
# include <linux/errno.h>
# include <linux/export.h>
# include <linux/module.h>
2012-09-21 10:07:50 +02:00
# include <linux/platform_device.h>
2019-07-16 08:42:18 +02:00
# include <video/imx-ipu-v3.h>
2016-07-08 17:40:57 +08:00
# include <drm/drm_atomic.h>
2016-07-08 17:40:56 +08:00
# include <drm/drm_atomic_helper.h>
2012-09-21 10:07:50 +02:00
# include <drm/drm_fb_cma_helper.h>
2019-01-17 22:03:34 +01:00
# include <drm/drm_gem_cma_helper.h>
2020-12-10 16:38:45 +01:00
# include <drm/drm_managed.h>
2019-01-17 22:03:34 +01:00
# include <drm/drm_probe_helper.h>
2019-07-16 08:42:18 +02:00
# include <drm/drm_vblank.h>
2012-09-21 10:07:50 +02:00
# include "imx-drm.h"
2013-10-10 16:18:45 +02:00
# include "ipuv3-plane.h"
2012-09-21 10:07:50 +02:00
# define DRIVER_DESC "i.MX IPUv3 Graphics"
struct ipu_crtc {
struct device * dev ;
struct drm_crtc base ;
2013-10-10 16:18:45 +02:00
/* plane[0] is the full plane, plane[1] is the partial plane */
struct ipu_plane * plane [ 2 ] ;
2012-09-21 10:07:50 +02:00
struct ipu_dc * dc ;
struct ipu_di * di ;
int irq ;
2018-09-11 16:03:16 +02:00
struct drm_pending_vblank_event * event ;
2012-09-21 10:07:50 +02:00
} ;
2016-07-06 15:47:11 +02:00
static inline struct ipu_crtc * to_ipu_crtc ( struct drm_crtc * crtc )
{
return container_of ( crtc , struct ipu_crtc , base ) ;
}
2012-09-21 10:07:50 +02:00
2017-06-30 12:36:44 +03:00
static void ipu_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 14:44:08 +02:00
struct drm_atomic_state * state )
2012-09-21 10:07:50 +02:00
{
2016-07-08 17:41:01 +08:00
struct ipu_crtc * ipu_crtc = to_ipu_crtc ( crtc ) ;
2014-04-14 23:53:23 +02:00
struct ipu_soc * ipu = dev_get_drvdata ( ipu_crtc - > dev - > parent ) ;
2017-03-08 12:13:20 +01:00
ipu_prg_enable ( ipu ) ;
2014-04-14 23:53:23 +02:00
ipu_dc_enable ( ipu ) ;
2014-04-14 23:53:22 +02:00
ipu_dc_enable_channel ( ipu_crtc - > dc ) ;
ipu_di_enable ( ipu_crtc - > di ) ;
2012-09-21 10:07:50 +02:00
}
2017-02-24 18:31:05 +01:00
static void ipu_crtc_disable_planes ( struct ipu_crtc * ipu_crtc ,
struct drm_crtc_state * old_crtc_state )
{
bool disable_partial = false ;
bool disable_full = false ;
struct drm_plane * plane ;
drm_atomic_crtc_state_for_each_plane ( plane , old_crtc_state ) {
if ( plane = = & ipu_crtc - > plane [ 0 ] - > base )
disable_full = true ;
if ( & ipu_crtc - > plane [ 1 ] & & plane = = & ipu_crtc - > plane [ 1 ] - > base )
disable_partial = true ;
}
if ( disable_partial )
ipu_plane_disable ( ipu_crtc - > plane [ 1 ] , true ) ;
if ( disable_full )
2019-04-12 17:59:41 +02:00
ipu_plane_disable ( ipu_crtc - > plane [ 0 ] , true ) ;
2017-02-24 18:31:05 +01:00
}
2016-08-26 15:30:42 +08:00
static void ipu_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 14:44:08 +02:00
struct drm_atomic_state * state )
2012-09-21 10:07:50 +02:00
{
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 14:44:08 +02:00
struct drm_crtc_state * old_crtc_state = drm_atomic_get_old_crtc_state ( state ,
crtc ) ;
2016-07-08 17:41:01 +08:00
struct ipu_crtc * ipu_crtc = to_ipu_crtc ( crtc ) ;
2014-04-14 23:53:23 +02:00
struct ipu_soc * ipu = dev_get_drvdata ( ipu_crtc - > dev - > parent ) ;
2012-09-21 10:07:50 +02:00
ipu_dc_disable_channel ( ipu_crtc - > dc ) ;
ipu_di_disable ( ipu_crtc - > di ) ;
2016-11-08 17:04:10 +01:00
/*
* Planes must be disabled before DC clock is removed , as otherwise the
* attached IDMACs will be left in undefined state , possibly hanging
* the IPU or even system .
*/
2017-02-24 18:31:05 +01:00
ipu_crtc_disable_planes ( ipu_crtc , old_crtc_state ) ;
2014-04-14 23:53:23 +02:00
ipu_dc_disable ( ipu ) ;
2017-03-08 12:13:20 +01:00
ipu_prg_disable ( ipu ) ;
2016-07-08 17:40:55 +08:00
2019-06-25 18:59:13 +01:00
drm_crtc_vblank_off ( crtc ) ;
2016-07-08 17:40:59 +08:00
spin_lock_irq ( & crtc - > dev - > event_lock ) ;
2019-06-25 18:59:15 +01:00
if ( crtc - > state - > event & & ! crtc - > state - > active ) {
2016-07-08 17:40:59 +08:00
drm_crtc_send_vblank_event ( crtc , crtc - > state - > event ) ;
crtc - > state - > event = NULL ;
}
spin_unlock_irq ( & crtc - > dev - > event_lock ) ;
2012-09-21 10:07:50 +02:00
}
2016-07-06 14:49:24 +02:00
static void imx_drm_crtc_reset ( struct drm_crtc * crtc )
{
struct imx_crtc_state * state ;
2020-06-12 18:00:51 +02:00
if ( crtc - > state )
__drm_atomic_helper_crtc_destroy_state ( crtc - > state ) ;
2016-07-06 14:49:24 +02:00
2020-06-12 18:00:51 +02:00
kfree ( to_imx_crtc_state ( crtc - > state ) ) ;
crtc - > state = NULL ;
state = kzalloc ( sizeof ( * state ) , GFP_KERNEL ) ;
if ( state )
__drm_atomic_helper_crtc_reset ( crtc , & state - > base ) ;
2016-07-06 14:49:24 +02:00
}
static struct drm_crtc_state * imx_drm_crtc_duplicate_state ( struct drm_crtc * crtc )
{
struct imx_crtc_state * state ;
state = kzalloc ( sizeof ( * state ) , GFP_KERNEL ) ;
if ( ! state )
return NULL ;
__drm_atomic_helper_crtc_duplicate_state ( crtc , & state - > base ) ;
WARN_ON ( state - > base . crtc ! = crtc ) ;
state - > base . crtc = crtc ;
return & state - > base ;
}
static void imx_drm_crtc_destroy_state ( struct drm_crtc * crtc ,
struct drm_crtc_state * state )
{
__drm_atomic_helper_crtc_destroy_state ( state ) ;
kfree ( to_imx_crtc_state ( state ) ) ;
}
2017-02-07 17:16:24 +08:00
static int ipu_enable_vblank ( struct drm_crtc * crtc )
{
struct ipu_crtc * ipu_crtc = to_ipu_crtc ( crtc ) ;
enable_irq ( ipu_crtc - > irq ) ;
return 0 ;
}
static void ipu_disable_vblank ( struct drm_crtc * crtc )
2016-08-11 11:18:49 +02:00
{
2017-02-07 17:16:24 +08:00
struct ipu_crtc * ipu_crtc = to_ipu_crtc ( crtc ) ;
disable_irq_nosync ( ipu_crtc - > irq ) ;
2016-08-11 11:18:49 +02:00
}
2012-09-21 10:07:50 +02:00
static const struct drm_crtc_funcs ipu_crtc_funcs = {
2016-07-08 17:40:59 +08:00
. set_config = drm_atomic_helper_set_config ,
. page_flip = drm_atomic_helper_page_flip ,
2016-07-06 14:49:24 +02:00
. reset = imx_drm_crtc_reset ,
. atomic_duplicate_state = imx_drm_crtc_duplicate_state ,
. atomic_destroy_state = imx_drm_crtc_destroy_state ,
2017-02-07 17:16:24 +08:00
. enable_vblank = ipu_enable_vblank ,
. disable_vblank = ipu_disable_vblank ,
2012-09-21 10:07:50 +02:00
} ;
static irqreturn_t ipu_irq_handler ( int irq , void * dev_id )
{
struct ipu_crtc * ipu_crtc = dev_id ;
2018-09-11 16:03:16 +02:00
struct drm_crtc * crtc = & ipu_crtc - > base ;
unsigned long flags ;
int i ;
drm_crtc_handle_vblank ( crtc ) ;
if ( ipu_crtc - > event ) {
for ( i = 0 ; i < ARRAY_SIZE ( ipu_crtc - > plane ) ; i + + ) {
struct ipu_plane * plane = ipu_crtc - > plane [ i ] ;
if ( ! plane )
continue ;
if ( ipu_plane_atomic_update_pending ( & plane - > base ) )
break ;
}
if ( i = = ARRAY_SIZE ( ipu_crtc - > plane ) ) {
spin_lock_irqsave ( & crtc - > dev - > event_lock , flags ) ;
drm_crtc_send_vblank_event ( crtc , ipu_crtc - > event ) ;
ipu_crtc - > event = NULL ;
drm_crtc_vblank_put ( crtc ) ;
spin_unlock_irqrestore ( & crtc - > dev - > event_lock , flags ) ;
}
}
2012-09-21 10:07:50 +02:00
return IRQ_HANDLED ;
}
static bool ipu_crtc_mode_fixup ( struct drm_crtc * crtc ,
const struct drm_display_mode * mode ,
struct drm_display_mode * adjusted_mode )
{
2014-12-18 18:00:23 -08:00
struct ipu_crtc * ipu_crtc = to_ipu_crtc ( crtc ) ;
struct videomode vm ;
int ret ;
drm_display_mode_to_videomode ( adjusted_mode , & vm ) ;
ret = ipu_di_adjust_videomode ( ipu_crtc - > di , & vm ) ;
if ( ret )
return false ;
2016-07-08 17:40:55 +08:00
if ( ( vm . vsync_len = = 0 ) | | ( vm . hsync_len = = 0 ) )
return false ;
2014-12-18 18:00:23 -08:00
drm_display_mode_from_videomode ( & vm , adjusted_mode ) ;
2012-09-21 10:07:50 +02:00
return true ;
}
2016-07-08 17:40:55 +08:00
static int ipu_crtc_atomic_check ( struct drm_crtc * crtc ,
drm/atomic: Pass the full state to CRTC atomic_check
The current atomic helpers have either their object state being passed as
an argument or the full atomic state.
The former is the pattern that was done at first, before switching to the
latter for new hooks or when it was needed.
Let's start convert all the remaining helpers to provide a consistent
interface, starting with the CRTC's atomic_check.
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;
struct drm_crtc *crtc;
struct drm_crtc_state *crtc_state;
identifier dev, state;
identifier ret, f;
@@
f(struct drm_device *dev, struct drm_atomic_state *state)
{
<...
- ret = FUNCS->atomic_check(crtc, crtc_state);
+ ret = FUNCS->atomic_check(crtc, state);
...>
}
@@
identifier crtc, new_state;
@@
struct drm_crtc_helper_funcs {
...
- int (*atomic_check)(struct drm_crtc *crtc, struct drm_crtc_state *new_state);
+ int (*atomic_check)(struct drm_crtc *crtc, struct drm_atomic_state *state);
...
}
@ crtc_atomic_func @
identifier helpers;
identifier func;
@@
static struct drm_crtc_helper_funcs helpers = {
...,
.atomic_check = func,
...,
};
@ ignores_new_state @
identifier crtc_atomic_func.func;
identifier crtc, new_state;
@@
int func(struct drm_crtc *crtc,
struct drm_crtc_state *new_state)
{
... when != new_state
}
@ adds_new_state depends on crtc_atomic_func && !ignores_new_state @
identifier crtc_atomic_func.func;
identifier crtc, new_state;
@@
int func(struct drm_crtc *crtc, struct drm_crtc_state *new_state)
{
+ struct drm_crtc_state *new_state = drm_atomic_get_new_crtc_state(state, crtc);
...
}
@ depends on crtc_atomic_func @
identifier crtc_atomic_func.func;
expression E;
type T;
@@
int func(...)
{
...
- T state = E;
+ T crtc_state = E;
<+...
- state
+ crtc_state
...+>
}
@ depends on crtc_atomic_func @
identifier crtc_atomic_func.func;
type T;
@@
int func(...)
{
...
- T state;
+ T crtc_state;
<+...
- state
+ crtc_state
...+>
}
@ depends on crtc_atomic_func @
identifier crtc_atomic_func.func;
identifier new_state;
identifier crtc;
@@
int func(struct drm_crtc *crtc,
- struct drm_crtc_state *new_state
+ struct drm_atomic_state *state
)
{ ... }
@@
identifier new_state;
identifier crtc;
@@
int vmw_du_crtc_atomic_check(struct drm_crtc *crtc,
- struct drm_crtc_state *new_state
+ struct drm_atomic_state *state
)
{
+ struct drm_crtc_state *new_state = drm_atomic_get_new_crtc_state(state, crtc);
...
}
@@
identifier new_state;
identifier crtc;
@@
int vmw_du_crtc_atomic_check(struct drm_crtc *crtc,
- struct drm_crtc_state *new_state
+ struct drm_atomic_state *state
);
@ include depends on adds_new_state @
@@
#include <drm/drm_atomic.h>
@ no_include depends on !include && adds_new_state @
@@
+ #include <drm/drm_atomic.h>
#include <drm/...>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Acked-by: Thomas Zimmermann <tzimmermann@suse.de>
Link: https://patchwork.freedesktop.org/patch/msgid/20201028123222.1732139-1-maxime@cerno.tech
2020-10-28 13:32:21 +01:00
struct drm_atomic_state * state )
2016-07-08 17:40:55 +08:00
{
drm/atomic: Pass the full state to CRTC atomic_check
The current atomic helpers have either their object state being passed as
an argument or the full atomic state.
The former is the pattern that was done at first, before switching to the
latter for new hooks or when it was needed.
Let's start convert all the remaining helpers to provide a consistent
interface, starting with the CRTC's atomic_check.
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;
struct drm_crtc *crtc;
struct drm_crtc_state *crtc_state;
identifier dev, state;
identifier ret, f;
@@
f(struct drm_device *dev, struct drm_atomic_state *state)
{
<...
- ret = FUNCS->atomic_check(crtc, crtc_state);
+ ret = FUNCS->atomic_check(crtc, state);
...>
}
@@
identifier crtc, new_state;
@@
struct drm_crtc_helper_funcs {
...
- int (*atomic_check)(struct drm_crtc *crtc, struct drm_crtc_state *new_state);
+ int (*atomic_check)(struct drm_crtc *crtc, struct drm_atomic_state *state);
...
}
@ crtc_atomic_func @
identifier helpers;
identifier func;
@@
static struct drm_crtc_helper_funcs helpers = {
...,
.atomic_check = func,
...,
};
@ ignores_new_state @
identifier crtc_atomic_func.func;
identifier crtc, new_state;
@@
int func(struct drm_crtc *crtc,
struct drm_crtc_state *new_state)
{
... when != new_state
}
@ adds_new_state depends on crtc_atomic_func && !ignores_new_state @
identifier crtc_atomic_func.func;
identifier crtc, new_state;
@@
int func(struct drm_crtc *crtc, struct drm_crtc_state *new_state)
{
+ struct drm_crtc_state *new_state = drm_atomic_get_new_crtc_state(state, crtc);
...
}
@ depends on crtc_atomic_func @
identifier crtc_atomic_func.func;
expression E;
type T;
@@
int func(...)
{
...
- T state = E;
+ T crtc_state = E;
<+...
- state
+ crtc_state
...+>
}
@ depends on crtc_atomic_func @
identifier crtc_atomic_func.func;
type T;
@@
int func(...)
{
...
- T state;
+ T crtc_state;
<+...
- state
+ crtc_state
...+>
}
@ depends on crtc_atomic_func @
identifier crtc_atomic_func.func;
identifier new_state;
identifier crtc;
@@
int func(struct drm_crtc *crtc,
- struct drm_crtc_state *new_state
+ struct drm_atomic_state *state
)
{ ... }
@@
identifier new_state;
identifier crtc;
@@
int vmw_du_crtc_atomic_check(struct drm_crtc *crtc,
- struct drm_crtc_state *new_state
+ struct drm_atomic_state *state
)
{
+ struct drm_crtc_state *new_state = drm_atomic_get_new_crtc_state(state, crtc);
...
}
@@
identifier new_state;
identifier crtc;
@@
int vmw_du_crtc_atomic_check(struct drm_crtc *crtc,
- struct drm_crtc_state *new_state
+ struct drm_atomic_state *state
);
@ include depends on adds_new_state @
@@
#include <drm/drm_atomic.h>
@ no_include depends on !include && adds_new_state @
@@
+ #include <drm/drm_atomic.h>
#include <drm/...>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Acked-by: Thomas Zimmermann <tzimmermann@suse.de>
Link: https://patchwork.freedesktop.org/patch/msgid/20201028123222.1732139-1-maxime@cerno.tech
2020-10-28 13:32:21 +01:00
struct drm_crtc_state * crtc_state = drm_atomic_get_new_crtc_state ( state ,
crtc ) ;
2018-06-26 22:47:12 +03:00
u32 primary_plane_mask = drm_plane_mask ( crtc - > primary ) ;
2016-07-08 17:40:59 +08:00
drm/atomic: Pass the full state to CRTC atomic_check
The current atomic helpers have either their object state being passed as
an argument or the full atomic state.
The former is the pattern that was done at first, before switching to the
latter for new hooks or when it was needed.
Let's start convert all the remaining helpers to provide a consistent
interface, starting with the CRTC's atomic_check.
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;
struct drm_crtc *crtc;
struct drm_crtc_state *crtc_state;
identifier dev, state;
identifier ret, f;
@@
f(struct drm_device *dev, struct drm_atomic_state *state)
{
<...
- ret = FUNCS->atomic_check(crtc, crtc_state);
+ ret = FUNCS->atomic_check(crtc, state);
...>
}
@@
identifier crtc, new_state;
@@
struct drm_crtc_helper_funcs {
...
- int (*atomic_check)(struct drm_crtc *crtc, struct drm_crtc_state *new_state);
+ int (*atomic_check)(struct drm_crtc *crtc, struct drm_atomic_state *state);
...
}
@ crtc_atomic_func @
identifier helpers;
identifier func;
@@
static struct drm_crtc_helper_funcs helpers = {
...,
.atomic_check = func,
...,
};
@ ignores_new_state @
identifier crtc_atomic_func.func;
identifier crtc, new_state;
@@
int func(struct drm_crtc *crtc,
struct drm_crtc_state *new_state)
{
... when != new_state
}
@ adds_new_state depends on crtc_atomic_func && !ignores_new_state @
identifier crtc_atomic_func.func;
identifier crtc, new_state;
@@
int func(struct drm_crtc *crtc, struct drm_crtc_state *new_state)
{
+ struct drm_crtc_state *new_state = drm_atomic_get_new_crtc_state(state, crtc);
...
}
@ depends on crtc_atomic_func @
identifier crtc_atomic_func.func;
expression E;
type T;
@@
int func(...)
{
...
- T state = E;
+ T crtc_state = E;
<+...
- state
+ crtc_state
...+>
}
@ depends on crtc_atomic_func @
identifier crtc_atomic_func.func;
type T;
@@
int func(...)
{
...
- T state;
+ T crtc_state;
<+...
- state
+ crtc_state
...+>
}
@ depends on crtc_atomic_func @
identifier crtc_atomic_func.func;
identifier new_state;
identifier crtc;
@@
int func(struct drm_crtc *crtc,
- struct drm_crtc_state *new_state
+ struct drm_atomic_state *state
)
{ ... }
@@
identifier new_state;
identifier crtc;
@@
int vmw_du_crtc_atomic_check(struct drm_crtc *crtc,
- struct drm_crtc_state *new_state
+ struct drm_atomic_state *state
)
{
+ struct drm_crtc_state *new_state = drm_atomic_get_new_crtc_state(state, crtc);
...
}
@@
identifier new_state;
identifier crtc;
@@
int vmw_du_crtc_atomic_check(struct drm_crtc *crtc,
- struct drm_crtc_state *new_state
+ struct drm_atomic_state *state
);
@ include depends on adds_new_state @
@@
#include <drm/drm_atomic.h>
@ no_include depends on !include && adds_new_state @
@@
+ #include <drm/drm_atomic.h>
#include <drm/...>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Acked-by: Thomas Zimmermann <tzimmermann@suse.de>
Link: https://patchwork.freedesktop.org/patch/msgid/20201028123222.1732139-1-maxime@cerno.tech
2020-10-28 13:32:21 +01:00
if ( crtc_state - > active & & ( primary_plane_mask & crtc_state - > plane_mask ) = = 0 )
2016-07-08 17:40:59 +08:00
return - EINVAL ;
2016-07-08 17:40:55 +08:00
return 0 ;
}
2016-07-08 17:40:59 +08:00
static void ipu_crtc_atomic_begin ( struct drm_crtc * crtc ,
drm/atomic: Pass the full state to CRTC atomic begin and flush
The current atomic helpers have either their object state being passed as
an argument or the full atomic state.
The former is the pattern that was done at first, before switching to the
latter for new hooks or when it was needed.
Let's start convert all the remaining helpers to provide a consistent
interface, starting with the CRTC's atomic_begin and atomic_flush.
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 old_crtc_state, old_state;
identifier crtc;
identifier f;
@@
f(struct drm_crtc_state *old_crtc_state)
{
...
struct drm_atomic_state *old_state = old_crtc_state->state;
<...
- FUNCS->atomic_begin(crtc, old_crtc_state);
+ FUNCS->atomic_begin(crtc, old_state);
...>
}
@@
struct drm_crtc_helper_funcs *FUNCS;
identifier old_crtc_state, old_state;
identifier crtc;
identifier f;
@@
f(struct drm_crtc_state *old_crtc_state)
{
...
struct drm_atomic_state *old_state = old_crtc_state->state;
<...
- FUNCS->atomic_flush(crtc, old_crtc_state);
+ FUNCS->atomic_flush(crtc, old_state);
...>
}
@@
struct drm_crtc_helper_funcs *FUNCS;
struct drm_crtc *crtc;
struct drm_crtc_state *crtc_state;
identifier dev, state;
identifier f;
@@
f(struct drm_device *dev, struct drm_atomic_state *state, ...)
{
<...
- FUNCS->atomic_begin(crtc, crtc_state);
+ FUNCS->atomic_begin(crtc, state);
...>
}
@@
struct drm_crtc_helper_funcs *FUNCS;
struct drm_crtc *crtc;
struct drm_crtc_state *crtc_state;
identifier dev, state;
identifier f;
@@
f(struct drm_device *dev, struct drm_atomic_state *state, ...)
{
<...
- FUNCS->atomic_flush(crtc, crtc_state);
+ FUNCS->atomic_flush(crtc, state);
...>
}
@@
identifier crtc, old_state;
@@
struct drm_crtc_helper_funcs {
...
- void (*atomic_begin)(struct drm_crtc *crtc, struct drm_crtc_state *old_state);
+ void (*atomic_begin)(struct drm_crtc *crtc, struct drm_atomic_state *state);
...
- void (*atomic_flush)(struct drm_crtc *crtc, struct drm_crtc_state *old_state);
+ void (*atomic_flush)(struct drm_crtc *crtc, struct drm_atomic_state *state);
...
}
@ crtc_atomic_func @
identifier helpers;
identifier func;
@@
(
static struct drm_crtc_helper_funcs helpers = {
...,
.atomic_begin = func,
...,
};
|
static struct drm_crtc_helper_funcs helpers = {
...,
.atomic_flush = 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
...+>
}
@@
identifier old_state;
identifier crtc;
@@
void vc4_hvs_atomic_flush(struct drm_crtc *crtc,
- struct drm_crtc_state *old_state
+ struct drm_atomic_state *state
)
{
+ struct drm_crtc_state *old_state = drm_atomic_get_old_crtc_state(state, crtc);
...
}
@@
identifier old_state;
identifier crtc;
@@
void vc4_hvs_atomic_flush(struct drm_crtc *crtc,
- struct drm_crtc_state *old_state
+ struct drm_atomic_state *state
);
@@
identifier old_state;
identifier crtc;
@@
void vmw_du_crtc_atomic_begin(struct drm_crtc *crtc,
- struct drm_crtc_state *old_state
+ struct drm_atomic_state *state
)
{
...
}
@@
identifier old_state;
identifier crtc;
@@
void vmw_du_crtc_atomic_begin(struct drm_crtc *crtc,
- struct drm_crtc_state *old_state
+ struct drm_atomic_state *state
);
@@
identifier old_state;
identifier crtc;
@@
void vmw_du_crtc_atomic_flush(struct drm_crtc *crtc,
- struct drm_crtc_state *old_state
+ struct drm_atomic_state *state
)
{
...
}
@@
identifier old_state;
identifier crtc;
@@
void vmw_du_crtc_atomic_flush(struct drm_crtc *crtc,
- struct drm_crtc_state *old_state
+ struct drm_atomic_state *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>
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Acked-by: Thomas Zimmermann <tzimmermann@suse.de>
Link: https://patchwork.freedesktop.org/patch/msgid/20201028123222.1732139-2-maxime@cerno.tech
2020-10-28 13:32:22 +01:00
struct drm_atomic_state * state )
2016-07-08 17:40:59 +08:00
{
2016-08-29 17:51:24 +02:00
drm_crtc_vblank_on ( crtc ) ;
2018-03-15 10:11:59 +01:00
}
2016-08-29 17:51:24 +02:00
2018-03-15 10:11:59 +01:00
static void ipu_crtc_atomic_flush ( struct drm_crtc * crtc ,
drm/atomic: Pass the full state to CRTC atomic begin and flush
The current atomic helpers have either their object state being passed as
an argument or the full atomic state.
The former is the pattern that was done at first, before switching to the
latter for new hooks or when it was needed.
Let's start convert all the remaining helpers to provide a consistent
interface, starting with the CRTC's atomic_begin and atomic_flush.
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 old_crtc_state, old_state;
identifier crtc;
identifier f;
@@
f(struct drm_crtc_state *old_crtc_state)
{
...
struct drm_atomic_state *old_state = old_crtc_state->state;
<...
- FUNCS->atomic_begin(crtc, old_crtc_state);
+ FUNCS->atomic_begin(crtc, old_state);
...>
}
@@
struct drm_crtc_helper_funcs *FUNCS;
identifier old_crtc_state, old_state;
identifier crtc;
identifier f;
@@
f(struct drm_crtc_state *old_crtc_state)
{
...
struct drm_atomic_state *old_state = old_crtc_state->state;
<...
- FUNCS->atomic_flush(crtc, old_crtc_state);
+ FUNCS->atomic_flush(crtc, old_state);
...>
}
@@
struct drm_crtc_helper_funcs *FUNCS;
struct drm_crtc *crtc;
struct drm_crtc_state *crtc_state;
identifier dev, state;
identifier f;
@@
f(struct drm_device *dev, struct drm_atomic_state *state, ...)
{
<...
- FUNCS->atomic_begin(crtc, crtc_state);
+ FUNCS->atomic_begin(crtc, state);
...>
}
@@
struct drm_crtc_helper_funcs *FUNCS;
struct drm_crtc *crtc;
struct drm_crtc_state *crtc_state;
identifier dev, state;
identifier f;
@@
f(struct drm_device *dev, struct drm_atomic_state *state, ...)
{
<...
- FUNCS->atomic_flush(crtc, crtc_state);
+ FUNCS->atomic_flush(crtc, state);
...>
}
@@
identifier crtc, old_state;
@@
struct drm_crtc_helper_funcs {
...
- void (*atomic_begin)(struct drm_crtc *crtc, struct drm_crtc_state *old_state);
+ void (*atomic_begin)(struct drm_crtc *crtc, struct drm_atomic_state *state);
...
- void (*atomic_flush)(struct drm_crtc *crtc, struct drm_crtc_state *old_state);
+ void (*atomic_flush)(struct drm_crtc *crtc, struct drm_atomic_state *state);
...
}
@ crtc_atomic_func @
identifier helpers;
identifier func;
@@
(
static struct drm_crtc_helper_funcs helpers = {
...,
.atomic_begin = func,
...,
};
|
static struct drm_crtc_helper_funcs helpers = {
...,
.atomic_flush = 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
...+>
}
@@
identifier old_state;
identifier crtc;
@@
void vc4_hvs_atomic_flush(struct drm_crtc *crtc,
- struct drm_crtc_state *old_state
+ struct drm_atomic_state *state
)
{
+ struct drm_crtc_state *old_state = drm_atomic_get_old_crtc_state(state, crtc);
...
}
@@
identifier old_state;
identifier crtc;
@@
void vc4_hvs_atomic_flush(struct drm_crtc *crtc,
- struct drm_crtc_state *old_state
+ struct drm_atomic_state *state
);
@@
identifier old_state;
identifier crtc;
@@
void vmw_du_crtc_atomic_begin(struct drm_crtc *crtc,
- struct drm_crtc_state *old_state
+ struct drm_atomic_state *state
)
{
...
}
@@
identifier old_state;
identifier crtc;
@@
void vmw_du_crtc_atomic_begin(struct drm_crtc *crtc,
- struct drm_crtc_state *old_state
+ struct drm_atomic_state *state
);
@@
identifier old_state;
identifier crtc;
@@
void vmw_du_crtc_atomic_flush(struct drm_crtc *crtc,
- struct drm_crtc_state *old_state
+ struct drm_atomic_state *state
)
{
...
}
@@
identifier old_state;
identifier crtc;
@@
void vmw_du_crtc_atomic_flush(struct drm_crtc *crtc,
- struct drm_crtc_state *old_state
+ struct drm_atomic_state *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>
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Acked-by: Thomas Zimmermann <tzimmermann@suse.de>
Link: https://patchwork.freedesktop.org/patch/msgid/20201028123222.1732139-2-maxime@cerno.tech
2020-10-28 13:32:22 +01:00
struct drm_atomic_state * state )
2018-03-15 10:11:59 +01:00
{
2016-07-08 17:40:59 +08:00
spin_lock_irq ( & crtc - > dev - > event_lock ) ;
if ( crtc - > state - > event ) {
2018-09-11 16:03:16 +02:00
struct ipu_crtc * ipu_crtc = to_ipu_crtc ( crtc ) ;
2016-07-08 17:40:59 +08:00
WARN_ON ( drm_crtc_vblank_get ( crtc ) ) ;
2018-09-11 16:03:16 +02:00
ipu_crtc - > event = crtc - > state - > event ;
2016-07-08 17:40:59 +08:00
crtc - > state - > event = NULL ;
}
spin_unlock_irq ( & crtc - > dev - > event_lock ) ;
}
2016-07-08 17:40:55 +08:00
static void ipu_crtc_mode_set_nofb ( struct drm_crtc * crtc )
{
struct drm_device * dev = crtc - > dev ;
struct drm_encoder * encoder ;
struct ipu_crtc * ipu_crtc = to_ipu_crtc ( crtc ) ;
struct drm_display_mode * mode = & crtc - > state - > adjusted_mode ;
2016-07-06 14:49:24 +02:00
struct imx_crtc_state * imx_crtc_state = to_imx_crtc_state ( crtc - > state ) ;
2016-07-08 17:40:55 +08:00
struct ipu_di_signal_cfg sig_cfg = { } ;
unsigned long encoder_types = 0 ;
dev_dbg ( ipu_crtc - > dev , " %s: mode->hdisplay: %d \n " , __func__ ,
mode - > hdisplay ) ;
dev_dbg ( ipu_crtc - > dev , " %s: mode->vdisplay: %d \n " , __func__ ,
mode - > vdisplay ) ;
2016-07-08 17:40:58 +08:00
list_for_each_entry ( encoder , & dev - > mode_config . encoder_list , head ) {
2016-07-06 14:49:24 +02:00
if ( encoder - > crtc = = crtc )
2016-07-08 17:40:55 +08:00
encoder_types | = BIT ( encoder - > encoder_type ) ;
2016-07-08 17:40:58 +08:00
}
2016-07-08 17:40:55 +08:00
dev_dbg ( ipu_crtc - > dev , " %s: attached to encoder types 0x%lx \n " ,
__func__ , encoder_types ) ;
/*
* If we have DAC or LDB , then we need the IPU DI clock to be
* the same as the LDB DI clock . For TVDAC , derive the IPU DI
* clock from 27 MHz TVE_DI clock , but allow to divide it .
*/
if ( encoder_types & ( BIT ( DRM_MODE_ENCODER_DAC ) |
BIT ( DRM_MODE_ENCODER_LVDS ) ) )
sig_cfg . clkflags = IPU_DI_CLKMODE_SYNC | IPU_DI_CLKMODE_EXT ;
else if ( encoder_types & BIT ( DRM_MODE_ENCODER_TVDAC ) )
sig_cfg . clkflags = IPU_DI_CLKMODE_EXT ;
else
sig_cfg . clkflags = 0 ;
2016-07-06 14:49:24 +02:00
sig_cfg . enable_pol = ! ( imx_crtc_state - > bus_flags & DRM_BUS_FLAG_DE_LOW ) ;
2016-07-08 17:40:55 +08:00
/* Default to driving pixel data on negative clock edges */
2016-07-06 14:49:24 +02:00
sig_cfg . clk_pol = ! ! ( imx_crtc_state - > bus_flags &
2018-09-22 15:02:42 +03:00
DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE ) ;
2016-07-06 14:49:24 +02:00
sig_cfg . bus_format = imx_crtc_state - > bus_format ;
2016-07-08 17:40:55 +08:00
sig_cfg . v_to_h_sync = 0 ;
2016-07-06 14:49:24 +02:00
sig_cfg . hsync_pin = imx_crtc_state - > di_hsync_pin ;
sig_cfg . vsync_pin = imx_crtc_state - > di_vsync_pin ;
2016-07-08 17:40:55 +08:00
drm_display_mode_to_videomode ( mode , & sig_cfg . mode ) ;
2021-04-29 00:29:50 +02:00
if ( ! IS_ALIGNED ( sig_cfg . mode . hactive , 8 ) ) {
unsigned int new_hactive = ALIGN ( sig_cfg . mode . hactive , 8 ) ;
dev_warn ( ipu_crtc - > dev , " 8-pixel align hactive %d -> %d \n " ,
sig_cfg . mode . hactive , new_hactive ) ;
sig_cfg . mode . hfront_porch = new_hactive - sig_cfg . mode . hactive ;
sig_cfg . mode . hactive = new_hactive ;
}
2016-07-08 17:40:55 +08:00
ipu_dc_init_sync ( ipu_crtc - > dc , ipu_crtc - > di ,
mode - > flags & DRM_MODE_FLAG_INTERLACE ,
2021-04-29 00:29:50 +02:00
imx_crtc_state - > bus_format , sig_cfg . mode . hactive ) ;
2016-07-08 17:40:55 +08:00
ipu_di_init_sync_panel ( ipu_crtc - > di , & sig_cfg ) ;
2012-09-21 10:07:50 +02:00
}
2015-12-15 12:21:09 +01:00
static const struct drm_crtc_helper_funcs ipu_helper_funcs = {
2012-09-21 10:07:50 +02:00
. mode_fixup = ipu_crtc_mode_fixup ,
2016-07-08 17:40:55 +08:00
. mode_set_nofb = ipu_crtc_mode_set_nofb ,
. atomic_check = ipu_crtc_atomic_check ,
2016-07-08 17:40:59 +08:00
. atomic_begin = ipu_crtc_atomic_begin ,
2018-03-15 10:11:59 +01:00
. atomic_flush = ipu_crtc_atomic_flush ,
2016-08-26 15:30:42 +08:00
. atomic_disable = ipu_crtc_atomic_disable ,
2017-06-30 12:36:44 +03:00
. atomic_enable = ipu_crtc_atomic_enable ,
2012-09-21 10:07:50 +02:00
} ;
2020-12-10 16:38:45 +01:00
static void ipu_put_resources ( struct drm_device * dev , void * ptr )
2012-09-21 10:07:50 +02:00
{
2020-12-10 16:38:45 +01:00
struct ipu_crtc * ipu_crtc = ptr ;
2013-10-10 16:18:45 +02:00
if ( ! IS_ERR_OR_NULL ( ipu_crtc - > dc ) )
ipu_dc_put ( ipu_crtc - > dc ) ;
2012-09-21 10:07:50 +02:00
if ( ! IS_ERR_OR_NULL ( ipu_crtc - > di ) )
ipu_di_put ( ipu_crtc - > di ) ;
}
2020-12-10 16:38:45 +01:00
static int ipu_get_resources ( struct drm_device * dev , struct ipu_crtc * ipu_crtc ,
struct ipu_client_platformdata * pdata )
2012-09-21 10:07:50 +02:00
{
struct ipu_soc * ipu = dev_get_drvdata ( ipu_crtc - > dev - > parent ) ;
int ret ;
ipu_crtc - > dc = ipu_dc_get ( ipu , pdata - > dc ) ;
2020-12-10 16:38:45 +01:00
if ( IS_ERR ( ipu_crtc - > dc ) )
return PTR_ERR ( ipu_crtc - > dc ) ;
ret = drmm_add_action_or_reset ( dev , ipu_put_resources , ipu_crtc ) ;
if ( ret )
return ret ;
2012-09-21 10:07:50 +02:00
ipu_crtc - > di = ipu_di_get ( ipu , pdata - > di ) ;
2020-12-10 16:38:45 +01:00
if ( IS_ERR ( ipu_crtc - > di ) )
return PTR_ERR ( ipu_crtc - > di ) ;
2012-09-21 10:07:50 +02:00
return 0 ;
}
2020-12-10 16:38:45 +01:00
static int ipu_drm_bind ( struct device * dev , struct device * master , void * data )
2012-09-21 10:07:50 +02:00
{
2020-12-10 16:38:45 +01:00
struct ipu_client_platformdata * pdata = dev - > platform_data ;
struct ipu_soc * ipu = dev_get_drvdata ( dev - > parent ) ;
struct drm_device * drm = data ;
struct ipu_plane * primary_plane ;
struct ipu_crtc * ipu_crtc ;
struct drm_crtc * crtc ;
2013-10-10 16:18:45 +02:00
int dp = - EINVAL ;
2012-09-21 10:07:50 +02:00
int ret ;
2015-11-06 11:08:02 +01:00
if ( pdata - > dp > = 0 )
dp = IPU_DP_FLOW_SYNC_BG ;
2020-12-10 16:38:45 +01:00
primary_plane = ipu_plane_init ( drm , ipu , pdata - > dma [ 0 ] , dp , 0 ,
DRM_PLANE_TYPE_PRIMARY ) ;
if ( IS_ERR ( primary_plane ) )
return PTR_ERR ( primary_plane ) ;
ipu_crtc = drmm_crtc_alloc_with_planes ( drm , struct ipu_crtc , base ,
& primary_plane - > base , NULL ,
& ipu_crtc_funcs , NULL ) ;
if ( IS_ERR ( ipu_crtc ) )
return PTR_ERR ( ipu_crtc ) ;
ipu_crtc - > dev = dev ;
ipu_crtc - > plane [ 0 ] = primary_plane ;
2015-11-06 11:08:02 +01:00
2020-12-10 16:38:45 +01:00
crtc = & ipu_crtc - > base ;
2017-02-07 17:16:24 +08:00
crtc - > port = pdata - > of_node ;
drm_crtc_helper_add ( crtc , & ipu_helper_funcs ) ;
2020-12-10 16:38:45 +01:00
ret = ipu_get_resources ( drm , ipu_crtc , pdata ) ;
if ( ret ) {
dev_err ( ipu_crtc - > dev , " getting resources failed with %d. \n " ,
ret ) ;
return ret ;
}
2012-09-21 10:07:50 +02:00
2013-10-10 16:18:45 +02:00
/* If this crtc is using the DP, add an overlay plane */
if ( pdata - > dp > = 0 & & pdata - > dma [ 1 ] > 0 ) {
2015-11-06 11:08:02 +01:00
ipu_crtc - > plane [ 1 ] = ipu_plane_init ( drm , ipu , pdata - > dma [ 1 ] ,
IPU_DP_FLOW_SYNC_FG ,
drm_crtc_mask ( & ipu_crtc - > base ) ,
DRM_PLANE_TYPE_OVERLAY ) ;
2020-12-10 16:38:44 +01:00
if ( IS_ERR ( ipu_crtc - > plane [ 1 ] ) )
2013-10-10 16:18:45 +02:00
ipu_crtc - > plane [ 1 ] = NULL ;
}
ipu_crtc - > irq = ipu_plane_irq ( ipu_crtc - > plane [ 0 ] ) ;
2013-02-20 10:57:01 +08:00
ret = devm_request_irq ( ipu_crtc - > dev , ipu_crtc - > irq , ipu_irq_handler , 0 ,
" imx_drm " , ipu_crtc ) ;
if ( ret < 0 ) {
dev_err ( ipu_crtc - > dev , " irq request failed with %d. \n " , ret ) ;
2020-12-10 16:38:45 +01:00
return ret ;
2013-02-20 10:57:01 +08:00
}
2016-02-09 11:43:08 +01:00
/* Only enable IRQ when we actually need it to trigger work. */
disable_irq ( ipu_crtc - > irq ) ;
2013-02-20 10:57:01 +08:00
2012-09-21 10:07:50 +02:00
return 0 ;
2013-11-03 11:23:34 +00:00
}
static const struct component_ops ipu_crtc_ops = {
. bind = ipu_drm_bind ,
} ;
2012-09-21 10:07:50 +02:00
2013-11-03 11:23:34 +00:00
static int ipu_drm_probe ( struct platform_device * pdev )
{
2014-03-05 10:20:52 +01:00
struct device * dev = & pdev - > dev ;
2013-11-03 11:23:34 +00:00
int ret ;
2014-03-05 10:20:52 +01:00
if ( ! dev - > platform_data )
2013-11-03 11:23:34 +00:00
return - EINVAL ;
2014-03-05 10:20:52 +01:00
ret = dma_set_coherent_mask ( dev , DMA_BIT_MASK ( 32 ) ) ;
2013-11-03 11:23:34 +00:00
if ( ret )
return ret ;
2014-03-05 10:20:52 +01:00
return component_add ( dev , & ipu_crtc_ops ) ;
2013-11-03 11:23:34 +00:00
}
static int ipu_drm_remove ( struct platform_device * pdev )
{
component_del ( & pdev - > dev , & ipu_crtc_ops ) ;
2012-09-21 10:07:50 +02:00
return 0 ;
}
2017-03-23 17:18:37 +01:00
struct platform_driver ipu_drm_driver = {
2012-09-21 10:07:50 +02:00
. driver = {
. name = " imx-ipuv3-crtc " ,
} ,
. probe = ipu_drm_probe ,
2012-11-19 13:20:51 -05:00
. remove = ipu_drm_remove ,
2012-09-21 10:07:50 +02:00
} ;