1 /**************************************************************************
2 * Copyright (c) 2007, Intel Corporation.
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
18 * Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
19 * develop this driver.
21 **************************************************************************/
23 #include <linux/module.h>
24 #include <linux/kernel.h>
25 #include <linux/errno.h>
26 #include <linux/string.h>
28 #include <linux/tty.h>
29 #include <linux/slab.h>
30 #include <linux/delay.h>
32 #include <linux/init.h>
33 #include <linux/console.h>
37 #include <drm/drm_crtc.h>
44 void psb_spank(struct drm_psb_private
*dev_priv
)
46 PSB_WSGX32(_PSB_CS_RESET_BIF_RESET
| _PSB_CS_RESET_DPM_RESET
|
47 _PSB_CS_RESET_TA_RESET
| _PSB_CS_RESET_USE_RESET
|
48 _PSB_CS_RESET_ISP_RESET
| _PSB_CS_RESET_TSP_RESET
|
49 _PSB_CS_RESET_TWOD_RESET
, PSB_CR_SOFT_RESET
);
50 (void) PSB_RSGX32(PSB_CR_SOFT_RESET
);
54 PSB_WSGX32(0, PSB_CR_SOFT_RESET
);
56 PSB_WSGX32(PSB_RSGX32(PSB_CR_BIF_CTRL
) | _PSB_CB_CTRL_CLEAR_FAULT
,
59 (void) PSB_RSGX32(PSB_CR_BIF_CTRL
);
62 PSB_WSGX32(PSB_RSGX32(PSB_CR_BIF_CTRL
) & ~_PSB_CB_CTRL_CLEAR_FAULT
,
64 (void) PSB_RSGX32(PSB_CR_BIF_CTRL
);
65 PSB_WSGX32(dev_priv
->pg
->gatt_start
, PSB_CR_BIF_TWOD_REQ_BASE
);
68 static int psb_2d_wait_available(struct drm_psb_private
*dev_priv
,
71 uint32_t avail
= PSB_RSGX32(PSB_CR_2D_SOCIF
);
72 unsigned long t
= jiffies
+ HZ
;
75 avail
= PSB_RSGX32(PSB_CR_2D_SOCIF
);
76 if (time_after(jiffies
, t
)) {
84 /* FIXME: Remember if we expose the 2D engine to the DRM we need to serialize
85 it with console use */
87 int psbfb_2d_submit(struct drm_psb_private
*dev_priv
, uint32_t *cmdbuf
,
95 submit_size
= (size
< 0x60) ? size
: 0x60;
97 ret
= psb_2d_wait_available(dev_priv
, submit_size
);
102 for (i
= 0; i
< submit_size
; i
+= 4) {
103 PSB_WSGX32(*cmdbuf
++, PSB_SGX_2D_SLAVE_PORT
+ i
);
105 (void)PSB_RSGX32(PSB_SGX_2D_SLAVE_PORT
+ i
- 4);
110 static int psb_accel_2d_fillrect(struct drm_psb_private
*dev_priv
,
111 uint32_t dst_offset
, uint32_t dst_stride
,
112 uint32_t dst_format
, uint16_t dst_x
,
113 uint16_t dst_y
, uint16_t size_x
,
114 uint16_t size_y
, uint32_t fill
)
121 *buf
++ = PSB_2D_FENCE_BH
;
124 PSB_2D_DST_SURF_BH
| dst_format
| (dst_stride
<<
125 PSB_2D_DST_STRIDE_SHIFT
);
131 PSB_2D_COPYORDER_TL2BR
|
132 PSB_2D_DSTCK_DISABLE
|
133 PSB_2D_SRCCK_DISABLE
| PSB_2D_USE_FILL
| PSB_2D_ROP3_PATCOPY
;
135 *buf
++ = fill
<< PSB_2D_FILLCOLOUR_SHIFT
;
137 (dst_x
<< PSB_2D_DST_XSTART_SHIFT
) | (dst_y
<<
138 PSB_2D_DST_YSTART_SHIFT
);
140 (size_x
<< PSB_2D_DST_XSIZE_SHIFT
) | (size_y
<<
141 PSB_2D_DST_YSIZE_SHIFT
);
142 *buf
++ = PSB_2D_FLUSH_BH
;
144 return psbfb_2d_submit(dev_priv
, buffer
, buf
- buffer
);
147 static void psbfb_fillrect_accel(struct fb_info
*info
,
148 const struct fb_fillrect
*r
)
150 struct psb_fbdev
*fbdev
= info
->par
;
151 struct psb_framebuffer
*psbfb
= fbdev
->pfb
;
152 struct drm_device
*dev
= psbfb
->base
.dev
;
153 struct drm_framebuffer
*fb
= fbdev
->psb_fb_helper
.fb
;
154 struct drm_psb_private
*dev_priv
= dev
->dev_private
;
163 offset
= psbfb
->offset
;
168 format
= PSB_2D_DST_332RGB
;
171 format
= PSB_2D_DST_555RGB
;
174 format
= PSB_2D_DST_565RGB
;
178 /* this is wrong but since we don't do blending its okay */
179 format
= PSB_2D_DST_8888ARGB
;
182 /* software fallback */
183 cfb_fillrect(info
, r
);
187 psb_accel_2d_fillrect(dev_priv
,
188 offset
, stride
, format
,
189 r
->dx
, r
->dy
, r
->width
, r
->height
, r
->color
);
192 void psbfb_fillrect(struct fb_info
*info
,
193 const struct fb_fillrect
*rect
)
195 if (unlikely(info
->state
!= FBINFO_STATE_RUNNING
))
198 if (1 || (info
->flags
& FBINFO_HWACCEL_DISABLED
))
199 return cfb_fillrect(info
, rect
);
201 /*psb_check_power_state(dev, PSB_DEVICE_SGX); */
202 psbfb_fillrect_accel(info
, rect
);
203 /* Drop power again here on MRST FIXMEAC */
206 static u32
psb_accel_2d_copy_direction(int xdir
, int ydir
)
209 return (ydir
< 0) ? PSB_2D_COPYORDER_BR2TL
:
210 PSB_2D_COPYORDER_TR2BL
;
212 return (ydir
< 0) ? PSB_2D_COPYORDER_BL2TR
:
213 PSB_2D_COPYORDER_TL2BR
;
217 * @src_offset in bytes
218 * @src_stride in bytes
219 * @src_format psb 2D format defines
220 * @dst_offset in bytes
221 * @dst_stride in bytes
222 * @dst_format psb 2D format defines
223 * @src_x offset in pixels
224 * @src_y offset in pixels
225 * @dst_x offset in pixels
226 * @dst_y offset in pixels
227 * @size_x of the copied area
228 * @size_y of the copied area
230 static int psb_accel_2d_copy(struct drm_psb_private
*dev_priv
,
231 uint32_t src_offset
, uint32_t src_stride
,
232 uint32_t src_format
, uint32_t dst_offset
,
233 uint32_t dst_stride
, uint32_t dst_format
,
234 uint16_t src_x
, uint16_t src_y
,
235 uint16_t dst_x
, uint16_t dst_y
,
236 uint16_t size_x
, uint16_t size_y
)
246 psb_accel_2d_copy_direction(src_x
- dst_x
, src_y
- dst_y
);
248 if (direction
== PSB_2D_COPYORDER_BR2TL
||
249 direction
== PSB_2D_COPYORDER_TR2BL
) {
253 if (direction
== PSB_2D_COPYORDER_BR2TL
||
254 direction
== PSB_2D_COPYORDER_BL2TR
) {
262 PSB_2D_DSTCK_DISABLE
|
263 PSB_2D_SRCCK_DISABLE
|
264 PSB_2D_USE_PAT
| PSB_2D_ROP3_SRCCOPY
| direction
;
266 *buf
++ = PSB_2D_FENCE_BH
;
268 PSB_2D_DST_SURF_BH
| dst_format
| (dst_stride
<<
269 PSB_2D_DST_STRIDE_SHIFT
);
272 PSB_2D_SRC_SURF_BH
| src_format
| (src_stride
<<
273 PSB_2D_SRC_STRIDE_SHIFT
);
276 PSB_2D_SRC_OFF_BH
| (src_x
<< PSB_2D_SRCOFF_XSTART_SHIFT
) |
277 (src_y
<< PSB_2D_SRCOFF_YSTART_SHIFT
);
280 (dst_x
<< PSB_2D_DST_XSTART_SHIFT
) | (dst_y
<<
281 PSB_2D_DST_YSTART_SHIFT
);
283 (size_x
<< PSB_2D_DST_XSIZE_SHIFT
) | (size_y
<<
284 PSB_2D_DST_YSIZE_SHIFT
);
285 *buf
++ = PSB_2D_FLUSH_BH
;
287 return psbfb_2d_submit(dev_priv
, buffer
, buf
- buffer
);
290 static void psbfb_copyarea_accel(struct fb_info
*info
,
291 const struct fb_copyarea
*a
)
293 struct psb_fbdev
*fbdev
= info
->par
;
294 struct psb_framebuffer
*psbfb
= fbdev
->pfb
;
295 struct drm_device
*dev
= psbfb
->base
.dev
;
296 struct drm_framebuffer
*fb
= fbdev
->psb_fb_helper
.fb
;
297 struct drm_psb_private
*dev_priv
= dev
->dev_private
;
306 offset
= psbfb
->offset
;
311 src_format
= PSB_2D_SRC_332RGB
;
312 dst_format
= PSB_2D_DST_332RGB
;
315 src_format
= PSB_2D_SRC_555RGB
;
316 dst_format
= PSB_2D_DST_555RGB
;
319 src_format
= PSB_2D_SRC_565RGB
;
320 dst_format
= PSB_2D_DST_565RGB
;
324 /* this is wrong but since we don't do blending its okay */
325 src_format
= PSB_2D_SRC_8888ARGB
;
326 dst_format
= PSB_2D_DST_8888ARGB
;
329 /* software fallback */
330 cfb_copyarea(info
, a
);
334 psb_accel_2d_copy(dev_priv
,
335 offset
, stride
, src_format
,
336 offset
, stride
, dst_format
,
337 a
->sx
, a
->sy
, a
->dx
, a
->dy
, a
->width
, a
->height
);
340 void psbfb_copyarea(struct fb_info
*info
,
341 const struct fb_copyarea
*region
)
343 if (unlikely(info
->state
!= FBINFO_STATE_RUNNING
))
346 if (info
->flags
& FBINFO_HWACCEL_DISABLED
)
347 return cfb_copyarea(info
, region
);
349 /* psb_check_power_state(dev, PSB_DEVICE_SGX); */
350 psbfb_copyarea_accel(info
, region
);
351 /* Need to power back off here for MRST FIXMEAC */
354 void psbfb_imageblit(struct fb_info
*info
, const struct fb_image
*image
)
357 cfb_imageblit(info
, image
);
360 int psbfb_sync(struct fb_info
*info
)
362 struct psb_fbdev
*fbdev
= info
->par
;
363 struct psb_framebuffer
*psbfb
= fbdev
->pfb
;
364 struct drm_device
*dev
= psbfb
->base
.dev
;
365 struct drm_psb_private
*dev_priv
= dev
->dev_private
;
366 unsigned long _end
= jiffies
+ DRM_HZ
;
370 /* Just a way to quickly test if cmd issue explodes */
374 psbfb_2d_submit(dev_priv
, test
, 1);
377 * First idle the 2D engine.
380 if ((PSB_RSGX32(PSB_CR_2D_SOCIF
) == _PSB_C2_SOCIF_EMPTY
) &&
381 ((PSB_RSGX32(PSB_CR_2D_BLIT_STATUS
) & _PSB_C2B_STATUS_BUSY
) == 0))
385 busy
= (PSB_RSGX32(PSB_CR_2D_SOCIF
) != _PSB_C2_SOCIF_EMPTY
);
387 } while (busy
&& !time_after_eq(jiffies
, _end
));
390 busy
= (PSB_RSGX32(PSB_CR_2D_SOCIF
) != _PSB_C2_SOCIF_EMPTY
);
395 busy
= ((PSB_RSGX32(PSB_CR_2D_BLIT_STATUS
) &
396 _PSB_C2B_STATUS_BUSY
) != 0);
398 } while (busy
&& !time_after_eq(jiffies
, _end
));
400 busy
= ((PSB_RSGX32(PSB_CR_2D_BLIT_STATUS
) &
401 _PSB_C2B_STATUS_BUSY
) != 0);
404 return (busy
) ? -EBUSY
: 0;
408 info->fix.accel = FB_ACCEL_I830;
409 info->flags = FBINFO_DEFAULT;