xref: /OK3568_Linux_fs/kernel/drivers/gpu/drm/gma500/accel_2d.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /**************************************************************************
3*4882a593Smuzhiyun  * Copyright (c) 2007-2011, Intel Corporation.
4*4882a593Smuzhiyun  * All Rights Reserved.
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
7*4882a593Smuzhiyun  * develop this driver.
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  **************************************************************************/
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include <linux/console.h>
12*4882a593Smuzhiyun #include <linux/delay.h>
13*4882a593Smuzhiyun #include <linux/errno.h>
14*4882a593Smuzhiyun #include <linux/init.h>
15*4882a593Smuzhiyun #include <linux/kernel.h>
16*4882a593Smuzhiyun #include <linux/mm.h>
17*4882a593Smuzhiyun #include <linux/module.h>
18*4882a593Smuzhiyun #include <linux/slab.h>
19*4882a593Smuzhiyun #include <linux/string.h>
20*4882a593Smuzhiyun #include <linux/tty.h>
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #include <drm/drm.h>
23*4882a593Smuzhiyun #include <drm/drm_crtc.h>
24*4882a593Smuzhiyun #include <drm/drm_fb_helper.h>
25*4882a593Smuzhiyun #include <drm/drm_fourcc.h>
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun #include "psb_drv.h"
28*4882a593Smuzhiyun #include "psb_reg.h"
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun /**
31*4882a593Smuzhiyun  *	psb_spank		-	reset the 2D engine
32*4882a593Smuzhiyun  *	@dev_priv: our PSB DRM device
33*4882a593Smuzhiyun  *
34*4882a593Smuzhiyun  *	Soft reset the graphics engine and then reload the necessary registers.
35*4882a593Smuzhiyun  *	We use this at initialisation time but it will become relevant for
36*4882a593Smuzhiyun  *	accelerated X later
37*4882a593Smuzhiyun  */
psb_spank(struct drm_psb_private * dev_priv)38*4882a593Smuzhiyun void psb_spank(struct drm_psb_private *dev_priv)
39*4882a593Smuzhiyun {
40*4882a593Smuzhiyun 	PSB_WSGX32(_PSB_CS_RESET_BIF_RESET | _PSB_CS_RESET_DPM_RESET |
41*4882a593Smuzhiyun 		_PSB_CS_RESET_TA_RESET | _PSB_CS_RESET_USE_RESET |
42*4882a593Smuzhiyun 		_PSB_CS_RESET_ISP_RESET | _PSB_CS_RESET_TSP_RESET |
43*4882a593Smuzhiyun 		_PSB_CS_RESET_TWOD_RESET, PSB_CR_SOFT_RESET);
44*4882a593Smuzhiyun 	PSB_RSGX32(PSB_CR_SOFT_RESET);
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun 	msleep(1);
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun 	PSB_WSGX32(0, PSB_CR_SOFT_RESET);
49*4882a593Smuzhiyun 	wmb();
50*4882a593Smuzhiyun 	PSB_WSGX32(PSB_RSGX32(PSB_CR_BIF_CTRL) | _PSB_CB_CTRL_CLEAR_FAULT,
51*4882a593Smuzhiyun 		   PSB_CR_BIF_CTRL);
52*4882a593Smuzhiyun 	wmb();
53*4882a593Smuzhiyun 	(void) PSB_RSGX32(PSB_CR_BIF_CTRL);
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun 	msleep(1);
56*4882a593Smuzhiyun 	PSB_WSGX32(PSB_RSGX32(PSB_CR_BIF_CTRL) & ~_PSB_CB_CTRL_CLEAR_FAULT,
57*4882a593Smuzhiyun 		   PSB_CR_BIF_CTRL);
58*4882a593Smuzhiyun 	(void) PSB_RSGX32(PSB_CR_BIF_CTRL);
59*4882a593Smuzhiyun 	PSB_WSGX32(dev_priv->gtt.gatt_start, PSB_CR_BIF_TWOD_REQ_BASE);
60*4882a593Smuzhiyun }
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun /**
63*4882a593Smuzhiyun  *	psb2_2d_wait_available	-	wait for FIFO room
64*4882a593Smuzhiyun  *	@dev_priv: our DRM device
65*4882a593Smuzhiyun  *	@size: size (in dwords) of the command we want to issue
66*4882a593Smuzhiyun  *
67*4882a593Smuzhiyun  *	Wait until there is room to load the FIFO with our data. If the
68*4882a593Smuzhiyun  *	device is not responding then reset it
69*4882a593Smuzhiyun  */
psb_2d_wait_available(struct drm_psb_private * dev_priv,unsigned size)70*4882a593Smuzhiyun static int psb_2d_wait_available(struct drm_psb_private *dev_priv,
71*4882a593Smuzhiyun 			  unsigned size)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun 	uint32_t avail = PSB_RSGX32(PSB_CR_2D_SOCIF);
74*4882a593Smuzhiyun 	unsigned long t = jiffies + HZ;
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun 	while (avail < size) {
77*4882a593Smuzhiyun 		avail = PSB_RSGX32(PSB_CR_2D_SOCIF);
78*4882a593Smuzhiyun 		if (time_after(jiffies, t)) {
79*4882a593Smuzhiyun 			psb_spank(dev_priv);
80*4882a593Smuzhiyun 			return -EIO;
81*4882a593Smuzhiyun 		}
82*4882a593Smuzhiyun 	}
83*4882a593Smuzhiyun 	return 0;
84*4882a593Smuzhiyun }
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun /**
87*4882a593Smuzhiyun  *	psb_2d_submit		-	submit a 2D command
88*4882a593Smuzhiyun  *	@dev_priv: our DRM device
89*4882a593Smuzhiyun  *	@cmdbuf: command to issue
90*4882a593Smuzhiyun  *	@size: length (in dwords)
91*4882a593Smuzhiyun  *
92*4882a593Smuzhiyun  *	Issue one or more 2D commands to the accelerator. This needs to be
93*4882a593Smuzhiyun  *	serialized later when we add the GEM interfaces for acceleration
94*4882a593Smuzhiyun  */
psbfb_2d_submit(struct drm_psb_private * dev_priv,uint32_t * cmdbuf,unsigned size)95*4882a593Smuzhiyun static int psbfb_2d_submit(struct drm_psb_private *dev_priv, uint32_t *cmdbuf,
96*4882a593Smuzhiyun 								unsigned size)
97*4882a593Smuzhiyun {
98*4882a593Smuzhiyun 	int ret = 0;
99*4882a593Smuzhiyun 	int i;
100*4882a593Smuzhiyun 	unsigned submit_size;
101*4882a593Smuzhiyun 	unsigned long flags;
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 	spin_lock_irqsave(&dev_priv->lock_2d, flags);
104*4882a593Smuzhiyun 	while (size > 0) {
105*4882a593Smuzhiyun 		submit_size = (size < 0x60) ? size : 0x60;
106*4882a593Smuzhiyun 		size -= submit_size;
107*4882a593Smuzhiyun 		ret = psb_2d_wait_available(dev_priv, submit_size);
108*4882a593Smuzhiyun 		if (ret)
109*4882a593Smuzhiyun 			break;
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 		submit_size <<= 2;
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 		for (i = 0; i < submit_size; i += 4)
114*4882a593Smuzhiyun 			PSB_WSGX32(*cmdbuf++, PSB_SGX_2D_SLAVE_PORT + i);
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun 		(void)PSB_RSGX32(PSB_SGX_2D_SLAVE_PORT + i - 4);
117*4882a593Smuzhiyun 	}
118*4882a593Smuzhiyun 	spin_unlock_irqrestore(&dev_priv->lock_2d, flags);
119*4882a593Smuzhiyun 	return ret;
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun /**
124*4882a593Smuzhiyun  *	psb_accel_2d_copy_direction	-	compute blit order
125*4882a593Smuzhiyun  *	@xdir: X direction of move
126*4882a593Smuzhiyun  *	@ydir: Y direction of move
127*4882a593Smuzhiyun  *
128*4882a593Smuzhiyun  *	Compute the correct order setings to ensure that an overlapping blit
129*4882a593Smuzhiyun  *	correctly copies all the pixels.
130*4882a593Smuzhiyun  */
psb_accel_2d_copy_direction(int xdir,int ydir)131*4882a593Smuzhiyun static u32 psb_accel_2d_copy_direction(int xdir, int ydir)
132*4882a593Smuzhiyun {
133*4882a593Smuzhiyun 	if (xdir < 0)
134*4882a593Smuzhiyun 		return (ydir < 0) ? PSB_2D_COPYORDER_BR2TL :
135*4882a593Smuzhiyun 						PSB_2D_COPYORDER_TR2BL;
136*4882a593Smuzhiyun 	else
137*4882a593Smuzhiyun 		return (ydir < 0) ? PSB_2D_COPYORDER_BL2TR :
138*4882a593Smuzhiyun 						PSB_2D_COPYORDER_TL2BR;
139*4882a593Smuzhiyun }
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun /**
142*4882a593Smuzhiyun  *	psb_accel_2d_copy		-	accelerated 2D copy
143*4882a593Smuzhiyun  *	@dev_priv: our DRM device
144*4882a593Smuzhiyun  *	@src_offset in bytes
145*4882a593Smuzhiyun  *	@src_stride in bytes
146*4882a593Smuzhiyun  *	@src_format psb 2D format defines
147*4882a593Smuzhiyun  *	@dst_offset in bytes
148*4882a593Smuzhiyun  *	@dst_stride in bytes
149*4882a593Smuzhiyun  *	@dst_format psb 2D format defines
150*4882a593Smuzhiyun  *	@src_x offset in pixels
151*4882a593Smuzhiyun  *	@src_y offset in pixels
152*4882a593Smuzhiyun  *	@dst_x offset in pixels
153*4882a593Smuzhiyun  *	@dst_y offset in pixels
154*4882a593Smuzhiyun  *	@size_x of the copied area
155*4882a593Smuzhiyun  *	@size_y of the copied area
156*4882a593Smuzhiyun  *
157*4882a593Smuzhiyun  *	Format and issue a 2D accelerated copy command.
158*4882a593Smuzhiyun  */
psb_accel_2d_copy(struct drm_psb_private * dev_priv,uint32_t src_offset,uint32_t src_stride,uint32_t src_format,uint32_t dst_offset,uint32_t dst_stride,uint32_t dst_format,uint16_t src_x,uint16_t src_y,uint16_t dst_x,uint16_t dst_y,uint16_t size_x,uint16_t size_y)159*4882a593Smuzhiyun static int psb_accel_2d_copy(struct drm_psb_private *dev_priv,
160*4882a593Smuzhiyun 			     uint32_t src_offset, uint32_t src_stride,
161*4882a593Smuzhiyun 			     uint32_t src_format, uint32_t dst_offset,
162*4882a593Smuzhiyun 			     uint32_t dst_stride, uint32_t dst_format,
163*4882a593Smuzhiyun 			     uint16_t src_x, uint16_t src_y,
164*4882a593Smuzhiyun 			     uint16_t dst_x, uint16_t dst_y,
165*4882a593Smuzhiyun 			     uint16_t size_x, uint16_t size_y)
166*4882a593Smuzhiyun {
167*4882a593Smuzhiyun 	uint32_t blit_cmd;
168*4882a593Smuzhiyun 	uint32_t buffer[10];
169*4882a593Smuzhiyun 	uint32_t *buf;
170*4882a593Smuzhiyun 	uint32_t direction;
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 	buf = buffer;
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 	direction =
175*4882a593Smuzhiyun 	    psb_accel_2d_copy_direction(src_x - dst_x, src_y - dst_y);
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun 	if (direction == PSB_2D_COPYORDER_BR2TL ||
178*4882a593Smuzhiyun 	    direction == PSB_2D_COPYORDER_TR2BL) {
179*4882a593Smuzhiyun 		src_x += size_x - 1;
180*4882a593Smuzhiyun 		dst_x += size_x - 1;
181*4882a593Smuzhiyun 	}
182*4882a593Smuzhiyun 	if (direction == PSB_2D_COPYORDER_BR2TL ||
183*4882a593Smuzhiyun 	    direction == PSB_2D_COPYORDER_BL2TR) {
184*4882a593Smuzhiyun 		src_y += size_y - 1;
185*4882a593Smuzhiyun 		dst_y += size_y - 1;
186*4882a593Smuzhiyun 	}
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	blit_cmd =
189*4882a593Smuzhiyun 	    PSB_2D_BLIT_BH |
190*4882a593Smuzhiyun 	    PSB_2D_ROT_NONE |
191*4882a593Smuzhiyun 	    PSB_2D_DSTCK_DISABLE |
192*4882a593Smuzhiyun 	    PSB_2D_SRCCK_DISABLE |
193*4882a593Smuzhiyun 	    PSB_2D_USE_PAT | PSB_2D_ROP3_SRCCOPY | direction;
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 	*buf++ = PSB_2D_FENCE_BH;
196*4882a593Smuzhiyun 	*buf++ =
197*4882a593Smuzhiyun 	    PSB_2D_DST_SURF_BH | dst_format | (dst_stride <<
198*4882a593Smuzhiyun 					       PSB_2D_DST_STRIDE_SHIFT);
199*4882a593Smuzhiyun 	*buf++ = dst_offset;
200*4882a593Smuzhiyun 	*buf++ =
201*4882a593Smuzhiyun 	    PSB_2D_SRC_SURF_BH | src_format | (src_stride <<
202*4882a593Smuzhiyun 					       PSB_2D_SRC_STRIDE_SHIFT);
203*4882a593Smuzhiyun 	*buf++ = src_offset;
204*4882a593Smuzhiyun 	*buf++ =
205*4882a593Smuzhiyun 	    PSB_2D_SRC_OFF_BH | (src_x << PSB_2D_SRCOFF_XSTART_SHIFT) |
206*4882a593Smuzhiyun 	    (src_y << PSB_2D_SRCOFF_YSTART_SHIFT);
207*4882a593Smuzhiyun 	*buf++ = blit_cmd;
208*4882a593Smuzhiyun 	*buf++ =
209*4882a593Smuzhiyun 	    (dst_x << PSB_2D_DST_XSTART_SHIFT) | (dst_y <<
210*4882a593Smuzhiyun 						  PSB_2D_DST_YSTART_SHIFT);
211*4882a593Smuzhiyun 	*buf++ =
212*4882a593Smuzhiyun 	    (size_x << PSB_2D_DST_XSIZE_SHIFT) | (size_y <<
213*4882a593Smuzhiyun 						  PSB_2D_DST_YSIZE_SHIFT);
214*4882a593Smuzhiyun 	*buf++ = PSB_2D_FLUSH_BH;
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun 	return psbfb_2d_submit(dev_priv, buffer, buf - buffer);
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun /**
220*4882a593Smuzhiyun  *	psbfb_copyarea_accel	-	copyarea acceleration for /dev/fb
221*4882a593Smuzhiyun  *	@info: our framebuffer
222*4882a593Smuzhiyun  *	@a: copyarea parameters from the framebuffer core
223*4882a593Smuzhiyun  *
224*4882a593Smuzhiyun  *	Perform a 2D copy via the accelerator
225*4882a593Smuzhiyun  */
psbfb_copyarea_accel(struct fb_info * info,const struct fb_copyarea * a)226*4882a593Smuzhiyun static void psbfb_copyarea_accel(struct fb_info *info,
227*4882a593Smuzhiyun 				 const struct fb_copyarea *a)
228*4882a593Smuzhiyun {
229*4882a593Smuzhiyun 	struct drm_fb_helper *fb_helper = info->par;
230*4882a593Smuzhiyun 	struct drm_framebuffer *fb = fb_helper->fb;
231*4882a593Smuzhiyun 	struct drm_device *dev;
232*4882a593Smuzhiyun 	struct drm_psb_private *dev_priv;
233*4882a593Smuzhiyun 	uint32_t offset;
234*4882a593Smuzhiyun 	uint32_t stride;
235*4882a593Smuzhiyun 	uint32_t src_format;
236*4882a593Smuzhiyun 	uint32_t dst_format;
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun 	if (!fb)
239*4882a593Smuzhiyun 		return;
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 	dev = fb->dev;
242*4882a593Smuzhiyun 	dev_priv = dev->dev_private;
243*4882a593Smuzhiyun 	offset = to_gtt_range(fb->obj[0])->offset;
244*4882a593Smuzhiyun 	stride = fb->pitches[0];
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 	switch (fb->format->depth) {
247*4882a593Smuzhiyun 	case 8:
248*4882a593Smuzhiyun 		src_format = PSB_2D_SRC_332RGB;
249*4882a593Smuzhiyun 		dst_format = PSB_2D_DST_332RGB;
250*4882a593Smuzhiyun 		break;
251*4882a593Smuzhiyun 	case 15:
252*4882a593Smuzhiyun 		src_format = PSB_2D_SRC_555RGB;
253*4882a593Smuzhiyun 		dst_format = PSB_2D_DST_555RGB;
254*4882a593Smuzhiyun 		break;
255*4882a593Smuzhiyun 	case 16:
256*4882a593Smuzhiyun 		src_format = PSB_2D_SRC_565RGB;
257*4882a593Smuzhiyun 		dst_format = PSB_2D_DST_565RGB;
258*4882a593Smuzhiyun 		break;
259*4882a593Smuzhiyun 	case 24:
260*4882a593Smuzhiyun 	case 32:
261*4882a593Smuzhiyun 		/* this is wrong but since we don't do blending its okay */
262*4882a593Smuzhiyun 		src_format = PSB_2D_SRC_8888ARGB;
263*4882a593Smuzhiyun 		dst_format = PSB_2D_DST_8888ARGB;
264*4882a593Smuzhiyun 		break;
265*4882a593Smuzhiyun 	default:
266*4882a593Smuzhiyun 		/* software fallback */
267*4882a593Smuzhiyun 		drm_fb_helper_cfb_copyarea(info, a);
268*4882a593Smuzhiyun 		return;
269*4882a593Smuzhiyun 	}
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 	if (!gma_power_begin(dev, false)) {
272*4882a593Smuzhiyun 		drm_fb_helper_cfb_copyarea(info, a);
273*4882a593Smuzhiyun 		return;
274*4882a593Smuzhiyun 	}
275*4882a593Smuzhiyun 	psb_accel_2d_copy(dev_priv,
276*4882a593Smuzhiyun 			  offset, stride, src_format,
277*4882a593Smuzhiyun 			  offset, stride, dst_format,
278*4882a593Smuzhiyun 			  a->sx, a->sy, a->dx, a->dy, a->width, a->height);
279*4882a593Smuzhiyun 	gma_power_end(dev);
280*4882a593Smuzhiyun }
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun /**
283*4882a593Smuzhiyun  *	psbfb_copyarea	-	2D copy interface
284*4882a593Smuzhiyun  *	@info: our framebuffer
285*4882a593Smuzhiyun  *	@region: region to copy
286*4882a593Smuzhiyun  *
287*4882a593Smuzhiyun  *	Copy an area of the framebuffer console either by the accelerator
288*4882a593Smuzhiyun  *	or directly using the cfb helpers according to the request
289*4882a593Smuzhiyun  */
psbfb_copyarea(struct fb_info * info,const struct fb_copyarea * region)290*4882a593Smuzhiyun void psbfb_copyarea(struct fb_info *info,
291*4882a593Smuzhiyun 			   const struct fb_copyarea *region)
292*4882a593Smuzhiyun {
293*4882a593Smuzhiyun 	if (unlikely(info->state != FBINFO_STATE_RUNNING))
294*4882a593Smuzhiyun 		return;
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun 	/* Avoid the 8 pixel erratum */
297*4882a593Smuzhiyun 	if (region->width == 8 || region->height == 8 ||
298*4882a593Smuzhiyun 		(info->flags & FBINFO_HWACCEL_DISABLED))
299*4882a593Smuzhiyun 		return drm_fb_helper_cfb_copyarea(info, region);
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 	psbfb_copyarea_accel(info, region);
302*4882a593Smuzhiyun }
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun /**
305*4882a593Smuzhiyun  *	psbfb_sync	-	synchronize 2D
306*4882a593Smuzhiyun  *	@info: our framebuffer
307*4882a593Smuzhiyun  *
308*4882a593Smuzhiyun  *	Wait for the 2D engine to quiesce so that we can do CPU
309*4882a593Smuzhiyun  *	access to the framebuffer again
310*4882a593Smuzhiyun  */
psbfb_sync(struct fb_info * info)311*4882a593Smuzhiyun int psbfb_sync(struct fb_info *info)
312*4882a593Smuzhiyun {
313*4882a593Smuzhiyun 	struct drm_fb_helper *fb_helper = info->par;
314*4882a593Smuzhiyun 	struct drm_framebuffer *fb = fb_helper->fb;
315*4882a593Smuzhiyun 	struct drm_device *dev = fb->dev;
316*4882a593Smuzhiyun 	struct drm_psb_private *dev_priv = dev->dev_private;
317*4882a593Smuzhiyun 	unsigned long _end = jiffies + HZ;
318*4882a593Smuzhiyun 	int busy = 0;
319*4882a593Smuzhiyun 	unsigned long flags;
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun 	spin_lock_irqsave(&dev_priv->lock_2d, flags);
322*4882a593Smuzhiyun 	/*
323*4882a593Smuzhiyun 	 * First idle the 2D engine.
324*4882a593Smuzhiyun 	 */
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 	if ((PSB_RSGX32(PSB_CR_2D_SOCIF) == _PSB_C2_SOCIF_EMPTY) &&
327*4882a593Smuzhiyun 	    ((PSB_RSGX32(PSB_CR_2D_BLIT_STATUS) & _PSB_C2B_STATUS_BUSY) == 0))
328*4882a593Smuzhiyun 		goto out;
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 	do {
331*4882a593Smuzhiyun 		busy = (PSB_RSGX32(PSB_CR_2D_SOCIF) != _PSB_C2_SOCIF_EMPTY);
332*4882a593Smuzhiyun 		cpu_relax();
333*4882a593Smuzhiyun 	} while (busy && !time_after_eq(jiffies, _end));
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	if (busy)
336*4882a593Smuzhiyun 		busy = (PSB_RSGX32(PSB_CR_2D_SOCIF) != _PSB_C2_SOCIF_EMPTY);
337*4882a593Smuzhiyun 	if (busy)
338*4882a593Smuzhiyun 		goto out;
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun 	do {
341*4882a593Smuzhiyun 		busy = ((PSB_RSGX32(PSB_CR_2D_BLIT_STATUS) &
342*4882a593Smuzhiyun 						_PSB_C2B_STATUS_BUSY) != 0);
343*4882a593Smuzhiyun 		cpu_relax();
344*4882a593Smuzhiyun 	} while (busy && !time_after_eq(jiffies, _end));
345*4882a593Smuzhiyun 	if (busy)
346*4882a593Smuzhiyun 		busy = ((PSB_RSGX32(PSB_CR_2D_BLIT_STATUS) &
347*4882a593Smuzhiyun 					_PSB_C2B_STATUS_BUSY) != 0);
348*4882a593Smuzhiyun 
349*4882a593Smuzhiyun out:
350*4882a593Smuzhiyun 	spin_unlock_irqrestore(&dev_priv->lock_2d, flags);
351*4882a593Smuzhiyun 	return (busy) ? -EBUSY : 0;
352*4882a593Smuzhiyun }
353