root/drivers/video/fbdev/i810/i810_accel.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. i810_report_error
  2. wait_for_space
  3. wait_for_engine_idle
  4. begin_iring
  5. end_iring
  6. source_copy_blit
  7. color_blit
  8. mono_src_copy_imm_blit
  9. load_front
  10. i810fb_iring_enable
  11. i810fb_fillrect
  12. i810fb_copyarea
  13. i810fb_imageblit
  14. i810fb_sync
  15. i810fb_load_front
  16. i810fb_init_ringbuffer

   1 /*-*- linux-c -*-
   2  *  linux/drivers/video/i810_accel.c -- Hardware Acceleration
   3  *
   4  *      Copyright (C) 2001 Antonino Daplas<adaplas@pol.net>
   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 
  50 /**
  51  * wait_for_space - check ring buffer free space
  52  * @space: amount of ringbuffer space needed in bytes
  53  * @par: pointer to i810fb_par structure
  54  *
  55  * DESCRIPTION:
  56  * The function waits until a free space from the ringbuffer
  57  * is available 
  58  */     
  59 static inline int wait_for_space(struct fb_info *info, u32 space)
  60 {
  61         struct i810fb_par *par = info->par;
  62         u32 head, count = WAIT_COUNT, tail;
  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 
  82 /** 
  83  * wait_for_engine_idle - waits for all hardware engines to finish
  84  * @par: pointer to i810fb_par structure
  85  *
  86  * DESCRIPTION:
  87  * This waits for lring(0), iring(1), and batch(3), etc to finish and
  88  * waits until ringbuffer is empty.
  89  */
  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 
 127 /**
 128  * end_iring - advances the buffer
 129  * @par: pointer to i810fb_par structure
 130  *
 131  * DESCRIPTION:
 132  * This advances the tail of the ringbuffer, effectively
 133  * beginning the execution of the graphics instruction sequence.
 134  */
 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 
 142 /**
 143  * source_copy_blit - BLIT transfer operation
 144  * @dwidth: width of rectangular graphics data
 145  * @dheight: height of rectangular graphics data
 146  * @dpitch: bytes per line of destination buffer
 147  * @xdir: direction of copy (left to right or right to left)
 148  * @src: address of first pixel to read from
 149  * @dest: address of first pixel to write to
 150  * @from: source address
 151  * @where: destination address
 152  * @rop: raster operation
 153  * @blit_bpp: pixel format which can be different from the 
 154  *            framebuffer's pixelformat
 155  * @par: pointer to i810fb_par structure
 156  *
 157  * DESCRIPTION:
 158  * This is a BLIT operation typically used when doing
 159  * a 'Copy and Paste'
 160  */
 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 
 169         PUT_RING(BLIT | SOURCE_COPY_BLIT | 4);
 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 
 179 /**
 180  * color_blit - solid color BLIT operation
 181  * @width: width of destination
 182  * @height: height of destination
 183  * @pitch: pixels per line of the buffer
 184  * @dest: address of first pixel to write to
 185  * @where: destination
 186  * @rop: raster operation
 187  * @what: color to transfer
 188  * @blit_bpp: pixel format which can be different from the 
 189  *            framebuffer's pixelformat
 190  * @par: pointer to i810fb_par structure
 191  *
 192  * DESCRIPTION:
 193  * A BLIT operation which can be used for  color fill/rectangular fill
 194  */
 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  
 213 /**
 214  * mono_src_copy_imm_blit - color expand from system memory to framebuffer
 215  * @dwidth: width of destination
 216  * @dheight: height of destination
 217  * @dpitch: pixels per line of the buffer
 218  * @dsize: size of bitmap in double words
 219  * @dest: address of first byte of pixel;
 220  * @rop: raster operation
 221  * @blit_bpp: pixelformat to use which can be different from the 
 222  *            framebuffer's pixelformat
 223  * @src: address of image data
 224  * @bg: backgound color
 225  * @fg: forground color
 226  * @par: pointer to i810fb_par structure
 227  *
 228  * DESCRIPTION:
 229  * A color expand operation where the  source data is placed in the 
 230  * ringbuffer itself. Useful for drawing text. 
 231  *
 232  * REQUIREMENT:
 233  * The end of a scanline must be padded to the next word.
 234  */
 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 
 275 /**
 276  * i810fb_iring_enable - enables/disables the ringbuffer
 277  * @mode: enable or disable
 278  * @par: pointer to i810fb_par structure
 279  *
 280  * DESCRIPTION:
 281  * Enables or disables the ringbuffer, effectively enabling or
 282  * disabling the instruction/acceleration engine.
 283  */
 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 
 426 /**
 427  * i810fb_init_ringbuffer - initialize the ringbuffer
 428  * @par: pointer to i810fb_par structure
 429  *
 430  * DESCRIPTION:
 431  * Initializes the ringbuffer by telling the device the
 432  * size and location of the ringbuffer.  It also sets 
 433  * the head and tail pointers = 0
 434  */
 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 }

/* [<][>][^][v][top][bottom][index][help] */