@@ -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,
@@ -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);
@@ -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 {
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@mediatek.com> --- 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(+)