Re: [PATCH v6 12/14] drm/mediatek: Support CRC in display driver

2024-03-31 Thread 胡俊光


[PATCH v6 12/14] drm/mediatek: Support CRC in display driver

2024-03-21 Thread Shawn Sung
From: Hsiao Chien Sung 

Register CRC related function pointers to support
CRC retrieval.

Signed-off-by: Hsiao Chien Sung 
---
 drivers/gpu/drm/mediatek/mtk_crtc.c | 260 
 drivers/gpu/drm/mediatek/mtk_crtc.h |  38 
 drivers/gpu/drm/mediatek/mtk_ddp_comp.h |   3 +
 3 files changed, 301 insertions(+)

diff --git a/drivers/gpu/drm/mediatek/mtk_crtc.c 
b/drivers/gpu/drm/mediatek/mtk_crtc.c
index d811e4e73a36c..6440c5fb336d7 100644
--- a/drivers/gpu/drm/mediatek/mtk_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_crtc.c
@@ -18,6 +18,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "mtk_crtc.h"
 #include "mtk_ddp_comp.h"
@@ -69,6 +70,9 @@ struct mtk_crtc {
/* lock for display hardware access */
struct mutexhw_lock;
boolconfig_updating;
+
+   struct mtk_ddp_comp *crc_provider;
+   struct drm_vblank_work  crc_work;
 };
 
 struct mtk_crtc_state {
@@ -703,6 +707,71 @@ 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);
+
+   if (mtk_crtc->base.crc.opened) {
+   struct mtk_ddp_comp *comp = mtk_crtc->crc_provider;
+   u64 vblank = drm_crtc_vblank_count(_crtc->base);
+
+   comp->funcs->crc_read(comp->dev);
+
+   /* could take more than 50ms to finish */
+   drm_crtc_add_crc_entry(_crtc->base, true, vblank,
+  comp->funcs->crc_entry(comp->dev));
+
+   drm_vblank_work_schedule(_crtc->crc_work, vblank + 1, true);
+   }
+}
+
+static int mtk_crtc_set_crc_source(struct drm_crtc *crtc, const char *src)
+{
+   struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc);
+
+   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;
+   }
+
+   /*
+* 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(_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)
 {
@@ -751,6 +820,8 @@ static void mtk_crtc_atomic_enable(struct drm_crtc *crtc,
 
drm_crtc_vblank_on(crtc);
mtk_crtc->enabled = true;
+
+   drm_vblank_work_init(_crtc->crc_work, crtc, mtk_crtc_crc_work);
 }
 
 static void mtk_crtc_atomic_disable(struct drm_crtc *crtc,
@@ -840,6 +911,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 = {
@@ -1033,6 +1106,11 @@ 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)
+   mtk_crtc->crc_provider = comp;
}
 
mtk_ddp_comp_register_vblank_cb(comp, mtk_crtc_ddp_irq,
@@ -1136,3 +1214,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;
+