Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
i810_accel.c
Go to the documentation of this file.
1 /*-*- linux-c -*-
2  * linux/drivers/video/i810_accel.c -- Hardware Acceleration
3  *
4  * Copyright (C) 2001 Antonino Daplas<[email protected]>
5  * All Rights Reserved
6  *
7  * This file is subject to the terms and conditions of the GNU General Public
8  * License. See the file COPYING in the main directory of this archive for
9  * more details.
10  */
11 #include <linux/kernel.h>
12 #include <linux/string.h>
13 #include <linux/fb.h>
14 
15 #include "i810_regs.h"
16 #include "i810.h"
17 #include "i810_main.h"
18 
19 static u32 i810fb_rop[] = {
20  COLOR_COPY_ROP, /* ROP_COPY */
21  XOR_ROP /* ROP_XOR */
22 };
23 
24 /* Macros */
25 #define PUT_RING(n) { \
26  i810_writel(par->cur_tail, par->iring.virtual, n); \
27  par->cur_tail += 4; \
28  par->cur_tail &= RING_SIZE_MASK; \
29 }
30 
31 extern void flush_cache(void);
32 
33 /************************************************************/
34 
35 /* BLT Engine Routines */
36 static inline void i810_report_error(u8 __iomem *mmio)
37 {
38  printk("IIR : 0x%04x\n"
39  "EIR : 0x%04x\n"
40  "PGTBL_ER: 0x%04x\n"
41  "IPEIR : 0x%04x\n"
42  "IPEHR : 0x%04x\n",
43  i810_readw(IIR, mmio),
44  i810_readb(EIR, mmio),
45  i810_readl(PGTBL_ER, mmio),
46  i810_readl(IPEIR, mmio),
47  i810_readl(IPEHR, mmio));
48 }
49 
59 static inline int wait_for_space(struct fb_info *info, u32 space)
60 {
61  struct i810fb_par *par = info->par;
63  u8 __iomem *mmio = par->mmio_start_virtual;
64 
65  tail = par->cur_tail;
66  while (count--) {
67  head = i810_readl(IRING + 4, mmio) & RBUFFER_HEAD_MASK;
68  if ((tail == head) ||
69  (tail > head &&
70  (par->iring.size - tail + head) >= space) ||
71  (tail < head && (head - tail) >= space)) {
72  return 0;
73  }
74  }
75  printk("ringbuffer lockup!!!\n");
76  i810_report_error(mmio);
77  par->dev_flags |= LOCKUP;
78  info->pixmap.scan_align = 1;
79  return 1;
80 }
81 
90 static inline int wait_for_engine_idle(struct fb_info *info)
91 {
92  struct i810fb_par *par = info->par;
93  u8 __iomem *mmio = par->mmio_start_virtual;
94  int count = WAIT_COUNT;
95 
96  if (wait_for_space(info, par->iring.size)) /* flush */
97  return 1;
98 
99  while((i810_readw(INSTDONE, mmio) & 0x7B) != 0x7B && --count);
100  if (count) return 0;
101 
102  printk("accel engine lockup!!!\n");
103  printk("INSTDONE: 0x%04x\n", i810_readl(INSTDONE, mmio));
104  i810_report_error(mmio);
105  par->dev_flags |= LOCKUP;
106  info->pixmap.scan_align = 1;
107  return 1;
108 }
109 
110 /* begin_iring - prepares the ringbuffer
111  * @space: length of sequence in dwords
112  * @par: pointer to i810fb_par structure
113  *
114  * DESCRIPTION:
115  * Checks/waits for sufficient space in ringbuffer of size
116  * space. Returns the tail of the buffer
117  */
118 static inline u32 begin_iring(struct fb_info *info, u32 space)
119 {
120  struct i810fb_par *par = info->par;
121 
122  if (par->dev_flags & ALWAYS_SYNC)
123  wait_for_engine_idle(info);
124  return wait_for_space(info, space);
125 }
126 
135 static inline void end_iring(struct i810fb_par *par)
136 {
137  u8 __iomem *mmio = par->mmio_start_virtual;
138 
139  i810_writel(IRING, mmio, par->cur_tail);
140 }
141 
161 static inline void source_copy_blit(int dwidth, int dheight, int dpitch,
162  int xdir, int src, int dest, int rop,
163  int blit_bpp, struct fb_info *info)
164 {
165  struct i810fb_par *par = info->par;
166 
167  if (begin_iring(info, 24 + IRING_PAD)) return;
168 
170  PUT_RING(xdir | rop << 16 | dpitch | DYN_COLOR_EN | blit_bpp);
171  PUT_RING(dheight << 16 | dwidth);
172  PUT_RING(dest);
173  PUT_RING(dpitch);
174  PUT_RING(src);
175 
176  end_iring(par);
177 }
178 
195 static inline void color_blit(int width, int height, int pitch, int dest,
196  int rop, int what, int blit_bpp,
197  struct fb_info *info)
198 {
199  struct i810fb_par *par = info->par;
200 
201  if (begin_iring(info, 24 + IRING_PAD)) return;
202 
203  PUT_RING(BLIT | COLOR_BLT | 3);
204  PUT_RING(rop << 16 | pitch | SOLIDPATTERN | DYN_COLOR_EN | blit_bpp);
205  PUT_RING(height << 16 | width);
206  PUT_RING(dest);
207  PUT_RING(what);
208  PUT_RING(NOP);
209 
210  end_iring(par);
211 }
212 
235 static inline void mono_src_copy_imm_blit(int dwidth, int dheight, int dpitch,
236  int dsize, int blit_bpp, int rop,
237  int dest, const u32 *src, int bg,
238  int fg, struct fb_info *info)
239 {
240  struct i810fb_par *par = info->par;
241 
242  if (begin_iring(info, 24 + (dsize << 2) + IRING_PAD)) return;
243 
244  PUT_RING(BLIT | MONO_SOURCE_COPY_IMMEDIATE | (4 + dsize));
245  PUT_RING(DYN_COLOR_EN | blit_bpp | rop << 16 | dpitch);
246  PUT_RING(dheight << 16 | dwidth);
247  PUT_RING(dest);
248  PUT_RING(bg);
249  PUT_RING(fg);
250  while (dsize--)
251  PUT_RING(*src++);
252 
253  end_iring(par);
254 }
255 
256 static inline void load_front(int offset, struct fb_info *info)
257 {
258  struct i810fb_par *par = info->par;
259 
260  if (begin_iring(info, 8 + IRING_PAD)) return;
261 
262  PUT_RING(PARSER | FLUSH);
263  PUT_RING(NOP);
264 
265  end_iring(par);
266 
267  if (begin_iring(info, 8 + IRING_PAD)) return;
268 
269  PUT_RING(PARSER | FRONT_BUFFER | ((par->pitch >> 3) << 8));
270  PUT_RING((par->fb.offset << 12) + offset);
271 
272  end_iring(par);
273 }
274 
284 static inline void i810fb_iring_enable(struct i810fb_par *par, u32 mode)
285 {
286  u32 tmp;
287  u8 __iomem *mmio = par->mmio_start_virtual;
288 
289  tmp = i810_readl(IRING + 12, mmio);
290  if (mode == OFF)
291  tmp &= ~1;
292  else
293  tmp |= 1;
294  flush_cache();
295  i810_writel(IRING + 12, mmio, tmp);
296 }
297 
298 void i810fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
299 {
300  struct i810fb_par *par = info->par;
301  u32 dx, dy, width, height, dest, rop = 0, color = 0;
302 
303  if (!info->var.accel_flags || par->dev_flags & LOCKUP ||
304  par->depth == 4) {
305  cfb_fillrect(info, rect);
306  return;
307  }
308 
309  if (par->depth == 1)
310  color = rect->color;
311  else
312  color = ((u32 *) (info->pseudo_palette))[rect->color];
313 
314  rop = i810fb_rop[rect->rop];
315 
316  dx = rect->dx * par->depth;
317  width = rect->width * par->depth;
318  dy = rect->dy;
319  height = rect->height;
320 
321  dest = info->fix.smem_start + (dy * info->fix.line_length) + dx;
322  color_blit(width, height, info->fix.line_length, dest, rop, color,
323  par->blit_bpp, info);
324 }
325 
326 void i810fb_copyarea(struct fb_info *info, const struct fb_copyarea *region)
327 {
328  struct i810fb_par *par = info->par;
329  u32 sx, sy, dx, dy, pitch, width, height, src, dest, xdir;
330 
331  if (!info->var.accel_flags || par->dev_flags & LOCKUP ||
332  par->depth == 4) {
333  cfb_copyarea(info, region);
334  return;
335  }
336 
337  dx = region->dx * par->depth;
338  sx = region->sx * par->depth;
339  width = region->width * par->depth;
340  sy = region->sy;
341  dy = region->dy;
342  height = region->height;
343 
344  if (dx <= sx) {
345  xdir = INCREMENT;
346  }
347  else {
348  xdir = DECREMENT;
349  sx += width - 1;
350  dx += width - 1;
351  }
352  if (dy <= sy) {
353  pitch = info->fix.line_length;
354  }
355  else {
356  pitch = (-(info->fix.line_length)) & 0xFFFF;
357  sy += height - 1;
358  dy += height - 1;
359  }
360  src = info->fix.smem_start + (sy * info->fix.line_length) + sx;
361  dest = info->fix.smem_start + (dy * info->fix.line_length) + dx;
362 
363  source_copy_blit(width, height, pitch, xdir, src, dest,
364  PAT_COPY_ROP, par->blit_bpp, info);
365 }
366 
367 void i810fb_imageblit(struct fb_info *info, const struct fb_image *image)
368 {
369  struct i810fb_par *par = info->par;
370  u32 fg = 0, bg = 0, size, dst;
371 
372  if (!info->var.accel_flags || par->dev_flags & LOCKUP ||
373  par->depth == 4 || image->depth != 1) {
374  cfb_imageblit(info, image);
375  return;
376  }
377 
378  switch (info->var.bits_per_pixel) {
379  case 8:
380  fg = image->fg_color;
381  bg = image->bg_color;
382  break;
383  case 16:
384  case 24:
385  fg = ((u32 *)(info->pseudo_palette))[image->fg_color];
386  bg = ((u32 *)(info->pseudo_palette))[image->bg_color];
387  break;
388  }
389 
390  dst = info->fix.smem_start + (image->dy * info->fix.line_length) +
391  (image->dx * par->depth);
392 
393  size = (image->width+7)/8 + 1;
394  size &= ~1;
395  size *= image->height;
396  size += 7;
397  size &= ~7;
398  mono_src_copy_imm_blit(image->width * par->depth,
399  image->height, info->fix.line_length,
400  size/4, par->blit_bpp,
401  PAT_COPY_ROP, dst, (u32 *) image->data,
402  bg, fg, info);
403 }
404 
405 int i810fb_sync(struct fb_info *info)
406 {
407  struct i810fb_par *par = info->par;
408 
409  if (!info->var.accel_flags || par->dev_flags & LOCKUP)
410  return 0;
411 
412  return wait_for_engine_idle(info);
413 }
414 
415 void i810fb_load_front(u32 offset, struct fb_info *info)
416 {
417  struct i810fb_par *par = info->par;
418  u8 __iomem *mmio = par->mmio_start_virtual;
419 
420  if (!info->var.accel_flags || par->dev_flags & LOCKUP)
421  i810_writel(DPLYBASE, mmio, par->fb.physical + offset);
422  else
423  load_front(offset, info);
424 }
425 
435 void i810fb_init_ringbuffer(struct fb_info *info)
436 {
437  struct i810fb_par *par = info->par;
438  u32 tmp1, tmp2;
439  u8 __iomem *mmio = par->mmio_start_virtual;
440 
441  wait_for_engine_idle(info);
442  i810fb_iring_enable(par, OFF);
443  i810_writel(IRING, mmio, 0);
444  i810_writel(IRING + 4, mmio, 0);
445  par->cur_tail = 0;
446 
447  tmp2 = i810_readl(IRING + 8, mmio) & ~RBUFFER_START_MASK;
448  tmp1 = par->iring.physical;
449  i810_writel(IRING + 8, mmio, tmp2 | tmp1);
450 
451  tmp1 = i810_readl(IRING + 12, mmio);
452  tmp1 &= ~RBUFFER_SIZE_MASK;
453  tmp2 = (par->iring.size - I810_PAGESIZE) & RBUFFER_SIZE_MASK;
454  i810_writel(IRING + 12, mmio, tmp1 | tmp2);
455  i810fb_iring_enable(par, ON);
456 }