[PATCH 10/15] drm/mediatek: Support CRC in display driver

From: Hsiao Chien Sung
Date: Wed Aug 23 2023 - 11:14:23 EST


Register CRC related function pointers to support CRC
retrieval.

Skip the first CRC because when the first vblank triggered,
the frame buffer is not ready for CRC calculation yet.

Signed-off-by: Hsiao Chien Sung <shawn.sung@xxxxxxxxxxxx>
---
drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 53 +++++++++++++++++++++
drivers/gpu/drm/mediatek/mtk_drm_crtc.h | 20 ++++++++
drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h | 5 ++
3 files changed, 78 insertions(+)

diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
index e8313739b54d..0fa713c550b1 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
@@ -573,6 +573,17 @@ static void mtk_crtc_ddp_irq(void *data)
struct drm_crtc *crtc = data;
struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
struct mtk_drm_private *priv = crtc->dev->dev_private;
+ static int skip;
+
+ if (mtk_crtc->crc.cnt && crtc->crc.opened) {
+ if (++skip > 1) {
+ drm_crtc_add_crc_entry(crtc, true,
+ drm_crtc_vblank_count(crtc),
+ (u32 *)mtk_crtc->crc.va);
+ }
+ } else {
+ skip = 0;
+ }

#if IS_REACHABLE(CONFIG_MTK_CMDQ)
if (!priv->data->shadow_register && !mtk_crtc->cmdq_client.chan)
@@ -605,6 +616,34 @@ static void mtk_drm_crtc_disable_vblank(struct drm_crtc *crtc)
mtk_ddp_comp_disable_vblank(comp);
}

+static int mtk_drm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src)
+{
+ if (src && strcmp(src, "auto") != 0) {
+ DRM_DEBUG_DRIVER("%s(crtc-%d): unknown source '%s'\n",
+ __func__, drm_crtc_index(crtc), src);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int mtk_drm_crtc_verify_crc_source(struct drm_crtc *crtc,
+ const char *src,
+ size_t *cnt)
+{
+ struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
+
+ if (src && strcmp(src, "auto") != 0) {
+ DRM_DEBUG_DRIVER("%s(crtc-%d): unknown source '%s'\n",
+ __func__, drm_crtc_index(crtc), src);
+ return -EINVAL;
+ }
+
+ *cnt = (size_t)mtk_crtc->crc.cnt;
+
+ return 0;
+}
+
int mtk_drm_crtc_plane_check(struct drm_crtc *crtc, struct drm_plane *plane,
struct mtk_plane_state *state)
{
@@ -737,6 +776,8 @@ static const struct drm_crtc_funcs mtk_crtc_funcs = {
.atomic_destroy_state = mtk_drm_crtc_destroy_state,
.enable_vblank = mtk_drm_crtc_enable_vblank,
.disable_vblank = mtk_drm_crtc_disable_vblank,
+ .set_crc_source = mtk_drm_crtc_set_crc_source,
+ .verify_crc_source = mtk_drm_crtc_verify_crc_source,
};

static const struct drm_crtc_helper_funcs mtk_crtc_helper_funcs = {
@@ -919,6 +960,18 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,

if (comp->funcs->ctm_set)
has_ctm = true;
+
+ if (comp->funcs->crc_cnt) {
+ mtk_crtc->crc.cnt = comp->funcs->crc_cnt(comp->dev);
+ mtk_crtc->crc.va = dma_alloc_coherent(dev,
+ mtk_crtc->crc.cnt * 4,
+ &mtk_crtc->crc.pa,
+ GFP_KERNEL);
+ if (!mtk_crtc->crc.va || !mtk_crtc->crc.pa) {
+ dev_err(dev, "failed to allocate CRC\n");
+ return -ENOMEM;
+ }
+ }
}

mtk_ddp_comp_register_vblank_cb(comp, mtk_crtc_ddp_irq,
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.h b/drivers/gpu/drm/mediatek/mtk_drm_crtc.h
index 34cd1bfed8b3..8303464f494c 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.h
@@ -14,6 +14,23 @@
#define MTK_MAX_BPC 10
#define MTK_MIN_BPC 3

+/*
+ * struct mtk_drm_crc - CRC info of the CRTC
+ * @cnt: how many CRCs the CRTC supports
+ * @va: virtual address for CPU to read the CRCs
+ * @pa: physical address for GCE to stored the CRCs
+ *
+ * Hardware components could generate more than one CRC,
+ * for example, one for odd lines, another for even lines of the frame buffer,
+ * and each CRC takes 4 bytes in memory, here we record how many CRC the
+ * generator supports, and access them as an array from the specified address.
+ */
+struct mtk_drm_crc {
+ u32 cnt;
+ void *va;
+ dma_addr_t pa;
+};
+
/*
* struct mtk_drm_crtc - MediaTek specific crtc structure.
* @base: crtc object.
@@ -24,6 +41,7 @@
* @mutex: handle to one of the ten disp_mutex streams
* @ddp_comp_nr: number of components in ddp_comp
* @ddp_comp: array of pointers the mtk_ddp_comp structures used by this crtc
+ * @crc: CRC info of the CRTC
*
* TODO: Needs update: this header is missing a bunch of member descriptions.
*/
@@ -56,6 +74,8 @@ struct mtk_drm_crtc {
/* lock for display hardware access */
struct mutex hw_lock;
bool config_updating;
+
+ struct mtk_drm_crc crc;
};

void mtk_drm_crtc_commit(struct drm_crtc *crtc);
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
index febcaeef16a1..3b67c3dc0525 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
@@ -45,6 +45,10 @@ enum mtk_ddp_comp_type {

struct mtk_ddp_comp;
struct cmdq_pkt;
+
+/* struct mtk_ddp_comp_funcs - function pointers of the ddp components
+ * @crc_cnt: how many CRCs the component supports
+ */
struct mtk_ddp_comp_funcs {
int (*clk_enable)(struct device *dev);
void (*clk_disable)(struct device *dev);
@@ -80,6 +84,7 @@ struct mtk_ddp_comp_funcs {
void (*disconnect)(struct device *dev, struct device *mmsys_dev, unsigned int next);
void (*add)(struct device *dev, struct mtk_mutex *mutex);
void (*remove)(struct device *dev, struct mtk_mutex *mutex);
+ u32 (*crc_cnt)(struct device *dev);
};

struct mtk_ddp_comp {
--
2.18.0