[PATCH 12/12] drm/mediatek: Add support for multiple mmsys in the one mediatek-drm driver

CK Hu (胡俊光) ck.hu at mediatek.com
Wed Feb 12 09:30:30 UTC 2025


Hi, Paul:

On Fri, 2025-01-10 at 20:34 +0800, paul-pl.chen wrote:
> From: "Nancy.Lin" <nancy.lin at mediatek.com>
> 
> To support multiple mmsys instances in the one mediatek-drm instance,
> providing improved flexibility and scalability by the following changes:
> 
> 1. Defined new DRM component IDs DDP_COMPONENT_DRM_OVLSYS_ADAPTOR*
>   to support different mmsys composition.
> 2. Added new component types MTK_DISP_VIRTUAL to support the
>   routing to virtual display components.
> 3. Added and adjusted the existed structure or interface to extend
>   the support of multiple mmsys instances.
> 4. Modified the component matching and binding logic to support
>   multiple mmsys instances.

I think the title would confuse me.
Original mediatek-drm driver already support multiple mmsys.
I try to understand MT8196 display.
Is one display pipeline separated into two mmsys?
The first is ovlsys and the second is dispsys?
If so, I would like mediatek-drm driver see only mmsys (dispsys),
and let ovlsys control is hidden in ovlsys sub driver, so mediatek-drm driver would not change so much.

> 
> Signed-off-by: Nancy.Lin <nancy.lin at mediatek.com>
> Signed-off-by: Paul-pl.Chen <paul-pl.chen at mediatek.com>
> ---
>  drivers/gpu/drm/mediatek/mtk_crtc.c     | 350 +++++++++++++++++++-----
>  drivers/gpu/drm/mediatek/mtk_crtc.h     |   6 +-
>  drivers/gpu/drm/mediatek/mtk_ddp_comp.c | 106 +++++--
>  drivers/gpu/drm/mediatek/mtk_ddp_comp.h |   2 +
>  drivers/gpu/drm/mediatek/mtk_drm_drv.c  | 223 ++++++++++++---
>  drivers/gpu/drm/mediatek/mtk_drm_drv.h  |  16 +-
>  6 files changed, 578 insertions(+), 125 deletions(-)
> 
> diff --git a/drivers/gpu/drm/mediatek/mtk_crtc.c b/drivers/gpu/drm/mediatek/mtk_crtc.c
> index eb0e1233ad04..eca6941bfaa2 100644
> --- a/drivers/gpu/drm/mediatek/mtk_crtc.c
> +++ b/drivers/gpu/drm/mediatek/mtk_crtc.c
> @@ -58,13 +58,17 @@ struct mtk_crtc {
>  	wait_queue_head_t		cb_blocking_queue;
>  #endif
>  
> -	struct device			*mmsys_dev;
> +	struct device			*mmsys_dev[MAX_MMSYS];
>  	struct device			*dma_dev;
> -	struct mtk_mutex		*mutex;
> +	struct device			*vdisp_ao_dev;
> +	struct mtk_mutex		*mutex[MAX_MMSYS];
>  	unsigned int			ddp_comp_nr;
>  	struct mtk_ddp_comp		**ddp_comp;
> +	enum mtk_drm_mmsys		*ddp_comp_sys;
> +	bool				exist[MAX_MMSYS];
>  	unsigned int			num_conn_routes;
>  	const struct mtk_drm_route	*conn_routes;
> +	enum mtk_drm_mmsys		conn_routes_sys;
>  
>  	/* lock for display hardware access */
>  	struct mutex			hw_lock;
> @@ -82,6 +86,11 @@ struct mtk_crtc_state {
>  	unsigned int			pending_vrefresh;
>  };
>  
> +struct mtk_crtc_comp_info {
> +	enum mtk_drm_mmsys sys;
> +	unsigned int comp_id;
> +};
> +
>  static inline struct mtk_crtc *to_mtk_crtc(struct drm_crtc *c)
>  {
>  	return container_of(c, struct mtk_crtc, base);
> @@ -125,7 +134,9 @@ static void mtk_crtc_destroy(struct drm_crtc *crtc)
>  	struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc);
>  	int i;
>  
> -	mtk_mutex_put(mtk_crtc->mutex);
> +	for (i = 0; i < MAX_MMSYS; i++)
> +		if (mtk_crtc->mutex[i])
> +			mtk_mutex_put(mtk_crtc->mutex[i]);
>  #if IS_REACHABLE(CONFIG_MTK_CMDQ)
>  	if (mtk_crtc->cmdq_client.chan) {
>  		cmdq_pkt_destroy(&mtk_crtc->cmdq_client, &mtk_crtc->cmdq_handle);
> @@ -223,7 +234,14 @@ static int mtk_crtc_ddp_clk_enable(struct mtk_crtc *mtk_crtc)
>  	int i;
>  
>  	for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
> +		enum mtk_drm_mmsys mmsys;
> +
>  		ret = mtk_ddp_comp_clk_enable(mtk_crtc->ddp_comp[i]);
> +		if (mtk_ddp_comp_get_type(mtk_crtc->ddp_comp[i]->id) == MTK_DISP_VIRTUAL) {
> +			mmsys = mtk_crtc->ddp_comp_sys[i];
> +			ret = mtk_mmsys_ddp_clk_enable(mtk_crtc->mmsys_dev[mmsys],
> +						       mtk_crtc->ddp_comp[i]->id);
> +		}
>  		if (ret) {
>  			DRM_ERROR("Failed to enable clock %d: %d\n", i, ret);
>  			goto err;
> @@ -232,17 +250,28 @@ static int mtk_crtc_ddp_clk_enable(struct mtk_crtc *mtk_crtc)
>  
>  	return 0;
>  err:
> -	while (--i >= 0)
> +	while (--i >= 0) {
>  		mtk_ddp_comp_clk_disable(mtk_crtc->ddp_comp[i]);
> +		if (mtk_ddp_comp_get_type(mtk_crtc->ddp_comp[i]->id) == MTK_DISP_VIRTUAL)
> +			mtk_mmsys_ddp_clk_disable(mtk_crtc->mmsys_dev[mtk_crtc->ddp_comp_sys[i]],
> +						  mtk_crtc->ddp_comp[i]->id);
> +	}
>  	return ret;
>  }
>  
>  static void mtk_crtc_ddp_clk_disable(struct mtk_crtc *mtk_crtc)
>  {
>  	int i;
> +	enum mtk_drm_mmsys mmsys;
>  
> -	for (i = 0; i < mtk_crtc->ddp_comp_nr; i++)
> +	for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
>  		mtk_ddp_comp_clk_disable(mtk_crtc->ddp_comp[i]);
> +		if (mtk_ddp_comp_get_type(mtk_crtc->ddp_comp[i]->id) == MTK_DISP_VIRTUAL) {
> +			mmsys = mtk_crtc->ddp_comp_sys[i];
> +			mtk_mmsys_ddp_clk_disable(mtk_crtc->mmsys_dev[mmsys],
> +						  mtk_crtc->ddp_comp[i]->id);
> +		}
> +	}
>  }
>  
>  static
> @@ -332,7 +361,8 @@ static int mtk_crtc_ddp_hw_init(struct mtk_crtc *mtk_crtc)
>  	struct drm_connector_list_iter conn_iter;
>  	unsigned int width, height, vrefresh, bpc = MTK_MAX_BPC;
>  	int ret;
> -	int i;
> +	int i, j;
> +	enum mtk_drm_mmsys mmsys;
>  
>  	if (WARN_ON(!crtc->state))
>  		return -EINVAL;
> @@ -362,10 +392,18 @@ static int mtk_crtc_ddp_hw_init(struct mtk_crtc *mtk_crtc)
>  		return ret;
>  	}
>  
> -	ret = mtk_mutex_prepare(mtk_crtc->mutex);
> -	if (ret < 0) {
> -		DRM_ERROR("Failed to enable mutex clock: %d\n", ret);
> -		goto err_pm_runtime_put;
> +	for (i = 0; i < MAX_MMSYS; i++)
> +		if (mtk_crtc->exist[i])
> +			mtk_mmsys_top_clk_enable(mtk_crtc->mmsys_dev[i]);
> +
> +	for (i = 0; i < MAX_MMSYS; i++) {
> +		if (!mtk_crtc->mutex[i] || !mtk_crtc->exist[i])
> +			continue;
> +		ret = mtk_mutex_prepare(mtk_crtc->mutex[i]);
> +		if (ret < 0) {
> +			DRM_ERROR("Failed to enable mmsys%d mutex clock: %d\n", i, ret);
> +			goto err_pm_runtime_put;
> +		}
>  	}
>  
>  	ret = mtk_crtc_ddp_clk_enable(mtk_crtc);
> @@ -374,19 +412,36 @@ static int mtk_crtc_ddp_hw_init(struct mtk_crtc *mtk_crtc)
>  		goto err_mutex_unprepare;
>  	}
>  
> +	if (mtk_crtc->vdisp_ao_dev)
> +		mtk_mmsys_default_config(mtk_crtc->vdisp_ao_dev);
> +
> +	for (i = 0; i < MAX_MMSYS; i++)
> +		if (mtk_crtc->exist[i])
> +			mtk_mmsys_default_config(mtk_crtc->mmsys_dev[i]);
> +
>  	for (i = 0; i < mtk_crtc->ddp_comp_nr - 1; i++) {
> -		if (!mtk_ddp_comp_connect(mtk_crtc->ddp_comp[i], mtk_crtc->mmsys_dev,
> +		mmsys = mtk_crtc->ddp_comp_sys[i];
> +		if (!mtk_ddp_comp_connect(mtk_crtc->ddp_comp[i], mtk_crtc->mmsys_dev[mmsys],
>  					  mtk_crtc->ddp_comp[i + 1]->id))
> -			mtk_mmsys_ddp_connect(mtk_crtc->mmsys_dev,
> +			mtk_mmsys_ddp_connect(mtk_crtc->mmsys_dev[mmsys],
>  					      mtk_crtc->ddp_comp[i]->id,
>  					      mtk_crtc->ddp_comp[i + 1]->id);
> -		if (!mtk_ddp_comp_add(mtk_crtc->ddp_comp[i], mtk_crtc->mutex))
> -			mtk_mutex_add_comp(mtk_crtc->mutex,
> +		if (!mtk_ddp_comp_add(mtk_crtc->ddp_comp[i], mtk_crtc->mutex[mmsys]))
> +			mtk_mutex_add_comp(mtk_crtc->mutex[mmsys],
>  					   mtk_crtc->ddp_comp[i]->id);
>  	}
> -	if (!mtk_ddp_comp_add(mtk_crtc->ddp_comp[i], mtk_crtc->mutex))
> -		mtk_mutex_add_comp(mtk_crtc->mutex, mtk_crtc->ddp_comp[i]->id);
> -	mtk_mutex_enable(mtk_crtc->mutex);
> +	mmsys = mtk_crtc->ddp_comp_sys[i];
> +	if (!mtk_ddp_comp_add(mtk_crtc->ddp_comp[i], mtk_crtc->mutex[mmsys]))
> +		mtk_mutex_add_comp(mtk_crtc->mutex[mmsys], mtk_crtc->ddp_comp[i]->id);
> +
> +	/* Need to set sof source for all mmsys mutexs in this crtc */
> +	for (j = 0; j < MAX_MMSYS; j++)
> +		if (mtk_crtc->exist[j] && mtk_crtc->mutex[j])
> +			mtk_mutex_write_comp_sof(mtk_crtc->mutex[j], mtk_crtc->ddp_comp[i]->id);
> +
> +	for (i = 0; i < MAX_MMSYS; i++)
> +		if (mtk_crtc->exist[i] && mtk_crtc->mutex[i])
> +			mtk_mutex_enable(mtk_crtc->mutex[i]);
>  
>  	for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
>  		struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[i];
> @@ -394,7 +449,11 @@ static int mtk_crtc_ddp_hw_init(struct mtk_crtc *mtk_crtc)
>  		if (i == 1)
>  			mtk_ddp_comp_bgclr_in_on(comp);
>  
> -		mtk_ddp_comp_config(comp, width, height, vrefresh, bpc, NULL);
> +		if (mtk_ddp_comp_get_type(comp->id) == MTK_DISP_VIRTUAL)
> +			mtk_mmsys_ddp_config(mtk_crtc->mmsys_dev[mtk_crtc->ddp_comp_sys[i]],
> +					     comp->id, width, height, NULL);
> +		else
> +			mtk_ddp_comp_config(comp, width, height, vrefresh, bpc, NULL);
>  		mtk_ddp_comp_start(comp);
>  	}
>  
> @@ -418,7 +477,10 @@ static int mtk_crtc_ddp_hw_init(struct mtk_crtc *mtk_crtc)
>  	return 0;
>  
>  err_mutex_unprepare:
> -	mtk_mutex_unprepare(mtk_crtc->mutex);
> +	for (i = 0; i < MAX_MMSYS; i++)
> +		if (mtk_crtc->exist[i] && mtk_crtc->mutex[i])
> +			mtk_mutex_unprepare(mtk_crtc->mutex[i]);
> +
>  err_pm_runtime_put:
>  	pm_runtime_put(crtc->dev->dev);
>  	return ret;
> @@ -430,6 +492,7 @@ static void mtk_crtc_ddp_hw_fini(struct mtk_crtc *mtk_crtc)
>  	struct drm_crtc *crtc = &mtk_crtc->base;
>  	unsigned long flags;
>  	int i;
> +	enum mtk_drm_mmsys mmsys;
>  
>  	for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
>  		mtk_ddp_comp_stop(mtk_crtc->ddp_comp[i]);
> @@ -437,27 +500,46 @@ static void mtk_crtc_ddp_hw_fini(struct mtk_crtc *mtk_crtc)
>  			mtk_ddp_comp_bgclr_in_off(mtk_crtc->ddp_comp[i]);
>  	}
>  
> -	for (i = 0; i < mtk_crtc->ddp_comp_nr; i++)
> -		if (!mtk_ddp_comp_remove(mtk_crtc->ddp_comp[i], mtk_crtc->mutex))
> -			mtk_mutex_remove_comp(mtk_crtc->mutex,
> +	for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
> +		mmsys = mtk_crtc->ddp_comp_sys[i];
> +		if (!mtk_ddp_comp_remove(mtk_crtc->ddp_comp[i], mtk_crtc->mutex[mmsys]))
> +			mtk_mutex_remove_comp(mtk_crtc->mutex[mtk_crtc->ddp_comp_sys[i]],
>  					      mtk_crtc->ddp_comp[i]->id);
> -	mtk_mutex_disable(mtk_crtc->mutex);
> +	}
> +	for (i = 0; i < MAX_MMSYS; i++)
> +		if (mtk_crtc->exist[i] && mtk_crtc->mutex[i])
> +			mtk_mutex_disable(mtk_crtc->mutex[i]);
> +
>  	for (i = 0; i < mtk_crtc->ddp_comp_nr - 1; i++) {
> -		if (!mtk_ddp_comp_disconnect(mtk_crtc->ddp_comp[i], mtk_crtc->mmsys_dev,
> -					     mtk_crtc->ddp_comp[i + 1]->id))
> -			mtk_mmsys_ddp_disconnect(mtk_crtc->mmsys_dev,
> -						 mtk_crtc->ddp_comp[i]->id,
> -						 mtk_crtc->ddp_comp[i + 1]->id);
> -		if (!mtk_ddp_comp_remove(mtk_crtc->ddp_comp[i], mtk_crtc->mutex))
> -			mtk_mutex_remove_comp(mtk_crtc->mutex,
> +		struct mtk_ddp_comp *comp;
> +		unsigned int curr, next;
> +
> +		comp = mtk_crtc->ddp_comp[i];
> +		curr = mtk_crtc->ddp_comp[i]->id;
> +		next = mtk_crtc->ddp_comp[i + 1]->id;
> +		mmsys = mtk_crtc->ddp_comp_sys[i];
> +		if (!mtk_ddp_comp_disconnect(comp, mtk_crtc->mmsys_dev[mmsys], next))
> +			mtk_mmsys_ddp_disconnect(mtk_crtc->mmsys_dev[mmsys], curr, next);
> +		if (!mtk_ddp_comp_remove(comp, mtk_crtc->mutex[mmsys]))
> +			mtk_mutex_remove_comp(mtk_crtc->mutex[mtk_crtc->ddp_comp_sys[i]],
>  					      mtk_crtc->ddp_comp[i]->id);
>  	}
> -	if (!mtk_ddp_comp_remove(mtk_crtc->ddp_comp[i], mtk_crtc->mutex))
> -		mtk_mutex_remove_comp(mtk_crtc->mutex, mtk_crtc->ddp_comp[i]->id);
> +
> +	mmsys = mtk_crtc->ddp_comp_sys[i];
> +	if (!mtk_ddp_comp_remove(mtk_crtc->ddp_comp[i], mtk_crtc->mutex[mmsys]))
> +		mtk_mutex_remove_comp(mtk_crtc->mutex[mmsys], mtk_crtc->ddp_comp[i]->id);
> +
>  	mtk_crtc_ddp_clk_disable(mtk_crtc);
> -	mtk_mutex_unprepare(mtk_crtc->mutex);
>  
> -	pm_runtime_put(drm->dev);
> +	for (i = 0; i < MAX_MMSYS; i++)
> +		if (mtk_crtc->exist[i] && mtk_crtc->mutex[i])
> +			mtk_mutex_unprepare(mtk_crtc->mutex[i]);
> +
> +	for (i = 0; i < MAX_MMSYS; i++)
> +		if (mtk_crtc->exist[i])
> +			mtk_mmsys_top_clk_disable(mtk_crtc->mmsys_dev[i]);
> +
> +	pm_runtime_put_sync(drm->dev);
>  
>  	if (crtc->state->event && !crtc->state->active) {
>  		spin_lock_irqsave(&crtc->dev->event_lock, flags);
> @@ -581,9 +663,15 @@ static void mtk_crtc_update_config(struct mtk_crtc *mtk_crtc, bool needs_vblank)
>  		mtk_crtc->pending_async_planes = true;
>  
>  	if (priv->data->shadow_register) {
> -		mtk_mutex_acquire(mtk_crtc->mutex);
> +		for (i = 0; i < MAX_MMSYS; i++)
> +			if (mtk_crtc->exist[i] && mtk_crtc->mutex[i])
> +				mtk_mutex_acquire(mtk_crtc->mutex[i]);
> +
>  		mtk_crtc_ddp_config(crtc, NULL);
> -		mtk_mutex_release(mtk_crtc->mutex);
> +
> +		for (i = 0; i < MAX_MMSYS; i++)
> +			if (mtk_crtc->exist[i] && mtk_crtc->mutex[i])
> +				mtk_mutex_release(mtk_crtc->mutex[i]);
>  	}
>  #if IS_REACHABLE(CONFIG_MTK_CMDQ)
>  	if (mtk_crtc->cmdq_client.chan) {
> @@ -659,6 +747,7 @@ static void mtk_crtc_update_output(struct drm_crtc *crtc,
>  {
>  	int crtc_index = drm_crtc_index(crtc);
>  	int i;
> +	unsigned int mmsys;
>  	struct device *dev;
>  	struct drm_crtc_state *crtc_state = state->crtcs[crtc_index].new_state;
>  	struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc);
> @@ -671,7 +760,8 @@ static void mtk_crtc_update_output(struct drm_crtc *crtc,
>  	if (!mtk_crtc->num_conn_routes)
>  		return;
>  
> -	priv = ((struct mtk_drm_private *)crtc->dev->dev_private)->all_drm_private[crtc_index];
> +	mmsys = mtk_crtc->conn_routes_sys;
> +	priv = ((struct mtk_drm_private *)crtc->dev->dev_private)->all_drm_private[mmsys];
>  	dev = priv->dev;
>  
>  	dev_dbg(dev, "connector change:%d, encoder mask:0x%x for crtc:%d\n",
> @@ -684,6 +774,8 @@ static void mtk_crtc_update_output(struct drm_crtc *crtc,
>  		if (comp->encoder_index >= 0 &&
>  		    (encoder_mask & BIT(comp->encoder_index))) {
>  			mtk_crtc->ddp_comp[mtk_crtc->ddp_comp_nr - 1] = comp;
> +			mtk_crtc->ddp_comp_sys[mtk_crtc->ddp_comp_nr - 1] = mmsys;
> +			mtk_crtc->exist[mmsys] = true;
>  			dev_dbg(dev, "Add comp_id: %d at path index %d\n",
>  				comp->id, mtk_crtc->ddp_comp_nr - 1);
>  			break;
> @@ -720,13 +812,35 @@ static void mtk_crtc_atomic_enable(struct drm_crtc *crtc,
>  	struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc);
>  	struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[0];
>  	int ret;
> +	int i, j;
> +	int mmsys_cnt = 0;
>  
>  	DRM_DEBUG_DRIVER("%s %d\n", __func__, crtc->base.id);
>  
> -	ret = mtk_ddp_comp_power_on(comp);
> -	if (ret < 0) {
> -		DRM_DEV_ERROR(comp->dev, "Failed to enable power domain: %d\n", ret);
> -		return;
> +	for (i = 0; i < MAX_MMSYS; i++)
> +		if (mtk_crtc->exist[i])
> +			mmsys_cnt++;
> +
> +	if (mmsys_cnt == 1) {
> +		ret = pm_runtime_resume_and_get(comp->dev);
> +		if (ret < 0) {
> +			DRM_DEV_ERROR(comp->dev, "Failed to enable power domain: %d\n", ret);
> +			return;
> +		}
> +	} else {
> +		for (i = 0; i < MAX_MMSYS; i++) {
> +			if (!mtk_crtc->exist[i])
> +				continue;
> +			ret = pm_runtime_resume_and_get(mtk_crtc->mmsys_dev[i]);
> +			if (ret < 0) {
> +				DRM_DEV_ERROR(mtk_crtc->mmsys_dev[i],
> +					      "Failed to enable power domain: %d\n", ret);
> +				for (j = i - 1; j >= 0; j--)
> +					if (mtk_crtc->exist[i])
> +						pm_runtime_put(comp->dev);
> +				return;
> +			}
> +		}
>  	}
>  
>  	mtk_crtc_update_output(crtc, state);
> @@ -746,12 +860,17 @@ static void mtk_crtc_atomic_disable(struct drm_crtc *crtc,
>  {
>  	struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc);
>  	struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[0];
> -	int i;
> +	int i, ret;
> +	int mmsys_cnt = 0;
>  
>  	DRM_DEBUG_DRIVER("%s %d\n", __func__, crtc->base.id);
>  	if (!mtk_crtc->enabled)
>  		return;
>  
> +	for (i = 0; i < MAX_MMSYS; i++)
> +		if (mtk_crtc->exist[i])
> +			mmsys_cnt++;
> +
>  	/* Set all pending plane state to disabled */
>  	for (i = 0; i < mtk_crtc->layer_nr; i++) {
>  		struct drm_plane *plane = &mtk_crtc->planes[i];
> @@ -776,7 +895,21 @@ static void mtk_crtc_atomic_disable(struct drm_crtc *crtc,
>  
>  	drm_crtc_vblank_off(crtc);
>  	mtk_crtc_ddp_hw_fini(mtk_crtc);
> -	mtk_ddp_comp_power_off(comp);
> +
> +	if (mmsys_cnt > 1) {
> +		for (i = 0; i < MAX_MMSYS; i++) {
> +			if (mtk_crtc->exist[i]) {
> +				ret = pm_runtime_put(mtk_crtc->mmsys_dev[i]);
> +				if (ret < 0)
> +					DRM_DEV_ERROR(mtk_crtc->mmsys_dev[i],
> +						      "Failed to disable power domain: %d\n", ret);
> +			}
> +		}
> +	} else {
> +		ret = pm_runtime_put(comp->dev);
> +		if (ret < 0)
> +			DRM_DEV_ERROR(comp->dev, "Failed to disable power domain: %d\n", ret);
> +	}
>  
>  	mtk_crtc->enabled = false;
>  }
> @@ -937,49 +1070,108 @@ struct device *mtk_crtc_dma_dev_get(struct drm_crtc *crtc)
>  	return mtk_crtc->dma_dev;
>  }
>  
> -int mtk_crtc_create(struct drm_device *drm_dev, const unsigned int *path,
> -		    unsigned int path_len, int priv_data_index,
> -		    const struct mtk_drm_route *conn_routes,
> -		    unsigned int num_conn_routes)
> +int mtk_crtc_create(struct drm_device *drm_dev, enum mtk_crtc_path path_sel)
>  {
>  	struct mtk_drm_private *priv = drm_dev->dev_private;
>  	struct device *dev = drm_dev->dev;
>  	struct mtk_crtc *mtk_crtc;
>  	unsigned int num_comp_planes = 0;
>  	int ret;
> -	int i;
> +	int i, j, k;
>  	bool has_ctm = false;
>  	uint gamma_lut_size = 0;
>  	struct drm_crtc *tmp;
>  	int crtc_i = 0;
> -
> -	if (!path)
> -		return 0;
> -
> -	priv = priv->all_drm_private[priv_data_index];
> +	struct mtk_drm_private *subsys_priv;
> +	struct mtk_crtc_comp_info path[DDP_COMPONENT_ID_MAX];
> +	unsigned int path_len = 0;
> +	const struct mtk_drm_route *conn_routes = NULL;
> +	unsigned int num_conn_routes = 0;
> +	enum mtk_drm_mmsys conn_mmsys;
>  
>  	drm_for_each_crtc(tmp, drm_dev)
>  		crtc_i++;
>  
> +	for (j = 0; j < priv->data->mmsys_dev_num; j++) {
> +		for (k = 0; k < MAX_MMSYS; k++) {
> +			const unsigned int *subsys_path;
> +			unsigned int subsys_path_len;
> +			unsigned int order = 0;
> +
> +			subsys_priv = priv->all_drm_private[k];
> +			if (!subsys_priv)
> +				continue;
> +
> +			if (path_sel == CRTC_MAIN) {
> +				subsys_path = subsys_priv->data->main_path;
> +				subsys_path_len = subsys_priv->data->main_len;
> +				order = subsys_priv->data->main_order;
> +			} else if (path_sel == CRTC_EXT) {
> +				subsys_path = subsys_priv->data->ext_path;
> +				subsys_path_len = subsys_priv->data->ext_len;
> +				order = subsys_priv->data->ext_order;
> +			} else if (path_sel == CRTC_THIRD) {
> +				subsys_path = subsys_priv->data->third_path;
> +				subsys_path_len = subsys_priv->data->third_len;
> +				order = subsys_priv->data->third_order;
> +			}
> +
> +			if (subsys_priv->data->num_conn_routes) {
> +				conn_routes = subsys_priv->data->conn_routes;
> +				num_conn_routes = subsys_priv->data->num_conn_routes;
> +				conn_mmsys = subsys_priv->data->mmsys_id;
> +			}
> +
> +			if (j != order)
> +				continue;
> +			if (!subsys_path_len)
> +				continue;
> +
> +			for (i = 0; i < subsys_path_len; i++) {
> +				path[path_len].sys = subsys_priv->data->mmsys_id;
> +				path[path_len].comp_id = subsys_path[i];
> +				path_len++;
> +			}
> +		}
> +	}
> +
> +	if (!path_len)
> +		return 0;
> +
> +	if (num_conn_routes) {
> +		for (i = 0; i < num_conn_routes; i++)
> +			if (conn_routes->crtc_id == crtc_i)
> +				break;
> +		if (i == num_conn_routes) {
> +			num_conn_routes = 0;
> +			conn_routes = NULL;
> +		}
> +	}
> +
>  	for (i = 0; i < path_len; i++) {
> -		enum mtk_ddp_comp_id comp_id = path[i];
> +		enum mtk_ddp_comp_id comp_id = path[i].comp_id;
>  		struct device_node *node;
>  		struct mtk_ddp_comp *comp;
>  
> +		priv = priv->all_drm_private[path[i].sys];
>  		node = priv->comp_node[comp_id];
>  		comp = &priv->ddp_comp[comp_id];
>  
>  		/* Not all drm components have a DTS device node, such as ovl_adaptor,
>  		 * which is the drm bring up sub driver
>  		 */
> -		if (!node && comp_id != DDP_COMPONENT_DRM_OVL_ADAPTOR) {
> +		if (!node && comp_id != DDP_COMPONENT_DRM_OVL_ADAPTOR &&
> +		    comp_id != DDP_COMPONENT_DRM_OVLSYS_ADAPTOR0 &&
> +		    comp_id != DDP_COMPONENT_DRM_OVLSYS_ADAPTOR1 &&
> +		    comp_id != DDP_COMPONENT_DRM_OVLSYS_ADAPTOR2 &&
> +		    mtk_ddp_comp_get_type(comp_id) != MTK_DISP_VIRTUAL) {
>  			dev_info(dev,
>  				"Not creating crtc %d because component %d is disabled or missing\n",
>  				crtc_i, comp_id);
>  			return 0;
>  		}
>  
> -		if (!comp->dev) {
> +		if (!comp->dev && mtk_ddp_comp_get_type(comp_id) != MTK_DISP_VIRTUAL) {
>  			dev_err(dev, "Component %pOF not initialized\n", node);
>  			return -ENODEV;
>  		}
> @@ -989,7 +1181,9 @@ int mtk_crtc_create(struct drm_device *drm_dev, const unsigned int *path,
>  	if (!mtk_crtc)
>  		return -ENOMEM;
>  
> -	mtk_crtc->mmsys_dev = priv->mmsys_dev;
> +	for (i = 0; i < MAX_MMSYS; i++)
> +		if (priv->all_drm_private[i])
> +			mtk_crtc->mmsys_dev[i] = priv->all_drm_private[i]->mmsys_dev;
>  	mtk_crtc->ddp_comp_nr = path_len;
>  	mtk_crtc->ddp_comp = devm_kcalloc(dev,
>  					  mtk_crtc->ddp_comp_nr + (conn_routes ? 1 : 0),
> @@ -998,19 +1192,36 @@ int mtk_crtc_create(struct drm_device *drm_dev, const unsigned int *path,
>  	if (!mtk_crtc->ddp_comp)
>  		return -ENOMEM;
>  
> -	mtk_crtc->mutex = mtk_mutex_get(priv->mutex_dev);
> -	if (IS_ERR(mtk_crtc->mutex)) {
> -		ret = PTR_ERR(mtk_crtc->mutex);
> -		dev_err(dev, "Failed to get mutex: %d\n", ret);
> -		return ret;
> +	mtk_crtc->ddp_comp_sys = devm_kmalloc_array(dev, mtk_crtc->ddp_comp_nr +
> +						    (conn_routes ? 1 : 0),
> +						    sizeof(mtk_crtc->ddp_comp_sys), GFP_KERNEL);
> +	if (!mtk_crtc->ddp_comp_sys)
> +		return -ENOMEM;
> +
> +	for (i = 0; i < MAX_MMSYS; i++) {
> +		if (!priv->all_drm_private[i])
> +			continue;
> +
> +		priv = priv->all_drm_private[i];
> +		mtk_crtc->mutex[i] = mtk_mutex_get(priv->mutex_dev);
> +		if (IS_ERR(mtk_crtc->mutex[i])) {
> +			ret = PTR_ERR(mtk_crtc->mutex[i]);
> +			dev_err(dev, "Failed to get mutex: %d\n", ret);
> +			return ret;
> +		}
>  	}
>  
>  	for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
> -		unsigned int comp_id = path[i];
> +		unsigned int comp_id = path[i].comp_id;
>  		struct mtk_ddp_comp *comp;
>  
> +		priv = priv->all_drm_private[path[i].sys];
>  		comp = &priv->ddp_comp[comp_id];
> +		if (mtk_ddp_comp_get_type(comp_id) == MTK_DISP_VIRTUAL)
> +			comp->id = comp_id;
>  		mtk_crtc->ddp_comp[i] = comp;
> +		mtk_crtc->ddp_comp_sys[i] = path[i].sys;
> +		mtk_crtc->exist[path[i].sys] = true;
>  
>  		if (comp->funcs) {
>  			if (comp->funcs->gamma_set && comp->funcs->gamma_get_lut_size) {
> @@ -1047,8 +1258,10 @@ int mtk_crtc_create(struct drm_device *drm_dev, const unsigned int *path,
>  	 * In the case of ovl_adaptor sub driver, it needs to use the
>  	 * dma_dev_get function to get representative dma dev.
>  	 */
> -	mtk_crtc->dma_dev = mtk_ddp_comp_dma_dev_get(&priv->ddp_comp[path[0]]);
> +	priv = priv->all_drm_private[path[0].sys];
> +	mtk_crtc->dma_dev = mtk_ddp_comp_dma_dev_get(&priv->ddp_comp[path[0].comp_id]);
>  
> +	mtk_crtc->vdisp_ao_dev = priv->vdisp_ao_dev;
>  	ret = mtk_crtc_init(drm_dev, mtk_crtc, crtc_i);
>  	if (ret < 0)
>  		return ret;
> @@ -1061,7 +1274,7 @@ int mtk_crtc_create(struct drm_device *drm_dev, const unsigned int *path,
>  
>  #if IS_REACHABLE(CONFIG_MTK_CMDQ)
>  	i = priv->mbox_index++;
> -	mtk_crtc->cmdq_client.client.dev = mtk_crtc->mmsys_dev;
> +	mtk_crtc->cmdq_client.client.dev = mtk_crtc->mmsys_dev[priv->data->mmsys_id];
>  	mtk_crtc->cmdq_client.client.tx_block = false;
>  	mtk_crtc->cmdq_client.client.knows_txdone = true;
>  	mtk_crtc->cmdq_client.client.rx_callback = ddp_cmdq_cb;
> @@ -1101,6 +1314,7 @@ int mtk_crtc_create(struct drm_device *drm_dev, const unsigned int *path,
>  #endif
>  
>  	if (conn_routes) {
> +		priv = priv->all_drm_private[conn_mmsys];
>  		for (i = 0; i < num_conn_routes; i++) {
>  			unsigned int comp_id = conn_routes[i].route_ddp;
>  			struct device_node *node = priv->comp_node[comp_id];
> @@ -1117,6 +1331,7 @@ int mtk_crtc_create(struct drm_device *drm_dev, const unsigned int *path,
>  			mtk_ddp_comp_encoder_index_set(&priv->ddp_comp[comp_id]);
>  		}
>  
> +		mtk_crtc->conn_routes_sys = conn_mmsys;
>  		mtk_crtc->num_conn_routes = num_conn_routes;
>  		mtk_crtc->conn_routes = conn_routes;
>  
> @@ -1124,5 +1339,10 @@ int mtk_crtc_create(struct drm_device *drm_dev, const unsigned int *path,
>  		mtk_crtc->ddp_comp_nr++;
>  	}
>  
> +	for (i = 0; i < MAX_MMSYS; i++)
> +		if (mtk_crtc->exist[i])
> +			device_link_add(mtk_crtc->base.dev->dev,
> +					priv->all_drm_private[i]->mutex_dev, 0);
> +
>  	return 0;
>  }
> diff --git a/drivers/gpu/drm/mediatek/mtk_crtc.h b/drivers/gpu/drm/mediatek/mtk_crtc.h
> index 388e900b6f4d..255f2823d17a 100644
> --- a/drivers/gpu/drm/mediatek/mtk_crtc.h
> +++ b/drivers/gpu/drm/mediatek/mtk_crtc.h
> @@ -15,10 +15,8 @@
>  #define MTK_MIN_BPC	3
>  
>  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,
> -		    const struct mtk_drm_route *conn_routes,
> -		    unsigned int num_conn_routes);
> +int mtk_crtc_create(struct drm_device *drm_dev,
> +		    enum mtk_crtc_path path_sel);
>  int mtk_crtc_plane_check(struct drm_crtc *crtc, struct drm_plane *plane,
>  			 struct mtk_plane_state *state);
>  void mtk_crtc_async_update(struct drm_crtc *crtc, struct drm_plane *plane,
> diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
> index 492b8d965309..f841184d1e06 100644
> --- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
> +++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
> @@ -464,6 +464,7 @@ static const char * const mtk_ddp_comp_stem[MTK_DDP_COMP_TYPE_MAX] = {
>  	[MTK_DISP_PWM] = "pwm",
>  	[MTK_DISP_RDMA] = "rdma",
>  	[MTK_DISP_UFOE] = "ufoe",
> +	[MTK_DISP_VIRTUAL] = "virtual",
>  	[MTK_DISP_WDMA] = "wdma",
>  	[MTK_DP_INTF] = "dp-intf",
>  	[MTK_DPI] = "dpi",
> @@ -487,6 +488,15 @@ static const struct mtk_ddp_comp_match mtk_ddp_matches[DDP_COMPONENT_DRM_ID_MAX]
>  	[DDP_COMPONENT_COLOR0]		= { MTK_DISP_COLOR,		0, &ddp_color },
>  	[DDP_COMPONENT_COLOR1]		= { MTK_DISP_COLOR,		1, &ddp_color },
>  	[DDP_COMPONENT_DITHER0]		= { MTK_DISP_DITHER,		0, &ddp_dither },
> +	[DDP_COMPONENT_DLI_ASYNC0]      = { MTK_DISP_VIRTUAL,           -1, NULL },
> +	[DDP_COMPONENT_DLI_ASYNC1]      = { MTK_DISP_VIRTUAL,           -1, NULL },
> +	[DDP_COMPONENT_DLI_ASYNC8]      = { MTK_DISP_VIRTUAL,           -1, NULL },
> +	[DDP_COMPONENT_DLI_ASYNC21]     = { MTK_DISP_VIRTUAL,           -1, NULL },
> +	[DDP_COMPONENT_DLI_ASYNC22]     = { MTK_DISP_VIRTUAL,           -1, NULL },
> +	[DDP_COMPONENT_DLI_ASYNC23]     = { MTK_DISP_VIRTUAL,           -1, NULL },
> +	[DDP_COMPONENT_DLO_ASYNC1]      = { MTK_DISP_VIRTUAL,           -1, NULL },
> +	[DDP_COMPONENT_DLO_ASYNC2]      = { MTK_DISP_VIRTUAL,           -1, NULL },
> +	[DDP_COMPONENT_DLO_ASYNC3]      = { MTK_DISP_VIRTUAL,           -1, NULL },
>  	[DDP_COMPONENT_DP_INTF0]	= { MTK_DP_INTF,		0, &ddp_dpi },
>  	[DDP_COMPONENT_DP_INTF1]	= { MTK_DP_INTF,		1, &ddp_dpi },
>  	[DDP_COMPONENT_DPI0]		= { MTK_DPI,			0, &ddp_dpi },
> @@ -494,6 +504,9 @@ static const struct mtk_ddp_comp_match mtk_ddp_matches[DDP_COMPONENT_DRM_ID_MAX]
>  	[DDP_COMPONENT_DRM_OVL_ADAPTOR]	= { MTK_DISP_OVL_ADAPTOR,	0, &ddp_ovl_adaptor },
>  	[DDP_COMPONENT_DRM_OVLSYS_ADAPTOR0] = { MTK_DISP_OVLSYS_ADAPTOR, 0, &ddp_ovlsys_adaptor},
>  	[DDP_COMPONENT_DRM_OVLSYS_ADAPTOR1] = { MTK_DISP_OVLSYS_ADAPTOR, 1, &ddp_ovlsys_adaptor},
> +	[DDP_COMPONENT_DRM_OVLSYS_ADAPTOR0] = { MTK_DISP_OVLSYS_ADAPTOR, 0, &ddp_ovlsys_adaptor},
> +	[DDP_COMPONENT_DRM_OVLSYS_ADAPTOR1] = { MTK_DISP_OVLSYS_ADAPTOR, 1, &ddp_ovlsys_adaptor},
> +	[DDP_COMPONENT_DRM_OVLSYS_ADAPTOR2] = { MTK_DISP_OVLSYS_ADAPTOR, 2, &ddp_ovlsys_adaptor},
>  	[DDP_COMPONENT_DSC0]		= { MTK_DISP_DSC,		0, &ddp_dsc },
>  	[DDP_COMPONENT_DSC1]		= { MTK_DISP_DSC,		1, &ddp_dsc },
>  	[DDP_COMPONENT_DSI0]		= { MTK_DSI,			0, &ddp_dsi },
> @@ -510,7 +523,10 @@ static const struct mtk_ddp_comp_match mtk_ddp_matches[DDP_COMPONENT_DRM_ID_MAX]
>  	[DDP_COMPONENT_OD0]		= { MTK_DISP_OD,		0, &ddp_od },
>  	[DDP_COMPONENT_OD1]		= { MTK_DISP_OD,		1, &ddp_od },
>  	[DDP_COMPONENT_OVL0]		= { MTK_DISP_OVL,		0, &ddp_ovl },
> +	[DDP_COMPONENT_OVL0_DLO_ASYNC5] = { MTK_DISP_VIRTUAL,           -1, NULL },
> +	[DDP_COMPONENT_OVL0_DLO_ASYNC6] = { MTK_DISP_VIRTUAL,           -1, NULL },
>  	[DDP_COMPONENT_OVL1]		= { MTK_DISP_OVL,		1, &ddp_ovl },
> +	[DDP_COMPONENT_OVL1_DLO_ASYNC5] = { MTK_DISP_VIRTUAL,           -1, NULL },
>  	[DDP_COMPONENT_OVL_2L0]		= { MTK_DISP_OVL_2L,		0, &ddp_ovl },
>  	[DDP_COMPONENT_OVL_2L1]		= { MTK_DISP_OVL_2L,		1, &ddp_ovl },
>  	[DDP_COMPONENT_OVL_2L2]		= { MTK_DISP_OVL_2L,		2, &ddp_ovl },
> @@ -567,12 +583,19 @@ static bool mtk_ddp_path_available(const unsigned int *path,
>  {
>  	unsigned int i;
>  
> +	if (!path_len)
> +		return true;
> +
>  	if (!path || !path_len)
>  		return false;
>  
>  	for (i = 0U; i < path_len; i++) {
>  		/* OVL_ADAPTOR doesn't have a device node */
> -		if (path[i] == DDP_COMPONENT_DRM_OVL_ADAPTOR)
> +		if (path[i] == DDP_COMPONENT_DRM_OVL_ADAPTOR ||
> +		    path[i] == DDP_COMPONENT_DRM_OVLSYS_ADAPTOR0 ||
> +			path[i] == DDP_COMPONENT_DRM_OVLSYS_ADAPTOR1 ||
> +			path[i] == DDP_COMPONENT_DRM_OVLSYS_ADAPTOR2 ||
> +			mtk_ddp_comp_get_type(path[i]) == MTK_DISP_VIRTUAL)
>  			continue;
>  
>  		if (!comp_node[path[i]])
> @@ -597,44 +620,81 @@ int mtk_ddp_comp_get_id(struct device_node *node,
>  	return -EINVAL;
>  }
>  
> +enum mtk_ddp_comp_type mtk_ddp_comp_get_type(unsigned int comp_id)
> +{
> +	return mtk_ddp_matches[comp_id].type;
> +}
> +
>  int mtk_find_possible_crtcs(struct drm_device *drm, struct device *dev)
>  {
>  	struct mtk_drm_private *private = drm->dev_private;
>  	const struct mtk_mmsys_driver_data *data;
>  	struct mtk_drm_private *priv_n;
> -	int i = 0, j;
>  	int ret;
> +	int i = 0, j, count = 0;
> +	bool found = false;
>  
>  	for (j = 0; j < private->data->mmsys_dev_num; j++) {
>  		priv_n = private->all_drm_private[j];
>  		data = priv_n->data;
>  
>  		if (mtk_ddp_path_available(data->main_path, data->main_len,
> -					   priv_n->comp_node)) {
> -			if (mtk_ddp_comp_find(dev, data->main_path,
> -					      data->main_len,
> -					      priv_n->ddp_comp))
> -				return BIT(i);
> -			i++;
> -		}
> +					   priv_n->comp_node))
> +			count++;
> +
> +		if (mtk_ddp_comp_find(dev, data->main_path, data->main_len,
> +				      priv_n->ddp_comp))
> +			found = true;
> +	}
> +
> +	if (count == private->data->mmsys_dev_num) {
> +		if (found)
> +			return BIT(i);
> +		i++;
> +	}
> +
> +	count = 0;
> +	found = false;
> +
> +	for (j = 0; j < private->data->mmsys_dev_num; j++) {
> +		priv_n = private->all_drm_private[j];
> +		data = priv_n->data;
>  
>  		if (mtk_ddp_path_available(data->ext_path, data->ext_len,
> -					   priv_n->comp_node)) {
> -			if (mtk_ddp_comp_find(dev, data->ext_path,
> -					      data->ext_len,
> -					      priv_n->ddp_comp))
> -				return BIT(i);
> -			i++;
> -		}
> +					   priv_n->comp_node))
> +			count++;
> +
> +		if (mtk_ddp_comp_find(dev, data->ext_path, data->ext_len,
> +				      priv_n->ddp_comp))
> +			found = true;
> +	}
> +
> +	if (count == private->data->mmsys_dev_num) {
> +		if (found)
> +			return BIT(i);
> +		i++;
> +	}
> +
> +	count = 0;
> +	found = false;
> +
> +	for (j = 0; j < private->data->mmsys_dev_num; j++) {
> +		priv_n = private->all_drm_private[j];
> +		data = priv_n->data;
>  
>  		if (mtk_ddp_path_available(data->third_path, data->third_len,
> -					   priv_n->comp_node)) {
> -			if (mtk_ddp_comp_find(dev, data->third_path,
> -					      data->third_len,
> -					      priv_n->ddp_comp))
> -				return BIT(i);
> -			i++;
> -		}
> +					priv_n->comp_node))
> +			count++;
> +
> +		if (mtk_ddp_comp_find(dev, data->third_path, data->third_len,
> +				      priv_n->ddp_comp))
> +			found = true;
> +	}
> +
> +	if (count == private->data->mmsys_dev_num) {
> +		if (found)
> +			return BIT(i);
> +		i++;
>  	}
>  
>  	ret = mtk_ddp_comp_find_in_route(dev,
> diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
> index ef64ce7a071f..badb42bd4f7c 100644
> --- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
> +++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
> @@ -40,6 +40,7 @@ enum mtk_ddp_comp_type {
>  	MTK_DISP_PWM,
>  	MTK_DISP_RDMA,
>  	MTK_DISP_UFOE,
> +	MTK_DISP_VIRTUAL,
>  	MTK_DISP_WDMA,
>  	MTK_DPI,
>  	MTK_DP_INTF,
> @@ -47,6 +48,7 @@ enum mtk_ddp_comp_type {
>  	MTK_OVL_BLENDER,
>  	MTK_OVL_EXDMA,
>  	MTK_OVL_OUTPROC,
> +	MTK_VDISP_AO,
>  	MTK_DDP_COMP_TYPE_MAX,
>  };
>  
> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
> index 7526bc38bcc7..0665a6feb546 100644
> --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
> +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
> @@ -193,6 +193,10 @@ static const struct mtk_drm_route mt8188_mtk_ddp_main_routes[] = {
>  	{0, DDP_COMPONENT_DSI0},
>  };
>  
> +static const struct mtk_drm_route mt8196_mtk_ddp_routes[] = {
> +	{2, DDP_COMPONENT_DSI0},
> +};
> +
>  static const unsigned int mt8192_mtk_ddp_main[] = {
>  	DDP_COMPONENT_OVL0,
>  	DDP_COMPONENT_OVL_2L0,
> @@ -231,6 +235,50 @@ static const unsigned int mt8195_mtk_ddp_ext[] = {
>  	DDP_COMPONENT_DP_INTF1,
>  };
>  
> +static const unsigned int mt8196_mtk_ddp_ovl0_main[] = {
> +	DDP_COMPONENT_DRM_OVLSYS_ADAPTOR0,
> +	DDP_COMPONENT_OVL0_DLO_ASYNC5,
> +};

Separate MT8196 part to another patch which add support MT8196.
Let this patch not related to specific SoC.

Regards,
CK

> +
> +static const unsigned int mt8196_mtk_ddp_disp0_main[] = {
> +	DDP_COMPONENT_DLI_ASYNC0,
> +	DDP_COMPONENT_DLO_ASYNC1,
> +};
> +
> +static const unsigned int mt8196_mtk_ddp_disp1_main[] = {
> +	DDP_COMPONENT_DLI_ASYNC21,
> +	DDP_COMPONENT_DVO0,
> +};
> +
> +static const unsigned int mt8196_mtk_ddp_ovl0_ext[] = {
> +	DDP_COMPONENT_DRM_OVLSYS_ADAPTOR1,
> +	DDP_COMPONENT_OVL0_DLO_ASYNC6,
> +};
> +
> +static const unsigned int mt8196_mtk_ddp_disp0_ext[] = {
> +	DDP_COMPONENT_DLI_ASYNC1,
> +	DDP_COMPONENT_DLO_ASYNC2,
> +};
> +
> +static const unsigned int mt8196_mtk_ddp_disp1_ext[] = {
> +	DDP_COMPONENT_DLI_ASYNC22,
> +	DDP_COMPONENT_DP_INTF0,
> +};
> +
> +static const unsigned int mt8196_mtk_ddp_ovl1_third[] = {
> +	DDP_COMPONENT_DRM_OVLSYS_ADAPTOR2,
> +	DDP_COMPONENT_OVL1_DLO_ASYNC5,
> +};
> +
> +static const unsigned int mt8196_mtk_ddp_disp0_third[] = {
> +	DDP_COMPONENT_DLI_ASYNC8,
> +	DDP_COMPONENT_DLO_ASYNC3,
> +};
> +
> +static const unsigned int mt8196_mtk_ddp_disp1_third[] = {
> +	DDP_COMPONENT_DLI_ASYNC23,
> +};
> +
>  static const struct mtk_mmsys_driver_data mt2701_mmsys_driver_data = {
>  	.main_path = mt2701_mtk_ddp_main,
>  	.main_len = ARRAY_SIZE(mt2701_mtk_ddp_main),
> @@ -327,6 +375,67 @@ static const struct mtk_mmsys_driver_data mt8195_vdosys1_driver_data = {
>  	.min_height = 1,
>  };
>  
> +static const struct mtk_mmsys_driver_data mt8196_dispsys0_driver_data = {
> +	.main_path = mt8196_mtk_ddp_disp0_main,
> +	.main_len = ARRAY_SIZE(mt8196_mtk_ddp_disp0_main),
> +	.main_order = 1,
> +	.ext_path = mt8196_mtk_ddp_disp0_ext,
> +	.ext_len = ARRAY_SIZE(mt8196_mtk_ddp_disp0_ext),
> +	.ext_order = 1,
> +	.third_path = mt8196_mtk_ddp_disp0_third,
> +	.third_len = ARRAY_SIZE(mt8196_mtk_ddp_disp0_third),
> +	.third_order = 1,
> +	.mmsys_id = DISPSYS0,
> +	.mmsys_dev_num = 4,
> +	.max_width = 8191,
> +	.min_width = 2, /* 2-pixel align when ethdr is bypassed */
> +	.min_height = 1,
> +};
> +
> +static const struct mtk_mmsys_driver_data mt8196_dispsys1_driver_data = {
> +	.main_path = mt8196_mtk_ddp_disp1_main,
> +	.main_len = ARRAY_SIZE(mt8196_mtk_ddp_disp1_main),
> +	.main_order = 2,
> +	.ext_path = mt8196_mtk_ddp_disp1_ext,
> +	.ext_len = ARRAY_SIZE(mt8196_mtk_ddp_disp1_ext),
> +	.ext_order = 2,
> +	.third_path = mt8196_mtk_ddp_disp1_third,
> +	.third_len = ARRAY_SIZE(mt8196_mtk_ddp_disp1_third),
> +	.conn_routes = mt8196_mtk_ddp_routes,
> +	.num_conn_routes = ARRAY_SIZE(mt8196_mtk_ddp_routes),
> +	.third_order = 2,
> +	.mmsys_id = DISPSYS1,
> +	.mmsys_dev_num = 4,
> +	.max_width = 8191,
> +	.min_width = 2, /* 2-pixel align when ethdr is bypassed */
> +	.min_height = 1,
> +};
> +
> +static const struct mtk_mmsys_driver_data mt8196_ovlsys0_driver_data = {
> +	.main_path = mt8196_mtk_ddp_ovl0_main,
> +	.main_len = ARRAY_SIZE(mt8196_mtk_ddp_ovl0_main),
> +	.main_order = 0,
> +	.ext_path = mt8196_mtk_ddp_ovl0_ext,
> +	.ext_len = ARRAY_SIZE(mt8196_mtk_ddp_ovl0_ext),
> +	.ext_order = 0,
> +	.mmsys_id = OVLSYS0,
> +	.mmsys_dev_num = 4,
> +	.max_width = 8191,
> +	.min_width = 2, /* 2-pixel align when ethdr is bypassed */
> +	.min_height = 1,
> +};
> +
> +static const struct mtk_mmsys_driver_data mt8196_ovlsys1_driver_data = {
> +	.third_path = mt8196_mtk_ddp_ovl1_third,
> +	.third_len = ARRAY_SIZE(mt8196_mtk_ddp_ovl1_third),
> +	.third_order = 0,
> +	.mmsys_id = OVLSYS1,
> +	.mmsys_dev_num = 4,
> +	.max_width = 8191,
> +	.min_width = 2, /* 2-pixel align when ethdr is bypassed */
> +	.min_height = 1,
> +};
> +
>  static const struct of_device_id mtk_drm_of_ids[] = {
>  	{ .compatible = "mediatek,mt2701-mmsys",
>  	  .data = &mt2701_mmsys_driver_data},
> @@ -354,6 +463,14 @@ static const struct of_device_id mtk_drm_of_ids[] = {
>  	  .data = &mt8195_vdosys0_driver_data},
>  	{ .compatible = "mediatek,mt8195-vdosys1",
>  	  .data = &mt8195_vdosys1_driver_data},
> +	{ .compatible = "mediatek,mt8196-dispsys0",
> +	  .data = &mt8196_dispsys0_driver_data},
> +	{ .compatible = "mediatek,mt8196-dispsys1",
> +	  .data = &mt8196_dispsys1_driver_data},
> +	{ .compatible = "mediatek,mt8196-ovlsys0",
> +	  .data = &mt8196_ovlsys0_driver_data},
> +	{ .compatible = "mediatek,mt8196-ovlsys1",
> +	  .data = &mt8196_ovlsys1_driver_data},
>  	{ }
>  };
>  MODULE_DEVICE_TABLE(of, mtk_drm_of_ids);
> @@ -368,7 +485,7 @@ static int mtk_drm_match(struct device *dev, const void *data)
>  static bool mtk_drm_get_all_drm_priv(struct device *dev)
>  {
>  	struct mtk_drm_private *drm_priv = dev_get_drvdata(dev);
> -	struct mtk_drm_private *all_drm_priv[MAX_CRTC];
> +	struct mtk_drm_private *all_drm_priv[MAX_MMSYS] = {NULL};
>  	struct mtk_drm_private *temp_drm_priv;
>  	struct device_node *phandle = dev->parent->of_node;
>  	const struct of_device_id *of_id;
> @@ -395,23 +512,18 @@ static bool mtk_drm_get_all_drm_priv(struct device *dev)
>  		if (!temp_drm_priv)
>  			continue;
>  
> -		if (temp_drm_priv->data->main_len)
> -			all_drm_priv[CRTC_MAIN] = temp_drm_priv;
> -		else if (temp_drm_priv->data->ext_len)
> -			all_drm_priv[CRTC_EXT] = temp_drm_priv;
> -		else if (temp_drm_priv->data->third_len)
> -			all_drm_priv[CRTC_THIRD] = temp_drm_priv;
> +		all_drm_priv[temp_drm_priv->data->mmsys_id] = temp_drm_priv;
>  
>  		if (temp_drm_priv->mtk_drm_bound)
>  			cnt++;
>  
> -		if (cnt == MAX_CRTC)
> +		if (cnt == temp_drm_priv->data->mmsys_dev_num)
>  			break;
>  	}
>  
>  	if (drm_priv->data->mmsys_dev_num == cnt) {
> -		for (i = 0; i < cnt; i++)
> -			for (j = 0; j < cnt; j++)
> +		for (i = 0; i < MAX_MMSYS; i++)
> +			for (j = 0; j < MAX_MMSYS; j++)
>  				all_drm_priv[j]->all_drm_private[i] = all_drm_priv[i];
>  
>  		return true;
> @@ -498,7 +610,10 @@ static int mtk_drm_kms_init(struct drm_device *drm)
>  	drm->mode_config.funcs = &mtk_drm_mode_config_funcs;
>  	drm->mode_config.helper_private = &mtk_drm_mode_config_helpers;
>  
> -	for (i = 0; i < private->data->mmsys_dev_num; i++) {
> +	for (i = 0; i < MAX_MMSYS; i++) {
> +		if (!private->all_drm_private[i])
> +			continue;
> +
>  		drm->dev_private = private->all_drm_private[i];
>  		ret = component_bind_all(private->all_drm_private[i]->dev, drm);
>  		if (ret)
> @@ -521,8 +636,10 @@ static int mtk_drm_kms_init(struct drm_device *drm)
>  	 *    third path.
>  	 */
>  	for (i = 0; i < MAX_CRTC; i++) {
> -		for (j = 0; j < private->data->mmsys_dev_num; j++) {
> +		for (j = 0; j < MAX_MMSYS; j++) {
>  			priv_n = private->all_drm_private[j];
> +			if (!priv_n)
> +				continue;
>  
>  			if (priv_n->data->max_width)
>  				drm->mode_config.max_width = priv_n->data->max_width;
> @@ -534,28 +651,23 @@ static int mtk_drm_kms_init(struct drm_device *drm)
>  				drm->mode_config.min_height = priv_n->data->min_height;
>  
>  			if (i == CRTC_MAIN && priv_n->data->main_len) {
> -				ret = mtk_crtc_create(drm, priv_n->data->main_path,
> -						      priv_n->data->main_len, j,
> -						      priv_n->data->conn_routes,
> -						      priv_n->data->num_conn_routes);
> +				ret = mtk_crtc_create(drm, CRTC_MAIN);
>  				if (ret)
>  					goto err_component_unbind;
>  
> -				continue;
> +				break;
>  			} else if (i == CRTC_EXT && priv_n->data->ext_len) {
> -				ret = mtk_crtc_create(drm, priv_n->data->ext_path,
> -						      priv_n->data->ext_len, j, NULL, 0);
> +				ret = mtk_crtc_create(drm, CRTC_EXT);
>  				if (ret)
>  					goto err_component_unbind;
>  
> -				continue;
> +				break;
>  			} else if (i == CRTC_THIRD && priv_n->data->third_len) {
> -				ret = mtk_crtc_create(drm, priv_n->data->third_path,
> -						      priv_n->data->third_len, j, NULL, 0);
> +				ret = mtk_crtc_create(drm, CRTC_THIRD);
>  				if (ret)
>  					goto err_component_unbind;
>  
> -				continue;
> +				break;
>  			}
>  		}
>  	}
> @@ -574,8 +686,9 @@ static int mtk_drm_kms_init(struct drm_device *drm)
>  		goto err_component_unbind;
>  	}
>  
> -	for (i = 0; i < private->data->mmsys_dev_num; i++)
> -		private->all_drm_private[i]->dma_dev = dma_dev;
> +	for (i = 0; i < MAX_MMSYS; i++)
> +		if (private->all_drm_private[i])
> +			private->all_drm_private[i]->dma_dev = dma_dev;
>  
>  	/*
>  	 * Configure the DMA segment size to make sure we get contiguous IOVA
> @@ -593,11 +706,13 @@ static int mtk_drm_kms_init(struct drm_device *drm)
>  	return 0;
>  
>  err_component_unbind:
> -	for (i = 0; i < private->data->mmsys_dev_num; i++)
> -		component_unbind_all(private->all_drm_private[i]->dev, drm);
> +	for (i = 0; i < MAX_MMSYS; i++)
> +		if (private->all_drm_private[i])
> +			component_unbind_all(private->all_drm_private[i]->dev, drm);
>  put_mutex_dev:
> -	for (i = 0; i < private->data->mmsys_dev_num; i++)
> -		put_device(private->all_drm_private[i]->mutex_dev);
> +	for (i = 0; i < MAX_MMSYS; i++)
> +		if (private->all_drm_private[i])
> +			put_device(private->all_drm_private[i]->mutex_dev);
>  
>  	return ret;
>  }
> @@ -661,6 +776,19 @@ static int mtk_drm_bind(struct device *dev)
>  	}
>  
>  	private->mutex_dev = &pdev->dev;
> +
> +	if (private->vdisp_ao_node) {
> +		pdev = of_find_device_by_node(private->vdisp_ao_node);
> +		if (!pdev) {
> +			dev_err(dev, "Waiting for vdisp_ao device %pOF\n",
> +				private->vdisp_ao_node);
> +			of_node_put(private->mutex_node);
> +			of_node_put(private->vdisp_ao_node);
> +			return -EPROBE_DEFER;
> +		}
> +		private->vdisp_ao_dev = &pdev->dev;
> +	}
> +
>  	private->mtk_drm_bound = true;
>  	private->dev = dev;
>  
> @@ -673,8 +801,9 @@ static int mtk_drm_bind(struct device *dev)
>  
>  	private->drm_master = true;
>  	drm->dev_private = private;
> -	for (i = 0; i < private->data->mmsys_dev_num; i++)
> -		private->all_drm_private[i]->drm = drm;
> +	for (i = 0; i < MAX_MMSYS; i++)
> +		if (private->all_drm_private[i])
> +			private->all_drm_private[i]->drm = drm;
>  
>  	ret = mtk_drm_kms_init(drm);
>  	if (ret < 0)
> @@ -771,6 +900,8 @@ static const struct of_device_id mtk_ddp_comp_dt_ids[] = {
>  	  .data = (void *)MTK_DISP_MUTEX },
>  	{ .compatible = "mediatek,mt8195-disp-mutex",
>  	  .data = (void *)MTK_DISP_MUTEX },
> +	{ .compatible = "mediatek,mt8196-disp-mutex",
> +	  .data = (void *)MTK_DISP_MUTEX },
>  	{ .compatible = "mediatek,mt8173-disp-od",
>  	  .data = (void *)MTK_DISP_OD },
>  	{ .compatible = "mediatek,mt2701-disp-ovl",
> @@ -837,6 +968,8 @@ static const struct of_device_id mtk_ddp_comp_dt_ids[] = {
>  	  .data = (void *)MTK_DSI },
>  	{ .compatible = "mediatek,mt8188-dsi",
>  	  .data = (void *)MTK_DSI },
> +	{ .compatible = "mediatek,mt8196-vdisp-ao",
> +	  .data = (void *)MTK_VDISP_AO },
>  	{ }
>  };
>  
> @@ -1111,7 +1244,7 @@ static int mtk_drm_probe(struct platform_device *pdev)
>  		private->data = mtk_drm_data;
>  	};
>  
> -	private->all_drm_private = devm_kmalloc_array(dev, private->data->mmsys_dev_num,
> +	private->all_drm_private = devm_kmalloc_array(dev, MAX_MMSYS,
>  						      sizeof(*private->all_drm_private),
>  						      GFP_KERNEL);
>  	if (!private->all_drm_private)
> @@ -1163,6 +1296,22 @@ static int mtk_drm_probe(struct platform_device *pdev)
>  		component_match_add(dev, &match, compare_dev, &ovl_adaptor->dev);
>  	}
>  
> +	if (mtk_drm_find_mmsys_comp(private, DDP_COMPONENT_DRM_OVLSYS_ADAPTOR2)) {
> +		struct mtk_drm_ovlsys_private ovlsys_priv;
> +
> +		ovlsys_priv.mmsys_dev = private->mmsys_dev;
> +		ovlsys_priv.use_path =
> +			mtk_drm_mmsys_comp_in_path(private, DDP_COMPONENT_DRM_OVLSYS_ADAPTOR2);
> +		ovl_adaptor = platform_device_register_data(dev, "mediatek-disp-ovlsys-adaptor",
> +							    PLATFORM_DEVID_AUTO,
> +							    (void *)&ovlsys_priv,
> +							    sizeof(struct mtk_drm_ovlsys_private));
> +		private->ddp_comp[DDP_COMPONENT_DRM_OVLSYS_ADAPTOR2].dev = &ovl_adaptor->dev;
> +		mtk_ddp_comp_init(NULL, &private->ddp_comp[DDP_COMPONENT_DRM_OVLSYS_ADAPTOR2],
> +				  DDP_COMPONENT_DRM_OVLSYS_ADAPTOR2);
> +		component_match_add(dev, &match, compare_dev, &ovl_adaptor->dev);
> +	}
> +
>  	/* Iterate over sibling DISP function blocks */
>  	for_each_child_of_node(phandle->parent, node) {
>  		enum mtk_ddp_comp_type comp_type;
> @@ -1189,6 +1338,12 @@ static int mtk_drm_probe(struct platform_device *pdev)
>  			continue;
>  		}
>  
> +		if (comp_type == MTK_VDISP_AO) {
> +			private->vdisp_ao_node = of_node_get(node);
> +			dev_dbg(dev, "get vdisp_ao node");
> +			continue;
> +		}
> +
>  		comp_id = mtk_ddp_comp_get_id(node, comp_type);
>  		if (comp_id < 0) {
>  			dev_warn(dev, "Skipping unknown component %pOF\n",
> @@ -1241,6 +1396,9 @@ static int mtk_drm_probe(struct platform_device *pdev)
>  
>  	platform_set_drvdata(pdev, private);
>  
> +	if (!match)
> +		drm_of_component_match_add(dev, &match, component_compare_of, NULL);
> +
>  	ret = component_master_add_with_match(dev, &mtk_drm_ops, match);
>  	if (ret)
>  		goto err_pm;
> @@ -1264,6 +1422,7 @@ static void mtk_drm_remove(struct platform_device *pdev)
>  	component_master_del(&pdev->dev, &mtk_drm_ops);
>  	pm_runtime_disable(&pdev->dev);
>  	of_node_put(private->mutex_node);
> +	of_node_put(private->vdisp_ao_node);
>  	for (i = 0; i < DDP_COMPONENT_DRM_ID_MAX; i++)
>  		of_node_put(private->comp_node[i]);
>  }
> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.h b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
> index aa17e743a1d0..36cfbfa30ff2 100644
> --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.h
> +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
> @@ -13,7 +13,8 @@
>  #define DDP_COMPONENT_DRM_OVL_ADAPTOR (DDP_COMPONENT_ID_MAX + 1)
>  #define DDP_COMPONENT_DRM_OVLSYS_ADAPTOR0 (DDP_COMPONENT_DRM_OVL_ADAPTOR + 1)
>  #define DDP_COMPONENT_DRM_OVLSYS_ADAPTOR1 (DDP_COMPONENT_DRM_OVLSYS_ADAPTOR0 + 1)
> -#define DDP_COMPONENT_DRM_ID_MAX (DDP_COMPONENT_DRM_OVLSYS_ADAPTOR1 + 1)
> +#define DDP_COMPONENT_DRM_OVLSYS_ADAPTOR2 (DDP_COMPONENT_DRM_OVLSYS_ADAPTOR1 + 1)
> +#define DDP_COMPONENT_DRM_ID_MAX (DDP_COMPONENT_DRM_OVLSYS_ADAPTOR2 + 1)
>  
>  enum mtk_crtc_path {
>  	CRTC_MAIN,
> @@ -22,6 +23,14 @@ enum mtk_crtc_path {
>  	MAX_CRTC,
>  };
>  
> +enum mtk_drm_mmsys {
> +	DISPSYS0,
> +	DISPSYS1,
> +	OVLSYS0,
> +	OVLSYS1,
> +	MAX_MMSYS,
> +};
> +
>  struct device;
>  struct device_node;
>  struct drm_crtc;
> @@ -38,10 +47,13 @@ struct mtk_drm_route {
>  struct mtk_mmsys_driver_data {
>  	const unsigned int *main_path;
>  	unsigned int main_len;
> +	unsigned int main_order;
>  	const unsigned int *ext_path;
>  	unsigned int ext_len;
> +	unsigned int ext_order;
>  	const unsigned int *third_path;
>  	unsigned int third_len;
> +	unsigned int third_order;
>  	const struct mtk_drm_route *conn_routes;
>  	unsigned int num_conn_routes;
>  
> @@ -63,6 +75,8 @@ struct mtk_drm_private {
>  	struct device_node *mutex_node;
>  	struct device *mutex_dev;
>  	struct device *mmsys_dev;
> +	struct device_node *vdisp_ao_node;
> +	struct device *vdisp_ao_dev;
>  	struct device_node *comp_node[DDP_COMPONENT_DRM_ID_MAX];
>  	struct mtk_ddp_comp ddp_comp[DDP_COMPONENT_DRM_ID_MAX];
>  	struct mtk_mmsys_driver_data *data;

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/dri-devel/attachments/20250212/fb325c4c/attachment-0001.htm>


More information about the dri-devel mailing list