Merge branches 'release', 'asus', 'sony-laptop' and 'thinkpad' into release
[pandora-kernel.git] / drivers / video / pm2fb.c
index 53dd639..30181b5 100644 (file)
@@ -66,7 +66,7 @@
 /*
  * Driver data
  */
-static int hwcursor;
+static int hwcursor = 1;
 static char *mode __devinitdata;
 
 /*
@@ -193,8 +193,8 @@ static inline void pm2v_RDAC_WR(struct pm2fb_par *p, s32 idx, u32 v)
 #else
 static inline void WAIT_FIFO(struct pm2fb_par *p, u32 a)
 {
-       while (pm2_RD(p, PM2R_IN_FIFO_SPACE) < a);
-       mb();
+       while (pm2_RD(p, PM2R_IN_FIFO_SPACE) < a)
+               cpu_relax();
 }
 #endif
 
@@ -328,7 +328,7 @@ static void reset_card(struct pm2fb_par *p)
        pm2_WR(p, PM2R_RESET_STATUS, 0);
        mb();
        while (pm2_RD(p, PM2R_RESET_STATUS) & PM2F_BEING_RESET)
-               ;
+               cpu_relax();
        mb();
 #ifdef CONFIG_FB_PM2_FIFO_DISCONNECT
        DPRINTK("FIFO disconnect enabled\n");
@@ -587,6 +587,11 @@ static int pm2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
                return -EINVAL;
        }
 
+       /* permedia cannot blit over 2048 */
+       if (var->yres_virtual > 2047) {
+               var->yres_virtual = 2047;
+       }
+
        if (var->xoffset) {
                DPRINTK("xoffset not supported\n");
                return -EINVAL;
@@ -1036,8 +1041,7 @@ static int pm2fb_sync(struct fb_info *info)
        mb();
        do {
                while (pm2_RD(par, PM2R_OUT_FIFO_WORDS) == 0)
-                       udelay(10);
-               rmb();
+                       cpu_relax();
        } while (pm2_RD(par, PM2R_OUT_FIFO) != PM2TAG(PM2R_SYNC));
 
        return 0;
@@ -1155,6 +1159,11 @@ static void pm2fb_imageblit(struct fb_info *info, const struct fb_image *image)
        u32 fgx, bgx;
        const u32 *src = (const u32 *)image->data;
        u32 xres = (info->var.xres + 31) & ~31;
+       int raster_mode = 1; /* invert bits */
+
+#ifdef __LITTLE_ENDIAN
+       raster_mode |= 3 << 7; /* reverse byte order */
+#endif
 
        if (info->state != FBINFO_STATE_RUNNING)
                return;
@@ -1204,9 +1213,8 @@ static void pm2fb_imageblit(struct fb_info *info, const struct fb_image *image)
                pm2_WR(par, PM2R_RENDER,
                        PM2F_RENDER_RECTANGLE |
                        PM2F_INCREASE_X | PM2F_INCREASE_Y);
-               /* BitMapPackEachScanline & invert bits and byte order*/
-               /* force background */
-               pm2_WR(par, PM2R_RASTERIZER_MODE,  (1 << 9) | 1 | (3 << 7));
+               /* BitMapPackEachScanline */
+               pm2_WR(par, PM2R_RASTERIZER_MODE, raster_mode | (1 << 9));
                pm2_WR(par, PM2R_CONSTANT_COLOR, fgx);
                pm2_WR(par, PM2R_RENDER,
                        PM2F_RENDER_RECTANGLE |
@@ -1220,8 +1228,7 @@ static void pm2fb_imageblit(struct fb_info *info, const struct fb_image *image)
                        PM2F_RENDER_RECTANGLE |
                        PM2F_RENDER_FASTFILL |
                        PM2F_INCREASE_X | PM2F_INCREASE_Y);
-               /* invert bits and byte order*/
-               pm2_WR(par, PM2R_RASTERIZER_MODE,  1 | (3 << 7));
+               pm2_WR(par, PM2R_RASTERIZER_MODE, raster_mode);
                pm2_WR(par, PM2R_FB_BLOCK_COLOR, fgx);
                pm2_WR(par, PM2R_RENDER,
                        PM2F_RENDER_RECTANGLE |
@@ -1257,23 +1264,22 @@ static const u8 cursor_bits_lookup[16] = {
 static int pm2vfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
 {
        struct pm2fb_par *par = info->par;
-       u8 mode;
-
-       if (!hwcursor)
-               return -EINVAL; /* just to force soft_cursor() call */
+       u8 mode = PM2F_CURSORMODE_TYPE_X;
+       int x = cursor->image.dx - info->var.xoffset;
+       int y = cursor->image.dy - info->var.yoffset;
 
-       /* Too large of a cursor or wrong bpp :-( */
-       if (cursor->image.width > 64 ||
-           cursor->image.height > 64 ||
-           cursor->image.depth > 1)
-               return -EINVAL;
-
-       mode = PM2F_CURSORMODE_TYPE_X;
        if (cursor->enable)
                mode |= PM2F_CURSORMODE_CURSOR_ENABLE;
 
        pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_MODE, mode);
 
+       if (!cursor->enable)
+               x = 2047;       /* push it outside display */
+       pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_X_LOW, x & 0xff);
+       pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_X_HIGH, (x >> 8) & 0xf);
+       pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_Y_LOW, y & 0xff);
+       pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_Y_HIGH, (y >> 8) & 0xf);
+
        /*
         * If the cursor is not be changed this means either we want the
         * current cursor state (if enable is set) or we want to query what
@@ -1282,16 +1288,6 @@ static int pm2vfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
        if (!cursor->set)
                return 0;
 
-       if (cursor->set & FB_CUR_SETPOS) {
-               int x = cursor->image.dx - info->var.xoffset;
-               int y = cursor->image.dy - info->var.yoffset;
-
-               pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_X_LOW, x & 0xff);
-               pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_X_HIGH, (x >> 8) & 0xf);
-               pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_Y_LOW, y & 0xff);
-               pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_Y_HIGH, (y >> 8) & 0xf);
-       }
-
        if (cursor->set & FB_CUR_SETHOT) {
                pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_X_HOT,
                             cursor->hot.x & 0x3f);
@@ -1369,11 +1365,121 @@ static int pm2vfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
 static int pm2fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
 {
        struct pm2fb_par *par = info->par;
+       u8 mode;
+
+       if (!hwcursor)
+               return -EINVAL; /* just to force soft_cursor() call */
+
+       /* Too large of a cursor or wrong bpp :-( */
+       if (cursor->image.width > 64 ||
+           cursor->image.height > 64 ||
+           cursor->image.depth > 1)
+               return -EINVAL;
 
        if (par->type == PM2_TYPE_PERMEDIA2V)
                return pm2vfb_cursor(info, cursor);
 
-       return -ENXIO;
+       mode = 0x40;
+       if (cursor->enable)
+                mode = 0x43;
+
+       pm2_RDAC_WR(par, PM2I_RD_CURSOR_CONTROL, mode);
+
+       /*
+        * If the cursor is not be changed this means either we want the
+        * current cursor state (if enable is set) or we want to query what
+        * we can do with the cursor (if enable is not set)
+        */
+       if (!cursor->set)
+               return 0;
+
+       if (cursor->set & FB_CUR_SETPOS) {
+               int x = cursor->image.dx - info->var.xoffset + 63;
+               int y = cursor->image.dy - info->var.yoffset + 63;
+
+               WAIT_FIFO(par, 4);
+               pm2_WR(par, PM2R_RD_CURSOR_X_LSB, x & 0xff);
+               pm2_WR(par, PM2R_RD_CURSOR_X_MSB, (x >> 8) & 0x7);
+               pm2_WR(par, PM2R_RD_CURSOR_Y_LSB, y & 0xff);
+               pm2_WR(par, PM2R_RD_CURSOR_Y_MSB, (y >> 8) & 0x7);
+       }
+
+       if (cursor->set & FB_CUR_SETCMAP) {
+               u32 fg_idx = cursor->image.fg_color;
+               u32 bg_idx = cursor->image.bg_color;
+
+               WAIT_FIFO(par, 7);
+               pm2_WR(par, PM2R_RD_CURSOR_COLOR_ADDRESS, 1);
+               pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA,
+                       info->cmap.red[bg_idx] >> 8);
+               pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA,
+                       info->cmap.green[bg_idx] >> 8);
+               pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA,
+                       info->cmap.blue[bg_idx] >> 8);
+
+               pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA,
+                       info->cmap.red[fg_idx] >> 8);
+               pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA,
+                       info->cmap.green[fg_idx] >> 8);
+               pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA,
+                       info->cmap.blue[fg_idx] >> 8);
+       }
+
+       if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) {
+               u8 *bitmap = (u8 *)cursor->image.data;
+               u8 *mask = (u8 *)cursor->mask;
+               int i;
+
+               WAIT_FIFO(par, 1);
+               pm2_WR(par, PM2R_RD_PALETTE_WRITE_ADDRESS, 0);
+
+               for (i = 0; i < cursor->image.height; i++) {
+                       int j = (cursor->image.width + 7) >> 3;
+                       int k = 8 - j;
+
+                       WAIT_FIFO(par, 8);
+                       for (; j > 0; j--) {
+                               u8 data = *bitmap ^ *mask;
+
+                               if (cursor->rop == ROP_COPY)
+                                       data = *mask & *bitmap;
+                               /* bitmap data */
+                               pm2_WR(par, PM2R_RD_CURSOR_DATA, data);
+                               bitmap++;
+                               mask++;
+                       }
+                       for (; k > 0; k--)
+                               pm2_WR(par, PM2R_RD_CURSOR_DATA, 0);
+               }
+               for (; i < 64; i++) {
+                       int j = 8;
+                       WAIT_FIFO(par, 8);
+                       while (j-- > 0)
+                               pm2_WR(par, PM2R_RD_CURSOR_DATA, 0);
+               }
+
+               mask = (u8 *)cursor->mask;
+               for (i = 0; i < cursor->image.height; i++) {
+                       int j = (cursor->image.width + 7) >> 3;
+                       int k = 8 - j;
+
+                       WAIT_FIFO(par, 8);
+                       for (; j > 0; j--) {
+                               /* mask */
+                               pm2_WR(par, PM2R_RD_CURSOR_DATA, *mask);
+                               mask++;
+                       }
+                       for (; k > 0; k--)
+                               pm2_WR(par, PM2R_RD_CURSOR_DATA, 0);
+               }
+               for (; i < 64; i++) {
+                       int j = 8;
+                       WAIT_FIFO(par, 8);
+                       while (j-- > 0)
+                               pm2_WR(par, PM2R_RD_CURSOR_DATA, 0);
+               }
+       }
+       return 0;
 }
 
 /* ------------ Hardware Independent Functions ------------ */
@@ -1737,7 +1843,7 @@ module_param(noaccel, bool, 0);
 MODULE_PARM_DESC(noaccel, "Disable acceleration");
 module_param(hwcursor, int, 0644);
 MODULE_PARM_DESC(hwcursor, "Enable hardware cursor "
-                       "(1=enable, 0=disable, default=0)");
+                       "(1=enable, 0=disable, default=1)");
 #ifdef CONFIG_MTRR
 module_param(nomtrr, bool, 0);
 MODULE_PARM_DESC(nomtrr, "Disable MTRR support (0 or 1=disabled) (default=0)");