From: Hsiao Chien Sung <[email protected]>
This series adds support for running IGT (Intel GPU Tool) tests with
MediaTek display driver. The following changes will be applied:
1. Add a new API for creating GCE thread loop to retrieve CRCs
from the hardware component
2. Support hardware CRC calculation in both VDOSYS0 and VDOSYS1
3. Support alpha blending in both VDOSYS0 and VDOSYS1
Changes in v9:
- Separate the patch into smaller ones
Changes in v8:
- Start/Stop CRC CMDQ thread on when needed
- Squash and rearrange the commits
- Add more information to the commit message and comments
Changes in v7:
- Separate the patch into smaller ones
Changes in v6:
- Use drm_vblank_work to deffer the CRC work into bottom halves
- Separate the patches for "Premultiplied" and "None" alpha blending
Changes in v5:
- Add more descriptions to the codes
- Add DRM mode configs to the driver data
- Squash and rearrange the commits
Changes in v4:
- Separate the patch into smaller ones
- Change the title of some patches
- Revert the changes that are not related to the series
Changes in v3:
- Modify the dt-binding document of Mediatek OVL
- Set DRM mode configs accroding to the hardware capabilities
- Replace cmdq_pkt_jump_absolute() with cmdq_pkt_jump()
Changes in v2:
- Simplify CMDQ by adding commands that are currently used only
- Integrate CRC related codes into new APIs for Mixer and OVL to reuse
- Add CPU version CRC retrieval when CMDQ is disabled
Hsiao Chien Sung (21):
soc: mediatek: Disable 9-bit alpha in ETHDR
drm/mediatek: Add OVL compatible name for MT8195
drm/mediatek: Add missing plane settings when async update
drm/mediatek: Add DRM_MODE_ROTATE_0 to rotation property
drm/mediatek: Set DRM mode configs accordingly
drm/mediatek: Turn off the layers with zero width or height
drm/mediatek: Support more 10bit formats in OVL
drm/mediatek: Support RGBA8888 and RGBX8888 in OVL on MT8195
drm/mediatek: Fix XRGB setting error in OVL
drm/mediatek: Fix XRGB setting error in Mixer
drm/mediatek: Add new color format MACROs in OVL
drm/mediatek: Support DRM plane alpha in OVL
drm/mediatek: Support DRM plane alpha in Mixer
drm/mediatek: Support "None" blending in OVL
drm/mediatek: Support "None" blending in Mixer
drm/mediatek: Support "Pre-multiplied" blending in OVL
drm/mediatek: Support "Pre-multiplied" blending in Mixer
drm/mediatek: Support alpha blending in display driver
drm/mediatek: Support CRC in display driver
drm/mediatek: Support CRC in OVL
drm/mediatek: Support CRC in OVL adaptor
drivers/gpu/drm/mediatek/mtk_crtc.c | 279 +++++++++++++++
drivers/gpu/drm/mediatek/mtk_crtc.h | 38 ++
drivers/gpu/drm/mediatek/mtk_ddp_comp.c | 10 +
drivers/gpu/drm/mediatek/mtk_ddp_comp.h | 11 +-
drivers/gpu/drm/mediatek/mtk_disp_drv.h | 10 +
drivers/gpu/drm/mediatek/mtk_disp_ovl.c | 330 +++++++++++++++---
.../gpu/drm/mediatek/mtk_disp_ovl_adaptor.c | 37 +-
drivers/gpu/drm/mediatek/mtk_drm_drv.c | 24 ++
drivers/gpu/drm/mediatek/mtk_drm_drv.h | 4 +
drivers/gpu/drm/mediatek/mtk_ethdr.c | 110 +++++-
drivers/gpu/drm/mediatek/mtk_ethdr.h | 7 +
drivers/gpu/drm/mediatek/mtk_plane.c | 15 +-
drivers/soc/mediatek/mtk-mmsys.c | 1 +
13 files changed, 826 insertions(+), 50 deletions(-)
--
2.18.0
From: Hsiao Chien Sung <[email protected]>
Support RGBA8888 and RGBX8888 formats in OVL on MT8195.
Reviewed-by: CK Hu <[email protected]>
Reviewed-by: AngeloGioacchino Del Regno <[email protected]>
Signed-off-by: Hsiao Chien Sung <[email protected]>
---
drivers/gpu/drm/mediatek/mtk_disp_ovl.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
index 878bfb966ed7..946b87ec48ca 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
@@ -114,6 +114,8 @@ static const u32 mt8195_formats[] = {
DRM_FORMAT_XBGR8888,
DRM_FORMAT_XBGR2101010,
DRM_FORMAT_ABGR2101010,
+ DRM_FORMAT_RGBX8888,
+ DRM_FORMAT_RGBA8888,
DRM_FORMAT_RGBX1010102,
DRM_FORMAT_RGBA1010102,
DRM_FORMAT_RGB888,
--
2.18.0
From: Hsiao Chien Sung <[email protected]>
Set the plane alpha according to DRM plane property.
Signed-off-by: Hsiao Chien Sung <[email protected]>
---
drivers/gpu/drm/mediatek/mtk_ethdr.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_ethdr.c b/drivers/gpu/drm/mediatek/mtk_ethdr.c
index 902dec03a7dd..7eaafd44f320 100644
--- a/drivers/gpu/drm/mediatek/mtk_ethdr.c
+++ b/drivers/gpu/drm/mediatek/mtk_ethdr.c
@@ -170,8 +170,10 @@ void mtk_ethdr_layer_config(struct device *dev, unsigned int idx,
return;
}
- if (state->base.fb && state->base.fb->format->has_alpha)
- alpha_con = MIXER_ALPHA_AEN | MIXER_ALPHA;
+ if (state->base.fb) {
+ alpha_con |= MIXER_ALPHA_AEN;
+ alpha_con |= state->base.alpha & MIXER_ALPHA;
+ }
if (state->base.fb && !state->base.fb->format->has_alpha) {
/*
--
2.18.0
From: Hsiao Chien Sung <[email protected]>
Support "None" alpha blending mode on MediaTek's chips.
Signed-off-by: Hsiao Chien Sung <[email protected]>
---
drivers/gpu/drm/mediatek/mtk_disp_ovl.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
index 2316d4a6dca7..6567806cf4e2 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
@@ -431,6 +431,7 @@ void mtk_ovl_layer_config(struct device *dev, unsigned int idx,
unsigned int fmt = pending->format;
unsigned int offset = (pending->y << 16) | pending->x;
unsigned int src_size = (pending->height << 16) | pending->width;
+ unsigned int blend_mode = state->base.pixel_blend_mode;
unsigned int ignore_pixel_alpha = 0;
unsigned int con;
bool is_afbc = pending->modifier != DRM_FORMAT_MOD_LINEAR;
@@ -460,7 +461,8 @@ void mtk_ovl_layer_config(struct device *dev, unsigned int idx,
* For RGB888 related formats, whether CONST_BLD is enabled or not won't
* affect the result. Therefore we use !has_alpha as the condition.
*/
- if (state->base.fb && !state->base.fb->format->has_alpha)
+ if ((state->base.fb && !state->base.fb->format->has_alpha) ||
+ blend_mode == DRM_MODE_BLEND_PIXEL_NONE)
ignore_pixel_alpha = OVL_CONST_BLEND;
if (pending->rotation & DRM_MODE_REFLECT_Y) {
--
2.18.0
From: Hsiao Chien Sung <[email protected]>
Support more 10bit formats in OVL.
Reviewed-by: CK Hu <[email protected]>
Reviewed-by: AngeloGioacchino Del Regno <[email protected]>
Signed-off-by: Hsiao Chien Sung <[email protected]>
---
drivers/gpu/drm/mediatek/mtk_disp_ovl.c | 32 ++++++++++++++++++++++---
1 file changed, 29 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
index 20faac97f910..878bfb966ed7 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
@@ -71,6 +71,22 @@
#define OVL_CON_VIRT_FLIP BIT(9)
#define OVL_CON_HORZ_FLIP BIT(10)
+static inline bool is_10bit_rgb(u32 fmt)
+{
+ switch (fmt) {
+ case DRM_FORMAT_XRGB2101010:
+ case DRM_FORMAT_ARGB2101010:
+ case DRM_FORMAT_RGBX1010102:
+ case DRM_FORMAT_RGBA1010102:
+ case DRM_FORMAT_XBGR2101010:
+ case DRM_FORMAT_ABGR2101010:
+ case DRM_FORMAT_BGRX1010102:
+ case DRM_FORMAT_BGRA1010102:
+ return true;
+ }
+ return false;
+}
+
static const u32 mt8173_formats[] = {
DRM_FORMAT_XRGB8888,
DRM_FORMAT_ARGB8888,
@@ -88,12 +104,18 @@ static const u32 mt8173_formats[] = {
static const u32 mt8195_formats[] = {
DRM_FORMAT_XRGB8888,
DRM_FORMAT_ARGB8888,
+ DRM_FORMAT_XRGB2101010,
DRM_FORMAT_ARGB2101010,
DRM_FORMAT_BGRX8888,
DRM_FORMAT_BGRA8888,
+ DRM_FORMAT_BGRX1010102,
DRM_FORMAT_BGRA1010102,
DRM_FORMAT_ABGR8888,
DRM_FORMAT_XBGR8888,
+ DRM_FORMAT_XBGR2101010,
+ DRM_FORMAT_ABGR2101010,
+ DRM_FORMAT_RGBX1010102,
+ DRM_FORMAT_RGBA1010102,
DRM_FORMAT_RGB888,
DRM_FORMAT_BGR888,
DRM_FORMAT_RGB565,
@@ -253,9 +275,7 @@ static void mtk_ovl_set_bit_depth(struct device *dev, int idx, u32 format,
reg = readl(ovl->regs + DISP_REG_OVL_CLRFMT_EXT);
reg &= ~OVL_CON_CLRFMT_BIT_DEPTH_MASK(idx);
- if (format == DRM_FORMAT_RGBA1010102 ||
- format == DRM_FORMAT_BGRA1010102 ||
- format == DRM_FORMAT_ARGB2101010)
+ if (is_10bit_rgb(format))
bit_depth = OVL_CON_CLRFMT_10_BIT;
reg |= OVL_CON_CLRFMT_BIT_DEPTH(bit_depth, idx);
@@ -368,17 +388,23 @@ static unsigned int ovl_fmt_convert(struct mtk_disp_ovl *ovl, unsigned int fmt)
return OVL_CON_CLRFMT_RGB888(ovl) | OVL_CON_BYTE_SWAP;
case DRM_FORMAT_RGBX8888:
case DRM_FORMAT_RGBA8888:
+ case DRM_FORMAT_RGBX1010102:
+ case DRM_FORMAT_RGBA1010102:
return OVL_CON_CLRFMT_ARGB8888;
case DRM_FORMAT_BGRX8888:
case DRM_FORMAT_BGRA8888:
+ case DRM_FORMAT_BGRX1010102:
case DRM_FORMAT_BGRA1010102:
return OVL_CON_CLRFMT_ARGB8888 | OVL_CON_BYTE_SWAP;
case DRM_FORMAT_XRGB8888:
case DRM_FORMAT_ARGB8888:
+ case DRM_FORMAT_XRGB2101010:
case DRM_FORMAT_ARGB2101010:
return OVL_CON_CLRFMT_RGBA8888;
case DRM_FORMAT_XBGR8888:
case DRM_FORMAT_ABGR8888:
+ case DRM_FORMAT_XBGR2101010:
+ case DRM_FORMAT_ABGR2101010:
return OVL_CON_CLRFMT_RGBA8888 | OVL_CON_BYTE_SWAP;
case DRM_FORMAT_UYVY:
return OVL_CON_CLRFMT_UYVY | OVL_CON_MTX_YUV_TO_RGB;
--
2.18.0
From: Hsiao Chien Sung <[email protected]>
We choose OVL as the CRC generator from other hardware
components that are also capable of calculating CRCs,
since its frame done event triggers vblanks, it can be
used as a signal to know when is safe to retrieve CRC of
the frame.
Please note that position of the hardware component
that is chosen as CRC generator in the display path is
significant. For example, while OVL is the first module
in VDOSYS0, its CRC won't be affected by the modules
after it, which means effects applied by PQ, Gamma,
Dither or any other components after OVL won't be
calculated in CRC generation.
Signed-off-by: Hsiao Chien Sung <[email protected]>
---
drivers/gpu/drm/mediatek/mtk_ddp_comp.c | 5 +
drivers/gpu/drm/mediatek/mtk_disp_drv.h | 5 +
drivers/gpu/drm/mediatek/mtk_disp_ovl.c | 209 ++++++++++++++++++++++--
3 files changed, 209 insertions(+), 10 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
index dc2b36a8bdd6..c583869b110a 100644
--- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
@@ -365,6 +365,11 @@ static const struct mtk_ddp_comp_funcs ddp_ovl = {
.clk_enable = mtk_ovl_clk_enable,
.clk_disable = mtk_ovl_clk_disable,
.config = mtk_ovl_config,
+ .crc_cnt = mtk_ovl_crc_cnt,
+ .crc_entry = mtk_ovl_crc_entry,
+ .crc_read = mtk_ovl_crc_read,
+ .crc_start = mtk_ovl_crc_start,
+ .crc_stop = mtk_ovl_crc_stop,
.start = mtk_ovl_start,
.stop = mtk_ovl_stop,
.register_vblank_cb = mtk_ovl_register_vblank_cb,
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_drv.h b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
index 082ac18fe04a..a03d7a10847a 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
@@ -105,6 +105,11 @@ void mtk_ovl_enable_vblank(struct device *dev);
void mtk_ovl_disable_vblank(struct device *dev);
const u32 *mtk_ovl_get_formats(struct device *dev);
size_t mtk_ovl_get_num_formats(struct device *dev);
+size_t mtk_ovl_crc_cnt(struct device *dev);
+u32 *mtk_ovl_crc_entry(struct device *dev);
+void mtk_ovl_crc_read(struct device *dev);
+void mtk_ovl_crc_start(struct device *dev);
+void mtk_ovl_crc_stop(struct device *dev);
void mtk_ovl_adaptor_add_comp(struct device *dev, struct mtk_mutex *mutex);
void mtk_ovl_adaptor_remove_comp(struct device *dev, struct mtk_mutex *mutex);
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
index 47d0b039a616..f43b31eec8ad 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
@@ -24,12 +24,20 @@
#define OVL_FME_CPL_INT BIT(1)
#define DISP_REG_OVL_INTSTA 0x0008
#define DISP_REG_OVL_EN 0x000c
+#define OVL_EN BIT(0)
+#define OVL_OP_8BIT_MODE BIT(4)
+#define OVL_HG_FOVL_CK_ON BIT(8)
+#define OVL_HF_FOVL_CK_ON BIT(10)
+#define DISP_REG_OVL_TRIG 0x0010
+#define OVL_CRC_EN BIT(8)
+#define OVL_CRC_CLR BIT(9)
#define DISP_REG_OVL_RST 0x0014
#define DISP_REG_OVL_ROI_SIZE 0x0020
#define DISP_REG_OVL_DATAPATH_CON 0x0024
#define OVL_LAYER_SMI_ID_EN BIT(0)
#define OVL_BGCLR_SEL_IN BIT(2)
#define OVL_LAYER_AFBC_EN(n) BIT(4+n)
+#define OVL_OUTPUT_CLAMP BIT(26)
#define DISP_REG_OVL_ROI_BGCLR 0x0028
#define DISP_REG_OVL_SRC_CON 0x002c
#define DISP_REG_OVL_CON(n) (0x0030 + 0x20 * (n))
@@ -42,7 +50,26 @@
#define DISP_REG_OVL_RDMA_CTRL(n) (0x00c0 + 0x20 * (n))
#define DISP_REG_OVL_RDMA_GMC(n) (0x00c8 + 0x20 * (n))
#define DISP_REG_OVL_ADDR_MT2701 0x0040
+#define DISP_REG_OVL_CRC 0x0270
+#define OVL_CRC_OUT_MASK GENMASK(30, 0)
#define DISP_REG_OVL_CLRFMT_EXT 0x02D0
+#define DISP_REG_OVL_CLRFMT_EXT1 0x02D8
+#define OVL_CLRFMT_EXT1_CSC_EN(n) (1 << (((n) * 4) + 1))
+#define DISP_REG_OVL_Y2R_PARA_R0(n) (0x0134 + 0x28 * (n))
+#define OVL_Y2R_PARA_C_CF_RMY (GENMASK(14, 0))
+#define DISP_REG_OVL_Y2R_PARA_G0(n) (0x013c + 0x28 * (n))
+#define OVL_Y2R_PARA_C_CF_GMU (GENMASK(30, 16))
+#define DISP_REG_OVL_Y2R_PARA_B1(n) (0x0148 + 0x28 * (n))
+#define OVL_Y2R_PARA_C_CF_BMV (GENMASK(14, 0))
+#define DISP_REG_OVL_Y2R_PARA_YUV_A_0(n) (0x014c + 0x28 * (n))
+#define OVL_Y2R_PARA_C_CF_YA (GENMASK(10, 0))
+#define OVL_Y2R_PARA_C_CF_UA (GENMASK(26, 16))
+#define DISP_REG_OVL_Y2R_PARA_YUV_A_1(n) (0x0150 + 0x28 * (n))
+#define OVL_Y2R_PARA_C_CF_VA (GENMASK(10, 0))
+#define DISP_REG_OVL_Y2R_PRE_ADD2(n) (0x0154 + 0x28 * (n))
+#define DISP_REG_OVL_R2R_R0(n) (0x0500 + 0x40 * (n))
+#define DISP_REG_OVL_R2R_G1(n) (0x0510 + 0x40 * (n))
+#define DISP_REG_OVL_R2R_B2(n) (0x0520 + 0x40 * (n))
#define DISP_REG_OVL_ADDR_MT8173 0x0f40
#define DISP_REG_OVL_ADDR(ovl, n) ((ovl)->data->addr + 0x20 * (n))
#define DISP_REG_OVL_HDR_ADDR(ovl, n) ((ovl)->data->addr + 0x20 * (n) + 0x04)
@@ -58,6 +85,8 @@
/* OVL_CON_RGB_SWAP works only if OVL_CON_CLRFMT_MAN is enabled */
#define OVL_CON_RGB_SWAP BIT(25)
+#define OVL_CON_MTX_AUTO_DIS BIT(26)
+#define OVL_CON_MTX_EN BIT(27)
#define OVL_CON_CLRFMT_RGB (1 << 12)
#define OVL_CON_CLRFMT_ARGB8888 (2 << 12)
#define OVL_CON_CLRFMT_RGBA8888 (3 << 12)
@@ -70,6 +99,7 @@
#define OVL_CON_CLRFMT_PABGR8888 (OVL_CON_CLRFMT_PARGB8888 | OVL_CON_RGB_SWAP)
#define OVL_CON_CLRFMT_PBGRA8888 (OVL_CON_CLRFMT_PARGB8888 | OVL_CON_BYTE_SWAP)
#define OVL_CON_CLRFMT_PRGBA8888 (OVL_CON_CLRFMT_PABGR8888 | OVL_CON_BYTE_SWAP)
+#define OVL_CON_MTX_PROGRAMMABLE (8 << 16)
#define OVL_CON_CLRFMT_RGB565(ovl) ((ovl)->data->fmt_rgb565_is_0 ? \
0 : OVL_CON_CLRFMT_RGB)
#define OVL_CON_CLRFMT_RGB888(ovl) ((ovl)->data->fmt_rgb565_is_0 ? \
@@ -139,6 +169,10 @@ static const u32 mt8195_formats[] = {
DRM_FORMAT_YUYV,
};
+static const u32 mt8195_ovl_crc_ofs[] = {
+ DISP_REG_OVL_CRC,
+};
+
struct mtk_disp_ovl_data {
unsigned int addr;
unsigned int gmc_bits;
@@ -149,12 +183,15 @@ struct mtk_disp_ovl_data {
const u32 *formats;
size_t num_formats;
bool supports_clrfmt_ext;
+ const u32 *crc_ofs;
+ size_t crc_cnt;
};
/*
* struct mtk_disp_ovl - DISP_OVL driver structure
* @crtc: associated crtc to report vblank events to
* @data: platform data
+ * @crc: crc related information
*/
struct mtk_disp_ovl {
struct drm_crtc *crtc;
@@ -164,8 +201,49 @@ struct mtk_disp_ovl {
const struct mtk_disp_ovl_data *data;
void (*vblank_cb)(void *data);
void *vblank_cb_data;
+ resource_size_t regs_pa;
+ struct mtk_crtc_crc crc;
};
+size_t mtk_ovl_crc_cnt(struct device *dev)
+{
+ struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
+
+ return ovl->crc.cnt;
+}
+
+u32 *mtk_ovl_crc_entry(struct device *dev)
+{
+ struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
+
+ return ovl->crc.va;
+}
+
+void mtk_ovl_crc_read(struct device *dev)
+{
+ struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
+
+ mtk_crtc_read_crc(&ovl->crc, ovl->regs);
+}
+
+void mtk_ovl_crc_start(struct device *dev)
+{
+ struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
+
+#if IS_REACHABLE(CONFIG_MTK_CMDQ)
+ mtk_crtc_start_crc_cmdq(&ovl->crc);
+#endif
+}
+
+void mtk_ovl_crc_stop(struct device *dev)
+{
+ struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
+
+#if IS_REACHABLE(CONFIG_MTK_CMDQ)
+ mtk_crtc_stop_crc_cmdq(&ovl->crc);
+#endif
+}
+
static irqreturn_t mtk_disp_ovl_irq_handler(int irq, void *dev_id)
{
struct mtk_disp_ovl *priv = dev_id;
@@ -245,15 +323,27 @@ void mtk_ovl_clk_disable(struct device *dev)
void mtk_ovl_start(struct device *dev)
{
struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
+ unsigned int reg = readl(ovl->regs + DISP_REG_OVL_DATAPATH_CON);
- if (ovl->data->smi_id_en) {
- unsigned int reg;
+ if (ovl->data->smi_id_en)
+ reg |= OVL_LAYER_SMI_ID_EN;
- reg = readl(ovl->regs + DISP_REG_OVL_DATAPATH_CON);
- reg = reg | OVL_LAYER_SMI_ID_EN;
- writel_relaxed(reg, ovl->regs + DISP_REG_OVL_DATAPATH_CON);
+ /*
+ * When doing Y2R conversion, it's common to get an output
+ * that is larger than 10 bits (negative numbers).
+ * Enable this bit to clamp the output to 10 bits per channel
+ * (should always be enabled)
+ */
+ reg |= OVL_OUTPUT_CLAMP;
+ writel_relaxed(reg, ovl->regs + DISP_REG_OVL_DATAPATH_CON);
+
+ reg = OVL_EN;
+ if (ovl->data->crc_cnt) {
+ /* enable crc and its related clocks */
+ writel_relaxed(OVL_CRC_EN, ovl->regs + DISP_REG_OVL_TRIG);
+ reg |= OVL_OP_8BIT_MODE | OVL_HG_FOVL_CK_ON | OVL_HF_FOVL_CK_ON;
}
- writel_relaxed(0x1, ovl->regs + DISP_REG_OVL_EN);
+ writel_relaxed(reg, ovl->regs + DISP_REG_OVL_EN);
}
void mtk_ovl_stop(struct device *dev)
@@ -491,6 +581,83 @@ void mtk_ovl_layer_config(struct device *dev, unsigned int idx,
blend_mode == DRM_MODE_BLEND_PIXEL_NONE)
ignore_pixel_alpha = OVL_CONST_BLEND;
+ /*
+ * OVL only supports 8 bits data in CRC calculation, transform 10-bit
+ * RGB to 8-bit RGB by leveraging the ability of the Y2R (YUV-to-RGB)
+ * hardware to multiply coefficients, although there is nothing to do
+ * with the YUV format.
+ */
+ if (ovl->data->supports_clrfmt_ext) {
+ u32 y2r_coef = 0, y2r_offset = 0, r2r_coef = 0, csc_en = 0;
+
+ if (is_10bit_rgb(fmt)) {
+ con |= OVL_CON_MTX_AUTO_DIS | OVL_CON_MTX_EN | OVL_CON_MTX_PROGRAMMABLE;
+
+ /*
+ * Y2R coefficient setting
+ * bit 13 is 2^1, bit 12 is 2^0, bit 11 is 2^-1,
+ * bit 10 is 2^-2 = 0.25
+ */
+ y2r_coef = BIT(10);
+
+ /* -1 in 10bit */
+ y2r_offset = GENMASK(10, 0) - 1;
+
+ /*
+ * R2R coefficient setting
+ * bit 19 is 2^1, bit 18 is 2^0, bit 17 is 2^-1,
+ * bit 20 is 2^2 = 4
+ */
+ r2r_coef = BIT(20);
+
+ /* CSC_EN is for R2R */
+ csc_en = OVL_CLRFMT_EXT1_CSC_EN(idx);
+
+ /*
+ * 1. YUV input data - 1 and shift right for 2 bits to remove it
+ * [R'] [0.25 0 0] [Y in - 1]
+ * [G'] = [ 0 0.25 0] * [U in - 1]
+ * [B'] [ 0 0 0.25] [V in - 1]
+ *
+ * 2. shift left for 2 bit letting the last 2 bits become 0
+ * [R out] [ 4 0 0] [R']
+ * [G out] = [ 0 4 0] * [G']
+ * [B out] [ 0 0 4] [B']
+ */
+ }
+
+ mtk_ddp_write_mask(cmdq_pkt, y2r_coef,
+ &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_Y2R_PARA_R0(idx),
+ OVL_Y2R_PARA_C_CF_RMY);
+ mtk_ddp_write_mask(cmdq_pkt, (y2r_coef << 16),
+ &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_Y2R_PARA_G0(idx),
+ OVL_Y2R_PARA_C_CF_GMU);
+ mtk_ddp_write_mask(cmdq_pkt, y2r_coef,
+ &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_Y2R_PARA_B1(idx),
+ OVL_Y2R_PARA_C_CF_BMV);
+
+ mtk_ddp_write_mask(cmdq_pkt, y2r_offset,
+ &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_Y2R_PARA_YUV_A_0(idx),
+ OVL_Y2R_PARA_C_CF_YA);
+ mtk_ddp_write_mask(cmdq_pkt, (y2r_offset << 16),
+ &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_Y2R_PARA_YUV_A_0(idx),
+ OVL_Y2R_PARA_C_CF_UA);
+ mtk_ddp_write_mask(cmdq_pkt, y2r_offset,
+ &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_Y2R_PARA_YUV_A_1(idx),
+ OVL_Y2R_PARA_C_CF_VA);
+
+ mtk_ddp_write_relaxed(cmdq_pkt, r2r_coef,
+ &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_R2R_R0(idx));
+ mtk_ddp_write_relaxed(cmdq_pkt, r2r_coef,
+ &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_R2R_G1(idx));
+ mtk_ddp_write_relaxed(cmdq_pkt, r2r_coef,
+ &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_R2R_B2(idx));
+
+ mtk_ddp_write_mask(cmdq_pkt, csc_en,
+ &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_CLRFMT_EXT1,
+ OVL_CLRFMT_EXT1_CSC_EN(idx));
+ }
+
if (pending->rotation & DRM_MODE_REFLECT_Y) {
con |= OVL_CON_VIRT_FLIP;
addr += (pending->height - 1) * pending->pitch;
@@ -602,15 +769,31 @@ static int mtk_disp_ovl_probe(struct platform_device *pdev)
dev_err(dev, "failed to ioremap ovl\n");
return PTR_ERR(priv->regs);
}
+
+ priv->data = of_device_get_match_data(dev);
+ platform_set_drvdata(pdev, priv);
+
+ if (priv->data->crc_cnt) {
+ mtk_crtc_init_crc(&priv->crc,
+ priv->data->crc_ofs, priv->data->crc_cnt,
+ DISP_REG_OVL_TRIG, OVL_CRC_CLR);
+ }
+
#if IS_REACHABLE(CONFIG_MTK_CMDQ)
ret = cmdq_dev_get_client_reg(dev, &priv->cmdq_reg, 0);
if (ret)
dev_dbg(dev, "get mediatek,gce-client-reg fail!\n");
-#endif
-
- priv->data = of_device_get_match_data(dev);
- platform_set_drvdata(pdev, priv);
+ if (priv->data->crc_cnt) {
+ if (of_property_read_u32_index(dev->of_node,
+ "mediatek,gce-events", 0,
+ &priv->crc.cmdq_event)) {
+ dev_warn(dev, "failed to get gce-events for crc\n");
+ }
+ priv->crc.cmdq_reg = &priv->cmdq_reg;
+ mtk_crtc_create_crc_cmdq(dev, &priv->crc);
+ }
+#endif
ret = devm_request_irq(dev, irq, mtk_disp_ovl_irq_handler,
IRQF_TRIGGER_NONE, dev_name(dev), priv);
if (ret < 0) {
@@ -631,6 +814,10 @@ static int mtk_disp_ovl_probe(struct platform_device *pdev)
static void mtk_disp_ovl_remove(struct platform_device *pdev)
{
+ struct device *dev = &pdev->dev;
+ struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
+
+ mtk_crtc_destroy_crc(&ovl->crc);
component_del(&pdev->dev, &mtk_disp_ovl_component_ops);
pm_runtime_disable(&pdev->dev);
}
@@ -701,6 +888,8 @@ static const struct mtk_disp_ovl_data mt8195_ovl_driver_data = {
.formats = mt8195_formats,
.num_formats = ARRAY_SIZE(mt8195_formats),
.supports_clrfmt_ext = true,
+ .crc_ofs = mt8195_ovl_crc_ofs,
+ .crc_cnt = ARRAY_SIZE(mt8195_ovl_crc_ofs),
};
static const struct of_device_id mtk_disp_ovl_driver_dt_match[] = {
--
2.18.0
From: Hsiao Chien Sung <[email protected]>
Support "Pre-multiplied" alpha blending mode on in OVL.
Before this patch, only the "coverage" mode is supported.
Signed-off-by: Hsiao Chien Sung <[email protected]>
---
drivers/gpu/drm/mediatek/mtk_disp_ovl.c | 42 ++++++++++++++++++++-----
1 file changed, 34 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
index 6567806cf4e2..47d0b039a616 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
@@ -52,8 +52,12 @@
#define GMC_THRESHOLD_HIGH ((1 << GMC_THRESHOLD_BITS) / 4)
#define GMC_THRESHOLD_LOW ((1 << GMC_THRESHOLD_BITS) / 8)
+#define OVL_CON_CLRFMT_MAN BIT(23)
#define OVL_CON_BYTE_SWAP BIT(24)
-#define OVL_CON_MTX_YUV_TO_RGB (6 << 16)
+
+/* OVL_CON_RGB_SWAP works only if OVL_CON_CLRFMT_MAN is enabled */
+#define OVL_CON_RGB_SWAP BIT(25)
+
#define OVL_CON_CLRFMT_RGB (1 << 12)
#define OVL_CON_CLRFMT_ARGB8888 (2 << 12)
#define OVL_CON_CLRFMT_RGBA8888 (3 << 12)
@@ -61,6 +65,11 @@
#define OVL_CON_CLRFMT_BGRA8888 (OVL_CON_CLRFMT_ARGB8888 | OVL_CON_BYTE_SWAP)
#define OVL_CON_CLRFMT_UYVY (4 << 12)
#define OVL_CON_CLRFMT_YUYV (5 << 12)
+#define OVL_CON_MTX_YUV_TO_RGB (6 << 16)
+#define OVL_CON_CLRFMT_PARGB8888 ((3 << 12) | OVL_CON_CLRFMT_MAN)
+#define OVL_CON_CLRFMT_PABGR8888 (OVL_CON_CLRFMT_PARGB8888 | OVL_CON_RGB_SWAP)
+#define OVL_CON_CLRFMT_PBGRA8888 (OVL_CON_CLRFMT_PARGB8888 | OVL_CON_BYTE_SWAP)
+#define OVL_CON_CLRFMT_PRGBA8888 (OVL_CON_CLRFMT_PABGR8888 | OVL_CON_BYTE_SWAP)
#define OVL_CON_CLRFMT_RGB565(ovl) ((ovl)->data->fmt_rgb565_is_0 ? \
0 : OVL_CON_CLRFMT_RGB)
#define OVL_CON_CLRFMT_RGB888(ovl) ((ovl)->data->fmt_rgb565_is_0 ? \
@@ -74,6 +83,8 @@
#define OVL_CON_VIRT_FLIP BIT(9)
#define OVL_CON_HORZ_FLIP BIT(10)
+#define OVL_COLOR_ALPHA GENMASK(31, 24)
+
static inline bool is_10bit_rgb(u32 fmt)
{
switch (fmt) {
@@ -298,7 +309,13 @@ void mtk_ovl_config(struct device *dev, unsigned int w,
if (w != 0 && h != 0)
mtk_ddp_write_relaxed(cmdq_pkt, h << 16 | w, &ovl->cmdq_reg, ovl->regs,
DISP_REG_OVL_ROI_SIZE);
- mtk_ddp_write_relaxed(cmdq_pkt, 0x0, &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_ROI_BGCLR);
+
+ /*
+ * The background color must be opaque black (ARGB),
+ * otherwise the alpha blending will have no effect
+ */
+ mtk_ddp_write_relaxed(cmdq_pkt, OVL_COLOR_ALPHA, &ovl->cmdq_reg,
+ ovl->regs, DISP_REG_OVL_ROI_BGCLR);
mtk_ddp_write(cmdq_pkt, 0x1, &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_RST);
mtk_ddp_write(cmdq_pkt, 0x0, &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_RST);
@@ -374,7 +391,8 @@ void mtk_ovl_layer_off(struct device *dev, unsigned int idx,
DISP_REG_OVL_RDMA_CTRL(idx));
}
-static unsigned int ovl_fmt_convert(struct mtk_disp_ovl *ovl, unsigned int fmt)
+static unsigned int ovl_fmt_convert(struct mtk_disp_ovl *ovl, unsigned int fmt,
+ unsigned int blend_mode)
{
/* The return value in switch "MEM_MODE_INPUT_FORMAT_XXX"
* is defined in mediatek HW data sheet.
@@ -395,22 +413,30 @@ static unsigned int ovl_fmt_convert(struct mtk_disp_ovl *ovl, unsigned int fmt)
case DRM_FORMAT_RGBA8888:
case DRM_FORMAT_RGBX1010102:
case DRM_FORMAT_RGBA1010102:
- return OVL_CON_CLRFMT_RGBA8888;
+ return blend_mode == DRM_MODE_BLEND_COVERAGE ?
+ OVL_CON_CLRFMT_RGBA8888 :
+ OVL_CON_CLRFMT_PRGBA8888;
case DRM_FORMAT_BGRX8888:
case DRM_FORMAT_BGRA8888:
case DRM_FORMAT_BGRX1010102:
case DRM_FORMAT_BGRA1010102:
- return OVL_CON_CLRFMT_BGRA8888;
+ return blend_mode == DRM_MODE_BLEND_COVERAGE ?
+ OVL_CON_CLRFMT_BGRA8888 :
+ OVL_CON_CLRFMT_PBGRA8888;
case DRM_FORMAT_XRGB8888:
case DRM_FORMAT_ARGB8888:
case DRM_FORMAT_XRGB2101010:
case DRM_FORMAT_ARGB2101010:
- return OVL_CON_CLRFMT_ARGB8888;
+ return blend_mode == DRM_MODE_BLEND_COVERAGE ?
+ OVL_CON_CLRFMT_ARGB8888 :
+ OVL_CON_CLRFMT_PARGB8888;
case DRM_FORMAT_XBGR8888:
case DRM_FORMAT_ABGR8888:
case DRM_FORMAT_XBGR2101010:
case DRM_FORMAT_ABGR2101010:
- return OVL_CON_CLRFMT_ABGR8888;
+ return blend_mode == DRM_MODE_BLEND_COVERAGE ?
+ OVL_CON_CLRFMT_ABGR8888 :
+ OVL_CON_CLRFMT_PABGR8888;
case DRM_FORMAT_UYVY:
return OVL_CON_CLRFMT_UYVY | OVL_CON_MTX_YUV_TO_RGB;
case DRM_FORMAT_YUYV:
@@ -450,7 +476,7 @@ void mtk_ovl_layer_config(struct device *dev, unsigned int idx,
return;
}
- con = ovl_fmt_convert(ovl, fmt);
+ con = ovl_fmt_convert(ovl, fmt, blend_mode);
if (state->base.fb) {
con |= OVL_CON_AEN;
con |= state->base.alpha & OVL_CON_ALPHA;
--
2.18.0
From: Hsiao Chien Sung <[email protected]>
Register CRC related function pointers to support
CRC retrieval.
Signed-off-by: Hsiao Chien Sung <[email protected]>
---
drivers/gpu/drm/mediatek/mtk_crtc.c | 279 ++++++++++++++++++++++++
drivers/gpu/drm/mediatek/mtk_crtc.h | 38 ++++
drivers/gpu/drm/mediatek/mtk_ddp_comp.h | 5 +
3 files changed, 322 insertions(+)
diff --git a/drivers/gpu/drm/mediatek/mtk_crtc.c b/drivers/gpu/drm/mediatek/mtk_crtc.c
index 0df9bf695f65..5dcd8b95b81e 100644
--- a/drivers/gpu/drm/mediatek/mtk_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_crtc.c
@@ -18,6 +18,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>
+#include <drm/drm_vblank_work.h>
#include "mtk_crtc.h"
#include "mtk_ddp_comp.h"
@@ -74,6 +75,9 @@ struct mtk_crtc {
/* lock for display hardware access */
struct mutex hw_lock;
bool config_updating;
+
+ struct mtk_ddp_comp *crc_provider;
+ struct drm_vblank_work crc_work;
bool sec_on;
};
@@ -894,6 +898,88 @@ static void mtk_crtc_update_output(struct drm_crtc *crtc,
}
}
+static void mtk_crtc_crc_work(struct kthread_work *base)
+{
+ struct drm_vblank_work *work = to_drm_vblank_work(base);
+ struct mtk_crtc *mtk_crtc =
+ container_of(work, typeof(*mtk_crtc), crc_work);
+ struct mtk_ddp_comp *comp = mtk_crtc->crc_provider;
+
+ if (!comp) {
+ DRM_WARN("%s(crtc-%d): no crc provider\n",
+ __func__, drm_crtc_index(&mtk_crtc->base));
+ return;
+ }
+
+ if (mtk_crtc->base.crc.opened) {
+ u64 vblank = drm_crtc_vblank_count(&mtk_crtc->base);
+
+ comp->funcs->crc_read(comp->dev);
+
+ /* could take more than 50ms to finish */
+ drm_crtc_add_crc_entry(&mtk_crtc->base, true, vblank,
+ comp->funcs->crc_entry(comp->dev));
+
+ drm_vblank_work_schedule(&mtk_crtc->crc_work, vblank + 1, true);
+ } else {
+ comp->funcs->crc_stop(comp->dev);
+ }
+}
+
+static int mtk_crtc_set_crc_source(struct drm_crtc *crtc, const char *src)
+{
+ struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc);
+ struct mtk_ddp_comp *comp = mtk_crtc->crc_provider;
+
+ if (!comp) {
+ DRM_ERROR("%s(crtc-%d): no crc provider\n",
+ __func__, drm_crtc_index(crtc));
+ return -ENOENT;
+ }
+
+ if (!src)
+ return -EINVAL;
+
+ if (strcmp(src, "auto") != 0) {
+ DRM_ERROR("%s(crtc-%d): unknown source '%s'\n",
+ __func__, drm_crtc_index(crtc), src);
+ return -EINVAL;
+ }
+
+ comp->funcs->crc_start(comp->dev);
+
+ /*
+ * skip the first crc because the first frame (vblank + 1) is configured
+ * by mtk_crtc_ddp_hw_init() when atomic enable
+ */
+ drm_vblank_work_schedule(&mtk_crtc->crc_work,
+ drm_crtc_vblank_count(crtc) + 2, false);
+ return 0;
+}
+
+static int mtk_crtc_verify_crc_source(struct drm_crtc *crtc, const char *src,
+ size_t *cnt)
+{
+ struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc);
+ struct mtk_ddp_comp *comp = mtk_crtc->crc_provider;
+
+ if (!comp) {
+ DRM_ERROR("%s(crtc-%d): no crc provider\n",
+ __func__, drm_crtc_index(crtc));
+ return -ENOENT;
+ }
+
+ if (src && strcmp(src, "auto") != 0) {
+ DRM_ERROR("%s(crtc-%d): unknown source '%s'\n",
+ __func__, drm_crtc_index(crtc), src);
+ return -EINVAL;
+ }
+
+ *cnt = comp->funcs->crc_cnt(comp->dev);
+
+ return 0;
+}
+
int mtk_crtc_plane_check(struct drm_crtc *crtc, struct drm_plane *plane,
struct mtk_plane_state *state)
{
@@ -942,6 +1028,8 @@ static void mtk_crtc_atomic_enable(struct drm_crtc *crtc,
drm_crtc_vblank_on(crtc);
mtk_crtc->enabled = true;
+
+ drm_vblank_work_init(&mtk_crtc->crc_work, crtc, mtk_crtc_crc_work);
}
static void mtk_crtc_atomic_disable(struct drm_crtc *crtc,
@@ -1035,6 +1123,8 @@ static const struct drm_crtc_funcs mtk_crtc_funcs = {
.atomic_destroy_state = mtk_crtc_destroy_state,
.enable_vblank = mtk_crtc_enable_vblank,
.disable_vblank = mtk_crtc_disable_vblank,
+ .set_crc_source = mtk_crtc_set_crc_source,
+ .verify_crc_source = mtk_crtc_verify_crc_source,
};
static const struct drm_crtc_helper_funcs mtk_crtc_helper_funcs = {
@@ -1228,6 +1318,13 @@ int mtk_crtc_create(struct drm_device *drm_dev, const unsigned int *path,
if (comp->funcs->ctm_set)
has_ctm = true;
+
+ if (comp->funcs->crc_cnt &&
+ comp->funcs->crc_entry &&
+ comp->funcs->crc_read &&
+ comp->funcs->crc_start &&
+ comp->funcs->crc_stop)
+ mtk_crtc->crc_provider = comp;
}
mtk_ddp_comp_register_vblank_cb(comp, mtk_crtc_ddp_irq,
@@ -1379,3 +1476,185 @@ int mtk_crtc_create(struct drm_device *drm_dev, const unsigned int *path,
return 0;
}
+
+void mtk_crtc_init_crc(struct mtk_crtc_crc *crc, const u32 *crc_offset_table,
+ size_t crc_count, u32 reset_offset, u32 reset_mask)
+{
+ crc->ofs = crc_offset_table;
+ crc->cnt = crc_count;
+ crc->rst_ofs = reset_offset;
+ crc->rst_msk = reset_mask;
+ crc->va = kcalloc(crc->cnt, sizeof(*crc->va), GFP_KERNEL);
+ if (!crc->va) {
+ DRM_ERROR("failed to allocate memory for crc\n");
+ crc->cnt = 0;
+ }
+}
+
+void mtk_crtc_read_crc(struct mtk_crtc_crc *crc, void __iomem *reg)
+{
+ if (!crc->cnt || !crc->ofs || !crc->va)
+ return;
+
+#if IS_REACHABLE(CONFIG_MTK_CMDQ)
+ /* sync to see the most up-to-date copy of the DMA buffer */
+ dma_sync_single_for_cpu(crc->cmdq_client.chan->mbox->dev,
+ crc->pa, crc->cnt * sizeof(*crc->va),
+ DMA_FROM_DEVICE);
+#endif
+}
+
+void mtk_crtc_destroy_crc(struct mtk_crtc_crc *crc)
+{
+ if (!crc->cnt)
+ return;
+
+#if IS_REACHABLE(CONFIG_MTK_CMDQ)
+ if (crc->pa) {
+ dma_unmap_single(crc->cmdq_client.chan->mbox->dev,
+ crc->pa, crc->cnt * sizeof(*crc->va),
+ DMA_TO_DEVICE);
+ crc->pa = 0;
+ }
+ if (crc->cmdq_client.chan) {
+ mtk_drm_cmdq_pkt_destroy(&crc->cmdq_handle);
+ mbox_free_channel(crc->cmdq_client.chan);
+ crc->cmdq_client.chan = NULL;
+ }
+#endif
+ kfree(crc->va);
+ crc->va = NULL;
+ crc->cnt = 0;
+}
+
+#if IS_REACHABLE(CONFIG_MTK_CMDQ)
+/**
+ * mtk_crtc_create_crc_cmdq - Create a CMDQ thread for syncing the CRCs
+ * @dev: Kernel device node of the CRC provider
+ * @crc: Pointer of the CRC to init
+ *
+ * This function will create a looping thread on GCE (Global Command Engine) to
+ * keep the CRC up to date by monitoring the assigned event (usually the frame
+ * done event) of the CRC provider, and read the CRCs from the registers to a
+ * shared memory for the workqueue to read. To start/stop the looping thread,
+ * please call `mtk_crtc_start_crc_cmdq()` and `mtk_crtc_stop_crc_cmdq()`
+ * defined blow.
+ *
+ * The reason why we don't update the CRCs with CPU is that the front porch of
+ * 4K60 timing in CEA-861 is less than 60us, and register read/write speed is
+ * relatively unreliable comparing to GCE due to the bus design.
+ *
+ * We must create a new thread instead of using the original one for plane
+ * update is because:
+ * 1. We cannot add another wait-for-event command at the end of cmdq packet, or
+ * the cmdq callback will delay for too long
+ * 2. Will get the CRC of the previous frame if using the existed wait-for-event
+ * command which is at the beginning of the packet
+ */
+void mtk_crtc_create_crc_cmdq(struct device *dev, struct mtk_crtc_crc *crc)
+{
+ int i;
+
+ if (!crc->cnt) {
+ dev_warn(dev, "%s: not support\n", __func__);
+ goto cleanup;
+ }
+
+ if (!crc->ofs) {
+ dev_warn(dev, "%s: not defined\n", __func__);
+ goto cleanup;
+ }
+
+ crc->cmdq_client.client.dev = dev;
+ crc->cmdq_client.client.tx_block = false;
+ crc->cmdq_client.client.knows_txdone = true;
+ crc->cmdq_client.client.rx_callback = NULL;
+ crc->cmdq_client.chan = mbox_request_channel(&crc->cmdq_client.client, 0);
+ if (IS_ERR(crc->cmdq_client.chan)) {
+ dev_warn(dev, "%s: failed to create mailbox client\n", __func__);
+ crc->cmdq_client.chan = NULL;
+ goto cleanup;
+ }
+
+ if (mtk_drm_cmdq_pkt_create(&crc->cmdq_client, &crc->cmdq_handle, PAGE_SIZE)) {
+ dev_warn(dev, "%s: failed to create cmdq packet\n", __func__);
+ goto cleanup;
+ }
+
+ if (!crc->va) {
+ dev_warn(dev, "%s: no memory\n", __func__);
+ goto cleanup;
+ }
+
+ /* map the entry to get a dma address for cmdq to store the crc */
+ crc->pa = dma_map_single(crc->cmdq_client.chan->mbox->dev,
+ crc->va, crc->cnt * sizeof(*crc->va),
+ DMA_FROM_DEVICE);
+
+ if (dma_mapping_error(crc->cmdq_client.chan->mbox->dev, crc->pa)) {
+ dev_err(dev, "%s: failed to map dma\n", __func__);
+ goto cleanup;
+ }
+
+ if (crc->cmdq_event)
+ cmdq_pkt_wfe(&crc->cmdq_handle, crc->cmdq_event, true);
+
+ for (i = 0; i < crc->cnt; i++) {
+ /* put crc to spr1 register */
+ cmdq_pkt_read_s(&crc->cmdq_handle, crc->cmdq_reg->subsys,
+ crc->cmdq_reg->offset + crc->ofs[i],
+ CMDQ_THR_SPR_IDX1);
+
+ /* copy spr1 register to physical address of the crc */
+ cmdq_pkt_assign(&crc->cmdq_handle, CMDQ_THR_SPR_IDX0,
+ CMDQ_ADDR_HIGH(crc->pa + i * sizeof(*crc->va)));
+ cmdq_pkt_write_s(&crc->cmdq_handle, CMDQ_THR_SPR_IDX0,
+ CMDQ_ADDR_LOW(crc->pa + i * sizeof(*crc->va)),
+ CMDQ_THR_SPR_IDX1);
+ }
+ /* reset crc */
+ mtk_ddp_write_mask(&crc->cmdq_handle, ~0, crc->cmdq_reg, 0,
+ crc->rst_ofs, crc->rst_msk);
+
+ /* clear reset bit */
+ mtk_ddp_write_mask(&crc->cmdq_handle, 0, crc->cmdq_reg, 0,
+ crc->rst_ofs, crc->rst_msk);
+
+ /* jump to head of the cmdq packet */
+ cmdq_pkt_jump(&crc->cmdq_handle, crc->cmdq_handle.pa_base);
+
+ return;
+cleanup:
+ mtk_crtc_destroy_crc(crc);
+}
+
+/**
+ * mtk_crtc_start_crc_cmdq - Start the GCE looping thread for CRC update
+ * @crc: Pointer of the CRC information
+ */
+void mtk_crtc_start_crc_cmdq(struct mtk_crtc_crc *crc)
+{
+ if (!crc->cmdq_client.chan)
+ return;
+
+ dma_sync_single_for_device(crc->cmdq_client.chan->mbox->dev,
+ crc->cmdq_handle.pa_base,
+ crc->cmdq_handle.cmd_buf_size,
+ DMA_TO_DEVICE);
+ mbox_send_message(crc->cmdq_client.chan, &crc->cmdq_handle);
+ mbox_client_txdone(crc->cmdq_client.chan, 0);
+}
+
+/**
+ * mtk_crtc_stop_crc_cmdq - Stop the GCE looping thread for CRC update
+ * @crc: Pointer of the CRC information
+ */
+void mtk_crtc_stop_crc_cmdq(struct mtk_crtc_crc *crc)
+{
+ if (!crc->cmdq_client.chan)
+ return;
+
+ /* remove all the commands from the cmdq packet */
+ mbox_flush(crc->cmdq_client.chan, 2000);
+}
+#endif
diff --git a/drivers/gpu/drm/mediatek/mtk_crtc.h b/drivers/gpu/drm/mediatek/mtk_crtc.h
index 0b0be01c25f2..fc95209994a1 100644
--- a/drivers/gpu/drm/mediatek/mtk_crtc.h
+++ b/drivers/gpu/drm/mediatek/mtk_crtc.h
@@ -14,6 +14,34 @@
#define MTK_MAX_BPC 10
#define MTK_MIN_BPC 3
+/**
+ * struct mtk_crtc_crc - crc related information
+ * @ofs: register offset of crc
+ * @rst_ofs: register offset of crc reset
+ * @rst_msk: register mask of crc reset
+ * @cnt: count of crc
+ * @va: pointer to the start of crc array
+ * @pa: physical address of the crc for gce to access
+ * @cmdq_event: the event to trigger the cmdq
+ * @cmdq_reg: address of the register that cmdq is going to access
+ * @cmdq_client: handler to control cmdq (mbox channel, thread ...etc.)
+ * @cmdq_handle: cmdq packet to store the commands
+ */
+struct mtk_crtc_crc {
+ const u32 *ofs;
+ u32 rst_ofs;
+ u32 rst_msk;
+ size_t cnt;
+ u32 *va;
+#if IS_REACHABLE(CONFIG_MTK_CMDQ)
+ dma_addr_t pa;
+ u32 cmdq_event;
+ struct cmdq_client_reg *cmdq_reg;
+ struct cmdq_client cmdq_client;
+ struct cmdq_pkt cmdq_handle;
+#endif
+};
+
void mtk_crtc_commit(struct drm_crtc *crtc);
int mtk_crtc_create(struct drm_device *drm_dev, const unsigned int *path,
unsigned int path_len, int priv_data_index,
@@ -26,4 +54,14 @@ void mtk_crtc_async_update(struct drm_crtc *crtc, struct drm_plane *plane,
struct drm_atomic_state *plane_state);
struct device *mtk_crtc_dma_dev_get(struct drm_crtc *crtc);
+void mtk_crtc_init_crc(struct mtk_crtc_crc *crc, const u32 *crc_offset_table,
+ size_t crc_count, u32 reset_offset, u32 reset_mask);
+void mtk_crtc_read_crc(struct mtk_crtc_crc *crc, void __iomem *reg);
+void mtk_crtc_destroy_crc(struct mtk_crtc_crc *crc);
+#if IS_REACHABLE(CONFIG_MTK_CMDQ)
+void mtk_crtc_create_crc_cmdq(struct device *dev, struct mtk_crtc_crc *crc);
+void mtk_crtc_start_crc_cmdq(struct mtk_crtc_crc *crc);
+void mtk_crtc_stop_crc_cmdq(struct mtk_crtc_crc *crc);
+#endif
+
#endif /* MTK_CRTC_H */
diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
index 2d9cdcb7100c..f3250b9567a0 100644
--- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
@@ -89,6 +89,11 @@ struct mtk_ddp_comp_funcs {
void (*remove)(struct device *dev, struct mtk_mutex *mutex);
unsigned int (*encoder_index)(struct device *dev);
enum drm_mode_status (*mode_valid)(struct device *dev, const struct drm_display_mode *mode);
+ size_t (*crc_cnt)(struct device *dev);
+ u32 *(*crc_entry)(struct device *dev);
+ void (*crc_read)(struct device *dev);
+ void (*crc_start)(struct device *dev);
+ void (*crc_stop)(struct device *dev);
};
struct mtk_ddp_comp {
--
2.18.0
Hi, Shawn:
On Fri, 2024-06-14 at 10:46 +0800, Shawn Sung wrote:
> From: Hsiao Chien Sung <[email protected]>
>
> Set the plane alpha according to DRM plane property.
Reviewed-by: CK Hu <[email protected]>
>
> Signed-off-by: Hsiao Chien Sung <[email protected]>
> ---
> drivers/gpu/drm/mediatek/mtk_ethdr.c | 6 ++++--
> 1 file changed, 4 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/gpu/drm/mediatek/mtk_ethdr.c b/drivers/gpu/drm/mediatek/mtk_ethdr.c
> index 902dec03a7dd..7eaafd44f320 100644
> --- a/drivers/gpu/drm/mediatek/mtk_ethdr.c
> +++ b/drivers/gpu/drm/mediatek/mtk_ethdr.c
> @@ -170,8 +170,10 @@ void mtk_ethdr_layer_config(struct device *dev, unsigned int idx,
> return;
> }
>
> - if (state->base.fb && state->base.fb->format->has_alpha)
> - alpha_con = MIXER_ALPHA_AEN | MIXER_ALPHA;
> + if (state->base.fb) {
> + alpha_con |= MIXER_ALPHA_AEN;
> + alpha_con |= state->base.alpha & MIXER_ALPHA;
> + }
>
> if (state->base.fb && !state->base.fb->format->has_alpha) {
> /*
Hi, Shawn:
On Fri, 2024-06-14 at 10:46 +0800, Shawn Sung wrote:
> From: Hsiao Chien Sung <[email protected]>
>
> Support "None" alpha blending mode on MediaTek's chips.
Reviewed-by: CK Hu <[email protected]>
>
> Signed-off-by: Hsiao Chien Sung <[email protected]>
> ---
> drivers/gpu/drm/mediatek/mtk_disp_ovl.c | 4 +++-
> 1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
> index 2316d4a6dca7..6567806cf4e2 100644
> --- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
> +++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
> @@ -431,6 +431,7 @@ void mtk_ovl_layer_config(struct device *dev, unsigned int idx,
> unsigned int fmt = pending->format;
> unsigned int offset = (pending->y << 16) | pending->x;
> unsigned int src_size = (pending->height << 16) | pending->width;
> + unsigned int blend_mode = state->base.pixel_blend_mode;
> unsigned int ignore_pixel_alpha = 0;
> unsigned int con;
> bool is_afbc = pending->modifier != DRM_FORMAT_MOD_LINEAR;
> @@ -460,7 +461,8 @@ void mtk_ovl_layer_config(struct device *dev, unsigned int idx,
> * For RGB888 related formats, whether CONST_BLD is enabled or not won't
> * affect the result. Therefore we use !has_alpha as the condition.
> */
> - if (state->base.fb && !state->base.fb->format->has_alpha)
> + if ((state->base.fb && !state->base.fb->format->has_alpha) ||
> + blend_mode == DRM_MODE_BLEND_PIXEL_NONE)
> ignore_pixel_alpha = OVL_CONST_BLEND;
>
> if (pending->rotation & DRM_MODE_REFLECT_Y) {
On Fri, 2024-06-14 at 10:46 +0800, Shawn Sung wrote:
> From: Hsiao Chien Sung <[email protected]>
>
> Support "Pre-multiplied" alpha blending mode on in OVL.
> Before this patch, only the "coverage" mode is supported.
>
> Signed-off-by: Hsiao Chien Sung <[email protected]>
> ---
> drivers/gpu/drm/mediatek/mtk_disp_ovl.c | 42 ++++++++++++++++++++-----
> 1 file changed, 34 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
> index 6567806cf4e2..47d0b039a616 100644
> --- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
> +++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
> @@ -52,8 +52,12 @@
> #define GMC_THRESHOLD_HIGH ((1 << GMC_THRESHOLD_BITS) / 4)
> #define GMC_THRESHOLD_LOW ((1 << GMC_THRESHOLD_BITS) / 8)
>
> +#define OVL_CON_CLRFMT_MAN BIT(23)
> #define OVL_CON_BYTE_SWAP BIT(24)
> -#define OVL_CON_MTX_YUV_TO_RGB (6 << 16)
> +
> +/* OVL_CON_RGB_SWAP works only if OVL_CON_CLRFMT_MAN is enabled */
> +#define OVL_CON_RGB_SWAP BIT(25)
> +
> #define OVL_CON_CLRFMT_RGB (1 << 12)
> #define OVL_CON_CLRFMT_ARGB8888 (2 << 12)
> #define OVL_CON_CLRFMT_RGBA8888 (3 << 12)
> @@ -61,6 +65,11 @@
> #define OVL_CON_CLRFMT_BGRA8888 (OVL_CON_CLRFMT_ARGB8888 | OVL_CON_BYTE_SWAP)
> #define OVL_CON_CLRFMT_UYVY (4 << 12)
> #define OVL_CON_CLRFMT_YUYV (5 << 12)
> +#define OVL_CON_MTX_YUV_TO_RGB (6 << 16)
> +#define OVL_CON_CLRFMT_PARGB8888 ((3 << 12) | OVL_CON_CLRFMT_MAN)
#define OVL_CON_CLRFMT_PARGB8888 (OVL_CON_CLRFMT_RGBA8888 | OVL_CON_CLRFMT_MAN)
But I'm confused with the naming.
> +#define OVL_CON_CLRFMT_PABGR8888 (OVL_CON_CLRFMT_PARGB8888 | OVL_CON_RGB_SWAP)
#define OVL_CON_CLRFMT_PABGR8888 (OVL_CON_CLRFMT_ABGR8888 | OVL_CON_CLRFMT_MAN)
> +#define OVL_CON_CLRFMT_PBGRA8888 (OVL_CON_CLRFMT_PARGB8888 | OVL_CON_BYTE_SWAP)
#define OVL_CON_CLRFMT_PBGRA8888 (OVL_CON_CLRFMT_BGRA8888 | OVL_CON_CLRFMT_MAN)
> +#define OVL_CON_CLRFMT_PRGBA8888 (OVL_CON_CLRFMT_PABGR8888 | OVL_CON_BYTE_SWAP)
> #define OVL_CON_CLRFMT_RGB565(ovl) ((ovl)->data->fmt_rgb565_is_0 ? \
> 0 : OVL_CON_CLRFMT_RGB)
> #define OVL_CON_CLRFMT_RGB888(ovl) ((ovl)->data->fmt_rgb565_is_0 ? \
> @@ -74,6 +83,8 @@
> #define OVL_CON_VIRT_FLIP BIT(9)
> #define OVL_CON_HORZ_FLIP BIT(10)
>
> +#define OVL_COLOR_ALPHA GENMASK(31, 24)
> +
> static inline bool is_10bit_rgb(u32 fmt)
> {
> switch (fmt) {
> @@ -298,7 +309,13 @@ void mtk_ovl_config(struct device *dev, unsigned int w,
> if (w != 0 && h != 0)
> mtk_ddp_write_relaxed(cmdq_pkt, h << 16 | w, &ovl->cmdq_reg, ovl->regs,
> DISP_REG_OVL_ROI_SIZE);
> - mtk_ddp_write_relaxed(cmdq_pkt, 0x0, &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_ROI_BGCLR);
> +
> + /*
> + * The background color must be opaque black (ARGB),
> + * otherwise the alpha blending will have no effect
> + */
> + mtk_ddp_write_relaxed(cmdq_pkt, OVL_COLOR_ALPHA, &ovl->cmdq_reg,
> + ovl->regs, DISP_REG_OVL_ROI_BGCLR);
The coverage mode formula is:
dst.RGB = src.RGB * src.A + dst.RGB * (1 - src.A)
The pre-multiplied mode formula is:
dst.RGB = src.RGB + dst.RGB * (1 - src.A)
Both formula has no destination alpha (I think background color is last destination),
why coverage mode work fine but pre-multiplied mode has something wrong?
Regards,
CK
>
> mtk_ddp_write(cmdq_pkt, 0x1, &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_RST);
> mtk_ddp_write(cmdq_pkt, 0x0, &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_RST);
> @@ -374,7 +391,8 @@ void mtk_ovl_layer_off(struct device *dev, unsigned int idx,
> DISP_REG_OVL_RDMA_CTRL(idx));
> }
>
> -static unsigned int ovl_fmt_convert(struct mtk_disp_ovl *ovl, unsigned int fmt)
> +static unsigned int ovl_fmt_convert(struct mtk_disp_ovl *ovl, unsigned int fmt,
> + unsigned int blend_mode)
> {
> /* The return value in switch "MEM_MODE_INPUT_FORMAT_XXX"
> * is defined in mediatek HW data sheet.
> @@ -395,22 +413,30 @@ static unsigned int ovl_fmt_convert(struct mtk_disp_ovl *ovl, unsigned int fmt)
> case DRM_FORMAT_RGBA8888:
> case DRM_FORMAT_RGBX1010102:
> case DRM_FORMAT_RGBA1010102:
> - return OVL_CON_CLRFMT_RGBA8888;
> + return blend_mode == DRM_MODE_BLEND_COVERAGE ?
> + OVL_CON_CLRFMT_RGBA8888 :
> + OVL_CON_CLRFMT_PRGBA8888;
> case DRM_FORMAT_BGRX8888:
> case DRM_FORMAT_BGRA8888:
> case DRM_FORMAT_BGRX1010102:
> case DRM_FORMAT_BGRA1010102:
> - return OVL_CON_CLRFMT_BGRA8888;
> + return blend_mode == DRM_MODE_BLEND_COVERAGE ?
> + OVL_CON_CLRFMT_BGRA8888 :
> + OVL_CON_CLRFMT_PBGRA8888;
> case DRM_FORMAT_XRGB8888:
> case DRM_FORMAT_ARGB8888:
> case DRM_FORMAT_XRGB2101010:
> case DRM_FORMAT_ARGB2101010:
> - return OVL_CON_CLRFMT_ARGB8888;
> + return blend_mode == DRM_MODE_BLEND_COVERAGE ?
> + OVL_CON_CLRFMT_ARGB8888 :
> + OVL_CON_CLRFMT_PARGB8888;
> case DRM_FORMAT_XBGR8888:
> case DRM_FORMAT_ABGR8888:
> case DRM_FORMAT_XBGR2101010:
> case DRM_FORMAT_ABGR2101010:
> - return OVL_CON_CLRFMT_ABGR8888;
> + return blend_mode == DRM_MODE_BLEND_COVERAGE ?
> + OVL_CON_CLRFMT_ABGR8888 :
> + OVL_CON_CLRFMT_PABGR8888;
> case DRM_FORMAT_UYVY:
> return OVL_CON_CLRFMT_UYVY | OVL_CON_MTX_YUV_TO_RGB;
> case DRM_FORMAT_YUYV:
> @@ -450,7 +476,7 @@ void mtk_ovl_layer_config(struct device *dev, unsigned int idx,
> return;
> }
>
> - con = ovl_fmt_convert(ovl, fmt);
> + con = ovl_fmt_convert(ovl, fmt, blend_mode);
> if (state->base.fb) {
> con |= OVL_CON_AEN;
> con |= state->base.alpha & OVL_CON_ALPHA;
Hi, Shawn:
On Fri, 2024-06-14 at 10:46 +0800, Shawn Sung wrote:
> From: Hsiao Chien Sung <[email protected]>
>
> Support "Pre-multiplied" alpha blending mode on in OVL.
> Before this patch, only the "coverage" mode is supported.
>
> Signed-off-by: Hsiao Chien Sung <[email protected]>
> ---
> drivers/gpu/drm/mediatek/mtk_disp_ovl.c | 42 ++++++++++++++++++++-----
> 1 file changed, 34 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
> index 6567806cf4e2..47d0b039a616 100644
> --- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
> +++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
> @@ -52,8 +52,12 @@
> #define GMC_THRESHOLD_HIGH ((1 << GMC_THRESHOLD_BITS) / 4)
> #define GMC_THRESHOLD_LOW ((1 << GMC_THRESHOLD_BITS) / 8)
>
> +#define OVL_CON_CLRFMT_MAN BIT(23)
> #define OVL_CON_BYTE_SWAP BIT(24)
> -#define OVL_CON_MTX_YUV_TO_RGB (6 << 16)
> +
> +/* OVL_CON_RGB_SWAP works only if OVL_CON_CLRFMT_MAN is enabled */
> +#define OVL_CON_RGB_SWAP BIT(25)
> +
> #define OVL_CON_CLRFMT_RGB (1 << 12)
> #define OVL_CON_CLRFMT_ARGB8888 (2 << 12)
> #define OVL_CON_CLRFMT_RGBA8888 (3 << 12)
> @@ -61,6 +65,11 @@
> #define OVL_CON_CLRFMT_BGRA8888 (OVL_CON_CLRFMT_ARGB8888 | OVL_CON_BYTE_SWAP)
> #define OVL_CON_CLRFMT_UYVY (4 << 12)
> #define OVL_CON_CLRFMT_YUYV (5 << 12)
> +#define OVL_CON_MTX_YUV_TO_RGB (6 << 16)
> +#define OVL_CON_CLRFMT_PARGB8888 ((3 << 12) | OVL_CON_CLRFMT_MAN)
> +#define OVL_CON_CLRFMT_PABGR8888 (OVL_CON_CLRFMT_PARGB8888 | OVL_CON_RGB_SWAP)
> +#define OVL_CON_CLRFMT_PBGRA8888 (OVL_CON_CLRFMT_PARGB8888 | OVL_CON_BYTE_SWAP)
> +#define OVL_CON_CLRFMT_PRGBA8888 (OVL_CON_CLRFMT_PABGR8888 | OVL_CON_BYTE_SWAP)
> #define OVL_CON_CLRFMT_RGB565(ovl) ((ovl)->data->fmt_rgb565_is_0 ? \
> 0 : OVL_CON_CLRFMT_RGB)
> #define OVL_CON_CLRFMT_RGB888(ovl) ((ovl)->data->fmt_rgb565_is_0 ? \
> @@ -74,6 +83,8 @@
> #define OVL_CON_VIRT_FLIP BIT(9)
> #define OVL_CON_HORZ_FLIP BIT(10)
>
>
[snip]
>
> -static unsigned int ovl_fmt_convert(struct mtk_disp_ovl *ovl, unsigned int fmt)
> +static unsigned int ovl_fmt_convert(struct mtk_disp_ovl *ovl, unsigned int fmt,
> + unsigned int blend_mode)
> {
> /* The return value in switch "MEM_MODE_INPUT_FORMAT_XXX"
> * is defined in mediatek HW data sheet.
> @@ -395,22 +413,30 @@ static unsigned int ovl_fmt_convert(struct mtk_disp_ovl *ovl, unsigned int fmt)
> case DRM_FORMAT_RGBA8888:
> case DRM_FORMAT_RGBX1010102:
> case DRM_FORMAT_RGBA1010102:
> - return OVL_CON_CLRFMT_RGBA8888;
> + return blend_mode == DRM_MODE_BLEND_COVERAGE ?
> + OVL_CON_CLRFMT_RGBA8888 :
> + OVL_CON_CLRFMT_PRGBA8888;
> case DRM_FORMAT_BGRX8888:
> case DRM_FORMAT_BGRA8888:
> case DRM_FORMAT_BGRX1010102:
> case DRM_FORMAT_BGRA1010102:
> - return OVL_CON_CLRFMT_BGRA8888;
> + return blend_mode == DRM_MODE_BLEND_COVERAGE ?
> + OVL_CON_CLRFMT_BGRA8888 :
> + OVL_CON_CLRFMT_PBGRA8888;
> case DRM_FORMAT_XRGB8888:
> case DRM_FORMAT_ARGB8888:
> case DRM_FORMAT_XRGB2101010:
> case DRM_FORMAT_ARGB2101010:
> - return OVL_CON_CLRFMT_ARGB8888;
> + return blend_mode == DRM_MODE_BLEND_COVERAGE ?
> + OVL_CON_CLRFMT_ARGB8888 :
> + OVL_CON_CLRFMT_PARGB8888;
> case DRM_FORMAT_XBGR8888:
> case DRM_FORMAT_ABGR8888:
> case DRM_FORMAT_XBGR2101010:
> case DRM_FORMAT_ABGR2101010:
> - return OVL_CON_CLRFMT_ABGR8888;
> + return blend_mode == DRM_MODE_BLEND_COVERAGE ?
> + OVL_CON_CLRFMT_ABGR8888 :
> + OVL_CON_CLRFMT_PABGR8888;
> case DRM_FORMAT_UYVY:
> return OVL_CON_CLRFMT_UYVY | OVL_CON_MTX_YUV_TO_RGB;
> case DRM_FORMAT_YUYV:
> @@ -450,7 +476,7 @@ void mtk_ovl_layer_config(struct device *dev, unsigned int idx,
> return;
> }
>
> - con = ovl_fmt_convert(ovl, fmt);
> + con = ovl_fmt_convert(ovl, fmt, blend_mode);
The simple way is
con |= blend_mode == DRM_MODE_BLEND_PREMULTI ? OVL_CON_CLRFMT_MAN : 0;
Regards,
CK
> if (state->base.fb) {
> con |= OVL_CON_AEN;
> con |= state->base.alpha & OVL_CON_ALPHA;