Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* |
| 2 | * |
| 3 | * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400 |
| 4 | * |
| 5 | * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz> |
| 6 | * |
| 7 | * Version: 1.65 2002/08/14 |
| 8 | * |
| 9 | * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org> |
| 10 | * |
| 11 | * Contributors: "menion?" <menion@mindless.com> |
| 12 | * Betatesting, fixes, ideas |
| 13 | * |
| 14 | * "Kurt Garloff" <garloff@suse.de> |
| 15 | * Betatesting, fixes, ideas, videomodes, videomodes timmings |
| 16 | * |
| 17 | * "Tom Rini" <trini@kernel.crashing.org> |
| 18 | * MTRR stuff, PPC cleanups, betatesting, fixes, ideas |
| 19 | * |
| 20 | * "Bibek Sahu" <scorpio@dodds.net> |
| 21 | * Access device through readb|w|l and write b|w|l |
| 22 | * Extensive debugging stuff |
| 23 | * |
| 24 | * "Daniel Haun" <haund@usa.net> |
| 25 | * Testing, hardware cursor fixes |
| 26 | * |
| 27 | * "Scott Wood" <sawst46+@pitt.edu> |
| 28 | * Fixes |
| 29 | * |
| 30 | * "Gerd Knorr" <kraxel@goldbach.isdn.cs.tu-berlin.de> |
| 31 | * Betatesting |
| 32 | * |
| 33 | * "Kelly French" <targon@hazmat.com> |
| 34 | * "Fernando Herrera" <fherrera@eurielec.etsit.upm.es> |
| 35 | * Betatesting, bug reporting |
| 36 | * |
| 37 | * "Pablo Bianucci" <pbian@pccp.com.ar> |
| 38 | * Fixes, ideas, betatesting |
| 39 | * |
| 40 | * "Inaky Perez Gonzalez" <inaky@peloncho.fis.ucm.es> |
| 41 | * Fixes, enhandcements, ideas, betatesting |
| 42 | * |
| 43 | * "Ryuichi Oikawa" <roikawa@rr.iiij4u.or.jp> |
| 44 | * PPC betatesting, PPC support, backward compatibility |
| 45 | * |
| 46 | * "Paul Womar" <Paul@pwomar.demon.co.uk> |
| 47 | * "Owen Waller" <O.Waller@ee.qub.ac.uk> |
| 48 | * PPC betatesting |
| 49 | * |
| 50 | * "Thomas Pornin" <pornin@bolet.ens.fr> |
| 51 | * Alpha betatesting |
| 52 | * |
| 53 | * "Pieter van Leuven" <pvl@iae.nl> |
| 54 | * "Ulf Jaenicke-Roessler" <ujr@physik.phy.tu-dresden.de> |
| 55 | * G100 testing |
| 56 | * |
| 57 | * "H. Peter Arvin" <hpa@transmeta.com> |
| 58 | * Ideas |
| 59 | * |
| 60 | * "Cort Dougan" <cort@cs.nmt.edu> |
| 61 | * CHRP fixes and PReP cleanup |
| 62 | * |
| 63 | * "Mark Vojkovich" <mvojkovi@ucsd.edu> |
| 64 | * G400 support |
| 65 | * |
| 66 | * (following author is not in any relation with this code, but his code |
| 67 | * is included in this driver) |
| 68 | * |
| 69 | * Based on framebuffer driver for VBE 2.0 compliant graphic boards |
| 70 | * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de> |
| 71 | * |
| 72 | * (following author is not in any relation with this code, but his ideas |
Robert P. J. Day | beb7dd8 | 2007-05-09 07:14:03 +0200 | [diff] [blame] | 73 | * were used when writing this driver) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 74 | * |
| 75 | * FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk> |
| 76 | * |
| 77 | */ |
| 78 | |
| 79 | #include "matroxfb_accel.h" |
| 80 | #include "matroxfb_DAC1064.h" |
| 81 | #include "matroxfb_Ti3026.h" |
| 82 | #include "matroxfb_misc.h" |
| 83 | |
Jean Delvare | fc2d10d | 2009-09-22 16:47:48 -0700 | [diff] [blame] | 84 | #define curr_ydstorg(x) ((x)->curr.ydstorg.pixels) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 85 | |
| 86 | #define mga_ydstlen(y,l) mga_outl(M_YDSTLEN | M_EXEC, ((y) << 16) | (l)) |
| 87 | |
| 88 | static inline void matrox_cfb4_pal(u_int32_t* pal) { |
| 89 | unsigned int i; |
| 90 | |
| 91 | for (i = 0; i < 16; i++) { |
| 92 | pal[i] = i * 0x11111111U; |
| 93 | } |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 94 | } |
| 95 | |
| 96 | static inline void matrox_cfb8_pal(u_int32_t* pal) { |
| 97 | unsigned int i; |
| 98 | |
| 99 | for (i = 0; i < 16; i++) { |
| 100 | pal[i] = i * 0x01010101U; |
| 101 | } |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 102 | } |
| 103 | |
| 104 | static void matroxfb_copyarea(struct fb_info* info, const struct fb_copyarea* area); |
| 105 | static void matroxfb_fillrect(struct fb_info* info, const struct fb_fillrect* rect); |
| 106 | static void matroxfb_imageblit(struct fb_info* info, const struct fb_image* image); |
| 107 | static void matroxfb_cfb4_fillrect(struct fb_info* info, const struct fb_fillrect* rect); |
| 108 | static void matroxfb_cfb4_copyarea(struct fb_info* info, const struct fb_copyarea* area); |
| 109 | |
Jean Delvare | 316b4d6 | 2009-09-22 16:47:49 -0700 | [diff] [blame] | 110 | void matrox_cfbX_init(struct matrox_fb_info *minfo) |
| 111 | { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 112 | u_int32_t maccess; |
| 113 | u_int32_t mpitch; |
| 114 | u_int32_t mopmode; |
| 115 | int accel; |
| 116 | |
Harvey Harrison | 5ae1217 | 2008-04-28 02:15:47 -0700 | [diff] [blame] | 117 | DBG(__func__) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 118 | |
Jean Delvare | fc2d10d | 2009-09-22 16:47:48 -0700 | [diff] [blame] | 119 | mpitch = minfo->fbcon.var.xres_virtual; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 120 | |
Jean Delvare | fc2d10d | 2009-09-22 16:47:48 -0700 | [diff] [blame] | 121 | minfo->fbops.fb_copyarea = cfb_copyarea; |
| 122 | minfo->fbops.fb_fillrect = cfb_fillrect; |
| 123 | minfo->fbops.fb_imageblit = cfb_imageblit; |
| 124 | minfo->fbops.fb_cursor = NULL; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 125 | |
Jean Delvare | fc2d10d | 2009-09-22 16:47:48 -0700 | [diff] [blame] | 126 | accel = (minfo->fbcon.var.accel_flags & FB_ACCELF_TEXT) == FB_ACCELF_TEXT; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 127 | |
Jean Delvare | fc2d10d | 2009-09-22 16:47:48 -0700 | [diff] [blame] | 128 | switch (minfo->fbcon.var.bits_per_pixel) { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 129 | case 4: maccess = 0x00000000; /* accelerate as 8bpp video */ |
| 130 | mpitch = (mpitch >> 1) | 0x8000; /* disable linearization */ |
| 131 | mopmode = M_OPMODE_4BPP; |
Jean Delvare | fc2d10d | 2009-09-22 16:47:48 -0700 | [diff] [blame] | 132 | matrox_cfb4_pal(minfo->cmap); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 133 | if (accel && !(mpitch & 1)) { |
Jean Delvare | fc2d10d | 2009-09-22 16:47:48 -0700 | [diff] [blame] | 134 | minfo->fbops.fb_copyarea = matroxfb_cfb4_copyarea; |
| 135 | minfo->fbops.fb_fillrect = matroxfb_cfb4_fillrect; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 136 | } |
| 137 | break; |
| 138 | case 8: maccess = 0x00000000; |
| 139 | mopmode = M_OPMODE_8BPP; |
Jean Delvare | fc2d10d | 2009-09-22 16:47:48 -0700 | [diff] [blame] | 140 | matrox_cfb8_pal(minfo->cmap); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 141 | if (accel) { |
Jean Delvare | fc2d10d | 2009-09-22 16:47:48 -0700 | [diff] [blame] | 142 | minfo->fbops.fb_copyarea = matroxfb_copyarea; |
| 143 | minfo->fbops.fb_fillrect = matroxfb_fillrect; |
| 144 | minfo->fbops.fb_imageblit = matroxfb_imageblit; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 145 | } |
| 146 | break; |
Jean Delvare | fc2d10d | 2009-09-22 16:47:48 -0700 | [diff] [blame] | 147 | case 16: if (minfo->fbcon.var.green.length == 5) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 148 | maccess = 0xC0000001; |
Antonino A. Daplas | 08a498d | 2007-07-17 04:05:45 -0700 | [diff] [blame] | 149 | else |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 150 | maccess = 0x40000001; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 151 | mopmode = M_OPMODE_16BPP; |
| 152 | if (accel) { |
Jean Delvare | fc2d10d | 2009-09-22 16:47:48 -0700 | [diff] [blame] | 153 | minfo->fbops.fb_copyarea = matroxfb_copyarea; |
| 154 | minfo->fbops.fb_fillrect = matroxfb_fillrect; |
| 155 | minfo->fbops.fb_imageblit = matroxfb_imageblit; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 156 | } |
| 157 | break; |
| 158 | case 24: maccess = 0x00000003; |
| 159 | mopmode = M_OPMODE_24BPP; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 160 | if (accel) { |
Jean Delvare | fc2d10d | 2009-09-22 16:47:48 -0700 | [diff] [blame] | 161 | minfo->fbops.fb_copyarea = matroxfb_copyarea; |
| 162 | minfo->fbops.fb_fillrect = matroxfb_fillrect; |
| 163 | minfo->fbops.fb_imageblit = matroxfb_imageblit; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 164 | } |
| 165 | break; |
| 166 | case 32: maccess = 0x00000002; |
| 167 | mopmode = M_OPMODE_32BPP; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 168 | if (accel) { |
Jean Delvare | fc2d10d | 2009-09-22 16:47:48 -0700 | [diff] [blame] | 169 | minfo->fbops.fb_copyarea = matroxfb_copyarea; |
| 170 | minfo->fbops.fb_fillrect = matroxfb_fillrect; |
| 171 | minfo->fbops.fb_imageblit = matroxfb_imageblit; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 172 | } |
| 173 | break; |
| 174 | default: maccess = 0x00000000; |
| 175 | mopmode = 0x00000000; |
| 176 | break; /* turn off acceleration!!! */ |
| 177 | } |
| 178 | mga_fifo(8); |
| 179 | mga_outl(M_PITCH, mpitch); |
Jean Delvare | fc2d10d | 2009-09-22 16:47:48 -0700 | [diff] [blame] | 180 | mga_outl(M_YDSTORG, curr_ydstorg(minfo)); |
| 181 | if (minfo->capable.plnwt) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 182 | mga_outl(M_PLNWT, -1); |
Jean Delvare | fc2d10d | 2009-09-22 16:47:48 -0700 | [diff] [blame] | 183 | if (minfo->capable.srcorg) { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 184 | mga_outl(M_SRCORG, 0); |
| 185 | mga_outl(M_DSTORG, 0); |
| 186 | } |
| 187 | mga_outl(M_OPMODE, mopmode); |
| 188 | mga_outl(M_CXBNDRY, 0xFFFF0000); |
| 189 | mga_outl(M_YTOP, 0); |
| 190 | mga_outl(M_YBOT, 0x01FFFFFF); |
| 191 | mga_outl(M_MACCESS, maccess); |
Jean Delvare | fc2d10d | 2009-09-22 16:47:48 -0700 | [diff] [blame] | 192 | minfo->accel.m_dwg_rect = M_DWG_TRAP | M_DWG_SOLID | M_DWG_ARZERO | M_DWG_SGNZERO | M_DWG_SHIFTZERO; |
| 193 | if (isMilleniumII(minfo)) minfo->accel.m_dwg_rect |= M_DWG_TRANSC; |
| 194 | minfo->accel.m_opmode = mopmode; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 195 | } |
| 196 | |
| 197 | EXPORT_SYMBOL(matrox_cfbX_init); |
| 198 | |
Jean Delvare | 316b4d6 | 2009-09-22 16:47:49 -0700 | [diff] [blame] | 199 | static void matrox_accel_bmove(struct matrox_fb_info *minfo, int vxres, int sy, |
| 200 | int sx, int dy, int dx, int height, int width) |
| 201 | { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 202 | int start, end; |
| 203 | CRITFLAGS |
| 204 | |
Harvey Harrison | 5ae1217 | 2008-04-28 02:15:47 -0700 | [diff] [blame] | 205 | DBG(__func__) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 206 | |
| 207 | CRITBEGIN |
| 208 | |
| 209 | if ((dy < sy) || ((dy == sy) && (dx <= sx))) { |
| 210 | mga_fifo(2); |
| 211 | mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO | |
| 212 | M_DWG_BFCOL | M_DWG_REPLACE); |
| 213 | mga_outl(M_AR5, vxres); |
| 214 | width--; |
Jean Delvare | fc2d10d | 2009-09-22 16:47:48 -0700 | [diff] [blame] | 215 | start = sy*vxres+sx+curr_ydstorg(minfo); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 216 | end = start+width; |
| 217 | } else { |
| 218 | mga_fifo(3); |
| 219 | mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_BFCOL | M_DWG_REPLACE); |
| 220 | mga_outl(M_SGN, 5); |
| 221 | mga_outl(M_AR5, -vxres); |
| 222 | width--; |
Jean Delvare | fc2d10d | 2009-09-22 16:47:48 -0700 | [diff] [blame] | 223 | end = (sy+height-1)*vxres+sx+curr_ydstorg(minfo); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 224 | start = end+width; |
| 225 | dy += height-1; |
| 226 | } |
| 227 | mga_fifo(4); |
| 228 | mga_outl(M_AR0, end); |
| 229 | mga_outl(M_AR3, start); |
| 230 | mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx); |
| 231 | mga_ydstlen(dy, height); |
| 232 | WaitTillIdle(); |
| 233 | |
| 234 | CRITEND |
| 235 | } |
| 236 | |
Jean Delvare | 316b4d6 | 2009-09-22 16:47:49 -0700 | [diff] [blame] | 237 | static void matrox_accel_bmove_lin(struct matrox_fb_info *minfo, int vxres, |
| 238 | int sy, int sx, int dy, int dx, int height, |
| 239 | int width) |
| 240 | { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 241 | int start, end; |
| 242 | CRITFLAGS |
| 243 | |
Harvey Harrison | 5ae1217 | 2008-04-28 02:15:47 -0700 | [diff] [blame] | 244 | DBG(__func__) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 245 | |
| 246 | CRITBEGIN |
| 247 | |
| 248 | if ((dy < sy) || ((dy == sy) && (dx <= sx))) { |
| 249 | mga_fifo(2); |
| 250 | mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO | |
| 251 | M_DWG_BFCOL | M_DWG_REPLACE); |
| 252 | mga_outl(M_AR5, vxres); |
| 253 | width--; |
Jean Delvare | fc2d10d | 2009-09-22 16:47:48 -0700 | [diff] [blame] | 254 | start = sy*vxres+sx+curr_ydstorg(minfo); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 255 | end = start+width; |
| 256 | } else { |
| 257 | mga_fifo(3); |
| 258 | mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_BFCOL | M_DWG_REPLACE); |
| 259 | mga_outl(M_SGN, 5); |
| 260 | mga_outl(M_AR5, -vxres); |
| 261 | width--; |
Jean Delvare | fc2d10d | 2009-09-22 16:47:48 -0700 | [diff] [blame] | 262 | end = (sy+height-1)*vxres+sx+curr_ydstorg(minfo); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 263 | start = end+width; |
| 264 | dy += height-1; |
| 265 | } |
| 266 | mga_fifo(5); |
| 267 | mga_outl(M_AR0, end); |
| 268 | mga_outl(M_AR3, start); |
| 269 | mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx); |
| 270 | mga_outl(M_YDST, dy*vxres >> 5); |
| 271 | mga_outl(M_LEN | M_EXEC, height); |
| 272 | WaitTillIdle(); |
| 273 | |
| 274 | CRITEND |
| 275 | } |
| 276 | |
| 277 | static void matroxfb_cfb4_copyarea(struct fb_info* info, const struct fb_copyarea* area) { |
Jean Delvare | ee5a274 | 2009-09-22 16:47:50 -0700 | [diff] [blame] | 278 | struct matrox_fb_info *minfo = info2minfo(info); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 279 | |
| 280 | if ((area->sx | area->dx | area->width) & 1) |
| 281 | cfb_copyarea(info, area); |
| 282 | else |
Jean Delvare | 316b4d6 | 2009-09-22 16:47:49 -0700 | [diff] [blame] | 283 | matrox_accel_bmove_lin(minfo, minfo->fbcon.var.xres_virtual >> 1, area->sy, area->sx >> 1, area->dy, area->dx >> 1, area->height, area->width >> 1); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 284 | } |
| 285 | |
| 286 | static void matroxfb_copyarea(struct fb_info* info, const struct fb_copyarea* area) { |
Jean Delvare | ee5a274 | 2009-09-22 16:47:50 -0700 | [diff] [blame] | 287 | struct matrox_fb_info *minfo = info2minfo(info); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 288 | |
Jean Delvare | 316b4d6 | 2009-09-22 16:47:49 -0700 | [diff] [blame] | 289 | matrox_accel_bmove(minfo, minfo->fbcon.var.xres_virtual, area->sy, area->sx, area->dy, area->dx, area->height, area->width); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 290 | } |
| 291 | |
Jean Delvare | 316b4d6 | 2009-09-22 16:47:49 -0700 | [diff] [blame] | 292 | static void matroxfb_accel_clear(struct matrox_fb_info *minfo, u_int32_t color, |
| 293 | int sy, int sx, int height, int width) |
| 294 | { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 295 | CRITFLAGS |
| 296 | |
Harvey Harrison | 5ae1217 | 2008-04-28 02:15:47 -0700 | [diff] [blame] | 297 | DBG(__func__) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 298 | |
| 299 | CRITBEGIN |
| 300 | |
| 301 | mga_fifo(5); |
Jean Delvare | fc2d10d | 2009-09-22 16:47:48 -0700 | [diff] [blame] | 302 | mga_outl(M_DWGCTL, minfo->accel.m_dwg_rect | M_DWG_REPLACE); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 303 | mga_outl(M_FCOL, color); |
| 304 | mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx); |
| 305 | mga_ydstlen(sy, height); |
| 306 | WaitTillIdle(); |
| 307 | |
| 308 | CRITEND |
| 309 | } |
| 310 | |
| 311 | static void matroxfb_fillrect(struct fb_info* info, const struct fb_fillrect* rect) { |
Jean Delvare | ee5a274 | 2009-09-22 16:47:50 -0700 | [diff] [blame] | 312 | struct matrox_fb_info *minfo = info2minfo(info); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 313 | |
| 314 | switch (rect->rop) { |
| 315 | case ROP_COPY: |
Jean Delvare | 316b4d6 | 2009-09-22 16:47:49 -0700 | [diff] [blame] | 316 | matroxfb_accel_clear(minfo, ((u_int32_t *)info->pseudo_palette)[rect->color], rect->dy, rect->dx, rect->height, rect->width); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 317 | break; |
| 318 | } |
| 319 | } |
| 320 | |
Jean Delvare | 316b4d6 | 2009-09-22 16:47:49 -0700 | [diff] [blame] | 321 | static void matroxfb_cfb4_clear(struct matrox_fb_info *minfo, u_int32_t bgx, |
| 322 | int sy, int sx, int height, int width) |
| 323 | { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 324 | int whattodo; |
| 325 | CRITFLAGS |
| 326 | |
Harvey Harrison | 5ae1217 | 2008-04-28 02:15:47 -0700 | [diff] [blame] | 327 | DBG(__func__) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 328 | |
| 329 | CRITBEGIN |
| 330 | |
| 331 | whattodo = 0; |
| 332 | if (sx & 1) { |
| 333 | sx ++; |
| 334 | if (!width) return; |
| 335 | width --; |
| 336 | whattodo = 1; |
| 337 | } |
| 338 | if (width & 1) { |
| 339 | whattodo |= 2; |
| 340 | } |
| 341 | width >>= 1; |
| 342 | sx >>= 1; |
| 343 | if (width) { |
| 344 | mga_fifo(5); |
Jean Delvare | fc2d10d | 2009-09-22 16:47:48 -0700 | [diff] [blame] | 345 | mga_outl(M_DWGCTL, minfo->accel.m_dwg_rect | M_DWG_REPLACE2); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 346 | mga_outl(M_FCOL, bgx); |
| 347 | mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx); |
Jean Delvare | fc2d10d | 2009-09-22 16:47:48 -0700 | [diff] [blame] | 348 | mga_outl(M_YDST, sy * minfo->fbcon.var.xres_virtual >> 6); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 349 | mga_outl(M_LEN | M_EXEC, height); |
| 350 | WaitTillIdle(); |
| 351 | } |
| 352 | if (whattodo) { |
Jean Delvare | fc2d10d | 2009-09-22 16:47:48 -0700 | [diff] [blame] | 353 | u_int32_t step = minfo->fbcon.var.xres_virtual >> 1; |
| 354 | vaddr_t vbase = minfo->video.vbase; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 355 | if (whattodo & 1) { |
| 356 | unsigned int uaddr = sy * step + sx - 1; |
| 357 | u_int32_t loop; |
| 358 | u_int8_t bgx2 = bgx & 0xF0; |
| 359 | for (loop = height; loop > 0; loop --) { |
| 360 | mga_writeb(vbase, uaddr, (mga_readb(vbase, uaddr) & 0x0F) | bgx2); |
| 361 | uaddr += step; |
| 362 | } |
| 363 | } |
| 364 | if (whattodo & 2) { |
| 365 | unsigned int uaddr = sy * step + sx + width; |
| 366 | u_int32_t loop; |
| 367 | u_int8_t bgx2 = bgx & 0x0F; |
| 368 | for (loop = height; loop > 0; loop --) { |
| 369 | mga_writeb(vbase, uaddr, (mga_readb(vbase, uaddr) & 0xF0) | bgx2); |
| 370 | uaddr += step; |
| 371 | } |
| 372 | } |
| 373 | } |
| 374 | |
| 375 | CRITEND |
| 376 | } |
| 377 | |
| 378 | static void matroxfb_cfb4_fillrect(struct fb_info* info, const struct fb_fillrect* rect) { |
Jean Delvare | ee5a274 | 2009-09-22 16:47:50 -0700 | [diff] [blame] | 379 | struct matrox_fb_info *minfo = info2minfo(info); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 380 | |
| 381 | switch (rect->rop) { |
| 382 | case ROP_COPY: |
Jean Delvare | 316b4d6 | 2009-09-22 16:47:49 -0700 | [diff] [blame] | 383 | matroxfb_cfb4_clear(minfo, ((u_int32_t *)info->pseudo_palette)[rect->color], rect->dy, rect->dx, rect->height, rect->width); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 384 | break; |
| 385 | } |
| 386 | } |
| 387 | |
Jean Delvare | 316b4d6 | 2009-09-22 16:47:49 -0700 | [diff] [blame] | 388 | static void matroxfb_1bpp_imageblit(struct matrox_fb_info *minfo, u_int32_t fgx, |
| 389 | u_int32_t bgx, const u_int8_t *chardata, |
| 390 | int width, int height, int yy, int xx) |
| 391 | { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 392 | u_int32_t step; |
| 393 | u_int32_t ydstlen; |
| 394 | u_int32_t xlen; |
| 395 | u_int32_t ar0; |
| 396 | u_int32_t charcell; |
| 397 | u_int32_t fxbndry; |
| 398 | vaddr_t mmio; |
| 399 | int easy; |
| 400 | CRITFLAGS |
| 401 | |
Harvey Harrison | 5ae1217 | 2008-04-28 02:15:47 -0700 | [diff] [blame] | 402 | DBG_HEAVY(__func__); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 403 | |
| 404 | step = (width + 7) >> 3; |
| 405 | charcell = height * step; |
| 406 | xlen = (charcell + 3) & ~3; |
| 407 | ydstlen = (yy << 16) | height; |
| 408 | if (width == step << 3) { |
| 409 | ar0 = height * width - 1; |
| 410 | easy = 1; |
| 411 | } else { |
| 412 | ar0 = width - 1; |
| 413 | easy = 0; |
| 414 | } |
| 415 | |
| 416 | CRITBEGIN |
| 417 | |
| 418 | mga_fifo(3); |
| 419 | if (easy) |
| 420 | mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE); |
| 421 | else |
| 422 | mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_REPLACE); |
| 423 | mga_outl(M_FCOL, fgx); |
| 424 | mga_outl(M_BCOL, bgx); |
| 425 | fxbndry = ((xx + width - 1) << 16) | xx; |
Jean Delvare | fc2d10d | 2009-09-22 16:47:48 -0700 | [diff] [blame] | 426 | mmio = minfo->mmio.vbase; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 427 | |
| 428 | mga_fifo(6); |
| 429 | mga_writel(mmio, M_FXBNDRY, fxbndry); |
| 430 | mga_writel(mmio, M_AR0, ar0); |
| 431 | mga_writel(mmio, M_AR3, 0); |
| 432 | if (easy) { |
| 433 | mga_writel(mmio, M_YDSTLEN | M_EXEC, ydstlen); |
| 434 | mga_memcpy_toio(mmio, chardata, xlen); |
| 435 | } else { |
| 436 | mga_writel(mmio, M_AR5, 0); |
| 437 | mga_writel(mmio, M_YDSTLEN | M_EXEC, ydstlen); |
| 438 | if ((step & 3) == 0) { |
| 439 | /* Great. Source has 32bit aligned lines, so we can feed them |
| 440 | directly to the accelerator. */ |
| 441 | mga_memcpy_toio(mmio, chardata, charcell); |
| 442 | } else if (step == 1) { |
| 443 | /* Special case for 1..8bit widths */ |
| 444 | while (height--) { |
| 445 | #if defined(__BIG_ENDIAN) |
| 446 | fb_writel((*chardata) << 24, mmio.vaddr); |
| 447 | #else |
| 448 | fb_writel(*chardata, mmio.vaddr); |
| 449 | #endif |
| 450 | chardata++; |
| 451 | } |
| 452 | } else if (step == 2) { |
| 453 | /* Special case for 9..15bit widths */ |
| 454 | while (height--) { |
| 455 | #if defined(__BIG_ENDIAN) |
| 456 | fb_writel((*(u_int16_t*)chardata) << 16, mmio.vaddr); |
| 457 | #else |
| 458 | fb_writel(*(u_int16_t*)chardata, mmio.vaddr); |
| 459 | #endif |
| 460 | chardata += 2; |
| 461 | } |
| 462 | } else { |
| 463 | /* Tell... well, why bother... */ |
| 464 | while (height--) { |
| 465 | size_t i; |
| 466 | |
| 467 | for (i = 0; i < step; i += 4) { |
| 468 | /* Hope that there are at least three readable bytes beyond the end of bitmap */ |
| 469 | fb_writel(get_unaligned((u_int32_t*)(chardata + i)),mmio.vaddr); |
| 470 | } |
| 471 | chardata += step; |
| 472 | } |
| 473 | } |
| 474 | } |
| 475 | WaitTillIdle(); |
| 476 | CRITEND |
| 477 | } |
| 478 | |
| 479 | |
| 480 | static void matroxfb_imageblit(struct fb_info* info, const struct fb_image* image) { |
Jean Delvare | ee5a274 | 2009-09-22 16:47:50 -0700 | [diff] [blame] | 481 | struct matrox_fb_info *minfo = info2minfo(info); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 482 | |
Harvey Harrison | 5ae1217 | 2008-04-28 02:15:47 -0700 | [diff] [blame] | 483 | DBG_HEAVY(__func__); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 484 | |
| 485 | if (image->depth == 1) { |
| 486 | u_int32_t fgx, bgx; |
| 487 | |
| 488 | fgx = ((u_int32_t*)info->pseudo_palette)[image->fg_color]; |
| 489 | bgx = ((u_int32_t*)info->pseudo_palette)[image->bg_color]; |
Jean Delvare | 316b4d6 | 2009-09-22 16:47:49 -0700 | [diff] [blame] | 490 | matroxfb_1bpp_imageblit(minfo, fgx, bgx, image->data, image->width, image->height, image->dy, image->dx); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 491 | } else { |
| 492 | /* Danger! image->depth is useless: logo painting code always |
| 493 | passes framebuffer color depth here, although logo data are |
| 494 | always 8bpp and info->pseudo_palette is changed to contain |
| 495 | logo palette to be used (but only for true/direct-color... sic...). |
| 496 | So do it completely in software... */ |
| 497 | cfb_imageblit(info, image); |
| 498 | } |
| 499 | } |
| 500 | |
| 501 | MODULE_LICENSE("GPL"); |