diff options
Diffstat (limited to 'drivers/gpu/drm/meson/meson_crtc.c')
| -rw-r--r-- | drivers/gpu/drm/meson/meson_crtc.c | 81 | 
1 files changed, 75 insertions, 6 deletions
| diff --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c index 57ae1c13d1e6..e66b6271ff58 100644 --- a/drivers/gpu/drm/meson/meson_crtc.c +++ b/drivers/gpu/drm/meson/meson_crtc.c @@ -23,7 +23,9 @@  #include "meson_registers.h"  #include "meson_venc.h"  #include "meson_viu.h" +#include "meson_rdma.h"  #include "meson_vpp.h" +#include "meson_osd_afbcd.h"  #define MESON_G12A_VIU_OFFSET	0x5ec0 @@ -35,7 +37,11 @@ struct meson_crtc {  	struct meson_drm *priv;  	void (*enable_osd1)(struct meson_drm *priv);  	void (*enable_vd1)(struct meson_drm *priv); +	void (*enable_osd1_afbc)(struct meson_drm *priv); +	void (*disable_osd1_afbc)(struct meson_drm *priv);  	unsigned int viu_offset; +	bool vsync_forced; +	bool vsync_disabled;  };  #define to_meson_crtc(x) container_of(x, struct meson_crtc, base) @@ -46,6 +52,7 @@ static int meson_crtc_enable_vblank(struct drm_crtc *crtc)  	struct meson_crtc *meson_crtc = to_meson_crtc(crtc);  	struct meson_drm *priv = meson_crtc->priv; +	meson_crtc->vsync_disabled = false;  	meson_venc_enable_vsync(priv);  	return 0; @@ -56,7 +63,10 @@ static void meson_crtc_disable_vblank(struct drm_crtc *crtc)  	struct meson_crtc *meson_crtc = to_meson_crtc(crtc);  	struct meson_drm *priv = meson_crtc->priv; -	meson_venc_disable_vsync(priv); +	if (!meson_crtc->vsync_forced) { +		meson_crtc->vsync_disabled = true; +		meson_venc_disable_vsync(priv); +	}  }  static const struct drm_crtc_funcs meson_crtc_funcs = { @@ -236,6 +246,26 @@ static void meson_crtc_enable_osd1(struct meson_drm *priv)  			    priv->io_base + _REG(VPP_MISC));  } +static void meson_crtc_g12a_enable_osd1_afbc(struct meson_drm *priv) +{ +	writel_relaxed(priv->viu.osd1_blk2_cfg4, +		       priv->io_base + _REG(VIU_OSD1_BLK2_CFG_W4)); + +	writel_bits_relaxed(OSD_MEM_LINEAR_ADDR, OSD_MEM_LINEAR_ADDR, +			    priv->io_base + _REG(VIU_OSD1_CTRL_STAT)); + +	writel_relaxed(priv->viu.osd1_blk1_cfg4, +		       priv->io_base + _REG(VIU_OSD1_BLK1_CFG_W4)); + +	meson_viu_g12a_enable_osd1_afbc(priv); + +	writel_bits_relaxed(OSD_MEM_LINEAR_ADDR, OSD_MEM_LINEAR_ADDR, +			    priv->io_base + _REG(VIU_OSD1_CTRL_STAT)); + +	writel_bits_relaxed(OSD_MALI_SRC_EN, OSD_MALI_SRC_EN, +			    priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W0)); +} +  static void meson_g12a_crtc_enable_osd1(struct meson_drm *priv)  {  	writel_relaxed(priv->viu.osd_blend_din0_scope_h, @@ -281,6 +311,8 @@ void meson_crtc_irq(struct meson_drm *priv)  	if (priv->viu.osd1_enabled && priv->viu.osd1_commit) {  		writel_relaxed(priv->viu.osd1_ctrl_stat,  				priv->io_base + _REG(VIU_OSD1_CTRL_STAT)); +		writel_relaxed(priv->viu.osd1_ctrl_stat2, +				priv->io_base + _REG(VIU_OSD1_CTRL_STAT2));  		writel_relaxed(priv->viu.osd1_blk0_cfg[0],  				priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W0));  		writel_relaxed(priv->viu.osd1_blk0_cfg[1], @@ -291,6 +323,20 @@ void meson_crtc_irq(struct meson_drm *priv)  				priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W3));  		writel_relaxed(priv->viu.osd1_blk0_cfg[4],  				priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W4)); + +		if (priv->viu.osd1_afbcd) { +			if (meson_crtc->enable_osd1_afbc) +				meson_crtc->enable_osd1_afbc(priv); +		} else { +			if (meson_crtc->disable_osd1_afbc) +				meson_crtc->disable_osd1_afbc(priv); +			if (priv->afbcd.ops) { +				priv->afbcd.ops->reset(priv); +				priv->afbcd.ops->disable(priv); +			} +			meson_crtc->vsync_forced = false; +		} +  		writel_relaxed(priv->viu.osd_sc_ctrl0,  				priv->io_base + _REG(VPP_OSD_SC_CTRL0));  		writel_relaxed(priv->viu.osd_sc_i_wh_m1, @@ -312,15 +358,25 @@ void meson_crtc_irq(struct meson_drm *priv)  		writel_relaxed(priv->viu.osd_sc_v_ctrl0,  				priv->io_base + _REG(VPP_OSD_VSC_CTRL0)); -		meson_canvas_config(priv->canvas, priv->canvas_id_osd1, -				priv->viu.osd1_addr, priv->viu.osd1_stride, -				priv->viu.osd1_height, MESON_CANVAS_WRAP_NONE, -				MESON_CANVAS_BLKMODE_LINEAR, 0); +		if (!priv->viu.osd1_afbcd) +			meson_canvas_config(priv->canvas, priv->canvas_id_osd1, +					    priv->viu.osd1_addr, +					    priv->viu.osd1_stride, +					    priv->viu.osd1_height, +					    MESON_CANVAS_WRAP_NONE, +					    MESON_CANVAS_BLKMODE_LINEAR, 0);  		/* Enable OSD1 */  		if (meson_crtc->enable_osd1)  			meson_crtc->enable_osd1(priv); +		if (priv->viu.osd1_afbcd) { +			priv->afbcd.ops->reset(priv); +			priv->afbcd.ops->setup(priv); +			priv->afbcd.ops->enable(priv); +			meson_crtc->vsync_forced = true; +		} +  		priv->viu.osd1_commit = false;  	} @@ -357,7 +413,7 @@ void meson_crtc_irq(struct meson_drm *priv)  					    MESON_CANVAS_WRAP_NONE,  					    MESON_CANVAS_BLKMODE_LINEAR,  					    MESON_CANVAS_ENDIAN_SWAP64); -		}; +		}  		writel_relaxed(priv->viu.vd1_if0_gen_reg,  				priv->io_base + meson_crtc->viu_offset + @@ -543,6 +599,9 @@ void meson_crtc_irq(struct meson_drm *priv)  		priv->viu.vd1_commit = false;  	} +	if (meson_crtc->vsync_disabled) +		return; +  	drm_crtc_handle_vblank(priv->crtc);  	spin_lock_irqsave(&priv->drm->event_lock, flags); @@ -579,10 +638,20 @@ int meson_crtc_create(struct meson_drm *priv)  		meson_crtc->enable_osd1 = meson_g12a_crtc_enable_osd1;  		meson_crtc->enable_vd1 = meson_g12a_crtc_enable_vd1;  		meson_crtc->viu_offset = MESON_G12A_VIU_OFFSET; +		meson_crtc->enable_osd1_afbc = +					meson_crtc_g12a_enable_osd1_afbc; +		meson_crtc->disable_osd1_afbc = +					meson_viu_g12a_disable_osd1_afbc;  		drm_crtc_helper_add(crtc, &meson_g12a_crtc_helper_funcs);  	} else {  		meson_crtc->enable_osd1 = meson_crtc_enable_osd1;  		meson_crtc->enable_vd1 = meson_crtc_enable_vd1; +		if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM)) { +			meson_crtc->enable_osd1_afbc = +					meson_viu_gxm_enable_osd1_afbc; +			meson_crtc->disable_osd1_afbc = +					meson_viu_gxm_disable_osd1_afbc; +		}  		drm_crtc_helper_add(crtc, &meson_crtc_helper_funcs);  	} |