2018-07-07 19:05:34 -07:00
// SPDX-License-Identifier: GPL-2.0
/*
* ZynqMP Display Controller Driver
*
* Copyright ( C ) 2017 - 2020 Xilinx , Inc .
*
* Authors :
* - Hyun Woo Kwon < hyun . kwon @ xilinx . com >
* - Laurent Pinchart < laurent . pinchart @ ideasonboard . com >
*/
# include <drm/drm_atomic.h>
# include <drm/drm_atomic_helper.h>
# include <drm/drm_atomic_uapi.h>
# include <drm/drm_crtc.h>
# include <drm/drm_device.h>
# include <drm/drm_fb_cma_helper.h>
# include <drm/drm_fourcc.h>
# include <drm/drm_framebuffer.h>
# include <drm/drm_managed.h>
# include <drm/drm_plane.h>
# include <drm/drm_plane_helper.h>
# include <drm/drm_vblank.h>
# include <linux/clk.h>
# include <linux/delay.h>
2021-11-22 23:22:01 +01:00
# include <linux/dma/xilinx_dpdma.h>
2018-07-07 19:05:34 -07:00
# include <linux/dma-mapping.h>
# include <linux/dmaengine.h>
# include <linux/module.h>
# include <linux/of.h>
# include <linux/platform_device.h>
# include <linux/pm_runtime.h>
# include <linux/spinlock.h>
# include "zynqmp_disp.h"
# include "zynqmp_disp_regs.h"
# include "zynqmp_dp.h"
# include "zynqmp_dpsub.h"
/*
* Overview
* - - - - - - - -
*
* The display controller part of ZynqMP DP subsystem , made of the Audio / Video
* Buffer Manager , the Video Rendering Pipeline ( blender ) and the Audio Mixer .
*
* + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
* + - - - - - - - - + | + - - - - - - - - - - - - - - - - + + - - - - - - - - - - - + |
* | DPDMA | - - - > | | - - > | Video | Video + - - - - - - - - - - - - - + |
* | 4 x vid | | | | | Rendering | - + - - > | | | + - - - - - - +
* | 2 x aud | | | Audio / Video | - - > | Pipeline | | | DisplayPort | - - - > | PHY0 |
* + - - - - - - - - + | | Buffer Manager | + - - - - - - - - - - - + | | Source | | + - - - - - - +
* | | and STC | + - - - - - - - - - - - + | | Controller | | + - - - - - - +
* Live Video - - - > | | - - > | Audio | Audio | | - - - > | PHY1 |
* | | | | Mixer | - - + - > | | | + - - - - - - +
* Live Audio - - - > | | - - > | | | | + - - - - - - - - - - - - - + |
* | + - - - - - - - - - - - - - - - - + + - - - - - - - - - - - + | | |
* + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | | - - - - - - - - - - - - - - - - - - - +
* vv
* Blended Video and
* Mixed Audio to PL
*
* Only non - live input from the DPDMA and output to the DisplayPort Source
* Controller are currently supported . Interface with the programmable logic
* for live streams is not implemented .
*
* The display controller code creates planes for the DPDMA video and graphics
* layers , and a CRTC for the Video Rendering Pipeline .
*/
# define ZYNQMP_DISP_AV_BUF_NUM_VID_GFX_BUFFERS 4
# define ZYNQMP_DISP_AV_BUF_NUM_BUFFERS 6
# define ZYNQMP_DISP_NUM_LAYERS 2
# define ZYNQMP_DISP_MAX_NUM_SUB_PLANES 3
/**
* struct zynqmp_disp_format - Display subsystem format information
* @ drm_fmt : DRM format ( 4 CC )
* @ buf_fmt : AV buffer format
* @ bus_fmt : Media bus formats ( live formats )
* @ swap : Flag to swap R & B for RGB formats , and U & V for YUV formats
* @ sf : Scaling factors for color components
*/
struct zynqmp_disp_format {
u32 drm_fmt ;
u32 buf_fmt ;
u32 bus_fmt ;
bool swap ;
const u32 * sf ;
} ;
/**
2021-06-02 15:32:51 +01:00
* enum zynqmp_disp_layer_id - Layer identifier
2018-07-07 19:05:34 -07:00
* @ ZYNQMP_DISP_LAYER_VID : Video layer
* @ ZYNQMP_DISP_LAYER_GFX : Graphics layer
*/
enum zynqmp_disp_layer_id {
ZYNQMP_DISP_LAYER_VID ,
ZYNQMP_DISP_LAYER_GFX
} ;
/**
* enum zynqmp_disp_layer_mode - Layer mode
* @ ZYNQMP_DISP_LAYER_NONLIVE : non - live ( memory ) mode
* @ ZYNQMP_DISP_LAYER_LIVE : live ( stream ) mode
*/
enum zynqmp_disp_layer_mode {
ZYNQMP_DISP_LAYER_NONLIVE ,
ZYNQMP_DISP_LAYER_LIVE
} ;
/**
* struct zynqmp_disp_layer_dma - DMA channel for one data plane of a layer
* @ chan : DMA channel
* @ xt : Interleaved DMA descriptor template
* @ sgl : Data chunk for dma_interleaved_template
*/
struct zynqmp_disp_layer_dma {
struct dma_chan * chan ;
struct dma_interleaved_template xt ;
struct data_chunk sgl ;
} ;
/**
* struct zynqmp_disp_layer_info - Static layer information
* @ formats : Array of supported formats
* @ num_formats : Number of formats in @ formats array
* @ num_channels : Number of DMA channels
*/
struct zynqmp_disp_layer_info {
const struct zynqmp_disp_format * formats ;
unsigned int num_formats ;
unsigned int num_channels ;
} ;
/**
* struct zynqmp_disp_layer - Display layer ( DRM plane )
* @ plane : DRM plane
* @ id : Layer ID
* @ disp : Back pointer to struct zynqmp_disp
* @ info : Static layer information
* @ dmas : DMA channels
* @ disp_fmt : Current format information
* @ drm_fmt : Current DRM format information
* @ mode : Current operation mode
*/
struct zynqmp_disp_layer {
struct drm_plane plane ;
enum zynqmp_disp_layer_id id ;
struct zynqmp_disp * disp ;
const struct zynqmp_disp_layer_info * info ;
struct zynqmp_disp_layer_dma dmas [ ZYNQMP_DISP_MAX_NUM_SUB_PLANES ] ;
const struct zynqmp_disp_format * disp_fmt ;
const struct drm_format_info * drm_fmt ;
enum zynqmp_disp_layer_mode mode ;
} ;
/**
* struct zynqmp_disp - Display controller
* @ dev : Device structure
* @ drm : DRM core
* @ dpsub : Display subsystem
* @ crtc : DRM CRTC
2021-03-07 02:56:58 +02:00
* @ blend . base : Register I / O base address for the blender
* @ avbuf . base : Register I / O base address for the audio / video buffer manager
* @ audio . base : Registers I / O base address for the audio mixer
* @ audio . clk : Audio clock
* @ audio . clk_from_ps : True of the audio clock comes from PS , false from PL
2018-07-07 19:05:34 -07:00
* @ layers : Layers ( planes )
* @ event : Pending vblank event request
* @ pclk : Pixel clock
* @ pclk_from_ps : True of the video clock comes from PS , false from PL
*/
struct zynqmp_disp {
struct device * dev ;
struct drm_device * drm ;
struct zynqmp_dpsub * dpsub ;
struct drm_crtc crtc ;
2021-03-07 02:56:58 +02:00
struct {
void __iomem * base ;
} blend ;
struct {
void __iomem * base ;
} avbuf ;
struct {
void __iomem * base ;
struct clk * clk ;
bool clk_from_ps ;
} audio ;
2018-07-07 19:05:34 -07:00
struct zynqmp_disp_layer layers [ ZYNQMP_DISP_NUM_LAYERS ] ;
struct drm_pending_vblank_event * event ;
struct clk * pclk ;
bool pclk_from_ps ;
} ;
/* -----------------------------------------------------------------------------
* Audio / Video Buffer Manager
*/
static const u32 scaling_factors_444 [ ] = {
ZYNQMP_DISP_AV_BUF_4BIT_SF ,
ZYNQMP_DISP_AV_BUF_4BIT_SF ,
ZYNQMP_DISP_AV_BUF_4BIT_SF ,
} ;
static const u32 scaling_factors_555 [ ] = {
ZYNQMP_DISP_AV_BUF_5BIT_SF ,
ZYNQMP_DISP_AV_BUF_5BIT_SF ,
ZYNQMP_DISP_AV_BUF_5BIT_SF ,
} ;
static const u32 scaling_factors_565 [ ] = {
ZYNQMP_DISP_AV_BUF_5BIT_SF ,
ZYNQMP_DISP_AV_BUF_6BIT_SF ,
ZYNQMP_DISP_AV_BUF_5BIT_SF ,
} ;
static const u32 scaling_factors_888 [ ] = {
ZYNQMP_DISP_AV_BUF_8BIT_SF ,
ZYNQMP_DISP_AV_BUF_8BIT_SF ,
ZYNQMP_DISP_AV_BUF_8BIT_SF ,
} ;
static const u32 scaling_factors_101010 [ ] = {
ZYNQMP_DISP_AV_BUF_10BIT_SF ,
ZYNQMP_DISP_AV_BUF_10BIT_SF ,
ZYNQMP_DISP_AV_BUF_10BIT_SF ,
} ;
/* List of video layer formats */
static const struct zynqmp_disp_format avbuf_vid_fmts [ ] = {
{
. drm_fmt = DRM_FORMAT_VYUY ,
. buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_VYUY ,
. swap = true ,
. sf = scaling_factors_888 ,
} , {
. drm_fmt = DRM_FORMAT_UYVY ,
. buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_VYUY ,
. swap = false ,
. sf = scaling_factors_888 ,
} , {
. drm_fmt = DRM_FORMAT_YUYV ,
. buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YUYV ,
. swap = false ,
. sf = scaling_factors_888 ,
} , {
. drm_fmt = DRM_FORMAT_YVYU ,
. buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YUYV ,
. swap = true ,
. sf = scaling_factors_888 ,
} , {
. drm_fmt = DRM_FORMAT_YUV422 ,
. buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16 ,
. swap = false ,
. sf = scaling_factors_888 ,
} , {
. drm_fmt = DRM_FORMAT_YVU422 ,
. buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16 ,
. swap = true ,
. sf = scaling_factors_888 ,
} , {
. drm_fmt = DRM_FORMAT_YUV444 ,
. buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV24 ,
. swap = false ,
. sf = scaling_factors_888 ,
} , {
. drm_fmt = DRM_FORMAT_YVU444 ,
. buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV24 ,
. swap = true ,
. sf = scaling_factors_888 ,
} , {
. drm_fmt = DRM_FORMAT_NV16 ,
. buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16CI ,
. swap = false ,
. sf = scaling_factors_888 ,
} , {
. drm_fmt = DRM_FORMAT_NV61 ,
. buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16CI ,
. swap = true ,
. sf = scaling_factors_888 ,
} , {
. drm_fmt = DRM_FORMAT_BGR888 ,
. buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_RGB888 ,
. swap = false ,
. sf = scaling_factors_888 ,
} , {
. drm_fmt = DRM_FORMAT_RGB888 ,
. buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_RGB888 ,
. swap = true ,
. sf = scaling_factors_888 ,
} , {
. drm_fmt = DRM_FORMAT_XBGR8888 ,
. buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_RGBA8880 ,
. swap = false ,
. sf = scaling_factors_888 ,
} , {
. drm_fmt = DRM_FORMAT_XRGB8888 ,
. buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_RGBA8880 ,
. swap = true ,
. sf = scaling_factors_888 ,
} , {
. drm_fmt = DRM_FORMAT_XBGR2101010 ,
. buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_RGB888_10 ,
. swap = false ,
. sf = scaling_factors_101010 ,
} , {
. drm_fmt = DRM_FORMAT_XRGB2101010 ,
. buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_RGB888_10 ,
. swap = true ,
. sf = scaling_factors_101010 ,
} , {
. drm_fmt = DRM_FORMAT_YUV420 ,
. buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16_420 ,
. swap = false ,
. sf = scaling_factors_888 ,
} , {
. drm_fmt = DRM_FORMAT_YVU420 ,
. buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16_420 ,
. swap = true ,
. sf = scaling_factors_888 ,
} , {
. drm_fmt = DRM_FORMAT_NV12 ,
. buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16CI_420 ,
. swap = false ,
. sf = scaling_factors_888 ,
} , {
. drm_fmt = DRM_FORMAT_NV21 ,
. buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16CI_420 ,
. swap = true ,
. sf = scaling_factors_888 ,
} ,
} ;
/* List of graphics layer formats */
static const struct zynqmp_disp_format avbuf_gfx_fmts [ ] = {
{
. drm_fmt = DRM_FORMAT_ABGR8888 ,
. buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGBA8888 ,
. swap = false ,
. sf = scaling_factors_888 ,
} , {
. drm_fmt = DRM_FORMAT_ARGB8888 ,
. buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGBA8888 ,
. swap = true ,
. sf = scaling_factors_888 ,
} , {
. drm_fmt = DRM_FORMAT_RGBA8888 ,
. buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_ABGR8888 ,
. swap = false ,
. sf = scaling_factors_888 ,
} , {
. drm_fmt = DRM_FORMAT_BGRA8888 ,
. buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_ABGR8888 ,
. swap = true ,
. sf = scaling_factors_888 ,
} , {
. drm_fmt = DRM_FORMAT_BGR888 ,
. buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGB888 ,
. swap = false ,
. sf = scaling_factors_888 ,
} , {
. drm_fmt = DRM_FORMAT_RGB888 ,
. buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_BGR888 ,
. swap = false ,
. sf = scaling_factors_888 ,
} , {
. drm_fmt = DRM_FORMAT_RGBA5551 ,
. buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGBA5551 ,
. swap = false ,
. sf = scaling_factors_555 ,
} , {
. drm_fmt = DRM_FORMAT_BGRA5551 ,
. buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGBA5551 ,
. swap = true ,
. sf = scaling_factors_555 ,
} , {
. drm_fmt = DRM_FORMAT_RGBA4444 ,
. buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGBA4444 ,
. swap = false ,
. sf = scaling_factors_444 ,
} , {
. drm_fmt = DRM_FORMAT_BGRA4444 ,
. buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGBA4444 ,
. swap = true ,
. sf = scaling_factors_444 ,
} , {
. drm_fmt = DRM_FORMAT_RGB565 ,
. buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGB565 ,
. swap = false ,
. sf = scaling_factors_565 ,
} , {
. drm_fmt = DRM_FORMAT_BGR565 ,
. buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGB565 ,
. swap = true ,
. sf = scaling_factors_565 ,
} ,
} ;
2021-03-07 02:56:58 +02:00
static u32 zynqmp_disp_avbuf_read ( struct zynqmp_disp * disp , int reg )
2018-07-07 19:05:34 -07:00
{
2021-03-07 02:56:58 +02:00
return readl ( disp - > avbuf . base + reg ) ;
2018-07-07 19:05:34 -07:00
}
2021-03-07 02:56:58 +02:00
static void zynqmp_disp_avbuf_write ( struct zynqmp_disp * disp , int reg , u32 val )
2018-07-07 19:05:34 -07:00
{
2021-03-07 02:56:58 +02:00
writel ( val , disp - > avbuf . base + reg ) ;
2018-07-07 19:05:34 -07:00
}
2021-03-07 02:56:58 +02:00
static bool zynqmp_disp_layer_is_gfx ( const struct zynqmp_disp_layer * layer )
{
return layer - > id = = ZYNQMP_DISP_LAYER_GFX ;
}
2021-05-18 17:50:18 +08:00
static bool zynqmp_disp_layer_is_video ( const struct zynqmp_disp_layer * layer )
{
return layer - > id = = ZYNQMP_DISP_LAYER_VID ;
}
2018-07-07 19:05:34 -07:00
/**
* zynqmp_disp_avbuf_set_format - Set the input format for a layer
2021-03-07 02:56:58 +02:00
* @ disp : Display controller
2021-05-18 17:50:18 +08:00
* @ layer : The layer
2018-07-07 19:05:34 -07:00
* @ fmt : The format information
*
* Set the video buffer manager format for @ layer to @ fmt .
*/
2021-03-07 02:56:58 +02:00
static void zynqmp_disp_avbuf_set_format ( struct zynqmp_disp * disp ,
2021-05-18 17:50:18 +08:00
struct zynqmp_disp_layer * layer ,
2018-07-07 19:05:34 -07:00
const struct zynqmp_disp_format * fmt )
{
unsigned int i ;
u32 val ;
2021-03-07 02:56:58 +02:00
val = zynqmp_disp_avbuf_read ( disp , ZYNQMP_DISP_AV_BUF_FMT ) ;
2021-05-18 17:50:18 +08:00
val & = zynqmp_disp_layer_is_video ( layer )
2018-07-07 19:05:34 -07:00
? ~ ZYNQMP_DISP_AV_BUF_FMT_NL_VID_MASK
: ~ ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_MASK ;
val | = fmt - > buf_fmt ;
2021-03-07 02:56:58 +02:00
zynqmp_disp_avbuf_write ( disp , ZYNQMP_DISP_AV_BUF_FMT , val ) ;
2018-07-07 19:05:34 -07:00
for ( i = 0 ; i < ZYNQMP_DISP_AV_BUF_NUM_SF ; i + + ) {
2021-05-18 17:50:18 +08:00
unsigned int reg = zynqmp_disp_layer_is_video ( layer )
2018-07-07 19:05:34 -07:00
? ZYNQMP_DISP_AV_BUF_VID_COMP_SF ( i )
: ZYNQMP_DISP_AV_BUF_GFX_COMP_SF ( i ) ;
2021-03-07 02:56:58 +02:00
zynqmp_disp_avbuf_write ( disp , reg , fmt - > sf [ i ] ) ;
2018-07-07 19:05:34 -07:00
}
}
/**
* zynqmp_disp_avbuf_set_clocks_sources - Set the clocks sources
2021-03-07 02:56:58 +02:00
* @ disp : Display controller
2018-07-07 19:05:34 -07:00
* @ video_from_ps : True if the video clock originates from the PS
* @ audio_from_ps : True if the audio clock originates from the PS
* @ timings_internal : True if video timings are generated internally
*
* Set the source for the video and audio clocks , as well as for the video
* timings . Clocks can originate from the PS or PL , and timings can be
* generated internally or externally .
*/
static void
2021-03-07 02:56:58 +02:00
zynqmp_disp_avbuf_set_clocks_sources ( struct zynqmp_disp * disp ,
2018-07-07 19:05:34 -07:00
bool video_from_ps , bool audio_from_ps ,
bool timings_internal )
{
u32 val = 0 ;
if ( video_from_ps )
val | = ZYNQMP_DISP_AV_BUF_CLK_SRC_VID_FROM_PS ;
if ( audio_from_ps )
val | = ZYNQMP_DISP_AV_BUF_CLK_SRC_AUD_FROM_PS ;
if ( timings_internal )
val | = ZYNQMP_DISP_AV_BUF_CLK_SRC_VID_INTERNAL_TIMING ;
2021-03-07 02:56:58 +02:00
zynqmp_disp_avbuf_write ( disp , ZYNQMP_DISP_AV_BUF_CLK_SRC , val ) ;
2018-07-07 19:05:34 -07:00
}
/**
* zynqmp_disp_avbuf_enable_channels - Enable buffer channels
2021-03-07 02:56:58 +02:00
* @ disp : Display controller
2018-07-07 19:05:34 -07:00
*
* Enable all ( video and audio ) buffer channels .
*/
2021-03-07 02:56:58 +02:00
static void zynqmp_disp_avbuf_enable_channels ( struct zynqmp_disp * disp )
2018-07-07 19:05:34 -07:00
{
unsigned int i ;
u32 val ;
val = ZYNQMP_DISP_AV_BUF_CHBUF_EN |
( ZYNQMP_DISP_AV_BUF_CHBUF_BURST_LEN_MAX < <
ZYNQMP_DISP_AV_BUF_CHBUF_BURST_LEN_SHIFT ) ;
for ( i = 0 ; i < ZYNQMP_DISP_AV_BUF_NUM_VID_GFX_BUFFERS ; i + + )
2021-03-07 02:56:58 +02:00
zynqmp_disp_avbuf_write ( disp , ZYNQMP_DISP_AV_BUF_CHBUF ( i ) ,
2018-07-07 19:05:34 -07:00
val ) ;
val = ZYNQMP_DISP_AV_BUF_CHBUF_EN |
( ZYNQMP_DISP_AV_BUF_CHBUF_BURST_LEN_AUD_MAX < <
ZYNQMP_DISP_AV_BUF_CHBUF_BURST_LEN_SHIFT ) ;
for ( ; i < ZYNQMP_DISP_AV_BUF_NUM_BUFFERS ; i + + )
2021-03-07 02:56:58 +02:00
zynqmp_disp_avbuf_write ( disp , ZYNQMP_DISP_AV_BUF_CHBUF ( i ) ,
2018-07-07 19:05:34 -07:00
val ) ;
}
/**
* zynqmp_disp_avbuf_disable_channels - Disable buffer channels
2021-03-07 02:56:58 +02:00
* @ disp : Display controller
2018-07-07 19:05:34 -07:00
*
* Disable all ( video and audio ) buffer channels .
*/
2021-03-07 02:56:58 +02:00
static void zynqmp_disp_avbuf_disable_channels ( struct zynqmp_disp * disp )
2018-07-07 19:05:34 -07:00
{
unsigned int i ;
for ( i = 0 ; i < ZYNQMP_DISP_AV_BUF_NUM_BUFFERS ; i + + )
2021-03-07 02:56:58 +02:00
zynqmp_disp_avbuf_write ( disp , ZYNQMP_DISP_AV_BUF_CHBUF ( i ) ,
2018-07-07 19:05:34 -07:00
ZYNQMP_DISP_AV_BUF_CHBUF_FLUSH ) ;
}
/**
* zynqmp_disp_avbuf_enable_audio - Enable audio
2021-03-07 02:56:58 +02:00
* @ disp : Display controller
2018-07-07 19:05:34 -07:00
*
* Enable all audio buffers with a non - live ( memory ) source .
*/
2021-03-07 02:56:58 +02:00
static void zynqmp_disp_avbuf_enable_audio ( struct zynqmp_disp * disp )
2018-07-07 19:05:34 -07:00
{
u32 val ;
2021-03-07 02:56:58 +02:00
val = zynqmp_disp_avbuf_read ( disp , ZYNQMP_DISP_AV_BUF_OUTPUT ) ;
2018-07-07 19:05:34 -07:00
val & = ~ ZYNQMP_DISP_AV_BUF_OUTPUT_AUD1_MASK ;
val | = ZYNQMP_DISP_AV_BUF_OUTPUT_AUD1_MEM ;
val | = ZYNQMP_DISP_AV_BUF_OUTPUT_AUD2_EN ;
2021-03-07 02:56:58 +02:00
zynqmp_disp_avbuf_write ( disp , ZYNQMP_DISP_AV_BUF_OUTPUT , val ) ;
2018-07-07 19:05:34 -07:00
}
/**
* zynqmp_disp_avbuf_disable_audio - Disable audio
2021-03-07 02:56:58 +02:00
* @ disp : Display controller
2018-07-07 19:05:34 -07:00
*
* Disable all audio buffers .
*/
2021-03-07 02:56:58 +02:00
static void zynqmp_disp_avbuf_disable_audio ( struct zynqmp_disp * disp )
2018-07-07 19:05:34 -07:00
{
u32 val ;
2021-03-07 02:56:58 +02:00
val = zynqmp_disp_avbuf_read ( disp , ZYNQMP_DISP_AV_BUF_OUTPUT ) ;
2018-07-07 19:05:34 -07:00
val & = ~ ZYNQMP_DISP_AV_BUF_OUTPUT_AUD1_MASK ;
val | = ZYNQMP_DISP_AV_BUF_OUTPUT_AUD1_DISABLE ;
val & = ~ ZYNQMP_DISP_AV_BUF_OUTPUT_AUD2_EN ;
2021-03-07 02:56:58 +02:00
zynqmp_disp_avbuf_write ( disp , ZYNQMP_DISP_AV_BUF_OUTPUT , val ) ;
2018-07-07 19:05:34 -07:00
}
/**
* zynqmp_disp_avbuf_enable_video - Enable a video layer
2021-03-07 02:56:58 +02:00
* @ disp : Display controller
2021-05-18 17:50:18 +08:00
* @ layer : The layer
2018-07-07 19:05:34 -07:00
* @ mode : Operating mode of layer
*
* Enable the video / graphics buffer for @ layer .
*/
2021-03-07 02:56:58 +02:00
static void zynqmp_disp_avbuf_enable_video ( struct zynqmp_disp * disp ,
2021-05-18 17:50:18 +08:00
struct zynqmp_disp_layer * layer ,
2018-07-07 19:05:34 -07:00
enum zynqmp_disp_layer_mode mode )
{
u32 val ;
2021-03-07 02:56:58 +02:00
val = zynqmp_disp_avbuf_read ( disp , ZYNQMP_DISP_AV_BUF_OUTPUT ) ;
2021-05-18 17:50:18 +08:00
if ( zynqmp_disp_layer_is_video ( layer ) ) {
2018-07-07 19:05:34 -07:00
val & = ~ ZYNQMP_DISP_AV_BUF_OUTPUT_VID1_MASK ;
if ( mode = = ZYNQMP_DISP_LAYER_NONLIVE )
val | = ZYNQMP_DISP_AV_BUF_OUTPUT_VID1_MEM ;
else
val | = ZYNQMP_DISP_AV_BUF_OUTPUT_VID1_LIVE ;
} else {
val & = ~ ZYNQMP_DISP_AV_BUF_OUTPUT_VID2_MASK ;
val | = ZYNQMP_DISP_AV_BUF_OUTPUT_VID2_MEM ;
if ( mode = = ZYNQMP_DISP_LAYER_NONLIVE )
val | = ZYNQMP_DISP_AV_BUF_OUTPUT_VID2_MEM ;
else
val | = ZYNQMP_DISP_AV_BUF_OUTPUT_VID2_LIVE ;
}
2021-03-07 02:56:58 +02:00
zynqmp_disp_avbuf_write ( disp , ZYNQMP_DISP_AV_BUF_OUTPUT , val ) ;
2018-07-07 19:05:34 -07:00
}
/**
* zynqmp_disp_avbuf_disable_video - Disable a video layer
2021-03-07 02:56:58 +02:00
* @ disp : Display controller
2021-05-18 17:50:18 +08:00
* @ layer : The layer
2018-07-07 19:05:34 -07:00
*
* Disable the video / graphics buffer for @ layer .
*/
2021-03-07 02:56:58 +02:00
static void zynqmp_disp_avbuf_disable_video ( struct zynqmp_disp * disp ,
2021-05-18 17:50:18 +08:00
struct zynqmp_disp_layer * layer )
2018-07-07 19:05:34 -07:00
{
u32 val ;
2021-03-07 02:56:58 +02:00
val = zynqmp_disp_avbuf_read ( disp , ZYNQMP_DISP_AV_BUF_OUTPUT ) ;
2021-05-18 17:50:18 +08:00
if ( zynqmp_disp_layer_is_video ( layer ) ) {
2018-07-07 19:05:34 -07:00
val & = ~ ZYNQMP_DISP_AV_BUF_OUTPUT_VID1_MASK ;
val | = ZYNQMP_DISP_AV_BUF_OUTPUT_VID1_NONE ;
} else {
val & = ~ ZYNQMP_DISP_AV_BUF_OUTPUT_VID2_MASK ;
val | = ZYNQMP_DISP_AV_BUF_OUTPUT_VID2_DISABLE ;
}
2021-03-07 02:56:58 +02:00
zynqmp_disp_avbuf_write ( disp , ZYNQMP_DISP_AV_BUF_OUTPUT , val ) ;
2018-07-07 19:05:34 -07:00
}
/**
* zynqmp_disp_avbuf_enable - Enable the video pipe
2021-03-07 02:56:58 +02:00
* @ disp : Display controller
2018-07-07 19:05:34 -07:00
*
* De - assert the video pipe reset .
*/
2021-03-07 02:56:58 +02:00
static void zynqmp_disp_avbuf_enable ( struct zynqmp_disp * disp )
2018-07-07 19:05:34 -07:00
{
2021-03-07 02:56:58 +02:00
zynqmp_disp_avbuf_write ( disp , ZYNQMP_DISP_AV_BUF_SRST_REG , 0 ) ;
2018-07-07 19:05:34 -07:00
}
/**
* zynqmp_disp_avbuf_disable - Disable the video pipe
2021-03-07 02:56:58 +02:00
* @ disp : Display controller
2018-07-07 19:05:34 -07:00
*
* Assert the video pipe reset .
*/
2021-03-07 02:56:58 +02:00
static void zynqmp_disp_avbuf_disable ( struct zynqmp_disp * disp )
2018-07-07 19:05:34 -07:00
{
2021-03-07 02:56:58 +02:00
zynqmp_disp_avbuf_write ( disp , ZYNQMP_DISP_AV_BUF_SRST_REG ,
2018-07-07 19:05:34 -07:00
ZYNQMP_DISP_AV_BUF_SRST_REG_VID_RST ) ;
}
/* -----------------------------------------------------------------------------
* Blender ( Video Pipeline )
*/
2021-03-07 02:56:58 +02:00
static void zynqmp_disp_blend_write ( struct zynqmp_disp * disp , int reg , u32 val )
2018-07-07 19:05:34 -07:00
{
2021-03-07 02:56:58 +02:00
writel ( val , disp - > blend . base + reg ) ;
2018-07-07 19:05:34 -07:00
}
/*
* Colorspace conversion matrices .
*
* Hardcode RGB < - > YUV conversion to full - range SDTV for now .
*/
static const u16 csc_zero_matrix [ ] = {
0x0 , 0x0 , 0x0 ,
0x0 , 0x0 , 0x0 ,
0x0 , 0x0 , 0x0
} ;
static const u16 csc_identity_matrix [ ] = {
0x1000 , 0x0 , 0x0 ,
0x0 , 0x1000 , 0x0 ,
0x0 , 0x0 , 0x1000
} ;
static const u32 csc_zero_offsets [ ] = {
0 , 0 , 0
} ;
static const u16 csc_rgb_to_sdtv_matrix [ ] = {
0x4c9 , 0x864 , 0x1d3 ,
0x7d4d , 0x7ab3 , 0x800 ,
0x800 , 0x794d , 0x7eb3
} ;
static const u32 csc_rgb_to_sdtv_offsets [ ] = {
0x0 , 0x8000000 , 0x8000000
} ;
static const u16 csc_sdtv_to_rgb_matrix [ ] = {
0x1000 , 0x166f , 0x0 ,
0x1000 , 0x7483 , 0x7a7f ,
0x1000 , 0x0 , 0x1c5a
} ;
static const u32 csc_sdtv_to_rgb_offsets [ ] = {
0x0 , 0x1800 , 0x1800
} ;
/**
* zynqmp_disp_blend_set_output_format - Set the output format of the blender
2021-03-07 02:56:58 +02:00
* @ disp : Display controller
2018-07-07 19:05:34 -07:00
* @ format : Output format
*
* Set the output format of the blender to @ format .
*/
2021-03-07 02:56:58 +02:00
static void zynqmp_disp_blend_set_output_format ( struct zynqmp_disp * disp ,
2018-07-07 19:05:34 -07:00
enum zynqmp_dpsub_format format )
{
static const unsigned int blend_output_fmts [ ] = {
[ ZYNQMP_DPSUB_FORMAT_RGB ] = ZYNQMP_DISP_V_BLEND_OUTPUT_VID_FMT_RGB ,
[ ZYNQMP_DPSUB_FORMAT_YCRCB444 ] = ZYNQMP_DISP_V_BLEND_OUTPUT_VID_FMT_YCBCR444 ,
[ ZYNQMP_DPSUB_FORMAT_YCRCB422 ] = ZYNQMP_DISP_V_BLEND_OUTPUT_VID_FMT_YCBCR422
| ZYNQMP_DISP_V_BLEND_OUTPUT_VID_FMT_EN_DOWNSAMPLE ,
[ ZYNQMP_DPSUB_FORMAT_YONLY ] = ZYNQMP_DISP_V_BLEND_OUTPUT_VID_FMT_YONLY ,
} ;
u32 fmt = blend_output_fmts [ format ] ;
const u16 * coeffs ;
const u32 * offsets ;
unsigned int i ;
2021-03-07 02:56:58 +02:00
zynqmp_disp_blend_write ( disp , ZYNQMP_DISP_V_BLEND_OUTPUT_VID_FMT , fmt ) ;
2018-07-07 19:05:34 -07:00
if ( fmt = = ZYNQMP_DISP_V_BLEND_OUTPUT_VID_FMT_RGB ) {
coeffs = csc_identity_matrix ;
offsets = csc_zero_offsets ;
} else {
coeffs = csc_rgb_to_sdtv_matrix ;
offsets = csc_rgb_to_sdtv_offsets ;
}
for ( i = 0 ; i < ZYNQMP_DISP_V_BLEND_NUM_COEFF ; i + + )
2021-03-07 02:56:58 +02:00
zynqmp_disp_blend_write ( disp ,
2018-07-07 19:05:34 -07:00
ZYNQMP_DISP_V_BLEND_RGB2YCBCR_COEFF ( i ) ,
coeffs [ i ] ) ;
for ( i = 0 ; i < ZYNQMP_DISP_V_BLEND_NUM_OFFSET ; i + + )
2021-03-07 02:56:58 +02:00
zynqmp_disp_blend_write ( disp ,
2018-07-07 19:05:34 -07:00
ZYNQMP_DISP_V_BLEND_OUTCSC_OFFSET ( i ) ,
offsets [ i ] ) ;
}
/**
* zynqmp_disp_blend_set_bg_color - Set the background color
2021-03-07 02:56:58 +02:00
* @ disp : Display controller
2018-07-07 19:05:34 -07:00
* @ rcr : Red / Cr color component
* @ gy : Green / Y color component
* @ bcb : Blue / Cb color component
*
* Set the background color to ( @ rcr , @ gy , @ bcb ) , corresponding to the R , G and
* B or Cr , Y and Cb components respectively depending on the selected output
* format .
*/
2021-03-07 02:56:58 +02:00
static void zynqmp_disp_blend_set_bg_color ( struct zynqmp_disp * disp ,
2018-07-07 19:05:34 -07:00
u32 rcr , u32 gy , u32 bcb )
{
2021-03-07 02:56:58 +02:00
zynqmp_disp_blend_write ( disp , ZYNQMP_DISP_V_BLEND_BG_CLR_0 , rcr ) ;
zynqmp_disp_blend_write ( disp , ZYNQMP_DISP_V_BLEND_BG_CLR_1 , gy ) ;
zynqmp_disp_blend_write ( disp , ZYNQMP_DISP_V_BLEND_BG_CLR_2 , bcb ) ;
2018-07-07 19:05:34 -07:00
}
/**
* zynqmp_disp_blend_set_global_alpha - Configure global alpha blending
2021-03-07 02:56:58 +02:00
* @ disp : Display controller
2018-07-07 19:05:34 -07:00
* @ enable : True to enable global alpha blending
* @ alpha : Global alpha value ( ignored if @ enabled is false )
*/
2021-03-07 02:56:58 +02:00
static void zynqmp_disp_blend_set_global_alpha ( struct zynqmp_disp * disp ,
2018-07-07 19:05:34 -07:00
bool enable , u32 alpha )
{
2021-03-07 02:56:58 +02:00
zynqmp_disp_blend_write ( disp , ZYNQMP_DISP_V_BLEND_SET_GLOBAL_ALPHA ,
2018-07-07 19:05:34 -07:00
ZYNQMP_DISP_V_BLEND_SET_GLOBAL_ALPHA_VALUE ( alpha ) |
( enable ? ZYNQMP_DISP_V_BLEND_SET_GLOBAL_ALPHA_EN : 0 ) ) ;
}
/**
* zynqmp_disp_blend_layer_set_csc - Configure colorspace conversion for layer
2021-03-07 02:56:58 +02:00
* @ disp : Display controller
2018-07-07 19:05:34 -07:00
* @ layer : The layer
* @ coeffs : Colorspace conversion matrix
* @ offsets : Colorspace conversion offsets
*
* Configure the input colorspace conversion matrix and offsets for the @ layer .
* Columns of the matrix are automatically swapped based on the input format to
* handle RGB and YCrCb components permutations .
*/
2021-03-07 02:56:58 +02:00
static void zynqmp_disp_blend_layer_set_csc ( struct zynqmp_disp * disp ,
2018-07-07 19:05:34 -07:00
struct zynqmp_disp_layer * layer ,
const u16 * coeffs ,
const u32 * offsets )
{
unsigned int swap [ 3 ] = { 0 , 1 , 2 } ;
unsigned int reg ;
unsigned int i ;
if ( layer - > disp_fmt - > swap ) {
if ( layer - > drm_fmt - > is_yuv ) {
/* Swap U and V. */
swap [ 1 ] = 2 ;
swap [ 2 ] = 1 ;
} else {
/* Swap R and B. */
swap [ 0 ] = 2 ;
swap [ 2 ] = 0 ;
}
}
2021-05-18 17:50:18 +08:00
if ( zynqmp_disp_layer_is_video ( layer ) )
2018-07-07 19:05:34 -07:00
reg = ZYNQMP_DISP_V_BLEND_IN1CSC_COEFF ( 0 ) ;
else
reg = ZYNQMP_DISP_V_BLEND_IN2CSC_COEFF ( 0 ) ;
for ( i = 0 ; i < ZYNQMP_DISP_V_BLEND_NUM_COEFF ; i + = 3 , reg + = 12 ) {
2021-03-07 02:56:58 +02:00
zynqmp_disp_blend_write ( disp , reg + 0 , coeffs [ i + swap [ 0 ] ] ) ;
zynqmp_disp_blend_write ( disp , reg + 4 , coeffs [ i + swap [ 1 ] ] ) ;
zynqmp_disp_blend_write ( disp , reg + 8 , coeffs [ i + swap [ 2 ] ] ) ;
2018-07-07 19:05:34 -07:00
}
2021-05-18 17:50:18 +08:00
if ( zynqmp_disp_layer_is_video ( layer ) )
2018-07-07 19:05:34 -07:00
reg = ZYNQMP_DISP_V_BLEND_IN1CSC_OFFSET ( 0 ) ;
else
reg = ZYNQMP_DISP_V_BLEND_IN2CSC_OFFSET ( 0 ) ;
for ( i = 0 ; i < ZYNQMP_DISP_V_BLEND_NUM_OFFSET ; i + + )
2021-03-07 02:56:58 +02:00
zynqmp_disp_blend_write ( disp , reg + i * 4 , offsets [ i ] ) ;
2018-07-07 19:05:34 -07:00
}
/**
* zynqmp_disp_blend_layer_enable - Enable a layer
2021-03-07 02:56:58 +02:00
* @ disp : Display controller
2018-07-07 19:05:34 -07:00
* @ layer : The layer
*/
2021-03-07 02:56:58 +02:00
static void zynqmp_disp_blend_layer_enable ( struct zynqmp_disp * disp ,
2018-07-07 19:05:34 -07:00
struct zynqmp_disp_layer * layer )
{
const u16 * coeffs ;
const u32 * offsets ;
u32 val ;
val = ( layer - > drm_fmt - > is_yuv ?
0 : ZYNQMP_DISP_V_BLEND_LAYER_CONTROL_RGB ) |
( layer - > drm_fmt - > hsub > 1 ?
ZYNQMP_DISP_V_BLEND_LAYER_CONTROL_EN_US : 0 ) ;
2021-03-07 02:56:58 +02:00
zynqmp_disp_blend_write ( disp ,
2018-07-07 19:05:34 -07:00
ZYNQMP_DISP_V_BLEND_LAYER_CONTROL ( layer - > id ) ,
val ) ;
if ( layer - > drm_fmt - > is_yuv ) {
coeffs = csc_sdtv_to_rgb_matrix ;
offsets = csc_sdtv_to_rgb_offsets ;
} else {
coeffs = csc_identity_matrix ;
offsets = csc_zero_offsets ;
}
2021-03-07 02:56:58 +02:00
zynqmp_disp_blend_layer_set_csc ( disp , layer , coeffs , offsets ) ;
2018-07-07 19:05:34 -07:00
}
/**
* zynqmp_disp_blend_layer_disable - Disable a layer
2021-03-07 02:56:58 +02:00
* @ disp : Display controller
2018-07-07 19:05:34 -07:00
* @ layer : The layer
*/
2021-03-07 02:56:58 +02:00
static void zynqmp_disp_blend_layer_disable ( struct zynqmp_disp * disp ,
2018-07-07 19:05:34 -07:00
struct zynqmp_disp_layer * layer )
{
2021-03-07 02:56:58 +02:00
zynqmp_disp_blend_write ( disp ,
2018-07-07 19:05:34 -07:00
ZYNQMP_DISP_V_BLEND_LAYER_CONTROL ( layer - > id ) ,
0 ) ;
2021-03-07 02:56:58 +02:00
zynqmp_disp_blend_layer_set_csc ( disp , layer , csc_zero_matrix ,
2018-07-07 19:05:34 -07:00
csc_zero_offsets ) ;
}
/* -----------------------------------------------------------------------------
* Audio Mixer
*/
2021-03-07 02:56:58 +02:00
static void zynqmp_disp_audio_write ( struct zynqmp_disp * disp , int reg , u32 val )
2018-07-07 19:05:34 -07:00
{
2021-03-07 02:56:58 +02:00
writel ( val , disp - > audio . base + reg ) ;
2018-07-07 19:05:34 -07:00
}
/**
* zynqmp_disp_audio_enable - Enable the audio mixer
2021-03-07 02:56:58 +02:00
* @ disp : Display controller
2018-07-07 19:05:34 -07:00
*
* Enable the audio mixer by de - asserting the soft reset . The audio state is set to
* default values by the reset , set the default mixer volume explicitly .
*/
2021-03-07 02:56:58 +02:00
static void zynqmp_disp_audio_enable ( struct zynqmp_disp * disp )
2018-07-07 19:05:34 -07:00
{
/* Clear the audio soft reset register as it's an non-reset flop. */
2021-03-07 02:56:58 +02:00
zynqmp_disp_audio_write ( disp , ZYNQMP_DISP_AUD_SOFT_RESET , 0 ) ;
zynqmp_disp_audio_write ( disp , ZYNQMP_DISP_AUD_MIXER_VOLUME ,
2018-07-07 19:05:34 -07:00
ZYNQMP_DISP_AUD_MIXER_VOLUME_NO_SCALE ) ;
}
/**
* zynqmp_disp_audio_disable - Disable the audio mixer
2021-03-07 02:56:58 +02:00
* @ disp : Display controller
2018-07-07 19:05:34 -07:00
*
* Disable the audio mixer by asserting its soft reset .
*/
2021-03-07 02:56:58 +02:00
static void zynqmp_disp_audio_disable ( struct zynqmp_disp * disp )
2018-07-07 19:05:34 -07:00
{
2021-03-07 02:56:58 +02:00
zynqmp_disp_audio_write ( disp , ZYNQMP_DISP_AUD_SOFT_RESET ,
2018-07-07 19:05:34 -07:00
ZYNQMP_DISP_AUD_SOFT_RESET_AUD_SRST ) ;
}
2021-03-07 02:56:58 +02:00
static void zynqmp_disp_audio_init ( struct zynqmp_disp * disp )
2018-07-07 19:05:34 -07:00
{
/* Try the live PL audio clock. */
2021-03-07 02:56:58 +02:00
disp - > audio . clk = devm_clk_get ( disp - > dev , " dp_live_audio_aclk " ) ;
if ( ! IS_ERR ( disp - > audio . clk ) ) {
disp - > audio . clk_from_ps = false ;
2018-07-07 19:05:34 -07:00
return ;
}
/* If the live PL audio clock is not valid, fall back to PS clock. */
2021-03-07 02:56:58 +02:00
disp - > audio . clk = devm_clk_get ( disp - > dev , " dp_aud_clk " ) ;
if ( ! IS_ERR ( disp - > audio . clk ) ) {
disp - > audio . clk_from_ps = true ;
2018-07-07 19:05:34 -07:00
return ;
}
2021-03-07 02:56:58 +02:00
dev_err ( disp - > dev , " audio disabled due to missing clock \n " ) ;
2018-07-07 19:05:34 -07:00
}
/* -----------------------------------------------------------------------------
* ZynqMP Display external functions for zynqmp_dp
*/
/**
* zynqmp_disp_handle_vblank - Handle the vblank event
* @ disp : Display controller
*
* This function handles the vblank interrupt , and sends an event to
* CRTC object . This will be called by the DP vblank interrupt handler .
*/
void zynqmp_disp_handle_vblank ( struct zynqmp_disp * disp )
{
struct drm_crtc * crtc = & disp - > crtc ;
drm_crtc_handle_vblank ( crtc ) ;
}
/**
* zynqmp_disp_audio_enabled - If the audio is enabled
* @ disp : Display controller
*
* Return if the audio is enabled depending on the audio clock .
*
* Return : true if audio is enabled , or false .
*/
bool zynqmp_disp_audio_enabled ( struct zynqmp_disp * disp )
{
return ! ! disp - > audio . clk ;
}
/**
* zynqmp_disp_get_audio_clk_rate - Get the current audio clock rate
* @ disp : Display controller
*
* Return : the current audio clock rate .
*/
unsigned int zynqmp_disp_get_audio_clk_rate ( struct zynqmp_disp * disp )
{
if ( zynqmp_disp_audio_enabled ( disp ) )
return 0 ;
return clk_get_rate ( disp - > audio . clk ) ;
}
/**
* zynqmp_disp_get_crtc_mask - Return the CRTC bit mask
* @ disp : Display controller
*
* Return : the crtc mask of the zyqnmp_disp CRTC .
*/
uint32_t zynqmp_disp_get_crtc_mask ( struct zynqmp_disp * disp )
{
return drm_crtc_mask ( & disp - > crtc ) ;
}
/* -----------------------------------------------------------------------------
* ZynqMP Display Layer & DRM Plane
*/
/**
* zynqmp_disp_layer_find_format - Find format information for a DRM format
* @ layer : The layer
* @ drm_fmt : DRM format to search
*
* Search display subsystem format information corresponding to the given DRM
* format @ drm_fmt for the @ layer , and return a pointer to the format
* descriptor .
*
* Return : A pointer to the format descriptor if found , NULL otherwise
*/
static const struct zynqmp_disp_format *
zynqmp_disp_layer_find_format ( struct zynqmp_disp_layer * layer ,
u32 drm_fmt )
{
unsigned int i ;
for ( i = 0 ; i < layer - > info - > num_formats ; i + + ) {
if ( layer - > info - > formats [ i ] . drm_fmt = = drm_fmt )
return & layer - > info - > formats [ i ] ;
}
return NULL ;
}
/**
* zynqmp_disp_layer_enable - Enable a layer
* @ layer : The layer
*
* Enable the @ layer in the audio / video buffer manager and the blender . DMA
* channels are started separately by zynqmp_disp_layer_update ( ) .
*/
static void zynqmp_disp_layer_enable ( struct zynqmp_disp_layer * layer )
{
2021-03-07 02:56:58 +02:00
zynqmp_disp_avbuf_enable_video ( layer - > disp , layer ,
2018-07-07 19:05:34 -07:00
ZYNQMP_DISP_LAYER_NONLIVE ) ;
2021-03-07 02:56:58 +02:00
zynqmp_disp_blend_layer_enable ( layer - > disp , layer ) ;
2018-07-07 19:05:34 -07:00
layer - > mode = ZYNQMP_DISP_LAYER_NONLIVE ;
}
/**
* zynqmp_disp_layer_disable - Disable the layer
* @ layer : The layer
*
* Disable the layer by stopping its DMA channels and disabling it in the
* audio / video buffer manager and the blender .
*/
static void zynqmp_disp_layer_disable ( struct zynqmp_disp_layer * layer )
{
unsigned int i ;
for ( i = 0 ; i < layer - > drm_fmt - > num_planes ; i + + )
dmaengine_terminate_sync ( layer - > dmas [ i ] . chan ) ;
2021-03-07 02:56:58 +02:00
zynqmp_disp_avbuf_disable_video ( layer - > disp , layer ) ;
zynqmp_disp_blend_layer_disable ( layer - > disp , layer ) ;
2018-07-07 19:05:34 -07:00
}
/**
* zynqmp_disp_layer_set_format - Set the layer format
* @ layer : The layer
* @ state : The plane state
*
* Set the format for @ layer based on @ state - > fb - > format . The layer must be
* disabled .
*/
static void zynqmp_disp_layer_set_format ( struct zynqmp_disp_layer * layer ,
struct drm_plane_state * state )
{
const struct drm_format_info * info = state - > fb - > format ;
unsigned int i ;
layer - > disp_fmt = zynqmp_disp_layer_find_format ( layer , info - > format ) ;
layer - > drm_fmt = info ;
2021-03-07 02:56:58 +02:00
zynqmp_disp_avbuf_set_format ( layer - > disp , layer , layer - > disp_fmt ) ;
2018-07-07 19:05:34 -07:00
/*
2021-11-22 23:22:01 +01:00
* Set pconfig for each DMA channel to indicate they ' re part of a
2018-07-07 19:05:34 -07:00
* video group .
*/
for ( i = 0 ; i < info - > num_planes ; i + + ) {
struct zynqmp_disp_layer_dma * dma = & layer - > dmas [ i ] ;
2021-11-22 23:22:01 +01:00
struct xilinx_dpdma_peripheral_config pconfig = {
. video_group = true ,
} ;
2018-07-07 19:05:34 -07:00
struct dma_slave_config config = {
. direction = DMA_MEM_TO_DEV ,
2021-11-22 23:22:01 +01:00
. peripheral_config = & pconfig ,
. peripheral_size = sizeof ( pconfig ) ,
2018-07-07 19:05:34 -07:00
} ;
dmaengine_slave_config ( dma - > chan , & config ) ;
}
}
/**
* zynqmp_disp_layer_update - Update the layer framebuffer
* @ layer : The layer
* @ state : The plane state
*
* Update the framebuffer for the layer by issuing a new DMA engine transaction
* for the new framebuffer .
*
* Return : 0 on success , or the DMA descriptor failure error otherwise
*/
static int zynqmp_disp_layer_update ( struct zynqmp_disp_layer * layer ,
struct drm_plane_state * state )
{
const struct drm_format_info * info = layer - > drm_fmt ;
unsigned int i ;
for ( i = 0 ; i < layer - > drm_fmt - > num_planes ; i + + ) {
unsigned int width = state - > crtc_w / ( i ? info - > hsub : 1 ) ;
unsigned int height = state - > crtc_h / ( i ? info - > vsub : 1 ) ;
struct zynqmp_disp_layer_dma * dma = & layer - > dmas [ i ] ;
struct dma_async_tx_descriptor * desc ;
dma_addr_t paddr ;
paddr = drm_fb_cma_get_gem_addr ( state - > fb , state , i ) ;
dma - > xt . numf = height ;
dma - > sgl . size = width * info - > cpp [ i ] ;
dma - > sgl . icg = state - > fb - > pitches [ i ] - dma - > sgl . size ;
dma - > xt . src_start = paddr ;
dma - > xt . frame_size = 1 ;
dma - > xt . dir = DMA_MEM_TO_DEV ;
dma - > xt . src_sgl = true ;
dma - > xt . dst_sgl = false ;
desc = dmaengine_prep_interleaved_dma ( dma - > chan , & dma - > xt ,
DMA_CTRL_ACK |
DMA_PREP_REPEAT |
DMA_PREP_LOAD_EOT ) ;
if ( ! desc ) {
dev_err ( layer - > disp - > dev ,
" failed to prepare DMA descriptor \n " ) ;
return - ENOMEM ;
}
dmaengine_submit ( desc ) ;
dma_async_issue_pending ( dma - > chan ) ;
}
return 0 ;
}
static inline struct zynqmp_disp_layer * plane_to_layer ( struct drm_plane * plane )
{
return container_of ( plane , struct zynqmp_disp_layer , plane ) ;
}
static int
zynqmp_disp_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 )
2018-07-07 19:05:34 -07: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 ) ;
2018-07-07 19:05:34 -07:00
struct drm_crtc_state * crtc_state ;
2021-02-19 13:00:22 +01:00
if ( ! new_plane_state - > crtc )
2018-07-07 19:05:34 -07:00
return 0 ;
drm: Use the state pointer directly in planes atomic_check
Now that atomic_check takes the global atomic state as a parameter, we
don't need to go through the pointer in the plane state.
This was done using the following coccinelle script:
@ plane_atomic_func @
identifier helpers;
identifier func;
@@
static struct drm_plane_helper_funcs helpers = {
...,
.atomic_check = func,
...,
};
@@
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_new_plane_state(state, plane);
<... when != plane_state
- plane_state->state
+ state
...>
}
@@
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_new_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-5-maxime@cerno.tech
2021-02-19 13:00:25 +01:00
crtc_state = drm_atomic_get_crtc_state ( state , new_plane_state - > crtc ) ;
2018-07-07 19:05:34 -07:00
if ( IS_ERR ( crtc_state ) )
return PTR_ERR ( crtc_state ) ;
2021-02-19 13:00:22 +01:00
return drm_atomic_helper_check_plane_state ( new_plane_state ,
crtc_state ,
2018-07-07 19:05:34 -07:00
DRM_PLANE_HELPER_NO_SCALING ,
DRM_PLANE_HELPER_NO_SCALING ,
false , false ) ;
}
static void
zynqmp_disp_plane_atomic_disable ( 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 )
2018-07-07 19:05:34 -07: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 ) ;
2018-07-07 19:05:34 -07:00
struct zynqmp_disp_layer * layer = plane_to_layer ( plane ) ;
if ( ! old_state - > fb )
return ;
zynqmp_disp_layer_disable ( layer ) ;
2021-03-07 02:56:58 +02:00
if ( zynqmp_disp_layer_is_gfx ( layer ) )
2021-03-07 02:56:58 +02:00
zynqmp_disp_blend_set_global_alpha ( layer - > disp , false ,
plane - > state - > alpha > > 8 ) ;
2018-07-07 19:05:34 -07:00
}
static void
zynqmp_disp_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 )
2018-07-07 19:05:34 -07: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 ) ;
2018-07-07 19:05:34 -07:00
struct zynqmp_disp_layer * layer = plane_to_layer ( plane ) ;
bool format_changed = false ;
if ( ! old_state - > fb | |
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
old_state - > fb - > format - > format ! = new_state - > fb - > format - > format )
2018-07-07 19:05:34 -07:00
format_changed = true ;
/*
* If the format has changed ( including going from a previously
* disabled state to any format ) , reconfigure the format . Disable the
* plane first if needed .
*/
if ( format_changed ) {
if ( old_state - > fb )
zynqmp_disp_layer_disable ( layer ) ;
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
zynqmp_disp_layer_set_format ( layer , new_state ) ;
2018-07-07 19:05:34 -07: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
zynqmp_disp_layer_update ( layer , new_state ) ;
2018-07-07 19:05:34 -07:00
2021-03-07 02:56:58 +02:00
if ( zynqmp_disp_layer_is_gfx ( layer ) )
2021-03-07 02:56:58 +02:00
zynqmp_disp_blend_set_global_alpha ( layer - > disp , true ,
plane - > state - > alpha > > 8 ) ;
2021-03-07 02:56:58 +02:00
2018-07-07 19:05:34 -07:00
/* Enable or re-enable the plane is the format has changed. */
if ( format_changed )
zynqmp_disp_layer_enable ( layer ) ;
}
static const struct drm_plane_helper_funcs zynqmp_disp_plane_helper_funcs = {
. atomic_check = zynqmp_disp_plane_atomic_check ,
. atomic_update = zynqmp_disp_plane_atomic_update ,
. atomic_disable = zynqmp_disp_plane_atomic_disable ,
} ;
static const struct drm_plane_funcs zynqmp_disp_plane_funcs = {
. update_plane = drm_atomic_helper_update_plane ,
. disable_plane = drm_atomic_helper_disable_plane ,
. destroy = drm_plane_cleanup ,
. reset = drm_atomic_helper_plane_reset ,
. atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state ,
. atomic_destroy_state = drm_atomic_helper_plane_destroy_state ,
} ;
static int zynqmp_disp_create_planes ( struct zynqmp_disp * disp )
{
unsigned int i , j ;
int ret ;
for ( i = 0 ; i < ZYNQMP_DISP_NUM_LAYERS ; i + + ) {
struct zynqmp_disp_layer * layer = & disp - > layers [ i ] ;
enum drm_plane_type type ;
u32 * drm_formats ;
drm_formats = drmm_kcalloc ( disp - > drm , sizeof ( * drm_formats ) ,
layer - > info - > num_formats ,
GFP_KERNEL ) ;
if ( ! drm_formats )
return - ENOMEM ;
for ( j = 0 ; j < layer - > info - > num_formats ; + + j )
drm_formats [ j ] = layer - > info - > formats [ j ] . drm_fmt ;
/* Graphics layer is primary, and video layer is overlay. */
2021-05-18 17:50:18 +08:00
type = zynqmp_disp_layer_is_video ( layer )
? DRM_PLANE_TYPE_OVERLAY : DRM_PLANE_TYPE_PRIMARY ;
2018-07-07 19:05:34 -07:00
ret = drm_universal_plane_init ( disp - > drm , & layer - > plane , 0 ,
& zynqmp_disp_plane_funcs ,
drm_formats ,
layer - > info - > num_formats ,
NULL , type , NULL ) ;
if ( ret )
return ret ;
drm_plane_helper_add ( & layer - > plane ,
& zynqmp_disp_plane_helper_funcs ) ;
2021-03-07 02:56:58 +02:00
2021-03-07 02:56:58 +02:00
drm_plane_create_zpos_immutable_property ( & layer - > plane , i ) ;
2021-03-07 02:56:58 +02:00
if ( zynqmp_disp_layer_is_gfx ( layer ) )
drm_plane_create_alpha_property ( & layer - > plane ) ;
2018-07-07 19:05:34 -07:00
}
return 0 ;
}
/**
* zynqmp_disp_layer_release_dma - Release DMA channels for a layer
* @ disp : Display controller
* @ layer : The layer
*
* Release the DMA channels associated with @ layer .
*/
static void zynqmp_disp_layer_release_dma ( struct zynqmp_disp * disp ,
struct zynqmp_disp_layer * layer )
{
unsigned int i ;
if ( ! layer - > info )
return ;
for ( i = 0 ; i < layer - > info - > num_channels ; i + + ) {
struct zynqmp_disp_layer_dma * dma = & layer - > dmas [ i ] ;
if ( ! dma - > chan )
continue ;
/* Make sure the channel is terminated before release. */
dmaengine_terminate_sync ( dma - > chan ) ;
dma_release_channel ( dma - > chan ) ;
}
}
/**
* zynqmp_disp_destroy_layers - Destroy all layers
* @ disp : Display controller
*/
static void zynqmp_disp_destroy_layers ( struct zynqmp_disp * disp )
{
unsigned int i ;
for ( i = 0 ; i < ZYNQMP_DISP_NUM_LAYERS ; i + + )
zynqmp_disp_layer_release_dma ( disp , & disp - > layers [ i ] ) ;
}
/**
* zynqmp_disp_layer_request_dma - Request DMA channels for a layer
* @ disp : Display controller
* @ layer : The layer
*
* Request all DMA engine channels needed by @ layer .
*
* Return : 0 on success , or the DMA channel request error otherwise
*/
static int zynqmp_disp_layer_request_dma ( struct zynqmp_disp * disp ,
struct zynqmp_disp_layer * layer )
{
static const char * const dma_names [ ] = { " vid " , " gfx " } ;
unsigned int i ;
int ret ;
for ( i = 0 ; i < layer - > info - > num_channels ; i + + ) {
struct zynqmp_disp_layer_dma * dma = & layer - > dmas [ i ] ;
char dma_channel_name [ 16 ] ;
snprintf ( dma_channel_name , sizeof ( dma_channel_name ) ,
" %s%u " , dma_names [ layer - > id ] , i ) ;
2020-10-23 12:46:02 +03:00
dma - > chan = dma_request_chan ( disp - > dev , dma_channel_name ) ;
2018-07-07 19:05:34 -07:00
if ( IS_ERR ( dma - > chan ) ) {
dev_err ( disp - > dev , " failed to request dma channel \n " ) ;
ret = PTR_ERR ( dma - > chan ) ;
dma - > chan = NULL ;
return ret ;
}
}
return 0 ;
}
/**
* zynqmp_disp_create_layers - Create and initialize all layers
* @ disp : Display controller
*
* Return : 0 on success , or the DMA channel request error otherwise
*/
static int zynqmp_disp_create_layers ( struct zynqmp_disp * disp )
{
static const struct zynqmp_disp_layer_info layer_info [ ] = {
[ ZYNQMP_DISP_LAYER_VID ] = {
. formats = avbuf_vid_fmts ,
. num_formats = ARRAY_SIZE ( avbuf_vid_fmts ) ,
. num_channels = 3 ,
} ,
[ ZYNQMP_DISP_LAYER_GFX ] = {
. formats = avbuf_gfx_fmts ,
. num_formats = ARRAY_SIZE ( avbuf_gfx_fmts ) ,
. num_channels = 1 ,
} ,
} ;
unsigned int i ;
int ret ;
for ( i = 0 ; i < ZYNQMP_DISP_NUM_LAYERS ; i + + ) {
struct zynqmp_disp_layer * layer = & disp - > layers [ i ] ;
layer - > id = i ;
layer - > disp = disp ;
layer - > info = & layer_info [ i ] ;
ret = zynqmp_disp_layer_request_dma ( disp , layer ) ;
if ( ret )
goto err ;
}
return 0 ;
err :
zynqmp_disp_destroy_layers ( disp ) ;
return ret ;
}
/* -----------------------------------------------------------------------------
* ZynqMP Display & DRM CRTC
*/
/**
* zynqmp_disp_enable - Enable the display controller
* @ disp : Display controller
*/
static void zynqmp_disp_enable ( struct zynqmp_disp * disp )
{
2021-03-07 02:56:58 +02:00
zynqmp_disp_avbuf_enable ( disp ) ;
2018-07-07 19:05:34 -07:00
/* Choose clock source based on the DT clock handle. */
2021-03-07 02:56:58 +02:00
zynqmp_disp_avbuf_set_clocks_sources ( disp , disp - > pclk_from_ps ,
2018-07-07 19:05:34 -07:00
disp - > audio . clk_from_ps , true ) ;
2021-03-07 02:56:58 +02:00
zynqmp_disp_avbuf_enable_channels ( disp ) ;
zynqmp_disp_avbuf_enable_audio ( disp ) ;
2018-07-07 19:05:34 -07:00
2021-03-07 02:56:58 +02:00
zynqmp_disp_audio_enable ( disp ) ;
2018-07-07 19:05:34 -07:00
}
/**
* zynqmp_disp_disable - Disable the display controller
* @ disp : Display controller
*/
static void zynqmp_disp_disable ( struct zynqmp_disp * disp )
{
2021-03-07 02:56:58 +02:00
zynqmp_disp_audio_disable ( disp ) ;
2018-07-07 19:05:34 -07:00
2021-03-07 02:56:58 +02:00
zynqmp_disp_avbuf_disable_audio ( disp ) ;
zynqmp_disp_avbuf_disable_channels ( disp ) ;
zynqmp_disp_avbuf_disable ( disp ) ;
2018-07-07 19:05:34 -07:00
}
static inline struct zynqmp_disp * crtc_to_disp ( struct drm_crtc * crtc )
{
return container_of ( crtc , struct zynqmp_disp , crtc ) ;
}
static int zynqmp_disp_crtc_setup_clock ( struct drm_crtc * crtc ,
struct drm_display_mode * adjusted_mode )
{
struct zynqmp_disp * disp = crtc_to_disp ( crtc ) ;
unsigned long mode_clock = adjusted_mode - > clock * 1000 ;
unsigned long rate ;
long diff ;
int ret ;
ret = clk_set_rate ( disp - > pclk , mode_clock ) ;
if ( ret ) {
dev_err ( disp - > dev , " failed to set a pixel clock \n " ) ;
return ret ;
}
rate = clk_get_rate ( disp - > pclk ) ;
diff = rate - mode_clock ;
if ( abs ( diff ) > mode_clock / 20 )
dev_info ( disp - > dev ,
" requested pixel rate: %lu actual rate: %lu \n " ,
mode_clock , rate ) ;
else
dev_dbg ( disp - > dev ,
" requested pixel rate: %lu actual rate: %lu \n " ,
mode_clock , rate ) ;
return 0 ;
}
static void
zynqmp_disp_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 )
2018-07-07 19:05:34 -07:00
{
struct zynqmp_disp * disp = crtc_to_disp ( crtc ) ;
struct drm_display_mode * adjusted_mode = & crtc - > state - > adjusted_mode ;
int ret , vrefresh ;
2021-03-10 12:59:45 +08:00
pm_runtime_get_sync ( disp - > dev ) ;
2018-07-07 19:05:34 -07:00
zynqmp_disp_crtc_setup_clock ( crtc , adjusted_mode ) ;
ret = clk_prepare_enable ( disp - > pclk ) ;
if ( ret ) {
dev_err ( disp - > dev , " failed to enable a pixel clock \n " ) ;
pm_runtime_put_sync ( disp - > dev ) ;
return ;
}
2021-03-07 02:56:58 +02:00
zynqmp_disp_blend_set_output_format ( disp , ZYNQMP_DPSUB_FORMAT_RGB ) ;
zynqmp_disp_blend_set_bg_color ( disp , 0 , 0 , 0 ) ;
2018-07-07 19:05:34 -07:00
zynqmp_disp_enable ( disp ) ;
/* Delay of 3 vblank intervals for timing gen to be stable */
vrefresh = ( adjusted_mode - > clock * 1000 ) /
( adjusted_mode - > vtotal * adjusted_mode - > htotal ) ;
msleep ( 3 * 1000 / vrefresh ) ;
}
static void
zynqmp_disp_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 )
2018-07-07 19:05:34 -07:00
{
struct zynqmp_disp * disp = crtc_to_disp ( crtc ) ;
struct drm_plane_state * old_plane_state ;
/*
* Disable the plane if active . The old plane state can be NULL in the
* . shutdown ( ) path if the plane is already disabled , skip
* zynqmp_disp_plane_atomic_disable ( ) in that case .
*/
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
old_plane_state = drm_atomic_get_old_plane_state ( state , crtc - > primary ) ;
2018-07-07 19:05:34 -07:00
if ( old_plane_state )
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
zynqmp_disp_plane_atomic_disable ( crtc - > primary , state ) ;
2018-07-07 19:05:34 -07:00
zynqmp_disp_disable ( disp ) ;
drm_crtc_vblank_off ( & disp - > crtc ) ;
2021-02-02 14:41:21 +08:00
spin_lock_irq ( & crtc - > dev - > event_lock ) ;
if ( crtc - > state - > event ) {
drm_crtc_send_vblank_event ( crtc , crtc - > state - > event ) ;
crtc - > state - > event = NULL ;
}
spin_unlock_irq ( & crtc - > dev - > event_lock ) ;
2018-07-07 19:05:34 -07:00
clk_disable_unprepare ( disp - > pclk ) ;
pm_runtime_put_sync ( disp - > dev ) ;
}
static int zynqmp_disp_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 )
2018-07-07 19:05:34 -07:00
{
2020-11-02 14:38:34 +01:00
return drm_atomic_add_affected_planes ( state , crtc ) ;
2018-07-07 19:05:34 -07:00
}
static void
zynqmp_disp_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 )
2018-07-07 19:05:34 -07:00
{
drm_crtc_vblank_on ( crtc ) ;
}
static void
zynqmp_disp_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-07-07 19:05:34 -07:00
{
if ( crtc - > state - > event ) {
struct drm_pending_vblank_event * event ;
/* Consume the flip_done event from atomic helper. */
event = crtc - > state - > event ;
crtc - > state - > event = NULL ;
event - > pipe = drm_crtc_index ( crtc ) ;
WARN_ON ( drm_crtc_vblank_get ( crtc ) ! = 0 ) ;
spin_lock_irq ( & crtc - > dev - > event_lock ) ;
drm_crtc_arm_vblank_event ( crtc , event ) ;
spin_unlock_irq ( & crtc - > dev - > event_lock ) ;
}
}
static const struct drm_crtc_helper_funcs zynqmp_disp_crtc_helper_funcs = {
. atomic_enable = zynqmp_disp_crtc_atomic_enable ,
. atomic_disable = zynqmp_disp_crtc_atomic_disable ,
. atomic_check = zynqmp_disp_crtc_atomic_check ,
. atomic_begin = zynqmp_disp_crtc_atomic_begin ,
. atomic_flush = zynqmp_disp_crtc_atomic_flush ,
} ;
static int zynqmp_disp_crtc_enable_vblank ( struct drm_crtc * crtc )
{
struct zynqmp_disp * disp = crtc_to_disp ( crtc ) ;
zynqmp_dp_enable_vblank ( disp - > dpsub - > dp ) ;
return 0 ;
}
static void zynqmp_disp_crtc_disable_vblank ( struct drm_crtc * crtc )
{
struct zynqmp_disp * disp = crtc_to_disp ( crtc ) ;
zynqmp_dp_disable_vblank ( disp - > dpsub - > dp ) ;
}
static const struct drm_crtc_funcs zynqmp_disp_crtc_funcs = {
. destroy = drm_crtc_cleanup ,
. set_config = drm_atomic_helper_set_config ,
. page_flip = drm_atomic_helper_page_flip ,
. reset = drm_atomic_helper_crtc_reset ,
. atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state ,
. atomic_destroy_state = drm_atomic_helper_crtc_destroy_state ,
. enable_vblank = zynqmp_disp_crtc_enable_vblank ,
. disable_vblank = zynqmp_disp_crtc_disable_vblank ,
} ;
static int zynqmp_disp_create_crtc ( struct zynqmp_disp * disp )
{
struct drm_plane * plane = & disp - > layers [ ZYNQMP_DISP_LAYER_GFX ] . plane ;
int ret ;
ret = drm_crtc_init_with_planes ( disp - > drm , & disp - > crtc , plane ,
NULL , & zynqmp_disp_crtc_funcs , NULL ) ;
if ( ret < 0 )
return ret ;
drm_crtc_helper_add ( & disp - > crtc , & zynqmp_disp_crtc_helper_funcs ) ;
/* Start with vertical blanking interrupt reporting disabled. */
drm_crtc_vblank_off ( & disp - > crtc ) ;
return 0 ;
}
static void zynqmp_disp_map_crtc_to_plane ( struct zynqmp_disp * disp )
{
u32 possible_crtcs = drm_crtc_mask ( & disp - > crtc ) ;
unsigned int i ;
for ( i = 0 ; i < ZYNQMP_DISP_NUM_LAYERS ; i + + )
disp - > layers [ i ] . plane . possible_crtcs = possible_crtcs ;
}
/* -----------------------------------------------------------------------------
* Initialization & Cleanup
*/
int zynqmp_disp_drm_init ( struct zynqmp_dpsub * dpsub )
{
struct zynqmp_disp * disp = dpsub - > disp ;
int ret ;
ret = zynqmp_disp_create_planes ( disp ) ;
if ( ret )
return ret ;
ret = zynqmp_disp_create_crtc ( disp ) ;
if ( ret < 0 )
return ret ;
zynqmp_disp_map_crtc_to_plane ( disp ) ;
return 0 ;
}
int zynqmp_disp_probe ( struct zynqmp_dpsub * dpsub , struct drm_device * drm )
{
struct platform_device * pdev = to_platform_device ( dpsub - > dev ) ;
struct zynqmp_disp * disp ;
struct zynqmp_disp_layer * layer ;
struct resource * res ;
int ret ;
disp = drmm_kzalloc ( drm , sizeof ( * disp ) , GFP_KERNEL ) ;
if ( ! disp )
return - ENOMEM ;
disp - > dev = & pdev - > dev ;
disp - > dpsub = dpsub ;
disp - > drm = drm ;
dpsub - > disp = disp ;
res = platform_get_resource_byname ( pdev , IORESOURCE_MEM , " blend " ) ;
disp - > blend . base = devm_ioremap_resource ( disp - > dev , res ) ;
if ( IS_ERR ( disp - > blend . base ) )
return PTR_ERR ( disp - > blend . base ) ;
res = platform_get_resource_byname ( pdev , IORESOURCE_MEM , " av_buf " ) ;
disp - > avbuf . base = devm_ioremap_resource ( disp - > dev , res ) ;
if ( IS_ERR ( disp - > avbuf . base ) )
return PTR_ERR ( disp - > avbuf . base ) ;
res = platform_get_resource_byname ( pdev , IORESOURCE_MEM , " aud " ) ;
disp - > audio . base = devm_ioremap_resource ( disp - > dev , res ) ;
if ( IS_ERR ( disp - > audio . base ) )
return PTR_ERR ( disp - > audio . base ) ;
/* Try the live PL video clock */
disp - > pclk = devm_clk_get ( disp - > dev , " dp_live_video_in_clk " ) ;
if ( ! IS_ERR ( disp - > pclk ) )
disp - > pclk_from_ps = false ;
else if ( PTR_ERR ( disp - > pclk ) = = - EPROBE_DEFER )
return PTR_ERR ( disp - > pclk ) ;
/* If the live PL video clock is not valid, fall back to PS clock */
if ( IS_ERR_OR_NULL ( disp - > pclk ) ) {
disp - > pclk = devm_clk_get ( disp - > dev , " dp_vtc_pixel_clk_in " ) ;
if ( IS_ERR ( disp - > pclk ) ) {
dev_err ( disp - > dev , " failed to init any video clock \n " ) ;
return PTR_ERR ( disp - > pclk ) ;
}
disp - > pclk_from_ps = true ;
}
2021-03-07 02:56:58 +02:00
zynqmp_disp_audio_init ( disp ) ;
2018-07-07 19:05:34 -07:00
ret = zynqmp_disp_create_layers ( disp ) ;
if ( ret )
return ret ;
layer = & disp - > layers [ ZYNQMP_DISP_LAYER_VID ] ;
dpsub - > dma_align = 1 < < layer - > dmas [ 0 ] . chan - > device - > copy_align ;
return 0 ;
}
void zynqmp_disp_remove ( struct zynqmp_dpsub * dpsub )
{
struct zynqmp_disp * disp = dpsub - > disp ;
zynqmp_disp_destroy_layers ( disp ) ;
}