2015-04-02 18:48:39 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2013-2015 ARM Limited
|
|
|
|
* Author: Liviu Dudau <Liviu.Dudau@arm.com>
|
|
|
|
*
|
|
|
|
* This file is subject to the terms and conditions of the GNU General Public
|
|
|
|
* License. See the file COPYING in the main directory of this archive
|
|
|
|
* for more details.
|
|
|
|
*
|
|
|
|
* Implementation of a CRTC class for the HDLCD driver.
|
|
|
|
*/
|
|
|
|
|
2019-08-04 09:41:32 +00:00
|
|
|
#include <linux/clk.h>
|
|
|
|
#include <linux/of_graph.h>
|
|
|
|
#include <linux/platform_data/simplefb.h>
|
|
|
|
|
|
|
|
#include <video/videomode.h>
|
|
|
|
|
2017-03-08 16:10:19 +00:00
|
|
|
#include <drm/drm_atomic.h>
|
2015-04-02 18:48:39 +00:00
|
|
|
#include <drm/drm_atomic_helper.h>
|
|
|
|
#include <drm/drm_crtc.h>
|
2022-08-02 00:04:02 +00:00
|
|
|
#include <drm/drm_fb_dma_helper.h>
|
2022-06-14 09:54:49 +00:00
|
|
|
#include <drm/drm_framebuffer.h>
|
2022-08-02 00:04:03 +00:00
|
|
|
#include <drm/drm_gem_dma_helper.h>
|
2015-04-02 18:48:39 +00:00
|
|
|
#include <drm/drm_of.h>
|
2019-01-17 21:03:34 +00:00
|
|
|
#include <drm/drm_probe_helper.h>
|
2019-08-04 09:41:32 +00:00
|
|
|
#include <drm/drm_vblank.h>
|
2015-04-02 18:48:39 +00:00
|
|
|
|
|
|
|
#include "hdlcd_drv.h"
|
|
|
|
#include "hdlcd_regs.h"
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The HDLCD controller is a dumb RGB streamer that gets connected to
|
|
|
|
* a single HDMI transmitter or in the case of the ARM Models it gets
|
|
|
|
* emulated by the software that does the actual rendering.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2016-05-17 09:06:54 +00:00
|
|
|
static void hdlcd_crtc_cleanup(struct drm_crtc *crtc)
|
|
|
|
{
|
|
|
|
struct hdlcd_drm_private *hdlcd = crtc_to_hdlcd_priv(crtc);
|
|
|
|
|
|
|
|
/* stop the controller on cleanup */
|
|
|
|
hdlcd_write(hdlcd, HDLCD_REG_COMMAND, 0);
|
|
|
|
drm_crtc_cleanup(crtc);
|
|
|
|
}
|
|
|
|
|
2017-02-07 09:16:16 +00:00
|
|
|
static int hdlcd_crtc_enable_vblank(struct drm_crtc *crtc)
|
|
|
|
{
|
|
|
|
struct hdlcd_drm_private *hdlcd = crtc_to_hdlcd_priv(crtc);
|
|
|
|
unsigned int mask = hdlcd_read(hdlcd, HDLCD_REG_INT_MASK);
|
|
|
|
|
|
|
|
hdlcd_write(hdlcd, HDLCD_REG_INT_MASK, mask | HDLCD_INTERRUPT_VSYNC);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void hdlcd_crtc_disable_vblank(struct drm_crtc *crtc)
|
|
|
|
{
|
|
|
|
struct hdlcd_drm_private *hdlcd = crtc_to_hdlcd_priv(crtc);
|
|
|
|
unsigned int mask = hdlcd_read(hdlcd, HDLCD_REG_INT_MASK);
|
|
|
|
|
|
|
|
hdlcd_write(hdlcd, HDLCD_REG_INT_MASK, mask & ~HDLCD_INTERRUPT_VSYNC);
|
|
|
|
}
|
|
|
|
|
2015-04-02 18:48:39 +00:00
|
|
|
static const struct drm_crtc_funcs hdlcd_crtc_funcs = {
|
2016-05-17 09:06:54 +00:00
|
|
|
.destroy = hdlcd_crtc_cleanup,
|
2015-04-02 18:48:39 +00:00
|
|
|
.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,
|
2017-02-07 09:16:16 +00:00
|
|
|
.enable_vblank = hdlcd_crtc_enable_vblank,
|
|
|
|
.disable_vblank = hdlcd_crtc_disable_vblank,
|
2015-04-02 18:48:39 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct simplefb_format supported_formats[] = SIMPLEFB_FORMATS;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Setup the HDLCD registers for decoding the pixels out of the framebuffer
|
|
|
|
*/
|
|
|
|
static int hdlcd_set_pxl_fmt(struct drm_crtc *crtc)
|
|
|
|
{
|
|
|
|
unsigned int btpp;
|
|
|
|
struct hdlcd_drm_private *hdlcd = crtc_to_hdlcd_priv(crtc);
|
2016-11-18 19:52:45 +00:00
|
|
|
const struct drm_framebuffer *fb = crtc->primary->state->fb;
|
2015-04-02 18:48:39 +00:00
|
|
|
uint32_t pixel_format;
|
|
|
|
struct simplefb_format *format = NULL;
|
|
|
|
int i;
|
|
|
|
|
2016-12-14 21:32:55 +00:00
|
|
|
pixel_format = fb->format->format;
|
2015-04-02 18:48:39 +00:00
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(supported_formats); i++) {
|
|
|
|
if (supported_formats[i].fourcc == pixel_format)
|
|
|
|
format = &supported_formats[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (WARN_ON(!format))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* HDLCD uses 'bytes per pixel', zero means 1 byte */
|
|
|
|
btpp = (format->bits_per_pixel + 7) / 8;
|
|
|
|
hdlcd_write(hdlcd, HDLCD_REG_PIXEL_FORMAT, (btpp - 1) << 3);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The format of the HDLCD_REG_<color>_SELECT register is:
|
|
|
|
* - bits[23:16] - default value for that color component
|
|
|
|
* - bits[11:8] - number of bits to extract for each color component
|
|
|
|
* - bits[4:0] - index of the lowest bit to extract
|
|
|
|
*
|
|
|
|
* The default color value is used when bits[11:8] are zero, when the
|
|
|
|
* pixel is outside the visible frame area or when there is a
|
|
|
|
* buffer underrun.
|
|
|
|
*/
|
|
|
|
hdlcd_write(hdlcd, HDLCD_REG_RED_SELECT, format->red.offset |
|
|
|
|
#ifdef CONFIG_DRM_HDLCD_SHOW_UNDERRUN
|
|
|
|
0x00ff0000 | /* show underruns in red */
|
|
|
|
#endif
|
|
|
|
((format->red.length & 0xf) << 8));
|
|
|
|
hdlcd_write(hdlcd, HDLCD_REG_GREEN_SELECT, format->green.offset |
|
|
|
|
((format->green.length & 0xf) << 8));
|
|
|
|
hdlcd_write(hdlcd, HDLCD_REG_BLUE_SELECT, format->blue.offset |
|
|
|
|
((format->blue.length & 0xf) << 8));
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void hdlcd_crtc_mode_set_nofb(struct drm_crtc *crtc)
|
|
|
|
{
|
|
|
|
struct hdlcd_drm_private *hdlcd = crtc_to_hdlcd_priv(crtc);
|
|
|
|
struct drm_display_mode *m = &crtc->state->adjusted_mode;
|
|
|
|
struct videomode vm;
|
2016-06-01 14:00:15 +00:00
|
|
|
unsigned int polarities, err;
|
2015-04-02 18:48:39 +00:00
|
|
|
|
|
|
|
vm.vfront_porch = m->crtc_vsync_start - m->crtc_vdisplay;
|
|
|
|
vm.vback_porch = m->crtc_vtotal - m->crtc_vsync_end;
|
|
|
|
vm.vsync_len = m->crtc_vsync_end - m->crtc_vsync_start;
|
|
|
|
vm.hfront_porch = m->crtc_hsync_start - m->crtc_hdisplay;
|
|
|
|
vm.hback_porch = m->crtc_htotal - m->crtc_hsync_end;
|
|
|
|
vm.hsync_len = m->crtc_hsync_end - m->crtc_hsync_start;
|
|
|
|
|
|
|
|
polarities = HDLCD_POLARITY_DATAEN | HDLCD_POLARITY_DATA;
|
|
|
|
|
|
|
|
if (m->flags & DRM_MODE_FLAG_PHSYNC)
|
|
|
|
polarities |= HDLCD_POLARITY_HSYNC;
|
|
|
|
if (m->flags & DRM_MODE_FLAG_PVSYNC)
|
|
|
|
polarities |= HDLCD_POLARITY_VSYNC;
|
|
|
|
|
|
|
|
/* Allow max number of outstanding requests and largest burst size */
|
|
|
|
hdlcd_write(hdlcd, HDLCD_REG_BUS_OPTIONS,
|
|
|
|
HDLCD_BUS_MAX_OUTSTAND | HDLCD_BUS_BURST_16);
|
|
|
|
|
|
|
|
hdlcd_write(hdlcd, HDLCD_REG_V_DATA, m->crtc_vdisplay - 1);
|
|
|
|
hdlcd_write(hdlcd, HDLCD_REG_V_BACK_PORCH, vm.vback_porch - 1);
|
|
|
|
hdlcd_write(hdlcd, HDLCD_REG_V_FRONT_PORCH, vm.vfront_porch - 1);
|
|
|
|
hdlcd_write(hdlcd, HDLCD_REG_V_SYNC, vm.vsync_len - 1);
|
2016-06-01 14:00:15 +00:00
|
|
|
hdlcd_write(hdlcd, HDLCD_REG_H_DATA, m->crtc_hdisplay - 1);
|
2015-04-02 18:48:39 +00:00
|
|
|
hdlcd_write(hdlcd, HDLCD_REG_H_BACK_PORCH, vm.hback_porch - 1);
|
|
|
|
hdlcd_write(hdlcd, HDLCD_REG_H_FRONT_PORCH, vm.hfront_porch - 1);
|
|
|
|
hdlcd_write(hdlcd, HDLCD_REG_H_SYNC, vm.hsync_len - 1);
|
|
|
|
hdlcd_write(hdlcd, HDLCD_REG_POLARITIES, polarities);
|
|
|
|
|
|
|
|
err = hdlcd_set_pxl_fmt(crtc);
|
|
|
|
if (err)
|
|
|
|
return;
|
|
|
|
|
|
|
|
clk_set_rate(hdlcd->clk, m->crtc_clock * 1000);
|
|
|
|
}
|
|
|
|
|
2017-06-30 09:36:44 +00:00
|
|
|
static void hdlcd_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 12:44:08 +00:00
|
|
|
struct drm_atomic_state *state)
|
2015-04-02 18:48:39 +00:00
|
|
|
{
|
|
|
|
struct hdlcd_drm_private *hdlcd = crtc_to_hdlcd_priv(crtc);
|
|
|
|
|
|
|
|
clk_prepare_enable(hdlcd->clk);
|
2016-06-01 14:00:15 +00:00
|
|
|
hdlcd_crtc_mode_set_nofb(crtc);
|
2015-04-02 18:48:39 +00:00
|
|
|
hdlcd_write(hdlcd, HDLCD_REG_COMMAND, 1);
|
2016-11-22 13:56:54 +00:00
|
|
|
drm_crtc_vblank_on(crtc);
|
2015-04-02 18:48:39 +00:00
|
|
|
}
|
|
|
|
|
2017-06-30 09:36:45 +00:00
|
|
|
static void hdlcd_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 12:44:08 +00:00
|
|
|
struct drm_atomic_state *state)
|
2015-04-02 18:48:39 +00:00
|
|
|
{
|
|
|
|
struct hdlcd_drm_private *hdlcd = crtc_to_hdlcd_priv(crtc);
|
|
|
|
|
2016-11-22 13:56:54 +00:00
|
|
|
drm_crtc_vblank_off(crtc);
|
2015-04-02 18:48:39 +00:00
|
|
|
hdlcd_write(hdlcd, HDLCD_REG_COMMAND, 0);
|
2016-05-17 09:06:54 +00:00
|
|
|
clk_disable_unprepare(hdlcd->clk);
|
2015-04-02 18:48:39 +00:00
|
|
|
}
|
|
|
|
|
2019-05-17 16:37:21 +00:00
|
|
|
static enum drm_mode_status hdlcd_crtc_mode_valid(struct drm_crtc *crtc,
|
|
|
|
const struct drm_display_mode *mode)
|
2015-04-02 18:48:39 +00:00
|
|
|
{
|
|
|
|
struct hdlcd_drm_private *hdlcd = crtc_to_hdlcd_priv(crtc);
|
|
|
|
long rate, clk_rate = mode->clock * 1000;
|
|
|
|
|
|
|
|
rate = clk_round_rate(hdlcd->clk, clk_rate);
|
2019-05-17 16:37:22 +00:00
|
|
|
/* 0.1% seems a close enough tolerance for the TDA19988 on Juno */
|
|
|
|
if (abs(rate - clk_rate) * 1000 > clk_rate) {
|
2015-04-02 18:48:39 +00:00
|
|
|
/* clock required by mode not supported by hardware */
|
2019-05-17 16:37:21 +00:00
|
|
|
return MODE_NOCLOCK;
|
2015-04-02 18:48:39 +00:00
|
|
|
}
|
|
|
|
|
2019-05-17 16:37:21 +00:00
|
|
|
return MODE_OK;
|
2015-04-02 18:48:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void hdlcd_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 12:32:22 +00:00
|
|
|
struct drm_atomic_state *state)
|
2015-04-02 18:48:39 +00:00
|
|
|
{
|
2016-05-31 16:21:13 +00:00
|
|
|
struct drm_pending_vblank_event *event = crtc->state->event;
|
2015-04-02 18:48:39 +00:00
|
|
|
|
2016-05-31 16:21:13 +00:00
|
|
|
if (event) {
|
2015-04-02 18:48:39 +00:00
|
|
|
crtc->state->event = NULL;
|
|
|
|
|
2016-05-31 16:21:13 +00:00
|
|
|
spin_lock_irq(&crtc->dev->event_lock);
|
|
|
|
if (drm_crtc_vblank_get(crtc) == 0)
|
|
|
|
drm_crtc_arm_vblank_event(crtc, event);
|
|
|
|
else
|
|
|
|
drm_crtc_send_vblank_event(crtc, event);
|
|
|
|
spin_unlock_irq(&crtc->dev->event_lock);
|
2015-04-02 18:48:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct drm_crtc_helper_funcs hdlcd_crtc_helper_funcs = {
|
2019-05-17 16:37:21 +00:00
|
|
|
.mode_valid = hdlcd_crtc_mode_valid,
|
2015-04-02 18:48:39 +00:00
|
|
|
.atomic_begin = hdlcd_crtc_atomic_begin,
|
2017-06-30 09:36:44 +00:00
|
|
|
.atomic_enable = hdlcd_crtc_atomic_enable,
|
2017-06-30 09:36:45 +00:00
|
|
|
.atomic_disable = hdlcd_crtc_atomic_disable,
|
2015-04-02 18:48:39 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static int hdlcd_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 12:00:24 +00:00
|
|
|
struct drm_atomic_state *state)
|
2015-04-02 18:48:39 +00: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 12:00:24 +00:00
|
|
|
struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
|
|
|
|
plane);
|
2018-07-23 11:05:53 +00:00
|
|
|
int i;
|
|
|
|
struct drm_crtc *crtc;
|
2017-03-08 16:10:19 +00:00
|
|
|
struct drm_crtc_state *crtc_state;
|
2021-02-19 12:00:22 +00:00
|
|
|
u32 src_h = new_plane_state->src_h >> 16;
|
2016-06-01 14:00:15 +00:00
|
|
|
|
2017-03-08 16:10:19 +00:00
|
|
|
/* only the HDLCD_REG_FB_LINE_COUNT register has a limit */
|
|
|
|
if (src_h >= HDLCD_MAX_YRES) {
|
|
|
|
DRM_DEBUG_KMS("Invalid source width: %d\n", src_h);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
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 12:00:25 +00:00
|
|
|
for_each_new_crtc_in_state(state, crtc, crtc_state,
|
2021-02-19 12:00:22 +00:00
|
|
|
i) {
|
2018-07-23 11:05:53 +00:00
|
|
|
/* we cannot disable the plane while the CRTC is active */
|
2021-02-19 12:00:22 +00:00
|
|
|
if (!new_plane_state->fb && crtc_state->active)
|
2018-07-23 11:05:53 +00:00
|
|
|
return -EINVAL;
|
2021-02-19 12:00:22 +00:00
|
|
|
return drm_atomic_helper_check_plane_state(new_plane_state,
|
|
|
|
crtc_state,
|
2022-07-20 08:30:54 +00:00
|
|
|
DRM_PLANE_NO_SCALING,
|
|
|
|
DRM_PLANE_NO_SCALING,
|
2021-02-19 12:00:22 +00:00
|
|
|
false, true);
|
2017-03-08 16:10:19 +00:00
|
|
|
}
|
2016-06-01 14:00:15 +00:00
|
|
|
|
2018-07-23 11:05:53 +00:00
|
|
|
return 0;
|
2015-04-02 18:48:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void hdlcd_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 12:00:29 +00:00
|
|
|
struct drm_atomic_state *state)
|
2015-04-02 18:48:39 +00:00
|
|
|
{
|
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 12:00:30 +00:00
|
|
|
struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
|
|
|
|
plane);
|
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 12:00:27 +00:00
|
|
|
struct drm_framebuffer *fb = new_plane_state->fb;
|
2015-04-02 18:48:39 +00:00
|
|
|
struct hdlcd_drm_private *hdlcd;
|
2017-06-20 20:30:38 +00:00
|
|
|
u32 dest_h;
|
2015-04-02 18:48:39 +00:00
|
|
|
dma_addr_t scanout_start;
|
|
|
|
|
2016-11-18 19:52:45 +00:00
|
|
|
if (!fb)
|
2015-04-02 18:48:39 +00:00
|
|
|
return;
|
|
|
|
|
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 12:00:27 +00:00
|
|
|
dest_h = drm_rect_height(&new_plane_state->dst);
|
2022-08-02 00:04:02 +00:00
|
|
|
scanout_start = drm_fb_dma_get_gem_addr(fb, new_plane_state, 0);
|
2016-06-01 14:00:15 +00:00
|
|
|
|
2022-10-26 15:34:29 +00:00
|
|
|
hdlcd = drm_to_hdlcd_priv(plane->dev);
|
2016-11-18 19:52:45 +00:00
|
|
|
hdlcd_write(hdlcd, HDLCD_REG_FB_LINE_LENGTH, fb->pitches[0]);
|
|
|
|
hdlcd_write(hdlcd, HDLCD_REG_FB_LINE_PITCH, fb->pitches[0]);
|
2016-06-01 14:00:15 +00:00
|
|
|
hdlcd_write(hdlcd, HDLCD_REG_FB_LINE_COUNT, dest_h - 1);
|
2015-04-02 18:48:39 +00:00
|
|
|
hdlcd_write(hdlcd, HDLCD_REG_FB_BASE, scanout_start);
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct drm_plane_helper_funcs hdlcd_plane_helper_funcs = {
|
|
|
|
.atomic_check = hdlcd_plane_atomic_check,
|
|
|
|
.atomic_update = hdlcd_plane_atomic_update,
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct drm_plane_funcs hdlcd_plane_funcs = {
|
|
|
|
.update_plane = drm_atomic_helper_update_plane,
|
|
|
|
.disable_plane = drm_atomic_helper_disable_plane,
|
|
|
|
.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 struct drm_plane *hdlcd_plane_init(struct drm_device *drm)
|
|
|
|
{
|
2022-10-26 15:34:29 +00:00
|
|
|
struct hdlcd_drm_private *hdlcd = drm_to_hdlcd_priv(drm);
|
2015-04-02 18:48:39 +00:00
|
|
|
struct drm_plane *plane = NULL;
|
|
|
|
u32 formats[ARRAY_SIZE(supported_formats)], i;
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(supported_formats); i++)
|
|
|
|
formats[i] = supported_formats[i].fourcc;
|
|
|
|
|
2022-10-26 15:34:30 +00:00
|
|
|
plane = drmm_universal_plane_alloc(drm, struct drm_plane, dev, 0xff,
|
|
|
|
&hdlcd_plane_funcs,
|
|
|
|
formats, ARRAY_SIZE(formats),
|
|
|
|
NULL, DRM_PLANE_TYPE_PRIMARY, NULL);
|
|
|
|
if (IS_ERR(plane))
|
|
|
|
return plane;
|
2015-04-02 18:48:39 +00:00
|
|
|
|
|
|
|
drm_plane_helper_add(plane, &hdlcd_plane_helper_funcs);
|
|
|
|
hdlcd->plane = plane;
|
|
|
|
|
|
|
|
return plane;
|
|
|
|
}
|
|
|
|
|
|
|
|
int hdlcd_setup_crtc(struct drm_device *drm)
|
|
|
|
{
|
2022-10-26 15:34:29 +00:00
|
|
|
struct hdlcd_drm_private *hdlcd = drm_to_hdlcd_priv(drm);
|
2015-04-02 18:48:39 +00:00
|
|
|
struct drm_plane *primary;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
primary = hdlcd_plane_init(drm);
|
|
|
|
if (IS_ERR(primary))
|
|
|
|
return PTR_ERR(primary);
|
|
|
|
|
|
|
|
ret = drm_crtc_init_with_planes(drm, &hdlcd->crtc, primary, NULL,
|
|
|
|
&hdlcd_crtc_funcs, NULL);
|
2018-01-17 21:55:27 +00:00
|
|
|
if (ret)
|
2015-04-02 18:48:39 +00:00
|
|
|
return ret;
|
|
|
|
|
|
|
|
drm_crtc_helper_add(&hdlcd->crtc, &hdlcd_crtc_helper_funcs);
|
|
|
|
return 0;
|
|
|
|
}
|