2018-11-06 17:40:00 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0+
|
|
|
|
/*
|
|
|
|
* Copyright (C) 2018 BayLibre, SAS
|
|
|
|
* Author: Neil Armstrong <narmstrong@baylibre.com>
|
|
|
|
* Copyright (C) 2015 Amlogic, Inc. All rights reserved.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/bitfield.h>
|
2019-07-16 14:42:02 +08:00
|
|
|
|
2018-11-06 17:40:00 +08:00
|
|
|
#include <drm/drm_atomic.h>
|
|
|
|
#include <drm/drm_atomic_helper.h>
|
2019-07-16 14:42:02 +08:00
|
|
|
#include <drm/drm_device.h>
|
2021-02-22 22:17:56 +08:00
|
|
|
#include <drm/drm_fb_cma_helper.h>
|
2019-07-16 14:42:02 +08:00
|
|
|
#include <drm/drm_fourcc.h>
|
2021-02-22 22:17:56 +08:00
|
|
|
#include <drm/drm_gem_atomic_helper.h>
|
2018-11-06 17:40:00 +08:00
|
|
|
#include <drm/drm_gem_cma_helper.h>
|
2021-02-22 22:17:56 +08:00
|
|
|
#include <drm/drm_plane_helper.h>
|
2018-11-06 17:40:00 +08:00
|
|
|
|
|
|
|
#include "meson_overlay.h"
|
|
|
|
#include "meson_registers.h"
|
2019-07-16 14:42:02 +08:00
|
|
|
#include "meson_viu.h"
|
|
|
|
#include "meson_vpp.h"
|
2018-11-06 17:40:00 +08:00
|
|
|
|
|
|
|
/* VD1_IF0_GEN_REG */
|
|
|
|
#define VD_URGENT_CHROMA BIT(28)
|
|
|
|
#define VD_URGENT_LUMA BIT(27)
|
|
|
|
#define VD_HOLD_LINES(lines) FIELD_PREP(GENMASK(24, 19), lines)
|
|
|
|
#define VD_DEMUX_MODE_RGB BIT(16)
|
|
|
|
#define VD_BYTES_PER_PIXEL(val) FIELD_PREP(GENMASK(15, 14), val)
|
|
|
|
#define VD_CHRO_RPT_LASTL_CTRL BIT(6)
|
|
|
|
#define VD_LITTLE_ENDIAN BIT(4)
|
|
|
|
#define VD_SEPARATE_EN BIT(1)
|
|
|
|
#define VD_ENABLE BIT(0)
|
|
|
|
|
|
|
|
/* VD1_IF0_CANVAS0 */
|
|
|
|
#define CANVAS_ADDR2(addr) FIELD_PREP(GENMASK(23, 16), addr)
|
|
|
|
#define CANVAS_ADDR1(addr) FIELD_PREP(GENMASK(15, 8), addr)
|
|
|
|
#define CANVAS_ADDR0(addr) FIELD_PREP(GENMASK(7, 0), addr)
|
|
|
|
|
|
|
|
/* VD1_IF0_LUMA_X0 VD1_IF0_CHROMA_X0 */
|
|
|
|
#define VD_X_START(value) FIELD_PREP(GENMASK(14, 0), value)
|
|
|
|
#define VD_X_END(value) FIELD_PREP(GENMASK(30, 16), value)
|
|
|
|
|
|
|
|
/* VD1_IF0_LUMA_Y0 VD1_IF0_CHROMA_Y0 */
|
|
|
|
#define VD_Y_START(value) FIELD_PREP(GENMASK(12, 0), value)
|
|
|
|
#define VD_Y_END(value) FIELD_PREP(GENMASK(28, 16), value)
|
|
|
|
|
|
|
|
/* VD1_IF0_GEN_REG2 */
|
|
|
|
#define VD_COLOR_MAP(value) FIELD_PREP(GENMASK(1, 0), value)
|
|
|
|
|
|
|
|
/* VIU_VD1_FMT_CTRL */
|
|
|
|
#define VD_HORZ_Y_C_RATIO(value) FIELD_PREP(GENMASK(22, 21), value)
|
|
|
|
#define VD_HORZ_FMT_EN BIT(20)
|
|
|
|
#define VD_VERT_RPT_LINE0 BIT(16)
|
|
|
|
#define VD_VERT_INITIAL_PHASE(value) FIELD_PREP(GENMASK(11, 8), value)
|
|
|
|
#define VD_VERT_PHASE_STEP(value) FIELD_PREP(GENMASK(7, 1), value)
|
|
|
|
#define VD_VERT_FMT_EN BIT(0)
|
|
|
|
|
|
|
|
/* VPP_POSTBLEND_VD1_H_START_END */
|
|
|
|
#define VD_H_END(value) FIELD_PREP(GENMASK(11, 0), value)
|
2020-07-07 21:50:09 +08:00
|
|
|
#define VD_H_START(value) FIELD_PREP(GENMASK(27, 16), \
|
|
|
|
((value) & GENMASK(13, 0)))
|
2018-11-06 17:40:00 +08:00
|
|
|
|
|
|
|
/* VPP_POSTBLEND_VD1_V_START_END */
|
|
|
|
#define VD_V_END(value) FIELD_PREP(GENMASK(11, 0), value)
|
|
|
|
#define VD_V_START(value) FIELD_PREP(GENMASK(27, 16), value)
|
|
|
|
|
|
|
|
/* VPP_BLEND_VD2_V_START_END */
|
|
|
|
#define VD2_V_END(value) FIELD_PREP(GENMASK(11, 0), value)
|
|
|
|
#define VD2_V_START(value) FIELD_PREP(GENMASK(27, 16), value)
|
|
|
|
|
|
|
|
/* VIU_VD1_FMT_W */
|
|
|
|
#define VD_V_WIDTH(value) FIELD_PREP(GENMASK(11, 0), value)
|
|
|
|
#define VD_H_WIDTH(value) FIELD_PREP(GENMASK(27, 16), value)
|
|
|
|
|
|
|
|
/* VPP_HSC_REGION12_STARTP VPP_HSC_REGION34_STARTP */
|
|
|
|
#define VD_REGION24_START(value) FIELD_PREP(GENMASK(11, 0), value)
|
|
|
|
#define VD_REGION13_END(value) FIELD_PREP(GENMASK(27, 16), value)
|
|
|
|
|
2020-07-03 16:07:25 +08:00
|
|
|
/* AFBC_ENABLE */
|
|
|
|
#define AFBC_DEC_ENABLE BIT(8)
|
|
|
|
#define AFBC_FRM_START BIT(0)
|
|
|
|
|
|
|
|
/* AFBC_MODE */
|
|
|
|
#define AFBC_HORZ_SKIP_UV(value) FIELD_PREP(GENMASK(1, 0), value)
|
|
|
|
#define AFBC_VERT_SKIP_UV(value) FIELD_PREP(GENMASK(3, 2), value)
|
|
|
|
#define AFBC_HORZ_SKIP_Y(value) FIELD_PREP(GENMASK(5, 4), value)
|
|
|
|
#define AFBC_VERT_SKIP_Y(value) FIELD_PREP(GENMASK(7, 6), value)
|
|
|
|
#define AFBC_COMPBITS_YUV(value) FIELD_PREP(GENMASK(13, 8), value)
|
|
|
|
#define AFBC_COMPBITS_8BIT 0
|
|
|
|
#define AFBC_COMPBITS_10BIT (2 | (2 << 2) | (2 << 4))
|
|
|
|
#define AFBC_BURST_LEN(value) FIELD_PREP(GENMASK(15, 14), value)
|
|
|
|
#define AFBC_HOLD_LINE_NUM(value) FIELD_PREP(GENMASK(22, 16), value)
|
|
|
|
#define AFBC_MIF_URGENT(value) FIELD_PREP(GENMASK(25, 24), value)
|
|
|
|
#define AFBC_REV_MODE(value) FIELD_PREP(GENMASK(27, 26), value)
|
|
|
|
#define AFBC_BLK_MEM_MODE BIT(28)
|
|
|
|
#define AFBC_SCATTER_MODE BIT(29)
|
|
|
|
#define AFBC_SOFT_RESET BIT(31)
|
|
|
|
|
|
|
|
/* AFBC_SIZE_IN */
|
|
|
|
#define AFBC_HSIZE_IN(value) FIELD_PREP(GENMASK(28, 16), value)
|
|
|
|
#define AFBC_VSIZE_IN(value) FIELD_PREP(GENMASK(12, 0), value)
|
|
|
|
|
|
|
|
/* AFBC_DEC_DEF_COLOR */
|
|
|
|
#define AFBC_DEF_COLOR_Y(value) FIELD_PREP(GENMASK(29, 20), value)
|
|
|
|
#define AFBC_DEF_COLOR_U(value) FIELD_PREP(GENMASK(19, 10), value)
|
|
|
|
#define AFBC_DEF_COLOR_V(value) FIELD_PREP(GENMASK(9, 0), value)
|
|
|
|
|
|
|
|
/* AFBC_CONV_CTRL */
|
|
|
|
#define AFBC_CONV_LBUF_LEN(value) FIELD_PREP(GENMASK(11, 0), value)
|
|
|
|
|
|
|
|
/* AFBC_LBUF_DEPTH */
|
|
|
|
#define AFBC_DEC_LBUF_DEPTH(value) FIELD_PREP(GENMASK(27, 16), value)
|
|
|
|
#define AFBC_MIF_LBUF_DEPTH(value) FIELD_PREP(GENMASK(11, 0), value)
|
|
|
|
|
|
|
|
/* AFBC_OUT_XSCOPE/AFBC_SIZE_OUT */
|
|
|
|
#define AFBC_HSIZE_OUT(value) FIELD_PREP(GENMASK(28, 16), value)
|
|
|
|
#define AFBC_VSIZE_OUT(value) FIELD_PREP(GENMASK(12, 0), value)
|
|
|
|
#define AFBC_OUT_HORZ_BGN(value) FIELD_PREP(GENMASK(28, 16), value)
|
|
|
|
#define AFBC_OUT_HORZ_END(value) FIELD_PREP(GENMASK(12, 0), value)
|
|
|
|
|
|
|
|
/* AFBC_OUT_YSCOPE */
|
|
|
|
#define AFBC_OUT_VERT_BGN(value) FIELD_PREP(GENMASK(28, 16), value)
|
|
|
|
#define AFBC_OUT_VERT_END(value) FIELD_PREP(GENMASK(12, 0), value)
|
|
|
|
|
|
|
|
/* AFBC_VD_CFMT_CTRL */
|
|
|
|
#define AFBC_HORZ_RPT_PIXEL0 BIT(23)
|
|
|
|
#define AFBC_HORZ_Y_C_RATIO(value) FIELD_PREP(GENMASK(22, 21), value)
|
|
|
|
#define AFBC_HORZ_FMT_EN BIT(20)
|
|
|
|
#define AFBC_VERT_RPT_LINE0 BIT(16)
|
|
|
|
#define AFBC_VERT_INITIAL_PHASE(value) FIELD_PREP(GENMASK(11, 8), value)
|
|
|
|
#define AFBC_VERT_PHASE_STEP(value) FIELD_PREP(GENMASK(7, 1), value)
|
|
|
|
#define AFBC_VERT_FMT_EN BIT(0)
|
|
|
|
|
|
|
|
/* AFBC_VD_CFMT_W */
|
|
|
|
#define AFBC_VD_V_WIDTH(value) FIELD_PREP(GENMASK(11, 0), value)
|
|
|
|
#define AFBC_VD_H_WIDTH(value) FIELD_PREP(GENMASK(27, 16), value)
|
|
|
|
|
|
|
|
/* AFBC_MIF_HOR_SCOPE */
|
|
|
|
#define AFBC_MIF_BLK_BGN_H(value) FIELD_PREP(GENMASK(25, 16), value)
|
|
|
|
#define AFBC_MIF_BLK_END_H(value) FIELD_PREP(GENMASK(9, 0), value)
|
|
|
|
|
|
|
|
/* AFBC_MIF_VER_SCOPE */
|
|
|
|
#define AFBC_MIF_BLK_BGN_V(value) FIELD_PREP(GENMASK(27, 16), value)
|
|
|
|
#define AFBC_MIF_BLK_END_V(value) FIELD_PREP(GENMASK(11, 0), value)
|
|
|
|
|
|
|
|
/* AFBC_PIXEL_HOR_SCOPE */
|
2020-07-07 21:50:09 +08:00
|
|
|
#define AFBC_DEC_PIXEL_BGN_H(value) FIELD_PREP(GENMASK(28, 16), \
|
|
|
|
((value) & GENMASK(12, 0)))
|
2020-07-03 16:07:25 +08:00
|
|
|
#define AFBC_DEC_PIXEL_END_H(value) FIELD_PREP(GENMASK(12, 0), value)
|
|
|
|
|
|
|
|
/* AFBC_PIXEL_VER_SCOPE */
|
|
|
|
#define AFBC_DEC_PIXEL_BGN_V(value) FIELD_PREP(GENMASK(28, 16), value)
|
|
|
|
#define AFBC_DEC_PIXEL_END_V(value) FIELD_PREP(GENMASK(12, 0), value)
|
|
|
|
|
|
|
|
/* AFBC_VD_CFMT_H */
|
|
|
|
#define AFBC_VD_HEIGHT(value) FIELD_PREP(GENMASK(12, 0), value)
|
|
|
|
|
2018-11-06 17:40:00 +08:00
|
|
|
struct meson_overlay {
|
|
|
|
struct drm_plane base;
|
|
|
|
struct meson_drm *priv;
|
|
|
|
};
|
|
|
|
#define to_meson_overlay(x) container_of(x, struct meson_overlay, base)
|
|
|
|
|
|
|
|
#define FRAC_16_16(mult, div) (((mult) << 16) / (div))
|
|
|
|
|
|
|
|
static int meson_overlay_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 20:00:24 +08:00
|
|
|
struct drm_atomic_state *state)
|
2018-11-06 17:40:00 +08: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 20:00:24 +08:00
|
|
|
struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
|
|
|
|
plane);
|
2018-11-06 17:40:00 +08:00
|
|
|
struct drm_crtc_state *crtc_state;
|
|
|
|
|
2021-02-19 20:00:22 +08:00
|
|
|
if (!new_plane_state->crtc)
|
2018-11-06 17:40:00 +08: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 20:00:25 +08:00
|
|
|
crtc_state = drm_atomic_get_crtc_state(state,
|
2021-02-19 20:00:22 +08:00
|
|
|
new_plane_state->crtc);
|
2018-11-06 17:40:00 +08:00
|
|
|
if (IS_ERR(crtc_state))
|
|
|
|
return PTR_ERR(crtc_state);
|
|
|
|
|
2021-02-19 20:00:22 +08:00
|
|
|
return drm_atomic_helper_check_plane_state(new_plane_state,
|
|
|
|
crtc_state,
|
2018-11-06 17:40:00 +08:00
|
|
|
FRAC_16_16(1, 5),
|
|
|
|
FRAC_16_16(5, 1),
|
|
|
|
true, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Takes a fixed 16.16 number and converts it to integer. */
|
|
|
|
static inline int64_t fixed16_to_int(int64_t value)
|
|
|
|
{
|
|
|
|
return value >> 16;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const uint8_t skip_tab[6] = {
|
|
|
|
0x24, 0x04, 0x68, 0x48, 0x28, 0x08,
|
|
|
|
};
|
|
|
|
|
|
|
|
static void meson_overlay_get_vertical_phase(unsigned int ratio_y, int *phase,
|
|
|
|
int *repeat, bool interlace)
|
|
|
|
{
|
|
|
|
int offset_in = 0;
|
|
|
|
int offset_out = 0;
|
|
|
|
int repeat_skip = 0;
|
|
|
|
|
|
|
|
if (!interlace && ratio_y > (1 << 18))
|
|
|
|
offset_out = (1 * ratio_y) >> 10;
|
|
|
|
|
|
|
|
while ((offset_in + (4 << 8)) <= offset_out) {
|
|
|
|
repeat_skip++;
|
|
|
|
offset_in += 4 << 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
*phase = (offset_out - offset_in) >> 2;
|
|
|
|
|
|
|
|
if (*phase > 0x100)
|
|
|
|
repeat_skip++;
|
|
|
|
|
|
|
|
*phase = *phase & 0xff;
|
|
|
|
|
|
|
|
if (repeat_skip > 5)
|
|
|
|
repeat_skip = 5;
|
|
|
|
|
|
|
|
*repeat = skip_tab[repeat_skip];
|
|
|
|
}
|
|
|
|
|
|
|
|
static void meson_overlay_setup_scaler_params(struct meson_drm *priv,
|
|
|
|
struct drm_plane *plane,
|
|
|
|
bool interlace_mode)
|
|
|
|
{
|
|
|
|
struct drm_crtc_state *crtc_state = priv->crtc->state;
|
|
|
|
int video_top, video_left, video_width, video_height;
|
|
|
|
struct drm_plane_state *state = plane->state;
|
|
|
|
unsigned int vd_start_lines, vd_end_lines;
|
|
|
|
unsigned int hd_start_lines, hd_end_lines;
|
|
|
|
unsigned int crtc_height, crtc_width;
|
|
|
|
unsigned int vsc_startp, vsc_endp;
|
|
|
|
unsigned int hsc_startp, hsc_endp;
|
|
|
|
unsigned int crop_top, crop_left;
|
|
|
|
int vphase, vphase_repeat_skip;
|
|
|
|
unsigned int ratio_x, ratio_y;
|
|
|
|
int temp_height, temp_width;
|
|
|
|
unsigned int w_in, h_in;
|
2020-07-03 16:07:25 +08:00
|
|
|
int afbc_left, afbc_right;
|
|
|
|
int afbc_top_src, afbc_bottom_src;
|
|
|
|
int afbc_top, afbc_bottom;
|
2018-11-06 17:40:00 +08:00
|
|
|
int temp, start, end;
|
|
|
|
|
|
|
|
if (!crtc_state) {
|
|
|
|
DRM_ERROR("Invalid crtc_state\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
crtc_height = crtc_state->mode.vdisplay;
|
|
|
|
crtc_width = crtc_state->mode.hdisplay;
|
|
|
|
|
|
|
|
w_in = fixed16_to_int(state->src_w);
|
|
|
|
h_in = fixed16_to_int(state->src_h);
|
2020-07-03 16:07:25 +08:00
|
|
|
crop_top = fixed16_to_int(state->src_y);
|
2018-11-06 17:40:00 +08:00
|
|
|
crop_left = fixed16_to_int(state->src_x);
|
|
|
|
|
|
|
|
video_top = state->crtc_y;
|
|
|
|
video_left = state->crtc_x;
|
|
|
|
video_width = state->crtc_w;
|
|
|
|
video_height = state->crtc_h;
|
|
|
|
|
|
|
|
DRM_DEBUG("crtc_width %d crtc_height %d interlace %d\n",
|
|
|
|
crtc_width, crtc_height, interlace_mode);
|
|
|
|
DRM_DEBUG("w_in %d h_in %d crop_top %d crop_left %d\n",
|
|
|
|
w_in, h_in, crop_top, crop_left);
|
|
|
|
DRM_DEBUG("video top %d left %d width %d height %d\n",
|
|
|
|
video_top, video_left, video_width, video_height);
|
|
|
|
|
|
|
|
ratio_x = (w_in << 18) / video_width;
|
|
|
|
ratio_y = (h_in << 18) / video_height;
|
|
|
|
|
|
|
|
if (ratio_x * video_width < (w_in << 18))
|
|
|
|
ratio_x++;
|
|
|
|
|
|
|
|
DRM_DEBUG("ratio x 0x%x y 0x%x\n", ratio_x, ratio_y);
|
|
|
|
|
|
|
|
meson_overlay_get_vertical_phase(ratio_y, &vphase, &vphase_repeat_skip,
|
|
|
|
interlace_mode);
|
|
|
|
|
|
|
|
DRM_DEBUG("vphase 0x%x skip %d\n", vphase, vphase_repeat_skip);
|
|
|
|
|
|
|
|
/* Vertical */
|
|
|
|
|
|
|
|
start = video_top + video_height / 2 - ((h_in << 17) / ratio_y);
|
|
|
|
end = (h_in << 18) / ratio_y + start - 1;
|
|
|
|
|
|
|
|
if (video_top < 0 && start < 0)
|
|
|
|
vd_start_lines = (-(start) * ratio_y) >> 18;
|
|
|
|
else if (start < video_top)
|
|
|
|
vd_start_lines = ((video_top - start) * ratio_y) >> 18;
|
|
|
|
else
|
|
|
|
vd_start_lines = 0;
|
|
|
|
|
|
|
|
if (video_top < 0)
|
|
|
|
temp_height = min_t(unsigned int,
|
|
|
|
video_top + video_height - 1,
|
|
|
|
crtc_height - 1);
|
|
|
|
else
|
|
|
|
temp_height = min_t(unsigned int,
|
|
|
|
video_top + video_height - 1,
|
|
|
|
crtc_height - 1) - video_top + 1;
|
|
|
|
|
|
|
|
temp = vd_start_lines + (temp_height * ratio_y >> 18);
|
|
|
|
vd_end_lines = (temp <= (h_in - 1)) ? temp : (h_in - 1);
|
|
|
|
|
|
|
|
vd_start_lines += crop_left;
|
|
|
|
vd_end_lines += crop_left;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* TOFIX: Input frames are handled and scaled like progressive frames,
|
|
|
|
* proper handling of interlaced field input frames need to be figured
|
|
|
|
* out using the proper framebuffer flags set by userspace.
|
|
|
|
*/
|
|
|
|
if (interlace_mode) {
|
|
|
|
start >>= 1;
|
|
|
|
end >>= 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
vsc_startp = max_t(int, start,
|
|
|
|
max_t(int, 0, video_top));
|
|
|
|
vsc_endp = min_t(int, end,
|
|
|
|
min_t(int, crtc_height - 1,
|
|
|
|
video_top + video_height - 1));
|
|
|
|
|
|
|
|
DRM_DEBUG("vsc startp %d endp %d start_lines %d end_lines %d\n",
|
|
|
|
vsc_startp, vsc_endp, vd_start_lines, vd_end_lines);
|
|
|
|
|
2020-07-03 16:07:25 +08:00
|
|
|
afbc_top = round_down(vd_start_lines, 4);
|
|
|
|
afbc_bottom = round_up(vd_end_lines + 1, 4);
|
|
|
|
afbc_top_src = 0;
|
|
|
|
afbc_bottom_src = round_up(h_in + 1, 4);
|
|
|
|
|
|
|
|
DRM_DEBUG("afbc top %d (src %d) bottom %d (src %d)\n",
|
|
|
|
afbc_top, afbc_top_src, afbc_bottom, afbc_bottom_src);
|
|
|
|
|
2018-11-06 17:40:00 +08:00
|
|
|
/* Horizontal */
|
|
|
|
|
|
|
|
start = video_left + video_width / 2 - ((w_in << 17) / ratio_x);
|
|
|
|
end = (w_in << 18) / ratio_x + start - 1;
|
|
|
|
|
|
|
|
if (video_left < 0 && start < 0)
|
|
|
|
hd_start_lines = (-(start) * ratio_x) >> 18;
|
|
|
|
else if (start < video_left)
|
|
|
|
hd_start_lines = ((video_left - start) * ratio_x) >> 18;
|
|
|
|
else
|
|
|
|
hd_start_lines = 0;
|
|
|
|
|
|
|
|
if (video_left < 0)
|
|
|
|
temp_width = min_t(unsigned int,
|
|
|
|
video_left + video_width - 1,
|
|
|
|
crtc_width - 1);
|
|
|
|
else
|
|
|
|
temp_width = min_t(unsigned int,
|
|
|
|
video_left + video_width - 1,
|
|
|
|
crtc_width - 1) - video_left + 1;
|
|
|
|
|
|
|
|
temp = hd_start_lines + (temp_width * ratio_x >> 18);
|
|
|
|
hd_end_lines = (temp <= (w_in - 1)) ? temp : (w_in - 1);
|
|
|
|
|
|
|
|
priv->viu.vpp_line_in_length = hd_end_lines - hd_start_lines + 1;
|
|
|
|
hsc_startp = max_t(int, start, max_t(int, 0, video_left));
|
|
|
|
hsc_endp = min_t(int, end, min_t(int, crtc_width - 1,
|
|
|
|
video_left + video_width - 1));
|
|
|
|
|
|
|
|
hd_start_lines += crop_top;
|
|
|
|
hd_end_lines += crop_top;
|
|
|
|
|
|
|
|
DRM_DEBUG("hsc startp %d endp %d start_lines %d end_lines %d\n",
|
|
|
|
hsc_startp, hsc_endp, hd_start_lines, hd_end_lines);
|
|
|
|
|
2020-07-03 16:07:25 +08:00
|
|
|
if (hd_start_lines > 0 || (hd_end_lines < w_in)) {
|
|
|
|
afbc_left = 0;
|
|
|
|
afbc_right = round_up(w_in, 32);
|
|
|
|
} else {
|
|
|
|
afbc_left = round_down(hd_start_lines, 32);
|
|
|
|
afbc_right = round_up(hd_end_lines + 1, 32);
|
|
|
|
}
|
|
|
|
|
|
|
|
DRM_DEBUG("afbc left %d right %d\n", afbc_left, afbc_right);
|
|
|
|
|
2018-11-06 17:40:00 +08:00
|
|
|
priv->viu.vpp_vsc_start_phase_step = ratio_y << 6;
|
|
|
|
|
|
|
|
priv->viu.vpp_vsc_ini_phase = vphase << 8;
|
|
|
|
priv->viu.vpp_vsc_phase_ctrl = (1 << 13) | (4 << 8) |
|
|
|
|
vphase_repeat_skip;
|
|
|
|
|
|
|
|
priv->viu.vd1_if0_luma_x0 = VD_X_START(hd_start_lines) |
|
|
|
|
VD_X_END(hd_end_lines);
|
|
|
|
priv->viu.vd1_if0_chroma_x0 = VD_X_START(hd_start_lines >> 1) |
|
|
|
|
VD_X_END(hd_end_lines >> 1);
|
|
|
|
|
|
|
|
priv->viu.viu_vd1_fmt_w =
|
|
|
|
VD_H_WIDTH(hd_end_lines - hd_start_lines + 1) |
|
|
|
|
VD_V_WIDTH(hd_end_lines/2 - hd_start_lines/2 + 1);
|
|
|
|
|
2020-07-03 16:07:25 +08:00
|
|
|
priv->viu.vd1_afbc_vd_cfmt_w =
|
|
|
|
AFBC_VD_H_WIDTH(afbc_right - afbc_left) |
|
|
|
|
AFBC_VD_V_WIDTH(afbc_right / 2 - afbc_left / 2);
|
|
|
|
|
|
|
|
priv->viu.vd1_afbc_vd_cfmt_h =
|
|
|
|
AFBC_VD_HEIGHT((afbc_bottom - afbc_top) / 2);
|
|
|
|
|
|
|
|
priv->viu.vd1_afbc_mif_hor_scope = AFBC_MIF_BLK_BGN_H(afbc_left / 32) |
|
|
|
|
AFBC_MIF_BLK_END_H((afbc_right / 32) - 1);
|
|
|
|
|
|
|
|
priv->viu.vd1_afbc_mif_ver_scope = AFBC_MIF_BLK_BGN_V(afbc_top / 4) |
|
|
|
|
AFBC_MIF_BLK_END_H((afbc_bottom / 4) - 1);
|
|
|
|
|
|
|
|
priv->viu.vd1_afbc_size_out =
|
|
|
|
AFBC_HSIZE_OUT(afbc_right - afbc_left) |
|
|
|
|
AFBC_VSIZE_OUT(afbc_bottom - afbc_top);
|
|
|
|
|
|
|
|
priv->viu.vd1_afbc_pixel_hor_scope =
|
|
|
|
AFBC_DEC_PIXEL_BGN_H(hd_start_lines - afbc_left) |
|
|
|
|
AFBC_DEC_PIXEL_END_H(hd_end_lines - afbc_left);
|
|
|
|
|
|
|
|
priv->viu.vd1_afbc_pixel_ver_scope =
|
|
|
|
AFBC_DEC_PIXEL_BGN_V(vd_start_lines - afbc_top) |
|
|
|
|
AFBC_DEC_PIXEL_END_V(vd_end_lines - afbc_top);
|
|
|
|
|
|
|
|
priv->viu.vd1_afbc_size_in =
|
|
|
|
AFBC_HSIZE_IN(afbc_right - afbc_left) |
|
|
|
|
AFBC_VSIZE_IN(afbc_bottom_src - afbc_top_src);
|
|
|
|
|
2018-11-06 17:40:00 +08:00
|
|
|
priv->viu.vd1_if0_luma_y0 = VD_Y_START(vd_start_lines) |
|
|
|
|
VD_Y_END(vd_end_lines);
|
|
|
|
|
|
|
|
priv->viu.vd1_if0_chroma_y0 = VD_Y_START(vd_start_lines >> 1) |
|
|
|
|
VD_Y_END(vd_end_lines >> 1);
|
|
|
|
|
|
|
|
priv->viu.vpp_pic_in_height = h_in;
|
|
|
|
|
|
|
|
priv->viu.vpp_postblend_vd1_h_start_end = VD_H_START(hsc_startp) |
|
|
|
|
VD_H_END(hsc_endp);
|
|
|
|
priv->viu.vpp_blend_vd2_h_start_end = VD_H_START(hd_start_lines) |
|
|
|
|
VD_H_END(hd_end_lines);
|
|
|
|
priv->viu.vpp_hsc_region12_startp = VD_REGION13_END(0) |
|
|
|
|
VD_REGION24_START(hsc_startp);
|
|
|
|
priv->viu.vpp_hsc_region34_startp =
|
|
|
|
VD_REGION13_END(hsc_startp) |
|
|
|
|
VD_REGION24_START(hsc_endp - hsc_startp);
|
|
|
|
priv->viu.vpp_hsc_region4_endp = hsc_endp - hsc_startp;
|
|
|
|
priv->viu.vpp_hsc_start_phase_step = ratio_x << 6;
|
|
|
|
priv->viu.vpp_hsc_region1_phase_slope = 0;
|
|
|
|
priv->viu.vpp_hsc_region3_phase_slope = 0;
|
|
|
|
priv->viu.vpp_hsc_phase_ctrl = (1 << 21) | (4 << 16);
|
|
|
|
|
|
|
|
priv->viu.vpp_line_in_length = hd_end_lines - hd_start_lines + 1;
|
|
|
|
priv->viu.vpp_preblend_h_size = hd_end_lines - hd_start_lines + 1;
|
|
|
|
|
|
|
|
priv->viu.vpp_postblend_vd1_v_start_end = VD_V_START(vsc_startp) |
|
|
|
|
VD_V_END(vsc_endp);
|
|
|
|
priv->viu.vpp_blend_vd2_v_start_end =
|
|
|
|
VD2_V_START((vd_end_lines + 1) >> 1) |
|
|
|
|
VD2_V_END(vd_end_lines);
|
|
|
|
|
|
|
|
priv->viu.vpp_vsc_region12_startp = 0;
|
|
|
|
priv->viu.vpp_vsc_region34_startp =
|
|
|
|
VD_REGION13_END(vsc_endp - vsc_startp) |
|
|
|
|
VD_REGION24_START(vsc_endp - vsc_startp);
|
|
|
|
priv->viu.vpp_vsc_region4_endp = vsc_endp - vsc_startp;
|
|
|
|
priv->viu.vpp_vsc_start_phase_step = ratio_y << 6;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void meson_overlay_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 20:00:29 +08:00
|
|
|
struct drm_atomic_state *state)
|
2018-11-06 17:40:00 +08:00
|
|
|
{
|
|
|
|
struct meson_overlay *meson_overlay = to_meson_overlay(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 20:00:30 +08:00
|
|
|
struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
|
|
|
|
plane);
|
drm: Rename plane->state variables in atomic update and disable
Some drivers are storing the plane->state pointer in atomic_update and
atomic_disable in a variable simply called state, while the state passed
as an argument is called old_state.
In order to ease subsequent reworks and to avoid confusing or
inconsistent names, let's rename those variables to new_state.
This was done using the following coccinelle script, plus some manual
changes for mtk and tegra.
@ 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,
...,
};
)
@ moves_new_state_old_state @
identifier plane_atomic_func.func;
identifier plane;
symbol old_state;
symbol state;
@@
func(struct drm_plane *plane, struct drm_plane_state *old_state)
{
...
- struct drm_plane_state *state = plane->state;
+ struct drm_plane_state *new_state = plane->state;
...
}
@ depends on moves_new_state_old_state @
identifier plane_atomic_func.func;
identifier plane;
identifier old_state;
symbol state;
@@
func(struct drm_plane *plane, struct drm_plane_state *old_state)
{
<...
- state
+ new_state
...>
}
@ moves_new_state_oldstate @
identifier plane_atomic_func.func;
identifier plane;
symbol oldstate;
symbol state;
@@
func(struct drm_plane *plane, struct drm_plane_state *oldstate)
{
...
- struct drm_plane_state *state = plane->state;
+ struct drm_plane_state *newstate = plane->state;
...
}
@ depends on moves_new_state_oldstate @
identifier plane_atomic_func.func;
identifier plane;
identifier old_state;
symbol state;
@@
func(struct drm_plane *plane, struct drm_plane_state *old_state)
{
<...
- state
+ newstate
...>
}
@ moves_new_state_old_pstate @
identifier plane_atomic_func.func;
identifier plane;
symbol old_pstate;
symbol state;
@@
func(struct drm_plane *plane, struct drm_plane_state *old_pstate)
{
...
- struct drm_plane_state *state = plane->state;
+ struct drm_plane_state *new_pstate = plane->state;
...
}
@ depends on moves_new_state_old_pstate @
identifier plane_atomic_func.func;
identifier plane;
identifier old_pstate;
symbol state;
@@
func(struct drm_plane *plane, struct drm_plane_state *old_pstate)
{
<...
- state
+ new_pstate
...>
}
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://patchwork.freedesktop.org/patch/msgid/20210219120032.260676-8-maxime@cerno.tech
2021-02-19 20:00:28 +08:00
|
|
|
struct drm_framebuffer *fb = new_state->fb;
|
2018-11-06 17:40:00 +08:00
|
|
|
struct meson_drm *priv = meson_overlay->priv;
|
|
|
|
struct drm_gem_cma_object *gem;
|
|
|
|
unsigned long flags;
|
|
|
|
bool interlace_mode;
|
|
|
|
|
|
|
|
DRM_DEBUG_DRIVER("\n");
|
|
|
|
|
drm: Rename plane->state variables in atomic update and disable
Some drivers are storing the plane->state pointer in atomic_update and
atomic_disable in a variable simply called state, while the state passed
as an argument is called old_state.
In order to ease subsequent reworks and to avoid confusing or
inconsistent names, let's rename those variables to new_state.
This was done using the following coccinelle script, plus some manual
changes for mtk and tegra.
@ 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,
...,
};
)
@ moves_new_state_old_state @
identifier plane_atomic_func.func;
identifier plane;
symbol old_state;
symbol state;
@@
func(struct drm_plane *plane, struct drm_plane_state *old_state)
{
...
- struct drm_plane_state *state = plane->state;
+ struct drm_plane_state *new_state = plane->state;
...
}
@ depends on moves_new_state_old_state @
identifier plane_atomic_func.func;
identifier plane;
identifier old_state;
symbol state;
@@
func(struct drm_plane *plane, struct drm_plane_state *old_state)
{
<...
- state
+ new_state
...>
}
@ moves_new_state_oldstate @
identifier plane_atomic_func.func;
identifier plane;
symbol oldstate;
symbol state;
@@
func(struct drm_plane *plane, struct drm_plane_state *oldstate)
{
...
- struct drm_plane_state *state = plane->state;
+ struct drm_plane_state *newstate = plane->state;
...
}
@ depends on moves_new_state_oldstate @
identifier plane_atomic_func.func;
identifier plane;
identifier old_state;
symbol state;
@@
func(struct drm_plane *plane, struct drm_plane_state *old_state)
{
<...
- state
+ newstate
...>
}
@ moves_new_state_old_pstate @
identifier plane_atomic_func.func;
identifier plane;
symbol old_pstate;
symbol state;
@@
func(struct drm_plane *plane, struct drm_plane_state *old_pstate)
{
...
- struct drm_plane_state *state = plane->state;
+ struct drm_plane_state *new_pstate = plane->state;
...
}
@ depends on moves_new_state_old_pstate @
identifier plane_atomic_func.func;
identifier plane;
identifier old_pstate;
symbol state;
@@
func(struct drm_plane *plane, struct drm_plane_state *old_pstate)
{
<...
- state
+ new_pstate
...>
}
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://patchwork.freedesktop.org/patch/msgid/20210219120032.260676-8-maxime@cerno.tech
2021-02-19 20:00:28 +08:00
|
|
|
interlace_mode = new_state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE;
|
2018-11-06 17:40:00 +08:00
|
|
|
|
|
|
|
spin_lock_irqsave(&priv->drm->event_lock, flags);
|
|
|
|
|
2020-07-03 16:07:25 +08:00
|
|
|
if ((fb->modifier & DRM_FORMAT_MOD_AMLOGIC_FBC(0, 0)) ==
|
|
|
|
DRM_FORMAT_MOD_AMLOGIC_FBC(0, 0)) {
|
|
|
|
priv->viu.vd1_afbc = true;
|
|
|
|
|
|
|
|
priv->viu.vd1_afbc_mode = AFBC_MIF_URGENT(3) |
|
|
|
|
AFBC_HOLD_LINE_NUM(8) |
|
|
|
|
AFBC_BURST_LEN(2);
|
|
|
|
|
2020-07-03 16:07:26 +08:00
|
|
|
if (fb->modifier & DRM_FORMAT_MOD_AMLOGIC_FBC(0,
|
|
|
|
AMLOGIC_FBC_OPTION_MEM_SAVING))
|
|
|
|
priv->viu.vd1_afbc_mode |= AFBC_BLK_MEM_MODE;
|
|
|
|
|
2020-07-03 16:07:27 +08:00
|
|
|
if ((fb->modifier & __fourcc_mod_amlogic_layout_mask) ==
|
|
|
|
AMLOGIC_FBC_LAYOUT_SCATTER)
|
|
|
|
priv->viu.vd1_afbc_mode |= AFBC_SCATTER_MODE;
|
|
|
|
|
2020-07-03 16:07:25 +08:00
|
|
|
priv->viu.vd1_afbc_en = 0x1600 | AFBC_DEC_ENABLE;
|
|
|
|
|
|
|
|
priv->viu.vd1_afbc_conv_ctrl = AFBC_CONV_LBUF_LEN(256);
|
|
|
|
|
|
|
|
priv->viu.vd1_afbc_dec_def_color = AFBC_DEF_COLOR_Y(1023);
|
|
|
|
|
|
|
|
/* 420: horizontal / 2, vertical / 4 */
|
|
|
|
priv->viu.vd1_afbc_vd_cfmt_ctrl = AFBC_HORZ_RPT_PIXEL0 |
|
|
|
|
AFBC_HORZ_Y_C_RATIO(1) |
|
|
|
|
AFBC_HORZ_FMT_EN |
|
|
|
|
AFBC_VERT_RPT_LINE0 |
|
|
|
|
AFBC_VERT_INITIAL_PHASE(12) |
|
|
|
|
AFBC_VERT_PHASE_STEP(8) |
|
|
|
|
AFBC_VERT_FMT_EN;
|
|
|
|
|
|
|
|
switch (fb->format->format) {
|
|
|
|
/* AFBC Only formats */
|
|
|
|
case DRM_FORMAT_YUV420_10BIT:
|
|
|
|
priv->viu.vd1_afbc_mode |=
|
|
|
|
AFBC_COMPBITS_YUV(AFBC_COMPBITS_10BIT);
|
|
|
|
priv->viu.vd1_afbc_dec_def_color |=
|
|
|
|
AFBC_DEF_COLOR_U(512) |
|
|
|
|
AFBC_DEF_COLOR_V(512);
|
|
|
|
break;
|
|
|
|
case DRM_FORMAT_YUV420_8BIT:
|
|
|
|
priv->viu.vd1_afbc_dec_def_color |=
|
|
|
|
AFBC_DEF_COLOR_U(128) |
|
|
|
|
AFBC_DEF_COLOR_V(128);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
priv->viu.vd1_if0_gen_reg = 0;
|
|
|
|
priv->viu.vd1_if0_canvas0 = 0;
|
|
|
|
priv->viu.viu_vd1_fmt_ctrl = 0;
|
|
|
|
} else {
|
|
|
|
priv->viu.vd1_afbc = false;
|
|
|
|
|
|
|
|
priv->viu.vd1_if0_gen_reg = VD_URGENT_CHROMA |
|
|
|
|
VD_URGENT_LUMA |
|
|
|
|
VD_HOLD_LINES(9) |
|
|
|
|
VD_CHRO_RPT_LASTL_CTRL |
|
|
|
|
VD_ENABLE;
|
|
|
|
}
|
2018-11-06 17:40:00 +08:00
|
|
|
|
|
|
|
/* Setup scaler params */
|
|
|
|
meson_overlay_setup_scaler_params(priv, plane, interlace_mode);
|
|
|
|
|
|
|
|
priv->viu.vd1_if0_repeat_loop = 0;
|
|
|
|
priv->viu.vd1_if0_luma0_rpt_pat = interlace_mode ? 8 : 0;
|
|
|
|
priv->viu.vd1_if0_chroma0_rpt_pat = interlace_mode ? 8 : 0;
|
|
|
|
priv->viu.vd1_range_map_y = 0;
|
|
|
|
priv->viu.vd1_range_map_cb = 0;
|
|
|
|
priv->viu.vd1_range_map_cr = 0;
|
|
|
|
|
|
|
|
/* Default values for RGB888/YUV444 */
|
|
|
|
priv->viu.vd1_if0_gen_reg2 = 0;
|
|
|
|
priv->viu.viu_vd1_fmt_ctrl = 0;
|
|
|
|
|
2020-07-03 16:07:25 +08:00
|
|
|
/* None will match for AFBC Only formats */
|
2018-11-06 17:40:00 +08:00
|
|
|
switch (fb->format->format) {
|
|
|
|
/* TOFIX DRM_FORMAT_RGB888 should be supported */
|
|
|
|
case DRM_FORMAT_YUYV:
|
|
|
|
priv->viu.vd1_if0_gen_reg |= VD_BYTES_PER_PIXEL(1);
|
|
|
|
priv->viu.vd1_if0_canvas0 =
|
|
|
|
CANVAS_ADDR2(priv->canvas_id_vd1_0) |
|
|
|
|
CANVAS_ADDR1(priv->canvas_id_vd1_0) |
|
|
|
|
CANVAS_ADDR0(priv->canvas_id_vd1_0);
|
|
|
|
priv->viu.viu_vd1_fmt_ctrl = VD_HORZ_Y_C_RATIO(1) | /* /2 */
|
|
|
|
VD_HORZ_FMT_EN |
|
|
|
|
VD_VERT_RPT_LINE0 |
|
|
|
|
VD_VERT_INITIAL_PHASE(12) |
|
|
|
|
VD_VERT_PHASE_STEP(16) | /* /2 */
|
|
|
|
VD_VERT_FMT_EN;
|
|
|
|
break;
|
|
|
|
case DRM_FORMAT_NV12:
|
|
|
|
case DRM_FORMAT_NV21:
|
|
|
|
priv->viu.vd1_if0_gen_reg |= VD_SEPARATE_EN;
|
|
|
|
priv->viu.vd1_if0_canvas0 =
|
|
|
|
CANVAS_ADDR2(priv->canvas_id_vd1_1) |
|
|
|
|
CANVAS_ADDR1(priv->canvas_id_vd1_1) |
|
|
|
|
CANVAS_ADDR0(priv->canvas_id_vd1_0);
|
|
|
|
if (fb->format->format == DRM_FORMAT_NV12)
|
|
|
|
priv->viu.vd1_if0_gen_reg2 = VD_COLOR_MAP(1);
|
|
|
|
else
|
|
|
|
priv->viu.vd1_if0_gen_reg2 = VD_COLOR_MAP(2);
|
|
|
|
priv->viu.viu_vd1_fmt_ctrl = VD_HORZ_Y_C_RATIO(1) | /* /2 */
|
|
|
|
VD_HORZ_FMT_EN |
|
|
|
|
VD_VERT_RPT_LINE0 |
|
|
|
|
VD_VERT_INITIAL_PHASE(12) |
|
|
|
|
VD_VERT_PHASE_STEP(8) | /* /4 */
|
|
|
|
VD_VERT_FMT_EN;
|
|
|
|
break;
|
|
|
|
case DRM_FORMAT_YUV444:
|
|
|
|
case DRM_FORMAT_YUV422:
|
|
|
|
case DRM_FORMAT_YUV420:
|
|
|
|
case DRM_FORMAT_YUV411:
|
|
|
|
case DRM_FORMAT_YUV410:
|
|
|
|
priv->viu.vd1_if0_gen_reg |= VD_SEPARATE_EN;
|
|
|
|
priv->viu.vd1_if0_canvas0 =
|
|
|
|
CANVAS_ADDR2(priv->canvas_id_vd1_2) |
|
|
|
|
CANVAS_ADDR1(priv->canvas_id_vd1_1) |
|
|
|
|
CANVAS_ADDR0(priv->canvas_id_vd1_0);
|
|
|
|
switch (fb->format->format) {
|
|
|
|
case DRM_FORMAT_YUV422:
|
|
|
|
priv->viu.viu_vd1_fmt_ctrl =
|
|
|
|
VD_HORZ_Y_C_RATIO(1) | /* /2 */
|
|
|
|
VD_HORZ_FMT_EN |
|
|
|
|
VD_VERT_RPT_LINE0 |
|
|
|
|
VD_VERT_INITIAL_PHASE(12) |
|
|
|
|
VD_VERT_PHASE_STEP(16) | /* /2 */
|
|
|
|
VD_VERT_FMT_EN;
|
|
|
|
break;
|
|
|
|
case DRM_FORMAT_YUV420:
|
|
|
|
priv->viu.viu_vd1_fmt_ctrl =
|
|
|
|
VD_HORZ_Y_C_RATIO(1) | /* /2 */
|
|
|
|
VD_HORZ_FMT_EN |
|
|
|
|
VD_VERT_RPT_LINE0 |
|
|
|
|
VD_VERT_INITIAL_PHASE(12) |
|
|
|
|
VD_VERT_PHASE_STEP(8) | /* /4 */
|
|
|
|
VD_VERT_FMT_EN;
|
|
|
|
break;
|
|
|
|
case DRM_FORMAT_YUV411:
|
|
|
|
priv->viu.viu_vd1_fmt_ctrl =
|
|
|
|
VD_HORZ_Y_C_RATIO(2) | /* /4 */
|
|
|
|
VD_HORZ_FMT_EN |
|
|
|
|
VD_VERT_RPT_LINE0 |
|
|
|
|
VD_VERT_INITIAL_PHASE(12) |
|
|
|
|
VD_VERT_PHASE_STEP(16) | /* /2 */
|
|
|
|
VD_VERT_FMT_EN;
|
|
|
|
break;
|
|
|
|
case DRM_FORMAT_YUV410:
|
|
|
|
priv->viu.viu_vd1_fmt_ctrl =
|
|
|
|
VD_HORZ_Y_C_RATIO(2) | /* /4 */
|
|
|
|
VD_HORZ_FMT_EN |
|
|
|
|
VD_VERT_RPT_LINE0 |
|
|
|
|
VD_VERT_INITIAL_PHASE(12) |
|
|
|
|
VD_VERT_PHASE_STEP(8) | /* /4 */
|
|
|
|
VD_VERT_FMT_EN;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Update Canvas with buffer address */
|
2019-05-16 18:31:47 +08:00
|
|
|
priv->viu.vd1_planes = fb->format->num_planes;
|
2018-11-06 17:40:00 +08:00
|
|
|
|
|
|
|
switch (priv->viu.vd1_planes) {
|
|
|
|
case 3:
|
|
|
|
gem = drm_fb_cma_get_gem_obj(fb, 2);
|
|
|
|
priv->viu.vd1_addr2 = gem->paddr + fb->offsets[2];
|
|
|
|
priv->viu.vd1_stride2 = fb->pitches[2];
|
|
|
|
priv->viu.vd1_height2 =
|
2019-05-16 18:31:50 +08:00
|
|
|
drm_format_info_plane_height(fb->format,
|
|
|
|
fb->height, 2);
|
2018-11-06 17:40:00 +08:00
|
|
|
DRM_DEBUG("plane 2 addr 0x%x stride %d height %d\n",
|
|
|
|
priv->viu.vd1_addr2,
|
|
|
|
priv->viu.vd1_stride2,
|
|
|
|
priv->viu.vd1_height2);
|
2020-08-24 06:36:59 +08:00
|
|
|
fallthrough;
|
2018-11-06 17:40:00 +08:00
|
|
|
case 2:
|
|
|
|
gem = drm_fb_cma_get_gem_obj(fb, 1);
|
|
|
|
priv->viu.vd1_addr1 = gem->paddr + fb->offsets[1];
|
|
|
|
priv->viu.vd1_stride1 = fb->pitches[1];
|
|
|
|
priv->viu.vd1_height1 =
|
2019-05-16 18:31:50 +08:00
|
|
|
drm_format_info_plane_height(fb->format,
|
|
|
|
fb->height, 1);
|
2018-11-06 17:40:00 +08:00
|
|
|
DRM_DEBUG("plane 1 addr 0x%x stride %d height %d\n",
|
|
|
|
priv->viu.vd1_addr1,
|
|
|
|
priv->viu.vd1_stride1,
|
|
|
|
priv->viu.vd1_height1);
|
2020-08-24 06:36:59 +08:00
|
|
|
fallthrough;
|
2018-11-06 17:40:00 +08:00
|
|
|
case 1:
|
|
|
|
gem = drm_fb_cma_get_gem_obj(fb, 0);
|
|
|
|
priv->viu.vd1_addr0 = gem->paddr + fb->offsets[0];
|
|
|
|
priv->viu.vd1_stride0 = fb->pitches[0];
|
|
|
|
priv->viu.vd1_height0 =
|
2019-05-16 18:31:50 +08:00
|
|
|
drm_format_info_plane_height(fb->format,
|
2020-07-03 16:07:25 +08:00
|
|
|
fb->height, 0);
|
2018-11-06 17:40:00 +08:00
|
|
|
DRM_DEBUG("plane 0 addr 0x%x stride %d height %d\n",
|
|
|
|
priv->viu.vd1_addr0,
|
|
|
|
priv->viu.vd1_stride0,
|
|
|
|
priv->viu.vd1_height0);
|
|
|
|
}
|
|
|
|
|
2020-07-03 16:07:25 +08:00
|
|
|
if (priv->viu.vd1_afbc) {
|
2020-07-03 16:07:27 +08:00
|
|
|
if (priv->viu.vd1_afbc_mode & AFBC_SCATTER_MODE) {
|
|
|
|
/*
|
|
|
|
* In Scatter mode, the header contains the physical
|
|
|
|
* body content layout, thus the body content
|
|
|
|
* size isn't needed.
|
|
|
|
*/
|
|
|
|
priv->viu.vd1_afbc_head_addr = priv->viu.vd1_addr0 >> 4;
|
|
|
|
priv->viu.vd1_afbc_body_addr = 0;
|
|
|
|
} else {
|
|
|
|
/* Default mode is 4k per superblock */
|
|
|
|
unsigned long block_size = 4096;
|
|
|
|
unsigned long body_size;
|
|
|
|
|
|
|
|
/* 8bit mem saving mode is 3072bytes per superblock */
|
|
|
|
if (priv->viu.vd1_afbc_mode & AFBC_BLK_MEM_MODE)
|
|
|
|
block_size = 3072;
|
|
|
|
|
|
|
|
body_size = (ALIGN(priv->viu.vd1_stride0, 64) / 64) *
|
|
|
|
(ALIGN(priv->viu.vd1_height0, 32) / 32) *
|
|
|
|
block_size;
|
|
|
|
|
|
|
|
priv->viu.vd1_afbc_body_addr = priv->viu.vd1_addr0 >> 4;
|
|
|
|
/* Header is after body content */
|
|
|
|
priv->viu.vd1_afbc_head_addr = (priv->viu.vd1_addr0 +
|
|
|
|
body_size) >> 4;
|
|
|
|
}
|
2020-07-03 16:07:25 +08:00
|
|
|
}
|
|
|
|
|
2018-11-06 17:40:00 +08:00
|
|
|
priv->viu.vd1_enabled = true;
|
|
|
|
|
|
|
|
spin_unlock_irqrestore(&priv->drm->event_lock, flags);
|
|
|
|
|
|
|
|
DRM_DEBUG_DRIVER("\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void meson_overlay_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 20:00:29 +08:00
|
|
|
struct drm_atomic_state *state)
|
2018-11-06 17:40:00 +08:00
|
|
|
{
|
|
|
|
struct meson_overlay *meson_overlay = to_meson_overlay(plane);
|
|
|
|
struct meson_drm *priv = meson_overlay->priv;
|
|
|
|
|
|
|
|
DRM_DEBUG_DRIVER("\n");
|
|
|
|
|
|
|
|
priv->viu.vd1_enabled = false;
|
|
|
|
|
|
|
|
/* Disable VD1 */
|
2019-08-22 22:43:41 +08:00
|
|
|
if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
|
2019-03-25 22:18:19 +08:00
|
|
|
writel_relaxed(0, priv->io_base + _REG(VD1_BLEND_SRC_CTRL));
|
|
|
|
writel_relaxed(0, priv->io_base + _REG(VD2_BLEND_SRC_CTRL));
|
|
|
|
writel_relaxed(0, priv->io_base + _REG(VD1_IF0_GEN_REG + 0x17b0));
|
|
|
|
writel_relaxed(0, priv->io_base + _REG(VD2_IF0_GEN_REG + 0x17b0));
|
|
|
|
} else
|
|
|
|
writel_bits_relaxed(VPP_VD1_POSTBLEND | VPP_VD1_PREBLEND, 0,
|
|
|
|
priv->io_base + _REG(VPP_MISC));
|
2018-11-06 17:40:00 +08:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct drm_plane_helper_funcs meson_overlay_helper_funcs = {
|
|
|
|
.atomic_check = meson_overlay_atomic_check,
|
|
|
|
.atomic_disable = meson_overlay_atomic_disable,
|
|
|
|
.atomic_update = meson_overlay_atomic_update,
|
2021-02-22 22:17:56 +08:00
|
|
|
.prepare_fb = drm_gem_plane_helper_prepare_fb,
|
2018-11-06 17:40:00 +08:00
|
|
|
};
|
|
|
|
|
2020-07-03 16:07:25 +08:00
|
|
|
static bool meson_overlay_format_mod_supported(struct drm_plane *plane,
|
|
|
|
u32 format, u64 modifier)
|
|
|
|
{
|
|
|
|
if (modifier == DRM_FORMAT_MOD_LINEAR &&
|
|
|
|
format != DRM_FORMAT_YUV420_8BIT &&
|
|
|
|
format != DRM_FORMAT_YUV420_10BIT)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if ((modifier & DRM_FORMAT_MOD_AMLOGIC_FBC(0, 0)) ==
|
|
|
|
DRM_FORMAT_MOD_AMLOGIC_FBC(0, 0)) {
|
|
|
|
unsigned int layout = modifier &
|
|
|
|
DRM_FORMAT_MOD_AMLOGIC_FBC(
|
|
|
|
__fourcc_mod_amlogic_layout_mask, 0);
|
2020-07-03 16:07:26 +08:00
|
|
|
unsigned int options =
|
|
|
|
(modifier >> __fourcc_mod_amlogic_options_shift) &
|
|
|
|
__fourcc_mod_amlogic_options_mask;
|
2020-07-03 16:07:25 +08:00
|
|
|
|
|
|
|
if (format != DRM_FORMAT_YUV420_8BIT &&
|
|
|
|
format != DRM_FORMAT_YUV420_10BIT) {
|
|
|
|
DRM_DEBUG_KMS("%llx invalid format 0x%08x\n",
|
|
|
|
modifier, format);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-07-03 16:07:27 +08:00
|
|
|
if (layout != AMLOGIC_FBC_LAYOUT_BASIC &&
|
|
|
|
layout != AMLOGIC_FBC_LAYOUT_SCATTER) {
|
2020-07-03 16:07:25 +08:00
|
|
|
DRM_DEBUG_KMS("%llx invalid layout %x\n",
|
|
|
|
modifier, layout);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-07-03 16:07:26 +08:00
|
|
|
if (options &&
|
|
|
|
options != AMLOGIC_FBC_OPTION_MEM_SAVING) {
|
|
|
|
DRM_DEBUG_KMS("%llx invalid layout %x\n",
|
|
|
|
modifier, layout);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-07-03 16:07:25 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
DRM_DEBUG_KMS("invalid modifier %llx for format 0x%08x\n",
|
|
|
|
modifier, format);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-11-06 17:40:00 +08:00
|
|
|
static const struct drm_plane_funcs meson_overlay_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,
|
2020-07-03 16:07:25 +08:00
|
|
|
.format_mod_supported = meson_overlay_format_mod_supported,
|
2018-11-06 17:40:00 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static const uint32_t supported_drm_formats[] = {
|
|
|
|
DRM_FORMAT_YUYV,
|
|
|
|
DRM_FORMAT_NV12,
|
|
|
|
DRM_FORMAT_NV21,
|
|
|
|
DRM_FORMAT_YUV444,
|
|
|
|
DRM_FORMAT_YUV422,
|
|
|
|
DRM_FORMAT_YUV420,
|
|
|
|
DRM_FORMAT_YUV411,
|
|
|
|
DRM_FORMAT_YUV410,
|
2020-07-03 16:07:25 +08:00
|
|
|
DRM_FORMAT_YUV420_8BIT, /* Amlogic FBC Only */
|
|
|
|
DRM_FORMAT_YUV420_10BIT, /* Amlogic FBC Only */
|
|
|
|
};
|
|
|
|
|
|
|
|
static const uint64_t format_modifiers[] = {
|
2020-07-03 16:07:27 +08:00
|
|
|
DRM_FORMAT_MOD_AMLOGIC_FBC(AMLOGIC_FBC_LAYOUT_SCATTER,
|
|
|
|
AMLOGIC_FBC_OPTION_MEM_SAVING),
|
2020-07-03 16:07:26 +08:00
|
|
|
DRM_FORMAT_MOD_AMLOGIC_FBC(AMLOGIC_FBC_LAYOUT_BASIC,
|
|
|
|
AMLOGIC_FBC_OPTION_MEM_SAVING),
|
2020-07-03 16:07:27 +08:00
|
|
|
DRM_FORMAT_MOD_AMLOGIC_FBC(AMLOGIC_FBC_LAYOUT_SCATTER, 0),
|
2020-07-03 16:07:25 +08:00
|
|
|
DRM_FORMAT_MOD_AMLOGIC_FBC(AMLOGIC_FBC_LAYOUT_BASIC, 0),
|
|
|
|
DRM_FORMAT_MOD_LINEAR,
|
|
|
|
DRM_FORMAT_MOD_INVALID,
|
2018-11-06 17:40:00 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
int meson_overlay_create(struct meson_drm *priv)
|
|
|
|
{
|
|
|
|
struct meson_overlay *meson_overlay;
|
|
|
|
struct drm_plane *plane;
|
|
|
|
|
|
|
|
DRM_DEBUG_DRIVER("\n");
|
|
|
|
|
|
|
|
meson_overlay = devm_kzalloc(priv->drm->dev, sizeof(*meson_overlay),
|
|
|
|
GFP_KERNEL);
|
|
|
|
if (!meson_overlay)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
meson_overlay->priv = priv;
|
|
|
|
plane = &meson_overlay->base;
|
|
|
|
|
|
|
|
drm_universal_plane_init(priv->drm, plane, 0xFF,
|
|
|
|
&meson_overlay_funcs,
|
|
|
|
supported_drm_formats,
|
|
|
|
ARRAY_SIZE(supported_drm_formats),
|
2020-07-03 16:07:25 +08:00
|
|
|
format_modifiers,
|
2018-11-06 17:40:00 +08:00
|
|
|
DRM_PLANE_TYPE_OVERLAY, "meson_overlay_plane");
|
|
|
|
|
|
|
|
drm_plane_helper_add(plane, &meson_overlay_helper_funcs);
|
|
|
|
|
2019-04-29 15:52:47 +08:00
|
|
|
/* For now, VD Overlay plane is always on the back */
|
|
|
|
drm_plane_create_zpos_immutable_property(plane, 0);
|
|
|
|
|
2018-11-06 17:40:00 +08:00
|
|
|
priv->overlay_plane = plane;
|
|
|
|
|
|
|
|
DRM_DEBUG_DRIVER("\n");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|