diff options
Diffstat (limited to 'drivers/gpu/drm/armada')
| -rw-r--r-- | drivers/gpu/drm/armada/armada_crtc.c | 47 | ||||
| -rw-r--r-- | drivers/gpu/drm/armada/armada_crtc.h | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/armada/armada_overlay.c | 38 | 
3 files changed, 48 insertions, 39 deletions
diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 2e065facdce7..a0f4d2a2a481 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -168,16 +168,23 @@ static void armada_drm_crtc_update(struct armada_crtc *dcrtc)  void armada_drm_plane_calc_addrs(u32 *addrs, struct drm_framebuffer *fb,  	int x, int y)  { +	const struct drm_format_info *format = fb->format; +	unsigned int num_planes = format->num_planes;  	u32 addr = drm_fb_obj(fb)->dev_addr; -	int num_planes = fb->format->num_planes;  	int i;  	if (num_planes > 3)  		num_planes = 3; -	for (i = 0; i < num_planes; i++) +	addrs[0] = addr + fb->offsets[0] + y * fb->pitches[0] + +		   x * format->cpp[0]; + +	y /= format->vsub; +	x /= format->hsub; + +	for (i = 1; i < num_planes; i++)  		addrs[i] = addr + fb->offsets[i] + y * fb->pitches[i] + -			     x * fb->format->cpp[i]; +			     x * format->cpp[i];  	for (; i < 3; i++)  		addrs[i] = 0;  } @@ -744,15 +751,14 @@ void armada_drm_crtc_plane_disable(struct armada_crtc *dcrtc,  	if (plane->fb)  		drm_framebuffer_put(plane->fb); -	/* Power down the Y/U/V FIFOs */ -	sram_para1 = CFG_PDWN16x66 | CFG_PDWN32x66; -  	/* Power down most RAMs and FIFOs if this is the primary plane */  	if (plane->type == DRM_PLANE_TYPE_PRIMARY) { -		sram_para1 |= CFG_PDWN256x32 | CFG_PDWN256x24 | CFG_PDWN256x8 | -			      CFG_PDWN32x32 | CFG_PDWN64x66; +		sram_para1 = CFG_PDWN256x32 | CFG_PDWN256x24 | CFG_PDWN256x8 | +			     CFG_PDWN32x32 | CFG_PDWN64x66;  		dma_ctrl0_mask = CFG_GRA_ENA;  	} else { +		/* Power down the Y/U/V FIFOs */ +		sram_para1 = CFG_PDWN16x66 | CFG_PDWN32x66;  		dma_ctrl0_mask = CFG_DMA_ENA;  	} @@ -1225,17 +1231,13 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev,  	ret = devm_request_irq(dev, irq, armada_drm_irq, 0, "armada_drm_crtc",  			       dcrtc); -	if (ret < 0) { -		kfree(dcrtc); -		return ret; -	} +	if (ret < 0) +		goto err_crtc;  	if (dcrtc->variant->init) {  		ret = dcrtc->variant->init(dcrtc, dev); -		if (ret) { -			kfree(dcrtc); -			return ret; -		} +		if (ret) +			goto err_crtc;  	}  	/* Ensure AXI pipeline is enabled */ @@ -1246,13 +1248,15 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev,  	dcrtc->crtc.port = port;  	primary = kzalloc(sizeof(*primary), GFP_KERNEL); -	if (!primary) -		return -ENOMEM; +	if (!primary) { +		ret = -ENOMEM; +		goto err_crtc; +	}  	ret = armada_drm_plane_init(primary);  	if (ret) {  		kfree(primary); -		return ret; +		goto err_crtc;  	}  	ret = drm_universal_plane_init(drm, &primary->base, 0, @@ -1263,7 +1267,7 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev,  				       DRM_PLANE_TYPE_PRIMARY, NULL);  	if (ret) {  		kfree(primary); -		return ret; +		goto err_crtc;  	}  	ret = drm_crtc_init_with_planes(drm, &dcrtc->crtc, &primary->base, NULL, @@ -1282,6 +1286,9 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev,  err_crtc_init:  	primary->base.funcs->destroy(&primary->base); +err_crtc: +	kfree(dcrtc); +  	return ret;  } diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h index bab11f483575..bfd3514fbe9b 100644 --- a/drivers/gpu/drm/armada/armada_crtc.h +++ b/drivers/gpu/drm/armada/armada_crtc.h @@ -42,6 +42,8 @@ struct armada_plane_work {  };  struct armada_plane_state { +	u16 src_x; +	u16 src_y;  	u32 src_hw;  	u32 dst_hw;  	u32 dst_yx; diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c index b411b608821a..aba947696178 100644 --- a/drivers/gpu/drm/armada/armada_overlay.c +++ b/drivers/gpu/drm/armada/armada_overlay.c @@ -99,6 +99,7 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,  {  	struct armada_ovl_plane *dplane = drm_to_armada_ovl_plane(plane);  	struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); +	const struct drm_format_info *format;  	struct drm_rect src = {  		.x1 = src_x,  		.y1 = src_y, @@ -117,7 +118,7 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,  	};  	uint32_t val, ctrl0;  	unsigned idx = 0; -	bool visible; +	bool visible, fb_changed;  	int ret;  	trace_armada_ovl_plane_update(plane, crtc, fb, @@ -138,6 +139,18 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,  	if (!visible)  		ctrl0 &= ~CFG_DMA_ENA; +	/* +	 * Shifting a YUV packed format image by one pixel causes the U/V +	 * planes to swap.  Compensate for it by also toggling the UV swap. +	 */ +	format = fb->format; +	if (format->num_planes == 1 && src.x1 >> 16 & (format->hsub - 1)) +		ctrl0 ^= CFG_DMA_MOD(CFG_SWAPUV); + +	fb_changed = plane->fb != fb || +		     dplane->base.state.src_x != src.x1 >> 16 || +	             dplane->base.state.src_y != src.y1 >> 16; +  	if (!dcrtc->plane) {  		dcrtc->plane = plane;  		armada_ovl_update_attr(&dplane->prop, dcrtc); @@ -145,7 +158,7 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,  	/* FIXME: overlay on an interlaced display */  	/* Just updating the position/size? */ -	if (plane->fb == fb && dplane->base.state.ctrl0 == ctrl0) { +	if (!fb_changed && dplane->base.state.ctrl0 == ctrl0) {  		val = (drm_rect_height(&src) & 0xffff0000) |  		      drm_rect_width(&src) >> 16;  		dplane->base.state.src_hw = val; @@ -169,9 +182,8 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,  	if (armada_drm_plane_work_wait(&dplane->base, HZ / 25) == 0)  		armada_drm_plane_work_cancel(dcrtc, &dplane->base); -	if (plane->fb != fb) { -		u32 addrs[3], pixel_format; -		int num_planes, hsub; +	if (fb_changed) { +		u32 addrs[3];  		/*  		 * Take a reference on the new framebuffer - we want to @@ -182,23 +194,11 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,  		if (plane->fb)  			armada_ovl_retire_fb(dplane, plane->fb); -		src_y = src.y1 >> 16; -		src_x = src.x1 >> 16; +		dplane->base.state.src_y = src_y = src.y1 >> 16; +		dplane->base.state.src_x = src_x = src.x1 >> 16;  		armada_drm_plane_calc_addrs(addrs, fb, src_x, src_y); -		pixel_format = fb->format->format; -		hsub = drm_format_horz_chroma_subsampling(pixel_format); -		num_planes = fb->format->num_planes; - -		/* -		 * Annoyingly, shifting a YUYV-format image by one pixel -		 * causes the U/V planes to toggle.  Toggle the UV swap. -		 * (Unfortunately, this causes momentary colour flickering.) -		 */ -		if (src_x & (hsub - 1) && num_planes == 1) -			ctrl0 ^= CFG_DMA_MOD(CFG_SWAPUV); -  		armada_reg_queue_set(dplane->vbl.regs, idx, addrs[0],  				     LCD_SPU_DMA_START_ADDR_Y0);  		armada_reg_queue_set(dplane->vbl.regs, idx, addrs[1],  | 

