diff options
Diffstat (limited to 'drivers/gpu/drm/mediatek/mtk_drm_plane.c')
| -rw-r--r-- | drivers/gpu/drm/mediatek/mtk_drm_plane.c | 74 | 
1 files changed, 71 insertions, 3 deletions
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_plane.c b/drivers/gpu/drm/mediatek/mtk_drm_plane.c index 2f5e007dd380..d54fbf34b000 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_plane.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_plane.c @@ -11,6 +11,7 @@  #include <drm/drm_fourcc.h>  #include <drm/drm_framebuffer.h>  #include <drm/drm_gem_atomic_helper.h> +#include <linux/align.h>  #include "mtk_drm_crtc.h"  #include "mtk_drm_ddp_comp.h" @@ -32,6 +33,14 @@ static const u32 formats[] = {  	DRM_FORMAT_YUYV,  }; +static const u64 modifiers[] = { +	DRM_FORMAT_MOD_LINEAR, +	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 | +				AFBC_FORMAT_MOD_SPLIT | +				AFBC_FORMAT_MOD_SPARSE), +	DRM_FORMAT_MOD_INVALID, +}; +  static void mtk_plane_reset(struct drm_plane *plane)  {  	struct mtk_plane_state *state; @@ -51,6 +60,7 @@ static void mtk_plane_reset(struct drm_plane *plane)  	state->base.plane = plane;  	state->pending.format = DRM_FORMAT_RGB565; +	state->pending.modifier = DRM_FORMAT_MOD_LINEAR;  }  static struct drm_plane_state *mtk_plane_duplicate_state(struct drm_plane *plane) @@ -71,6 +81,32 @@ static struct drm_plane_state *mtk_plane_duplicate_state(struct drm_plane *plane  	return &state->base;  } +static bool mtk_plane_format_mod_supported(struct drm_plane *plane, +					   uint32_t format, +					   uint64_t modifier) +{ +	if (modifier == DRM_FORMAT_MOD_LINEAR) +		return true; + +	if (modifier != DRM_FORMAT_MOD_ARM_AFBC( +				AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 | +				AFBC_FORMAT_MOD_SPLIT | +				AFBC_FORMAT_MOD_SPARSE)) +		return false; + +	if (format != DRM_FORMAT_XRGB8888 && +	    format != DRM_FORMAT_ARGB8888 && +	    format != DRM_FORMAT_BGRX8888 && +	    format != DRM_FORMAT_BGRA8888 && +	    format != DRM_FORMAT_ABGR8888 && +	    format != DRM_FORMAT_XBGR8888 && +	    format != DRM_FORMAT_RGB888 && +	    format != DRM_FORMAT_BGR888) +		return false; + +	return true; +} +  static void mtk_drm_plane_destroy_state(struct drm_plane *plane,  					struct drm_plane_state *state)  { @@ -119,21 +155,52 @@ static void mtk_plane_update_new_state(struct drm_plane_state *new_state,  	struct drm_gem_object *gem;  	struct mtk_drm_gem_obj *mtk_gem;  	unsigned int pitch, format; +	u64 modifier;  	dma_addr_t addr; +	dma_addr_t hdr_addr = 0; +	unsigned int hdr_pitch = 0;  	gem = fb->obj[0];  	mtk_gem = to_mtk_gem_obj(gem);  	addr = mtk_gem->dma_addr;  	pitch = fb->pitches[0];  	format = fb->format->format; +	modifier = fb->modifier; -	addr += (new_state->src.x1 >> 16) * fb->format->cpp[0]; -	addr += (new_state->src.y1 >> 16) * pitch; +	if (modifier == DRM_FORMAT_MOD_LINEAR) { +		addr += (new_state->src.x1 >> 16) * fb->format->cpp[0]; +		addr += (new_state->src.y1 >> 16) * pitch; +	} else { +		int width_in_blocks = ALIGN(fb->width, AFBC_DATA_BLOCK_WIDTH) +				      / AFBC_DATA_BLOCK_WIDTH; +		int height_in_blocks = ALIGN(fb->height, AFBC_DATA_BLOCK_HEIGHT) +				       / AFBC_DATA_BLOCK_HEIGHT; +		int x_offset_in_blocks = (new_state->src.x1 >> 16) / AFBC_DATA_BLOCK_WIDTH; +		int y_offset_in_blocks = (new_state->src.y1 >> 16) / AFBC_DATA_BLOCK_HEIGHT; +		int hdr_size; + +		hdr_pitch = width_in_blocks * AFBC_HEADER_BLOCK_SIZE; +		pitch = width_in_blocks * AFBC_DATA_BLOCK_WIDTH * +			AFBC_DATA_BLOCK_HEIGHT * fb->format->cpp[0]; + +		hdr_size = ALIGN(hdr_pitch * height_in_blocks, AFBC_HEADER_ALIGNMENT); + +		hdr_addr = addr + hdr_pitch * y_offset_in_blocks + +			   AFBC_HEADER_BLOCK_SIZE * x_offset_in_blocks; +		/* The data plane is offset by 1 additional block. */ +		addr = addr + hdr_size + +		       pitch * y_offset_in_blocks + +		       AFBC_DATA_BLOCK_WIDTH * AFBC_DATA_BLOCK_HEIGHT * +		       fb->format->cpp[0] * (x_offset_in_blocks + 1); +	}  	mtk_plane_state->pending.enable = true;  	mtk_plane_state->pending.pitch = pitch; +	mtk_plane_state->pending.hdr_pitch = hdr_pitch;  	mtk_plane_state->pending.format = format; +	mtk_plane_state->pending.modifier = modifier;  	mtk_plane_state->pending.addr = addr; +	mtk_plane_state->pending.hdr_addr = hdr_addr;  	mtk_plane_state->pending.x = new_state->dst.x1;  	mtk_plane_state->pending.y = new_state->dst.y1;  	mtk_plane_state->pending.width = drm_rect_width(&new_state->dst); @@ -172,6 +239,7 @@ static const struct drm_plane_funcs mtk_plane_funcs = {  	.reset = mtk_plane_reset,  	.atomic_duplicate_state = mtk_plane_duplicate_state,  	.atomic_destroy_state = mtk_drm_plane_destroy_state, +	.format_mod_supported = mtk_plane_format_mod_supported,  };  static int mtk_plane_atomic_check(struct drm_plane *plane, @@ -253,7 +321,7 @@ int mtk_plane_init(struct drm_device *dev, struct drm_plane *plane,  	err = drm_universal_plane_init(dev, plane, possible_crtcs,  				       &mtk_plane_funcs, formats, -				       ARRAY_SIZE(formats), NULL, type, NULL); +				       ARRAY_SIZE(formats), modifiers, type, NULL);  	if (err) {  		DRM_ERROR("failed to initialize plane\n");  		return err;  |