diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-10 14:04:36 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-10 14:04:36 -0500 |
commit | 1a464cbb3d483f2f195b614cffa4aa1b910a0440 (patch) | |
tree | af57dee6436532dbb546b8670e9e1f6910d489b5 /drivers/gpu/drm/gma500/accel_2d.c | |
parent | dbe950f201a8edd353b0bd9079e8d536ee4ce37c (diff) | |
parent | 095f979a539245a46b9e5d600ec9c720b4d928e5 (diff) |
Merge branch 'drm-core-next' of git://people.freedesktop.org/~airlied/linux
* 'drm-core-next' of git://people.freedesktop.org/~airlied/linux: (307 commits)
drm/nouveau/pm: fix build with HWMON off
gma500: silence gcc warnings in mid_get_vbt_data()
drm/ttm: fix condition (and vs or)
drm/radeon: double lock typo in radeon_vm_bo_rmv()
drm/radeon: use after free in radeon_vm_bo_add()
drm/sis|via: don't return stack garbage from free_mem ioctl
drm/radeon/kms: remove pointless CS flags priority struct
drm/radeon/kms: check if vm is supported in VA ioctl
drm: introduce drm_can_sleep and use in intel/radeon drivers. (v2)
radeon: Fix disabling PCI bus mastering on big endian hosts.
ttm: fix agp since ttm tt rework
agp: Fix multi-line warning message whitespace
drm/ttm/dma: Fix accounting error when calling ttm_mem_global_free_page and don't try to free freed pages.
drm/ttm/dma: Only call set_pages_array_wb when the page is not in WB pool.
drm/radeon/kms: sync across multiple rings when doing bo moves v3
drm/radeon/kms: Add support for multi-ring sync in CS ioctl (v2)
drm/radeon: GPU virtual memory support v22
drm: make DRM_UNLOCKED ioctls with their own mutex
drm: no need to hold global mutex for static data
drm/radeon/benchmark: common modes sweep ignores 640x480@32
...
Fix up trivial conflicts in radeon/evergreen.c and vmwgfx/vmwgfx_kms.c
Diffstat (limited to 'drivers/gpu/drm/gma500/accel_2d.c')
-rw-r--r-- | drivers/gpu/drm/gma500/accel_2d.c | 364 |
1 files changed, 364 insertions, 0 deletions
diff --git a/drivers/gpu/drm/gma500/accel_2d.c b/drivers/gpu/drm/gma500/accel_2d.c new file mode 100644 index 00000000000..d5ef1a5793c --- /dev/null +++ b/drivers/gpu/drm/gma500/accel_2d.c | |||
@@ -0,0 +1,364 @@ | |||
1 | /************************************************************************** | ||
2 | * Copyright (c) 2007-2011, Intel Corporation. | ||
3 | * All Rights Reserved. | ||
4 | * | ||
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. | ||
8 | * | ||
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 | ||
12 | * more details. | ||
13 | * | ||
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. | ||
17 | * | ||
18 | * Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to | ||
19 | * develop this driver. | ||
20 | * | ||
21 | **************************************************************************/ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/errno.h> | ||
26 | #include <linux/string.h> | ||
27 | #include <linux/mm.h> | ||
28 | #include <linux/tty.h> | ||
29 | #include <linux/slab.h> | ||
30 | #include <linux/delay.h> | ||
31 | #include <linux/fb.h> | ||
32 | #include <linux/init.h> | ||
33 | #include <linux/console.h> | ||
34 | |||
35 | #include <drm/drmP.h> | ||
36 | #include <drm/drm.h> | ||
37 | #include <drm/drm_crtc.h> | ||
38 | |||
39 | #include "psb_drv.h" | ||
40 | #include "psb_reg.h" | ||
41 | #include "framebuffer.h" | ||
42 | |||
43 | /** | ||
44 | * psb_spank - reset the 2D engine | ||
45 | * @dev_priv: our PSB DRM device | ||
46 | * | ||
47 | * Soft reset the graphics engine and then reload the necessary registers. | ||
48 | * We use this at initialisation time but it will become relevant for | ||
49 | * accelerated X later | ||
50 | */ | ||
51 | void psb_spank(struct drm_psb_private *dev_priv) | ||
52 | { | ||
53 | PSB_WSGX32(_PSB_CS_RESET_BIF_RESET | _PSB_CS_RESET_DPM_RESET | | ||
54 | _PSB_CS_RESET_TA_RESET | _PSB_CS_RESET_USE_RESET | | ||
55 | _PSB_CS_RESET_ISP_RESET | _PSB_CS_RESET_TSP_RESET | | ||
56 | _PSB_CS_RESET_TWOD_RESET, PSB_CR_SOFT_RESET); | ||
57 | PSB_RSGX32(PSB_CR_SOFT_RESET); | ||
58 | |||
59 | msleep(1); | ||
60 | |||
61 | PSB_WSGX32(0, PSB_CR_SOFT_RESET); | ||
62 | wmb(); | ||
63 | PSB_WSGX32(PSB_RSGX32(PSB_CR_BIF_CTRL) | _PSB_CB_CTRL_CLEAR_FAULT, | ||
64 | PSB_CR_BIF_CTRL); | ||
65 | wmb(); | ||
66 | (void) PSB_RSGX32(PSB_CR_BIF_CTRL); | ||
67 | |||
68 | msleep(1); | ||
69 | PSB_WSGX32(PSB_RSGX32(PSB_CR_BIF_CTRL) & ~_PSB_CB_CTRL_CLEAR_FAULT, | ||
70 | PSB_CR_BIF_CTRL); | ||
71 | (void) PSB_RSGX32(PSB_CR_BIF_CTRL); | ||
72 | PSB_WSGX32(dev_priv->gtt.gatt_start, PSB_CR_BIF_TWOD_REQ_BASE); | ||
73 | } | ||
74 | |||
75 | /** | ||
76 | * psb2_2d_wait_available - wait for FIFO room | ||
77 | * @dev_priv: our DRM device | ||
78 | * @size: size (in dwords) of the command we want to issue | ||
79 | * | ||
80 | * Wait until there is room to load the FIFO with our data. If the | ||
81 | * device is not responding then reset it | ||
82 | */ | ||
83 | static int psb_2d_wait_available(struct drm_psb_private *dev_priv, | ||
84 | unsigned size) | ||
85 | { | ||
86 | uint32_t avail = PSB_RSGX32(PSB_CR_2D_SOCIF); | ||
87 | unsigned long t = jiffies + HZ; | ||
88 | |||
89 | while (avail < size) { | ||
90 | avail = PSB_RSGX32(PSB_CR_2D_SOCIF); | ||
91 | if (time_after(jiffies, t)) { | ||
92 | psb_spank(dev_priv); | ||
93 | return -EIO; | ||
94 | } | ||
95 | } | ||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | /** | ||
100 | * psb_2d_submit - submit a 2D command | ||
101 | * @dev_priv: our DRM device | ||
102 | * @cmdbuf: command to issue | ||
103 | * @size: length (in dwords) | ||
104 | * | ||
105 | * Issue one or more 2D commands to the accelerator. This needs to be | ||
106 | * serialized later when we add the GEM interfaces for acceleration | ||
107 | */ | ||
108 | static int psbfb_2d_submit(struct drm_psb_private *dev_priv, uint32_t *cmdbuf, | ||
109 | unsigned size) | ||
110 | { | ||
111 | int ret = 0; | ||
112 | int i; | ||
113 | unsigned submit_size; | ||
114 | unsigned long flags; | ||
115 | |||
116 | spin_lock_irqsave(&dev_priv->lock_2d, flags); | ||
117 | while (size > 0) { | ||
118 | submit_size = (size < 0x60) ? size : 0x60; | ||
119 | size -= submit_size; | ||
120 | ret = psb_2d_wait_available(dev_priv, submit_size); | ||
121 | if (ret) | ||
122 | break; | ||
123 | |||
124 | submit_size <<= 2; | ||
125 | |||
126 | for (i = 0; i < submit_size; i += 4) | ||
127 | PSB_WSGX32(*cmdbuf++, PSB_SGX_2D_SLAVE_PORT + i); | ||
128 | |||
129 | (void)PSB_RSGX32(PSB_SGX_2D_SLAVE_PORT + i - 4); | ||
130 | } | ||
131 | spin_unlock_irqrestore(&dev_priv->lock_2d, flags); | ||
132 | return ret; | ||
133 | } | ||
134 | |||
135 | |||
136 | /** | ||
137 | * psb_accel_2d_copy_direction - compute blit order | ||
138 | * @xdir: X direction of move | ||
139 | * @ydir: Y direction of move | ||
140 | * | ||
141 | * Compute the correct order setings to ensure that an overlapping blit | ||
142 | * correctly copies all the pixels. | ||
143 | */ | ||
144 | static u32 psb_accel_2d_copy_direction(int xdir, int ydir) | ||
145 | { | ||
146 | if (xdir < 0) | ||
147 | return (ydir < 0) ? PSB_2D_COPYORDER_BR2TL : | ||
148 | PSB_2D_COPYORDER_TR2BL; | ||
149 | else | ||
150 | return (ydir < 0) ? PSB_2D_COPYORDER_BL2TR : | ||
151 | PSB_2D_COPYORDER_TL2BR; | ||
152 | } | ||
153 | |||
154 | /** | ||
155 | * psb_accel_2d_copy - accelerated 2D copy | ||
156 | * @dev_priv: our DRM device | ||
157 | * @src_offset in bytes | ||
158 | * @src_stride in bytes | ||
159 | * @src_format psb 2D format defines | ||
160 | * @dst_offset in bytes | ||
161 | * @dst_stride in bytes | ||
162 | * @dst_format psb 2D format defines | ||
163 | * @src_x offset in pixels | ||
164 | * @src_y offset in pixels | ||
165 | * @dst_x offset in pixels | ||
166 | * @dst_y offset in pixels | ||
167 | * @size_x of the copied area | ||
168 | * @size_y of the copied area | ||
169 | * | ||
170 | * Format and issue a 2D accelerated copy command. | ||
171 | */ | ||
172 | static int psb_accel_2d_copy(struct drm_psb_private *dev_priv, | ||
173 | uint32_t src_offset, uint32_t src_stride, | ||
174 | uint32_t src_format, uint32_t dst_offset, | ||
175 | uint32_t dst_stride, uint32_t dst_format, | ||
176 | uint16_t src_x, uint16_t src_y, | ||
177 | uint16_t dst_x, uint16_t dst_y, | ||
178 | uint16_t size_x, uint16_t size_y) | ||
179 | { | ||
180 | uint32_t blit_cmd; | ||
181 | uint32_t buffer[10]; | ||
182 | uint32_t *buf; | ||
183 | uint32_t direction; | ||
184 | |||
185 | buf = buffer; | ||
186 | |||
187 | direction = | ||
188 | psb_accel_2d_copy_direction(src_x - dst_x, src_y - dst_y); | ||
189 | |||
190 | if (direction == PSB_2D_COPYORDER_BR2TL || | ||
191 | direction == PSB_2D_COPYORDER_TR2BL) { | ||
192 | src_x += size_x - 1; | ||
193 | dst_x += size_x - 1; | ||
194 | } | ||
195 | if (direction == PSB_2D_COPYORDER_BR2TL || | ||
196 | direction == PSB_2D_COPYORDER_BL2TR) { | ||
197 | src_y += size_y - 1; | ||
198 | dst_y += size_y - 1; | ||
199 | } | ||
200 | |||
201 | blit_cmd = | ||
202 | PSB_2D_BLIT_BH | | ||
203 | PSB_2D_ROT_NONE | | ||
204 | PSB_2D_DSTCK_DISABLE | | ||
205 | PSB_2D_SRCCK_DISABLE | | ||
206 | PSB_2D_USE_PAT | PSB_2D_ROP3_SRCCOPY | direction; | ||
207 | |||
208 | *buf++ = PSB_2D_FENCE_BH; | ||
209 | *buf++ = | ||
210 | PSB_2D_DST_SURF_BH | dst_format | (dst_stride << | ||
211 | PSB_2D_DST_STRIDE_SHIFT); | ||
212 | *buf++ = dst_offset; | ||
213 | *buf++ = | ||
214 | PSB_2D_SRC_SURF_BH | src_format | (src_stride << | ||
215 | PSB_2D_SRC_STRIDE_SHIFT); | ||
216 | *buf++ = src_offset; | ||
217 | *buf++ = | ||
218 | PSB_2D_SRC_OFF_BH | (src_x << PSB_2D_SRCOFF_XSTART_SHIFT) | | ||
219 | (src_y << PSB_2D_SRCOFF_YSTART_SHIFT); | ||
220 | *buf++ = blit_cmd; | ||
221 | *buf++ = | ||
222 | (dst_x << PSB_2D_DST_XSTART_SHIFT) | (dst_y << | ||
223 | PSB_2D_DST_YSTART_SHIFT); | ||
224 | *buf++ = | ||
225 | (size_x << PSB_2D_DST_XSIZE_SHIFT) | (size_y << | ||
226 | PSB_2D_DST_YSIZE_SHIFT); | ||
227 | *buf++ = PSB_2D_FLUSH_BH; | ||
228 | |||
229 | return psbfb_2d_submit(dev_priv, buffer, buf - buffer); | ||
230 | } | ||
231 | |||
232 | /** | ||
233 | * psbfb_copyarea_accel - copyarea acceleration for /dev/fb | ||
234 | * @info: our framebuffer | ||
235 | * @a: copyarea parameters from the framebuffer core | ||
236 | * | ||
237 | * Perform a 2D copy via the accelerator | ||
238 | */ | ||
239 | static void psbfb_copyarea_accel(struct fb_info *info, | ||
240 | const struct fb_copyarea *a) | ||
241 | { | ||
242 | struct psb_fbdev *fbdev = info->par; | ||
243 | struct psb_framebuffer *psbfb = &fbdev->pfb; | ||
244 | struct drm_device *dev = psbfb->base.dev; | ||
245 | struct drm_framebuffer *fb = fbdev->psb_fb_helper.fb; | ||
246 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
247 | uint32_t offset; | ||
248 | uint32_t stride; | ||
249 | uint32_t src_format; | ||
250 | uint32_t dst_format; | ||
251 | |||
252 | if (!fb) | ||
253 | return; | ||
254 | |||
255 | offset = psbfb->gtt->offset; | ||
256 | stride = fb->pitches[0]; | ||
257 | |||
258 | switch (fb->depth) { | ||
259 | case 8: | ||
260 | src_format = PSB_2D_SRC_332RGB; | ||
261 | dst_format = PSB_2D_DST_332RGB; | ||
262 | break; | ||
263 | case 15: | ||
264 | src_format = PSB_2D_SRC_555RGB; | ||
265 | dst_format = PSB_2D_DST_555RGB; | ||
266 | break; | ||
267 | case 16: | ||
268 | src_format = PSB_2D_SRC_565RGB; | ||
269 | dst_format = PSB_2D_DST_565RGB; | ||
270 | break; | ||
271 | case 24: | ||
272 | case 32: | ||
273 | /* this is wrong but since we don't do blending its okay */ | ||
274 | src_format = PSB_2D_SRC_8888ARGB; | ||
275 | dst_format = PSB_2D_DST_8888ARGB; | ||
276 | break; | ||
277 | default: | ||
278 | /* software fallback */ | ||
279 | cfb_copyarea(info, a); | ||
280 | return; | ||
281 | } | ||
282 | |||
283 | if (!gma_power_begin(dev, false)) { | ||
284 | cfb_copyarea(info, a); | ||
285 | return; | ||
286 | } | ||
287 | psb_accel_2d_copy(dev_priv, | ||
288 | offset, stride, src_format, | ||
289 | offset, stride, dst_format, | ||
290 | a->sx, a->sy, a->dx, a->dy, a->width, a->height); | ||
291 | gma_power_end(dev); | ||
292 | } | ||
293 | |||
294 | /** | ||
295 | * psbfb_copyarea - 2D copy interface | ||
296 | * @info: our framebuffer | ||
297 | * @region: region to copy | ||
298 | * | ||
299 | * Copy an area of the framebuffer console either by the accelerator | ||
300 | * or directly using the cfb helpers according to the request | ||
301 | */ | ||
302 | void psbfb_copyarea(struct fb_info *info, | ||
303 | const struct fb_copyarea *region) | ||
304 | { | ||
305 | if (unlikely(info->state != FBINFO_STATE_RUNNING)) | ||
306 | return; | ||
307 | |||
308 | /* Avoid the 8 pixel erratum */ | ||
309 | if (region->width == 8 || region->height == 8 || | ||
310 | (info->flags & FBINFO_HWACCEL_DISABLED)) | ||
311 | return cfb_copyarea(info, region); | ||
312 | |||
313 | psbfb_copyarea_accel(info, region); | ||
314 | } | ||
315 | |||
316 | /** | ||
317 | * psbfb_sync - synchronize 2D | ||
318 | * @info: our framebuffer | ||
319 | * | ||
320 | * Wait for the 2D engine to quiesce so that we can do CPU | ||
321 | * access to the framebuffer again | ||
322 | */ | ||
323 | int psbfb_sync(struct fb_info *info) | ||
324 | { | ||
325 | struct psb_fbdev *fbdev = info->par; | ||
326 | struct psb_framebuffer *psbfb = &fbdev->pfb; | ||
327 | struct drm_device *dev = psbfb->base.dev; | ||
328 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
329 | unsigned long _end = jiffies + DRM_HZ; | ||
330 | int busy = 0; | ||
331 | unsigned long flags; | ||
332 | |||
333 | spin_lock_irqsave(&dev_priv->lock_2d, flags); | ||
334 | /* | ||
335 | * First idle the 2D engine. | ||
336 | */ | ||
337 | |||
338 | if ((PSB_RSGX32(PSB_CR_2D_SOCIF) == _PSB_C2_SOCIF_EMPTY) && | ||
339 | ((PSB_RSGX32(PSB_CR_2D_BLIT_STATUS) & _PSB_C2B_STATUS_BUSY) == 0)) | ||
340 | goto out; | ||
341 | |||
342 | do { | ||
343 | busy = (PSB_RSGX32(PSB_CR_2D_SOCIF) != _PSB_C2_SOCIF_EMPTY); | ||
344 | cpu_relax(); | ||
345 | } while (busy && !time_after_eq(jiffies, _end)); | ||
346 | |||
347 | if (busy) | ||
348 | busy = (PSB_RSGX32(PSB_CR_2D_SOCIF) != _PSB_C2_SOCIF_EMPTY); | ||
349 | if (busy) | ||
350 | goto out; | ||
351 | |||
352 | do { | ||
353 | busy = ((PSB_RSGX32(PSB_CR_2D_BLIT_STATUS) & | ||
354 | _PSB_C2B_STATUS_BUSY) != 0); | ||
355 | cpu_relax(); | ||
356 | } while (busy && !time_after_eq(jiffies, _end)); | ||
357 | if (busy) | ||
358 | busy = ((PSB_RSGX32(PSB_CR_2D_BLIT_STATUS) & | ||
359 | _PSB_C2B_STATUS_BUSY) != 0); | ||
360 | |||
361 | out: | ||
362 | spin_unlock_irqrestore(&dev_priv->lock_2d, flags); | ||
363 | return (busy) ? -EBUSY : 0; | ||
364 | } | ||