2018-07-26 02:37:32 +00:00
// SPDX-License-Identifier: GPL-2.0+
2015-09-07 17:14:58 +03:00
/*
2022-04-24 23:44:35 +03:00
* R - Car Display Unit VSP - Based Compositor
2015-09-07 17:14:58 +03:00
*
* Copyright ( C ) 2015 Renesas Electronics Corporation
*
* Contact : Laurent Pinchart ( laurent . pinchart @ ideasonboard . com )
*/
drm/atomic: Pass the full state to planes 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 convert all the remaining helpers to provide a consistent
interface, starting with the planes atomic_check.
The conversion was done using the coccinelle script below plus some
manual changes for vmwgfx, built tested on all the drivers.
@@
identifier plane, plane_state;
symbol state;
@@
struct drm_plane_helper_funcs {
...
int (*atomic_check)(struct drm_plane *plane,
- struct drm_plane_state *plane_state);
+ struct drm_atomic_state *state);
...
}
@ plane_atomic_func @
identifier helpers;
identifier func;
@@
static const struct drm_plane_helper_funcs helpers = {
...,
.atomic_check = func,
...,
};
@@
struct drm_plane_helper_funcs *FUNCS;
identifier f;
identifier dev;
identifier plane, plane_state, state;
@@
f(struct drm_device *dev, struct drm_atomic_state *state)
{
<+...
- FUNCS->atomic_check(plane, plane_state)
+ FUNCS->atomic_check(plane, state)
...+>
}
@ ignores_new_state @
identifier plane_atomic_func.func;
identifier plane, new_plane_state;
@@
func(struct drm_plane *plane, struct drm_plane_state *new_plane_state)
{
... when != new_plane_state
}
@ adds_new_state depends on plane_atomic_func && !ignores_new_state @
identifier plane_atomic_func.func;
identifier plane, new_plane_state;
@@
func(struct drm_plane *plane, struct drm_plane_state *new_plane_state)
{
+ struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane);
...
}
@ depends on plane_atomic_func @
identifier plane_atomic_func.func;
identifier plane, new_plane_state;
@@
func(struct drm_plane *plane,
- struct drm_plane_state *new_plane_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/...>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Acked-by: Thomas Zimmermann <tzimmermann@suse.de>
Link: https://patchwork.freedesktop.org/patch/msgid/20210219120032.260676-4-maxime@cerno.tech
2021-02-19 13:00:24 +01:00
# include <drm/drm_atomic.h>
2015-09-07 17:14:58 +03:00
# include <drm/drm_atomic_helper.h>
2022-06-13 23:03:12 +03:00
# include <drm/drm_blend.h>
2015-09-07 17:14:58 +03:00
# include <drm/drm_crtc.h>
2022-08-02 02:04:02 +02:00
# include <drm/drm_fb_dma_helper.h>
2019-02-21 03:20:42 +02:00
# include <drm/drm_fourcc.h>
2022-06-14 12:54:49 +03:00
# include <drm/drm_framebuffer.h>
2021-02-22 15:17:56 +01:00
# include <drm/drm_gem_atomic_helper.h>
2022-08-02 02:04:03 +02:00
# include <drm/drm_gem_dma_helper.h>
2020-09-16 02:23:47 +03:00
# include <drm/drm_managed.h>
2019-01-26 13:25:25 +01:00
# include <drm/drm_vblank.h>
2015-09-07 17:14:58 +03:00
2017-06-26 13:12:01 +03:00
# include <linux/bitops.h>
2017-05-17 02:20:07 +03:00
# include <linux/dma-mapping.h>
2015-09-07 17:14:58 +03:00
# include <linux/of_platform.h>
2017-05-17 02:20:07 +03:00
# include <linux/scatterlist.h>
2020-12-03 15:09:22 +02:00
# include <linux/slab.h>
2015-09-07 17:14:58 +03:00
# include <linux/videodev2.h>
# include <media/vsp1.h>
# include "rcar_du_drv.h"
# include "rcar_du_kms.h"
# include "rcar_du_vsp.h"
2019-02-21 03:40:12 +02:00
# include "rcar_du_writeback.h"
2015-09-07 17:14:58 +03:00
2019-02-21 03:38:06 +02:00
static void rcar_du_vsp_complete ( void * private , unsigned int status , u32 crc )
2017-03-04 02:01:19 +00:00
{
struct rcar_du_crtc * crtc = private ;
2017-06-30 13:14:11 +01:00
if ( crtc - > vblank_enable )
drm_crtc_handle_vblank ( & crtc - > crtc ) ;
2019-02-21 03:38:06 +02:00
if ( status & VSP1_DU_STATUS_COMPLETE )
2017-06-30 13:14:11 +01:00
rcar_du_crtc_finish_page_flip ( crtc ) ;
2019-02-21 03:40:12 +02:00
if ( status & VSP1_DU_STATUS_WRITEBACK )
rcar_du_writeback_complete ( crtc ) ;
2017-12-01 06:59:55 -05:00
drm_crtc_add_crc_entry ( & crtc - > crtc , false , 0 , & crc ) ;
2017-03-04 02:01:19 +00:00
}
2015-09-07 17:14:58 +03:00
void rcar_du_vsp_enable ( struct rcar_du_crtc * crtc )
{
const struct drm_display_mode * mode = & crtc - > crtc . state - > adjusted_mode ;
2019-03-15 17:01:05 +00:00
struct rcar_du_device * rcdu = crtc - > dev ;
2017-03-03 06:31:48 -03:00
struct vsp1_du_lif_config cfg = {
. width = mode - > hdisplay ,
. height = mode - > vdisplay ,
2018-08-03 12:37:30 +01:00
. interlaced = mode - > flags & DRM_MODE_FLAG_INTERLACE ,
2017-03-04 02:01:19 +00:00
. callback = rcar_du_vsp_complete ,
. callback_data = crtc ,
2017-03-03 06:31:48 -03:00
} ;
2015-09-07 17:14:58 +03:00
struct rcar_du_plane_state state = {
. state = {
2018-04-11 09:39:27 +02:00
. alpha = DRM_BLEND_ALPHA_OPAQUE ,
2015-09-07 17:14:58 +03:00
. crtc = & crtc - > crtc ,
2017-08-15 18:52:04 +03:00
. dst . x1 = 0 ,
. dst . y1 = 0 ,
. dst . x2 = mode - > hdisplay ,
. dst . y2 = mode - > vdisplay ,
. src . x1 = 0 ,
. src . y1 = 0 ,
. src . x2 = mode - > hdisplay < < 16 ,
. src . y2 = mode - > vdisplay < < 16 ,
2016-07-22 14:28:27 +02:00
. zpos = 0 ,
2015-09-07 17:14:58 +03:00
} ,
. format = rcar_du_format_info ( DRM_FORMAT_ARGB8888 ) ,
. source = RCAR_DU_PLANE_VSPD1 ,
. colorkey = 0 ,
} ;
2015-09-07 17:34:26 +03:00
if ( rcdu - > info - > gen > = 3 )
state . hwindex = ( crtc - > index % 2 ) ? 2 : 0 ;
else
state . hwindex = crtc - > index % 2 ;
2015-09-07 17:14:58 +03:00
__rcar_du_plane_setup ( crtc - > group , & state ) ;
2017-06-26 13:12:01 +03:00
vsp1_du_setup_lif ( crtc - > vsp - > vsp , crtc - > vsp_pipe , & cfg ) ;
2015-09-07 17:14:58 +03:00
}
void rcar_du_vsp_disable ( struct rcar_du_crtc * crtc )
{
2017-06-26 13:12:01 +03:00
vsp1_du_setup_lif ( crtc - > vsp - > vsp , crtc - > vsp_pipe , NULL ) ;
2015-09-07 17:14:58 +03:00
}
void rcar_du_vsp_atomic_begin ( struct rcar_du_crtc * crtc )
{
2017-06-26 13:12:01 +03:00
vsp1_du_atomic_begin ( crtc - > vsp - > vsp , crtc - > vsp_pipe ) ;
2015-09-07 17:14:58 +03:00
}
void rcar_du_vsp_atomic_flush ( struct rcar_du_crtc * crtc )
{
2017-12-01 06:47:19 -05:00
struct vsp1_du_atomic_pipe_config cfg = { { 0 , } } ;
2017-12-01 06:59:55 -05:00
struct rcar_du_crtc_state * state ;
state = to_rcar_crtc_state ( crtc - > crtc . state ) ;
cfg . crc = state - > crc ;
2017-12-01 06:47:19 -05:00
2019-02-21 03:40:12 +02:00
rcar_du_writeback_setup ( crtc , & cfg . writeback ) ;
2017-12-01 06:47:19 -05:00
vsp1_du_atomic_flush ( crtc - > vsp - > vsp , crtc - > vsp_pipe , & cfg ) ;
2015-09-07 17:14:58 +03:00
}
2019-02-21 03:18:05 +02:00
static const u32 rcar_du_vsp_formats [ ] = {
2015-09-07 17:14:58 +03:00
DRM_FORMAT_RGB332 ,
DRM_FORMAT_ARGB4444 ,
DRM_FORMAT_XRGB4444 ,
DRM_FORMAT_ARGB1555 ,
DRM_FORMAT_XRGB1555 ,
DRM_FORMAT_RGB565 ,
DRM_FORMAT_BGR888 ,
DRM_FORMAT_RGB888 ,
DRM_FORMAT_BGRA8888 ,
DRM_FORMAT_BGRX8888 ,
DRM_FORMAT_ARGB8888 ,
DRM_FORMAT_XRGB8888 ,
DRM_FORMAT_UYVY ,
DRM_FORMAT_YUYV ,
DRM_FORMAT_YVYU ,
DRM_FORMAT_NV12 ,
DRM_FORMAT_NV21 ,
DRM_FORMAT_NV16 ,
DRM_FORMAT_NV61 ,
2015-11-12 02:03:47 +02:00
DRM_FORMAT_YUV420 ,
DRM_FORMAT_YVU420 ,
DRM_FORMAT_YUV422 ,
DRM_FORMAT_YVU422 ,
DRM_FORMAT_YUV444 ,
DRM_FORMAT_YVU444 ,
2015-09-07 17:14:58 +03:00
} ;
2022-12-21 11:24:48 +02:00
/*
* Gen4 supports the same formats as above , and additionally 2 - 10 - 10 - 10 RGB
* formats and Y210 & Y212 formats .
*/
static const u32 rcar_du_vsp_formats_gen4 [ ] = {
DRM_FORMAT_RGB332 ,
DRM_FORMAT_ARGB4444 ,
DRM_FORMAT_XRGB4444 ,
DRM_FORMAT_ARGB1555 ,
DRM_FORMAT_XRGB1555 ,
DRM_FORMAT_RGB565 ,
DRM_FORMAT_BGR888 ,
DRM_FORMAT_RGB888 ,
DRM_FORMAT_BGRA8888 ,
DRM_FORMAT_BGRX8888 ,
DRM_FORMAT_ARGB8888 ,
DRM_FORMAT_XRGB8888 ,
DRM_FORMAT_RGBX1010102 ,
DRM_FORMAT_RGBA1010102 ,
DRM_FORMAT_ARGB2101010 ,
DRM_FORMAT_UYVY ,
DRM_FORMAT_YUYV ,
DRM_FORMAT_YVYU ,
DRM_FORMAT_NV12 ,
DRM_FORMAT_NV21 ,
DRM_FORMAT_NV16 ,
DRM_FORMAT_NV61 ,
DRM_FORMAT_YUV420 ,
DRM_FORMAT_YVU420 ,
DRM_FORMAT_YUV422 ,
DRM_FORMAT_YVU422 ,
DRM_FORMAT_YUV444 ,
DRM_FORMAT_YVU444 ,
DRM_FORMAT_Y210 ,
DRM_FORMAT_Y212 ,
} ;
2015-09-07 17:14:58 +03:00
static void rcar_du_vsp_plane_setup ( struct rcar_du_vsp_plane * plane )
{
struct rcar_du_vsp_plane_state * state =
to_rcar_vsp_plane_state ( plane - > plane . state ) ;
2017-06-26 13:12:01 +03:00
struct rcar_du_crtc * crtc = to_rcar_crtc ( state - > state . crtc ) ;
2015-09-07 17:14:58 +03:00
struct drm_framebuffer * fb = plane - > plane . state - > fb ;
2019-02-21 03:18:05 +02:00
const struct rcar_du_format_info * format ;
2016-03-24 05:15:59 -03:00
struct vsp1_du_atomic_config cfg = {
. pixelformat = 0 ,
. pitch = fb - > pitches [ 0 ] ,
2018-04-11 09:39:27 +02:00
. alpha = state - > state . alpha > > 8 ,
2016-07-22 14:28:27 +02:00
. zpos = state - > state . zpos ,
2016-03-24 05:15:59 -03:00
} ;
2022-08-10 17:37:11 +09:00
u32 fourcc = state - > format - > fourcc ;
2015-09-07 17:14:58 +03:00
unsigned int i ;
2017-08-15 18:52:04 +03:00
cfg . src . left = state - > state . src . x1 > > 16 ;
cfg . src . top = state - > state . src . y1 > > 16 ;
cfg . src . width = drm_rect_width ( & state - > state . src ) > > 16 ;
cfg . src . height = drm_rect_height ( & state - > state . src ) > > 16 ;
2015-09-07 17:14:58 +03:00
2017-08-15 18:52:04 +03:00
cfg . dst . left = state - > state . dst . x1 ;
cfg . dst . top = state - > state . dst . y1 ;
cfg . dst . width = drm_rect_width ( & state - > state . dst ) ;
cfg . dst . height = drm_rect_height ( & state - > state . dst ) ;
2015-09-07 17:14:58 +03:00
2017-05-17 02:20:07 +03:00
for ( i = 0 ; i < state - > format - > planes ; + + i )
cfg . mem [ i ] = sg_dma_address ( state - > sg_tables [ i ] . sgl )
+ fb - > offsets [ i ] ;
2015-09-07 17:14:58 +03:00
2022-08-10 17:37:11 +09:00
if ( state - > state . pixel_blend_mode = = DRM_MODE_BLEND_PIXEL_NONE ) {
switch ( fourcc ) {
case DRM_FORMAT_ARGB1555 :
fourcc = DRM_FORMAT_XRGB1555 ;
break ;
case DRM_FORMAT_ARGB4444 :
fourcc = DRM_FORMAT_XRGB4444 ;
break ;
case DRM_FORMAT_ARGB8888 :
fourcc = DRM_FORMAT_XRGB8888 ;
break ;
}
}
format = rcar_du_format_info ( fourcc ) ;
2019-02-21 03:18:05 +02:00
cfg . pixelformat = format - > v4l2 ;
2015-09-07 17:14:58 +03:00
2022-08-10 17:37:10 +09:00
cfg . premult = state - > state . pixel_blend_mode = = DRM_MODE_BLEND_PREMULTI ;
2017-06-26 13:12:01 +03:00
vsp1_du_atomic_update ( plane - > vsp - > vsp , crtc - > vsp_pipe ,
plane - > index , & cfg ) ;
2015-09-07 17:14:58 +03:00
}
2019-02-21 03:20:42 +02:00
int rcar_du_vsp_map_fb ( struct rcar_du_vsp * vsp , struct drm_framebuffer * fb ,
struct sg_table sg_tables [ 3 ] )
2017-05-17 02:20:07 +03:00
{
struct rcar_du_device * rcdu = vsp - > dev ;
drm: rcar-du: Allow importing non-contiguous dma-buf with VSP
On R-Car Gen3, the DU uses a separate IP core named VSP to perform DMA
from memory and composition of planes. The DU hardware then only handles
the video timings and the interface with the encoders. This differs from
Gen2, where the DU included a composer with DMA engines.
When sourcing from the VSP, the DU hardware performs no memory access,
and thus has no requirements on imported dma-buf memory types. The GEM
CMA helpers however still create a DMA mapping to the DU device, which
isn't used. The mapping to the VSP is done when processing the atomic
commits, in the plane .prepare_fb() handler.
When the system uses an IOMMU, the VSP device is attached to it, which
enables the VSP to use non physically contiguous memory. The DU, as it
performs no memory access, isn't connected to the IOMMU. The GEM CMA
drm_gem_cma_prime_import_sg_table() helper will in that case fail to map
non-contiguous imported dma-bufs, as the DMA mapping to the DU device
will have multiple entries in its sgtable. The prevents using non
physically contiguous memory for display.
The DRM PRIME and GEM CMA helpers are designed to create the sgtable
when the dma-buf is imported. By default, the device referenced by the
drm_device is used to create the dma-buf attachment. Drivers can use a
different device by using the drm_gem_prime_import_dev() function. While
the DU has access to the VSP device, this won't help here, as different
CRTCs use different VSP instances, connected to different IOMMU
channels. The driver doesn't know at import time which CRTC a GEM object
will be used, and thus can't select the right VSP device to pass to
drm_gem_prime_import_dev().
To support non-contiguous memory, implement a custom
.gem_prime_import_sg_table() operation that accepts all imported dma-buf
regardless of the number of scatterlist entries. The sgtable will be
mapped to the VSP at .prepare_fb() time, which will reject the
framebuffer if the VSP isn't connected to an IOMMU.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
2017-11-13 04:40:30 +02:00
unsigned int i , j ;
2017-05-17 02:20:07 +03:00
int ret ;
2019-02-21 03:20:42 +02:00
for ( i = 0 ; i < fb - > format - > num_planes ; + + i ) {
2022-08-02 02:04:03 +02:00
struct drm_gem_dma_object * gem = drm_fb_dma_get_gem_obj ( fb , i ) ;
2019-02-21 03:20:42 +02:00
struct sg_table * sgt = & sg_tables [ i ] ;
2017-05-17 02:20:07 +03:00
drm: rcar-du: Allow importing non-contiguous dma-buf with VSP
On R-Car Gen3, the DU uses a separate IP core named VSP to perform DMA
from memory and composition of planes. The DU hardware then only handles
the video timings and the interface with the encoders. This differs from
Gen2, where the DU included a composer with DMA engines.
When sourcing from the VSP, the DU hardware performs no memory access,
and thus has no requirements on imported dma-buf memory types. The GEM
CMA helpers however still create a DMA mapping to the DU device, which
isn't used. The mapping to the VSP is done when processing the atomic
commits, in the plane .prepare_fb() handler.
When the system uses an IOMMU, the VSP device is attached to it, which
enables the VSP to use non physically contiguous memory. The DU, as it
performs no memory access, isn't connected to the IOMMU. The GEM CMA
drm_gem_cma_prime_import_sg_table() helper will in that case fail to map
non-contiguous imported dma-bufs, as the DMA mapping to the DU device
will have multiple entries in its sgtable. The prevents using non
physically contiguous memory for display.
The DRM PRIME and GEM CMA helpers are designed to create the sgtable
when the dma-buf is imported. By default, the device referenced by the
drm_device is used to create the dma-buf attachment. Drivers can use a
different device by using the drm_gem_prime_import_dev() function. While
the DU has access to the VSP device, this won't help here, as different
CRTCs use different VSP instances, connected to different IOMMU
channels. The driver doesn't know at import time which CRTC a GEM object
will be used, and thus can't select the right VSP device to pass to
drm_gem_prime_import_dev().
To support non-contiguous memory, implement a custom
.gem_prime_import_sg_table() operation that accepts all imported dma-buf
regardless of the number of scatterlist entries. The sgtable will be
mapped to the VSP at .prepare_fb() time, which will reject the
framebuffer if the VSP isn't connected to an IOMMU.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
2017-11-13 04:40:30 +02:00
if ( gem - > sgt ) {
struct scatterlist * src ;
struct scatterlist * dst ;
/*
* If the GEM buffer has a scatter gather table , it has
* been imported from a dma - buf and has no physical
* address as it might not be physically contiguous .
* Copy the original scatter gather table to map it to
* the VSP .
*/
ret = sg_alloc_table ( sgt , gem - > sgt - > orig_nents ,
GFP_KERNEL ) ;
if ( ret )
goto fail ;
src = gem - > sgt - > sgl ;
dst = sgt - > sgl ;
for ( j = 0 ; j < gem - > sgt - > orig_nents ; + + j ) {
sg_set_page ( dst , sg_page ( src ) , src - > length ,
src - > offset ) ;
src = sg_next ( src ) ;
dst = sg_next ( dst ) ;
}
} else {
ret = dma_get_sgtable ( rcdu - > dev , sgt , gem - > vaddr ,
2022-08-02 02:04:04 +02:00
gem - > dma_addr , gem - > base . size ) ;
drm: rcar-du: Allow importing non-contiguous dma-buf with VSP
On R-Car Gen3, the DU uses a separate IP core named VSP to perform DMA
from memory and composition of planes. The DU hardware then only handles
the video timings and the interface with the encoders. This differs from
Gen2, where the DU included a composer with DMA engines.
When sourcing from the VSP, the DU hardware performs no memory access,
and thus has no requirements on imported dma-buf memory types. The GEM
CMA helpers however still create a DMA mapping to the DU device, which
isn't used. The mapping to the VSP is done when processing the atomic
commits, in the plane .prepare_fb() handler.
When the system uses an IOMMU, the VSP device is attached to it, which
enables the VSP to use non physically contiguous memory. The DU, as it
performs no memory access, isn't connected to the IOMMU. The GEM CMA
drm_gem_cma_prime_import_sg_table() helper will in that case fail to map
non-contiguous imported dma-bufs, as the DMA mapping to the DU device
will have multiple entries in its sgtable. The prevents using non
physically contiguous memory for display.
The DRM PRIME and GEM CMA helpers are designed to create the sgtable
when the dma-buf is imported. By default, the device referenced by the
drm_device is used to create the dma-buf attachment. Drivers can use a
different device by using the drm_gem_prime_import_dev() function. While
the DU has access to the VSP device, this won't help here, as different
CRTCs use different VSP instances, connected to different IOMMU
channels. The driver doesn't know at import time which CRTC a GEM object
will be used, and thus can't select the right VSP device to pass to
drm_gem_prime_import_dev().
To support non-contiguous memory, implement a custom
.gem_prime_import_sg_table() operation that accepts all imported dma-buf
regardless of the number of scatterlist entries. The sgtable will be
mapped to the VSP at .prepare_fb() time, which will reject the
framebuffer if the VSP isn't connected to an IOMMU.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
2017-11-13 04:40:30 +02:00
if ( ret )
goto fail ;
}
2017-05-17 02:20:07 +03:00
ret = vsp1_du_map_sg ( vsp - > vsp , sgt ) ;
drm: rcar-du: fix common struct sg_table related issues
The Documentation/DMA-API-HOWTO.txt states that the dma_map_sg() function
returns the number of the created entries in the DMA address space.
However the subsequent calls to the dma_sync_sg_for_{device,cpu}() and
dma_unmap_sg must be called with the original number of the entries
passed to the dma_map_sg().
struct sg_table is a common structure used for describing a non-contiguous
memory buffer, used commonly in the DRM and graphics subsystems. It
consists of a scatterlist with memory pages and DMA addresses (sgl entry),
as well as the number of scatterlist entries: CPU pages (orig_nents entry)
and DMA mapped pages (nents entry).
It turned out that it was a common mistake to misuse nents and orig_nents
entries, calling DMA-mapping functions with a wrong number of entries or
ignoring the number of mapped entries returned by the dma_map_sg()
function.
To avoid such issues, lets use a common dma-mapping wrappers operating
directly on the struct sg_table objects and use scatterlist page
iterators where possible. This, almost always, hides references to the
nents and orig_nents entries, making the code robust, easier to follow
and copy/paste safe.
dma_map_sgtable() function returns zero or an error code, so adjust the
return value check for the vsp1_du_map_sg() function.
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
2020-05-08 16:10:16 +02:00
if ( ret ) {
2017-05-17 02:20:07 +03:00
sg_free_table ( sgt ) ;
goto fail ;
}
}
return 0 ;
fail :
while ( i - - ) {
2019-02-21 03:20:42 +02:00
struct sg_table * sgt = & sg_tables [ i ] ;
2017-05-17 02:20:07 +03:00
vsp1_du_unmap_sg ( vsp - > vsp , sgt ) ;
sg_free_table ( sgt ) ;
}
return ret ;
}
2019-02-21 03:20:42 +02:00
static int rcar_du_vsp_plane_prepare_fb ( struct drm_plane * plane ,
struct drm_plane_state * state )
2017-05-17 02:20:07 +03:00
{
struct rcar_du_vsp_plane_state * rstate = to_rcar_vsp_plane_state ( state ) ;
struct rcar_du_vsp * vsp = to_rcar_vsp_plane ( plane ) - > vsp ;
2019-02-21 03:20:42 +02:00
int ret ;
2017-05-17 02:20:07 +03:00
2019-02-21 03:20:42 +02:00
/*
* There ' s no need to prepare ( and unprepare ) the framebuffer when the
* plane is not visible , as it will not be displayed .
*/
2017-08-15 18:52:04 +03:00
if ( ! state - > visible )
2019-02-21 03:20:42 +02:00
return 0 ;
ret = rcar_du_vsp_map_fb ( vsp , state - > fb , rstate - > sg_tables ) ;
if ( ret < 0 )
return ret ;
2021-02-22 15:17:56 +01:00
return drm_gem_plane_helper_prepare_fb ( plane , state ) ;
2019-02-21 03:20:42 +02:00
}
2017-05-17 02:20:07 +03:00
2019-02-21 03:20:42 +02:00
void rcar_du_vsp_unmap_fb ( struct rcar_du_vsp * vsp , struct drm_framebuffer * fb ,
struct sg_table sg_tables [ 3 ] )
{
unsigned int i ;
for ( i = 0 ; i < fb - > format - > num_planes ; + + i ) {
struct sg_table * sgt = & sg_tables [ i ] ;
2017-05-17 02:20:07 +03:00
vsp1_du_unmap_sg ( vsp - > vsp , sgt ) ;
sg_free_table ( sgt ) ;
}
}
2019-02-21 03:20:42 +02:00
static void rcar_du_vsp_plane_cleanup_fb ( struct drm_plane * plane ,
struct drm_plane_state * state )
{
struct rcar_du_vsp_plane_state * rstate = to_rcar_vsp_plane_state ( state ) ;
struct rcar_du_vsp * vsp = to_rcar_vsp_plane ( plane ) - > vsp ;
if ( ! state - > visible )
return ;
rcar_du_vsp_unmap_fb ( vsp , state - > fb , rstate - > sg_tables ) ;
}
2015-09-07 17:14:58 +03:00
static int rcar_du_vsp_plane_atomic_check ( struct drm_plane * plane ,
drm/atomic: Pass the full state to planes 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 convert all the remaining helpers to provide a consistent
interface, starting with the planes atomic_check.
The conversion was done using the coccinelle script below plus some
manual changes for vmwgfx, built tested on all the drivers.
@@
identifier plane, plane_state;
symbol state;
@@
struct drm_plane_helper_funcs {
...
int (*atomic_check)(struct drm_plane *plane,
- struct drm_plane_state *plane_state);
+ struct drm_atomic_state *state);
...
}
@ plane_atomic_func @
identifier helpers;
identifier func;
@@
static const struct drm_plane_helper_funcs helpers = {
...,
.atomic_check = func,
...,
};
@@
struct drm_plane_helper_funcs *FUNCS;
identifier f;
identifier dev;
identifier plane, plane_state, state;
@@
f(struct drm_device *dev, struct drm_atomic_state *state)
{
<+...
- FUNCS->atomic_check(plane, plane_state)
+ FUNCS->atomic_check(plane, state)
...+>
}
@ ignores_new_state @
identifier plane_atomic_func.func;
identifier plane, new_plane_state;
@@
func(struct drm_plane *plane, struct drm_plane_state *new_plane_state)
{
... when != new_plane_state
}
@ adds_new_state depends on plane_atomic_func && !ignores_new_state @
identifier plane_atomic_func.func;
identifier plane, new_plane_state;
@@
func(struct drm_plane *plane, struct drm_plane_state *new_plane_state)
{
+ struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane);
...
}
@ depends on plane_atomic_func @
identifier plane_atomic_func.func;
identifier plane, new_plane_state;
@@
func(struct drm_plane *plane,
- struct drm_plane_state *new_plane_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/...>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Acked-by: Thomas Zimmermann <tzimmermann@suse.de>
Link: https://patchwork.freedesktop.org/patch/msgid/20210219120032.260676-4-maxime@cerno.tech
2021-02-19 13:00:24 +01:00
struct drm_atomic_state * state )
2015-09-07 17:14:58 +03:00
{
drm/atomic: Pass the full state to planes 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 convert all the remaining helpers to provide a consistent
interface, starting with the planes atomic_check.
The conversion was done using the coccinelle script below plus some
manual changes for vmwgfx, built tested on all the drivers.
@@
identifier plane, plane_state;
symbol state;
@@
struct drm_plane_helper_funcs {
...
int (*atomic_check)(struct drm_plane *plane,
- struct drm_plane_state *plane_state);
+ struct drm_atomic_state *state);
...
}
@ plane_atomic_func @
identifier helpers;
identifier func;
@@
static const struct drm_plane_helper_funcs helpers = {
...,
.atomic_check = func,
...,
};
@@
struct drm_plane_helper_funcs *FUNCS;
identifier f;
identifier dev;
identifier plane, plane_state, state;
@@
f(struct drm_device *dev, struct drm_atomic_state *state)
{
<+...
- FUNCS->atomic_check(plane, plane_state)
+ FUNCS->atomic_check(plane, state)
...+>
}
@ ignores_new_state @
identifier plane_atomic_func.func;
identifier plane, new_plane_state;
@@
func(struct drm_plane *plane, struct drm_plane_state *new_plane_state)
{
... when != new_plane_state
}
@ adds_new_state depends on plane_atomic_func && !ignores_new_state @
identifier plane_atomic_func.func;
identifier plane, new_plane_state;
@@
func(struct drm_plane *plane, struct drm_plane_state *new_plane_state)
{
+ struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane);
...
}
@ depends on plane_atomic_func @
identifier plane_atomic_func.func;
identifier plane, new_plane_state;
@@
func(struct drm_plane *plane,
- struct drm_plane_state *new_plane_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/...>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Acked-by: Thomas Zimmermann <tzimmermann@suse.de>
Link: https://patchwork.freedesktop.org/patch/msgid/20210219120032.260676-4-maxime@cerno.tech
2021-02-19 13:00:24 +01:00
struct drm_plane_state * new_plane_state = drm_atomic_get_new_plane_state ( state ,
plane ) ;
2021-02-19 13:00:22 +01:00
struct rcar_du_vsp_plane_state * rstate = to_rcar_vsp_plane_state ( new_plane_state ) ;
2015-09-07 17:14:58 +03:00
2021-02-19 13:00:22 +01:00
return __rcar_du_plane_atomic_check ( plane , new_plane_state ,
& rstate - > format ) ;
2015-09-07 17:14:58 +03:00
}
static void rcar_du_vsp_plane_atomic_update ( struct drm_plane * plane ,
drm/atomic: Pass the full state to planes atomic disable and update
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 convert the remaining helpers to provide a consistent interface,
this time with the planes atomic_update and atomic_disable.
The conversion was done using the coccinelle script below, built tested on
all the drivers.
@@
identifier plane, plane_state;
symbol state;
@@
struct drm_plane_helper_funcs {
...
void (*atomic_update)(struct drm_plane *plane,
- struct drm_plane_state *plane_state);
+ struct drm_atomic_state *state);
...
}
@@
identifier plane, plane_state;
symbol state;
@@
struct drm_plane_helper_funcs {
...
void (*atomic_disable)(struct drm_plane *plane,
- struct drm_plane_state *plane_state);
+ struct drm_atomic_state *state);
...
}
@ plane_atomic_func @
identifier helpers;
identifier func;
@@
(
static const struct drm_plane_helper_funcs helpers = {
...,
.atomic_update = func,
...,
};
|
static const struct drm_plane_helper_funcs helpers = {
...,
.atomic_disable = func,
...,
};
)
@@
struct drm_plane_helper_funcs *FUNCS;
identifier f;
identifier crtc_state;
identifier plane, plane_state, state;
expression e;
@@
f(struct drm_crtc_state *crtc_state)
{
...
struct drm_atomic_state *state = e;
<+...
(
- FUNCS->atomic_disable(plane, plane_state)
+ FUNCS->atomic_disable(plane, state)
|
- FUNCS->atomic_update(plane, plane_state)
+ FUNCS->atomic_update(plane, state)
)
...+>
}
@@
identifier plane_atomic_func.func;
identifier plane;
symbol state;
@@
func(struct drm_plane *plane,
- struct drm_plane_state *state)
+ struct drm_plane_state *old_plane_state)
{
<...
- state
+ old_plane_state
...>
}
@ ignores_old_state @
identifier plane_atomic_func.func;
identifier plane, old_state;
@@
func(struct drm_plane *plane, struct drm_plane_state *old_state)
{
... when != old_state
}
@ adds_old_state depends on plane_atomic_func && !ignores_old_state @
identifier plane_atomic_func.func;
identifier plane, plane_state;
@@
func(struct drm_plane *plane, struct drm_plane_state *plane_state)
{
+ struct drm_plane_state *plane_state = drm_atomic_get_old_plane_state(state, plane);
...
}
@ depends on plane_atomic_func @
identifier plane_atomic_func.func;
identifier plane, plane_state;
@@
func(struct drm_plane *plane,
- struct drm_plane_state *plane_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/...>
@@
identifier plane_atomic_func.func;
identifier plane, state;
identifier plane_state;
@@
func(struct drm_plane *plane, struct drm_atomic_state *state) {
...
struct drm_plane_state *plane_state = drm_atomic_get_old_plane_state(state, plane);
<+...
- plane_state->state
+ state
...+>
}
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Acked-by: Thomas Zimmermann <tzimmermann@suse.de>
Link: https://patchwork.freedesktop.org/patch/msgid/20210219120032.260676-9-maxime@cerno.tech
2021-02-19 13:00:29 +01:00
struct drm_atomic_state * state )
2015-09-07 17:14:58 +03:00
{
drm/atomic: Pass the full state to planes atomic disable and update
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 convert the remaining helpers to provide a consistent interface,
this time with the planes atomic_update and atomic_disable.
The conversion was done using the coccinelle script below, built tested on
all the drivers.
@@
identifier plane, plane_state;
symbol state;
@@
struct drm_plane_helper_funcs {
...
void (*atomic_update)(struct drm_plane *plane,
- struct drm_plane_state *plane_state);
+ struct drm_atomic_state *state);
...
}
@@
identifier plane, plane_state;
symbol state;
@@
struct drm_plane_helper_funcs {
...
void (*atomic_disable)(struct drm_plane *plane,
- struct drm_plane_state *plane_state);
+ struct drm_atomic_state *state);
...
}
@ plane_atomic_func @
identifier helpers;
identifier func;
@@
(
static const struct drm_plane_helper_funcs helpers = {
...,
.atomic_update = func,
...,
};
|
static const struct drm_plane_helper_funcs helpers = {
...,
.atomic_disable = func,
...,
};
)
@@
struct drm_plane_helper_funcs *FUNCS;
identifier f;
identifier crtc_state;
identifier plane, plane_state, state;
expression e;
@@
f(struct drm_crtc_state *crtc_state)
{
...
struct drm_atomic_state *state = e;
<+...
(
- FUNCS->atomic_disable(plane, plane_state)
+ FUNCS->atomic_disable(plane, state)
|
- FUNCS->atomic_update(plane, plane_state)
+ FUNCS->atomic_update(plane, state)
)
...+>
}
@@
identifier plane_atomic_func.func;
identifier plane;
symbol state;
@@
func(struct drm_plane *plane,
- struct drm_plane_state *state)
+ struct drm_plane_state *old_plane_state)
{
<...
- state
+ old_plane_state
...>
}
@ ignores_old_state @
identifier plane_atomic_func.func;
identifier plane, old_state;
@@
func(struct drm_plane *plane, struct drm_plane_state *old_state)
{
... when != old_state
}
@ adds_old_state depends on plane_atomic_func && !ignores_old_state @
identifier plane_atomic_func.func;
identifier plane, plane_state;
@@
func(struct drm_plane *plane, struct drm_plane_state *plane_state)
{
+ struct drm_plane_state *plane_state = drm_atomic_get_old_plane_state(state, plane);
...
}
@ depends on plane_atomic_func @
identifier plane_atomic_func.func;
identifier plane, plane_state;
@@
func(struct drm_plane *plane,
- struct drm_plane_state *plane_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/...>
@@
identifier plane_atomic_func.func;
identifier plane, state;
identifier plane_state;
@@
func(struct drm_plane *plane, struct drm_atomic_state *state) {
...
struct drm_plane_state *plane_state = drm_atomic_get_old_plane_state(state, plane);
<+...
- plane_state->state
+ state
...+>
}
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Acked-by: Thomas Zimmermann <tzimmermann@suse.de>
Link: https://patchwork.freedesktop.org/patch/msgid/20210219120032.260676-9-maxime@cerno.tech
2021-02-19 13:00:29 +01:00
struct drm_plane_state * old_state = drm_atomic_get_old_plane_state ( state , plane ) ;
drm: Use state helper instead of the plane state pointer
Many drivers reference the plane->state pointer in order to get the
current plane state in their atomic_update or atomic_disable hooks,
which would be the new plane state in the global atomic state since
_swap_state happened when those hooks are run.
Use the drm_atomic_get_new_plane_state helper to get that state to make it
more obvious.
This was made using the coccinelle script below:
@ plane_atomic_func @
identifier helpers;
identifier func;
@@
(
static const struct drm_plane_helper_funcs helpers = {
...,
.atomic_disable = func,
...,
};
|
static const struct drm_plane_helper_funcs helpers = {
...,
.atomic_update = func,
...,
};
)
@ adds_new_state @
identifier plane_atomic_func.func;
identifier plane, state;
identifier new_state;
@@
func(struct drm_plane *plane, struct drm_atomic_state *state)
{
...
- struct drm_plane_state *new_state = plane->state;
+ struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane);
...
}
@ 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/...>
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Acked-by: Thomas Zimmermann <tzimmermann@suse.de>
Link: https://lore.kernel.org/r/20210219120032.260676-1-maxime@cerno.tech
2021-02-19 13:00:30 +01:00
struct drm_plane_state * new_state = drm_atomic_get_new_plane_state ( state , plane ) ;
2015-09-07 17:14:58 +03:00
struct rcar_du_vsp_plane * rplane = to_rcar_vsp_plane ( plane ) ;
2017-06-26 13:12:01 +03:00
struct rcar_du_crtc * crtc = to_rcar_crtc ( old_state - > crtc ) ;
2015-09-07 17:14:58 +03:00
drm: Store new plane state in a variable for atomic_update and disable
In order to store the new plane state in a subsequent helper, let's move
the plane->state dereferences into a variable.
This was done using the following coccinelle script, plus some hand
changes for vmwgfx:
@ plane_atomic_func @
identifier helpers;
identifier func;
@@
(
static const struct drm_plane_helper_funcs helpers = {
...,
.atomic_disable = func,
...,
};
|
static const struct drm_plane_helper_funcs helpers = {
...,
.atomic_update = func,
...,
};
)
@ has_new_state_old_state @
identifier plane_atomic_func.func;
identifier plane;
identifier new_state;
symbol old_state;
@@
func(struct drm_plane *plane, struct drm_plane_state *old_state)
{
...
struct drm_plane_state *new_state = plane->state;
...
}
@ depends on !has_new_state_old_state @
identifier plane_atomic_func.func;
identifier plane;
symbol old_state;
@@
func(struct drm_plane *plane, struct drm_plane_state *old_state)
{
+ struct drm_plane_state *new_state = plane->state;
<+...
- plane->state
+ new_state
...+>
}
@ has_new_state_state @
identifier plane_atomic_func.func;
identifier plane;
identifier new_state;
symbol state;
@@
func(struct drm_plane *plane, struct drm_plane_state *state)
{
...
struct drm_plane_state *new_state = plane->state;
...
}
@ depends on !has_new_state_state @
identifier plane_atomic_func.func;
identifier plane;
symbol state;
@@
func(struct drm_plane *plane, struct drm_plane_state *state)
{
+ struct drm_plane_state *new_plane_state = plane->state;
<+...
- plane->state
+ new_plane_state
...+>
}
@ has_new_state_old_s @
identifier plane_atomic_func.func;
identifier plane;
identifier new_state;
symbol old_s;
@@
func(struct drm_plane *plane, struct drm_plane_state *old_s)
{
...
struct drm_plane_state *new_state = plane->state;
...
}
@ depends on !has_new_state_old_s @
identifier plane_atomic_func.func;
identifier plane;
symbol old_s;
@@
func(struct drm_plane *plane, struct drm_plane_state *old_s)
{
+ struct drm_plane_state *new_s = plane->state;
<+...
- plane->state
+ new_s
...+>
}
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Acked-by: Thomas Zimmermann <tzimmermann@suse.de>
Link: https://lore.kernel.org/r/20210219120032.260676-1-maxime@cerno.tech
2021-02-19 13:00:27 +01:00
if ( new_state - > visible )
2015-09-07 17:14:58 +03:00
rcar_du_vsp_plane_setup ( rplane ) ;
2020-08-08 00:07:21 +03:00
else if ( old_state - > crtc )
2017-06-26 13:12:01 +03:00
vsp1_du_atomic_update ( rplane - > vsp - > vsp , crtc - > vsp_pipe ,
rplane - > index , NULL ) ;
2015-09-07 17:14:58 +03:00
}
static const struct drm_plane_helper_funcs rcar_du_vsp_plane_helper_funcs = {
2017-05-17 02:20:07 +03:00
. prepare_fb = rcar_du_vsp_plane_prepare_fb ,
. cleanup_fb = rcar_du_vsp_plane_cleanup_fb ,
2015-09-07 17:14:58 +03:00
. atomic_check = rcar_du_vsp_plane_atomic_check ,
. atomic_update = rcar_du_vsp_plane_atomic_update ,
} ;
static struct drm_plane_state *
rcar_du_vsp_plane_atomic_duplicate_state ( struct drm_plane * plane )
{
struct rcar_du_vsp_plane_state * copy ;
if ( WARN_ON ( ! plane - > state ) )
return NULL ;
2018-01-17 22:18:41 +02:00
copy = kzalloc ( sizeof ( * copy ) , GFP_KERNEL ) ;
2015-09-07 17:14:58 +03:00
if ( copy = = NULL )
return NULL ;
__drm_atomic_helper_plane_duplicate_state ( plane , & copy - > state ) ;
return & copy - > state ;
}
static void rcar_du_vsp_plane_atomic_destroy_state ( struct drm_plane * plane ,
struct drm_plane_state * state )
{
2016-05-09 16:34:10 +02:00
__drm_atomic_helper_plane_destroy_state ( state ) ;
2015-09-07 17:14:58 +03:00
kfree ( to_rcar_vsp_plane_state ( state ) ) ;
}
static void rcar_du_vsp_plane_reset ( struct drm_plane * plane )
{
struct rcar_du_vsp_plane_state * state ;
if ( plane - > state ) {
rcar_du_vsp_plane_atomic_destroy_state ( plane , plane - > state ) ;
plane - > state = NULL ;
}
state = kzalloc ( sizeof ( * state ) , GFP_KERNEL ) ;
if ( state = = NULL )
return ;
2018-08-04 17:15:27 +01:00
__drm_atomic_helper_plane_reset ( plane , & state - > state ) ;
2015-09-07 17:14:58 +03:00
}
static const struct drm_plane_funcs rcar_du_vsp_plane_funcs = {
. update_plane = drm_atomic_helper_update_plane ,
. disable_plane = drm_atomic_helper_disable_plane ,
. reset = rcar_du_vsp_plane_reset ,
. destroy = drm_plane_cleanup ,
. atomic_duplicate_state = rcar_du_vsp_plane_atomic_duplicate_state ,
. atomic_destroy_state = rcar_du_vsp_plane_atomic_destroy_state ,
} ;
2020-09-16 02:23:47 +03:00
static void rcar_du_vsp_cleanup ( struct drm_device * dev , void * res )
{
struct rcar_du_vsp * vsp = res ;
2020-12-03 15:09:22 +02:00
unsigned int i ;
for ( i = 0 ; i < vsp - > num_planes ; + + i ) {
struct rcar_du_vsp_plane * plane = & vsp - > planes [ i ] ;
drm_plane_cleanup ( & plane - > plane ) ;
}
kfree ( vsp - > planes ) ;
2020-09-16 02:23:47 +03:00
put_device ( vsp - > vsp ) ;
}
2017-06-26 13:12:01 +03:00
int rcar_du_vsp_init ( struct rcar_du_vsp * vsp , struct device_node * np ,
unsigned int crtcs )
2015-09-07 17:14:58 +03:00
{
struct rcar_du_device * rcdu = vsp - > dev ;
struct platform_device * pdev ;
2017-06-26 13:12:01 +03:00
unsigned int num_crtcs = hweight32 ( crtcs ) ;
2020-12-03 15:09:22 +02:00
unsigned int num_planes ;
2015-09-07 17:14:58 +03:00
unsigned int i ;
int ret ;
/* Find the VSP device and initialize it. */
pdev = of_find_device_by_node ( np ) ;
if ( ! pdev )
return - ENXIO ;
vsp - > vsp = & pdev - > dev ;
2020-12-03 18:21:55 +02:00
ret = drmm_add_action_or_reset ( & rcdu - > ddev , rcar_du_vsp_cleanup , vsp ) ;
2020-09-16 02:23:47 +03:00
if ( ret < 0 )
return ret ;
2015-09-07 17:14:58 +03:00
ret = vsp1_du_init ( vsp - > vsp ) ;
if ( ret < 0 )
return ret ;
2022-04-21 17:31:27 +01:00
num_planes = rcdu - > info - > num_rpf ;
2015-09-07 17:14:58 +03:00
2020-12-03 15:09:22 +02:00
vsp - > planes = kcalloc ( num_planes , sizeof ( * vsp - > planes ) , GFP_KERNEL ) ;
2015-09-07 17:14:58 +03:00
if ( ! vsp - > planes )
return - ENOMEM ;
2020-12-03 15:09:22 +02:00
for ( i = 0 ; i < num_planes ; + + i ) {
2017-06-26 13:12:01 +03:00
enum drm_plane_type type = i < num_crtcs
? DRM_PLANE_TYPE_PRIMARY
: DRM_PLANE_TYPE_OVERLAY ;
2015-09-07 17:14:58 +03:00
struct rcar_du_vsp_plane * plane = & vsp - > planes [ i ] ;
2022-12-21 11:24:48 +02:00
unsigned int num_formats ;
const u32 * formats ;
if ( rcdu - > info - > gen < 4 ) {
num_formats = ARRAY_SIZE ( rcar_du_vsp_formats ) ;
formats = rcar_du_vsp_formats ;
} else {
num_formats = ARRAY_SIZE ( rcar_du_vsp_formats_gen4 ) ;
formats = rcar_du_vsp_formats_gen4 ;
}
2015-09-07 17:14:58 +03:00
plane - > vsp = vsp ;
plane - > index = i ;
2020-12-03 18:21:55 +02:00
ret = drm_universal_plane_init ( & rcdu - > ddev , & plane - > plane ,
crtcs , & rcar_du_vsp_plane_funcs ,
2022-12-21 11:24:48 +02:00
formats , num_formats ,
2017-07-23 20:46:38 -07:00
NULL , type , NULL ) ;
2015-09-07 17:14:58 +03:00
if ( ret < 0 )
return ret ;
drm_plane_helper_add ( & plane - > plane ,
& rcar_du_vsp_plane_helper_funcs ) ;
2022-06-07 19:33:22 +03:00
drm_plane_create_alpha_property ( & plane - > plane ) ;
drm_plane_create_zpos_property ( & plane - > plane , i , 0 ,
num_planes - 1 ) ;
2020-12-03 15:09:22 +02:00
2022-08-10 17:37:10 +09:00
drm_plane_create_blend_mode_property ( & plane - > plane ,
2022-08-10 17:37:11 +09:00
BIT ( DRM_MODE_BLEND_PIXEL_NONE ) |
2022-08-10 17:37:10 +09:00
BIT ( DRM_MODE_BLEND_PREMULTI ) |
BIT ( DRM_MODE_BLEND_COVERAGE ) ) ;
2020-12-03 15:09:22 +02:00
vsp - > num_planes + + ;
2015-09-07 17:14:58 +03:00
}
return 0 ;
}