0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032 #include <linux/module.h>
0033 #include <linux/kernel.h>
0034 #include <linux/errno.h>
0035 #include <linux/string.h>
0036 #include <linux/mm.h>
0037 #include <linux/vmalloc.h>
0038 #include <linux/delay.h>
0039 #include <linux/interrupt.h>
0040 #include <linux/fb.h>
0041 #include <linux/init.h>
0042 #include <linux/pci.h>
0043 #include <asm/io.h>
0044
0045
0046 static const unsigned Fref = 14318180;
0047
0048 #define mmio_base (p->screen_base + 0x400000)
0049
0050 #define mm_write_ind(num, val, ap, dp) do { \
0051 writeb((num), mmio_base + (ap)); writeb((val), mmio_base + (dp)); \
0052 } while (0)
0053
0054 static void mm_write_xr(struct fb_info *p, u8 reg, u8 data)
0055 {
0056 mm_write_ind(reg, data, 0x7ac, 0x7ad);
0057 }
0058 #define write_xr(num, val) mm_write_xr(p, num, val)
0059
0060 static void mm_write_fr(struct fb_info *p, u8 reg, u8 data)
0061 {
0062 mm_write_ind(reg, data, 0x7a0, 0x7a1);
0063 }
0064 #define write_fr(num, val) mm_write_fr(p, num, val)
0065
0066 static void mm_write_cr(struct fb_info *p, u8 reg, u8 data)
0067 {
0068 mm_write_ind(reg, data, 0x7a8, 0x7a9);
0069 }
0070 #define write_cr(num, val) mm_write_cr(p, num, val)
0071
0072 static void mm_write_gr(struct fb_info *p, u8 reg, u8 data)
0073 {
0074 mm_write_ind(reg, data, 0x79c, 0x79d);
0075 }
0076 #define write_gr(num, val) mm_write_gr(p, num, val)
0077
0078 static void mm_write_sr(struct fb_info *p, u8 reg, u8 data)
0079 {
0080 mm_write_ind(reg, data, 0x788, 0x789);
0081 }
0082 #define write_sr(num, val) mm_write_sr(p, num, val)
0083
0084 static void mm_write_ar(struct fb_info *p, u8 reg, u8 data)
0085 {
0086 readb(mmio_base + 0x7b4);
0087 mm_write_ind(reg, data, 0x780, 0x780);
0088 }
0089 #define write_ar(num, val) mm_write_ar(p, num, val)
0090
0091 static int asiliantfb_pci_init(struct pci_dev *dp, const struct pci_device_id *);
0092 static int asiliantfb_check_var(struct fb_var_screeninfo *var,
0093 struct fb_info *info);
0094 static int asiliantfb_set_par(struct fb_info *info);
0095 static int asiliantfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
0096 u_int transp, struct fb_info *info);
0097
0098 static const struct fb_ops asiliantfb_ops = {
0099 .owner = THIS_MODULE,
0100 .fb_check_var = asiliantfb_check_var,
0101 .fb_set_par = asiliantfb_set_par,
0102 .fb_setcolreg = asiliantfb_setcolreg,
0103 .fb_fillrect = cfb_fillrect,
0104 .fb_copyarea = cfb_copyarea,
0105 .fb_imageblit = cfb_imageblit,
0106 };
0107
0108
0109
0110 static void asiliant_calc_dclk2(u32 *ppixclock, u8 *dclk2_m, u8 *dclk2_n, u8 *dclk2_div)
0111 {
0112 unsigned pixclock = *ppixclock;
0113 unsigned Ftarget;
0114 unsigned n;
0115 unsigned best_error = 0xffffffff;
0116 unsigned best_m = 0xffffffff,
0117 best_n = 0xffffffff;
0118 unsigned ratio;
0119 unsigned remainder;
0120 unsigned char divisor = 0;
0121
0122
0123 ratio = 1000000 / pixclock;
0124 remainder = 1000000 % pixclock;
0125 Ftarget = 1000000 * ratio + (1000000 * remainder) / pixclock;
0126
0127 while (Ftarget < 100000000) {
0128 divisor += 0x10;
0129 Ftarget <<= 1;
0130 }
0131
0132 ratio = Ftarget / Fref;
0133 remainder = Ftarget % Fref;
0134
0135
0136
0137 for (n = 3; n <= 257; n++) {
0138 unsigned m = n * ratio + (n * remainder) / Fref;
0139
0140
0141 if (m >= 3 && m <= 257) {
0142 unsigned new_error = Ftarget * n >= Fref * m ?
0143 ((Ftarget * n) - (Fref * m)) : ((Fref * m) - (Ftarget * n));
0144 if (new_error < best_error) {
0145 best_n = n;
0146 best_m = m;
0147 best_error = new_error;
0148 }
0149 }
0150
0151 else if (m <= 1028) {
0152
0153
0154 unsigned new_error = Ftarget * n >= Fref * (m & ~3) ?
0155 ((Ftarget * n) - (Fref * (m & ~3))) : ((Fref * (m & ~3)) - (Ftarget * n));
0156 if (new_error < best_error) {
0157 best_n = n;
0158 best_m = m;
0159 best_error = new_error;
0160 }
0161 }
0162 }
0163 if (best_m > 257)
0164 best_m >>= 2;
0165 else
0166 divisor |= 4;
0167 *dclk2_m = best_m - 2;
0168 *dclk2_n = best_n - 2;
0169 *dclk2_div = divisor;
0170 *ppixclock = pixclock;
0171 return;
0172 }
0173
0174 static void asiliant_set_timing(struct fb_info *p)
0175 {
0176 unsigned hd = p->var.xres / 8;
0177 unsigned hs = (p->var.xres + p->var.right_margin) / 8;
0178 unsigned he = (p->var.xres + p->var.right_margin + p->var.hsync_len) / 8;
0179 unsigned ht = (p->var.left_margin + p->var.xres + p->var.right_margin + p->var.hsync_len) / 8;
0180 unsigned vd = p->var.yres;
0181 unsigned vs = p->var.yres + p->var.lower_margin;
0182 unsigned ve = p->var.yres + p->var.lower_margin + p->var.vsync_len;
0183 unsigned vt = p->var.upper_margin + p->var.yres + p->var.lower_margin + p->var.vsync_len;
0184 unsigned wd = (p->var.xres_virtual * ((p->var.bits_per_pixel+7)/8)) / 8;
0185
0186 if ((p->var.xres == 640) && (p->var.yres == 480) && (p->var.pixclock == 39722)) {
0187 write_fr(0x01, 0x02);
0188 } else {
0189 write_fr(0x01, 0x01);
0190 }
0191
0192 write_cr(0x11, (ve - 1) & 0x0f);
0193 write_cr(0x00, (ht - 5) & 0xff);
0194 write_cr(0x01, hd - 1);
0195 write_cr(0x02, hd);
0196 write_cr(0x03, ((ht - 1) & 0x1f) | 0x80);
0197 write_cr(0x04, hs);
0198 write_cr(0x05, (((ht - 1) & 0x20) <<2) | (he & 0x1f));
0199 write_cr(0x3c, (ht - 1) & 0xc0);
0200 write_cr(0x06, (vt - 2) & 0xff);
0201 write_cr(0x30, (vt - 2) >> 8);
0202 write_cr(0x07, 0x00);
0203 write_cr(0x08, 0x00);
0204 write_cr(0x09, 0x00);
0205 write_cr(0x10, (vs - 1) & 0xff);
0206 write_cr(0x32, ((vs - 1) >> 8) & 0xf);
0207 write_cr(0x11, ((ve - 1) & 0x0f) | 0x80);
0208 write_cr(0x12, (vd - 1) & 0xff);
0209 write_cr(0x31, ((vd - 1) & 0xf00) >> 8);
0210 write_cr(0x13, wd & 0xff);
0211 write_cr(0x41, (wd & 0xf00) >> 8);
0212 write_cr(0x15, (vs - 1) & 0xff);
0213 write_cr(0x33, ((vs - 1) >> 8) & 0xf);
0214 write_cr(0x38, ((ht - 5) & 0x100) >> 8);
0215 write_cr(0x16, (vt - 1) & 0xff);
0216 write_cr(0x18, 0x00);
0217
0218 if (p->var.xres == 640) {
0219 writeb(0xc7, mmio_base + 0x784);
0220 } else {
0221 writeb(0x07, mmio_base + 0x784);
0222 }
0223 }
0224
0225 static int asiliantfb_check_var(struct fb_var_screeninfo *var,
0226 struct fb_info *p)
0227 {
0228 unsigned long Ftarget, ratio, remainder;
0229
0230 if (!var->pixclock)
0231 return -EINVAL;
0232
0233 ratio = 1000000 / var->pixclock;
0234 remainder = 1000000 % var->pixclock;
0235 Ftarget = 1000000 * ratio + (1000000 * remainder) / var->pixclock;
0236
0237
0238
0239 if (Ftarget > 220000000 || Ftarget < 3125000) {
0240 printk(KERN_ERR "asiliantfb dotclock must be between 3.125 and 220MHz\n");
0241 return -ENXIO;
0242 }
0243 var->xres_virtual = var->xres;
0244 var->yres_virtual = var->yres;
0245
0246 if (var->bits_per_pixel == 24) {
0247 var->red.offset = 16;
0248 var->green.offset = 8;
0249 var->blue.offset = 0;
0250 var->red.length = var->blue.length = var->green.length = 8;
0251 } else if (var->bits_per_pixel == 16) {
0252 switch (var->red.offset) {
0253 case 11:
0254 var->green.length = 6;
0255 break;
0256 case 10:
0257 var->green.length = 5;
0258 break;
0259 default:
0260 return -EINVAL;
0261 }
0262 var->green.offset = 5;
0263 var->blue.offset = 0;
0264 var->red.length = var->blue.length = 5;
0265 } else if (var->bits_per_pixel == 8) {
0266 var->red.offset = var->green.offset = var->blue.offset = 0;
0267 var->red.length = var->green.length = var->blue.length = 8;
0268 }
0269 return 0;
0270 }
0271
0272 static int asiliantfb_set_par(struct fb_info *p)
0273 {
0274 u8 dclk2_m;
0275 u8 dclk2_n;
0276 u8 dclk2_div;
0277
0278
0279 asiliant_calc_dclk2(&p->var.pixclock, &dclk2_m, &dclk2_n, &dclk2_div);
0280
0281
0282 if (p->var.bits_per_pixel == 24) {
0283 write_xr(0x81, 0x16);
0284 write_xr(0x82, 0x00);
0285 write_xr(0x20, 0x20);
0286 } else if (p->var.bits_per_pixel == 16) {
0287 if (p->var.red.offset == 11)
0288 write_xr(0x81, 0x15);
0289 else
0290 write_xr(0x81, 0x14);
0291 write_xr(0x82, 0x00);
0292 write_xr(0x20, 0x10);
0293 } else if (p->var.bits_per_pixel == 8) {
0294 write_xr(0x0a, 0x02);
0295 write_xr(0x81, 0x12);
0296 write_xr(0x82, 0x00);
0297 write_xr(0x20, 0x00);
0298 }
0299 p->fix.line_length = p->var.xres * (p->var.bits_per_pixel >> 3);
0300 p->fix.visual = (p->var.bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
0301 write_xr(0xc4, dclk2_m);
0302 write_xr(0xc5, dclk2_n);
0303 write_xr(0xc7, dclk2_div);
0304
0305 asiliant_set_timing(p);
0306 return 0;
0307 }
0308
0309 static int asiliantfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
0310 u_int transp, struct fb_info *p)
0311 {
0312 if (regno > 255)
0313 return 1;
0314 red >>= 8;
0315 green >>= 8;
0316 blue >>= 8;
0317
0318
0319 writeb(regno, mmio_base + 0x790);
0320 udelay(1);
0321 writeb(red, mmio_base + 0x791);
0322 writeb(green, mmio_base + 0x791);
0323 writeb(blue, mmio_base + 0x791);
0324
0325 if (regno < 16) {
0326 switch(p->var.red.offset) {
0327 case 10:
0328 ((u32 *)(p->pseudo_palette))[regno] =
0329 ((red & 0xf8) << 7) |
0330 ((green & 0xf8) << 2) |
0331 ((blue & 0xf8) >> 3);
0332 break;
0333 case 11:
0334 ((u32 *)(p->pseudo_palette))[regno] =
0335 ((red & 0xf8) << 8) |
0336 ((green & 0xfc) << 3) |
0337 ((blue & 0xf8) >> 3);
0338 break;
0339 case 16:
0340 ((u32 *)(p->pseudo_palette))[regno] =
0341 (red << 16) |
0342 (green << 8) |
0343 (blue);
0344 break;
0345 }
0346 }
0347
0348 return 0;
0349 }
0350
0351 struct chips_init_reg {
0352 unsigned char addr;
0353 unsigned char data;
0354 };
0355
0356 static struct chips_init_reg chips_init_sr[] =
0357 {
0358 {0x00, 0x03},
0359 {0x01, 0x01},
0360 {0x02, 0x0f},
0361 {0x04, 0x0e}
0362 };
0363
0364 static struct chips_init_reg chips_init_gr[] =
0365 {
0366 {0x03, 0x00},
0367 {0x05, 0x00},
0368 {0x06, 0x01},
0369 {0x08, 0x00}
0370 };
0371
0372 static struct chips_init_reg chips_init_ar[] =
0373 {
0374 {0x10, 0x01},
0375 {0x11, 0x00},
0376 {0x12, 0x0f},
0377 {0x13, 0x00}
0378 };
0379
0380 static struct chips_init_reg chips_init_cr[] =
0381 {
0382 {0x0c, 0x00},
0383 {0x0d, 0x00},
0384 {0x40, 0x00},
0385 {0x41, 0x00},
0386 {0x14, 0x00},
0387 {0x17, 0xe3},
0388 {0x70, 0x00}
0389 };
0390
0391
0392 static struct chips_init_reg chips_init_fr[] =
0393 {
0394 {0x01, 0x02},
0395 {0x03, 0x08},
0396 {0x08, 0xcc},
0397 {0x0a, 0x08},
0398 {0x18, 0x00},
0399 {0x1e, 0x80},
0400 {0x40, 0x83},
0401 {0x41, 0x00},
0402 {0x48, 0x13},
0403 {0x4d, 0x60},
0404 {0x4e, 0x0f},
0405
0406 {0x0b, 0x01},
0407
0408 {0x21, 0x51},
0409 {0x22, 0x1d},
0410 {0x23, 0x5f},
0411 {0x20, 0x4f},
0412 {0x34, 0x00},
0413 {0x24, 0x51},
0414 {0x25, 0x00},
0415 {0x27, 0x0b},
0416 {0x26, 0x00},
0417 {0x37, 0x80},
0418 {0x33, 0x0b},
0419 {0x35, 0x11},
0420 {0x36, 0x02},
0421 {0x31, 0xea},
0422 {0x32, 0x0c},
0423 {0x30, 0xdf},
0424 {0x10, 0x0c},
0425 {0x11, 0xe0},
0426 {0x12, 0x50},
0427 {0x13, 0x00},
0428 {0x16, 0x03},
0429 {0x17, 0xbd},
0430 {0x1a, 0x00},
0431 };
0432
0433
0434 static struct chips_init_reg chips_init_xr[] =
0435 {
0436 {0xce, 0x00},
0437 {0xcc, 200 },
0438 {0xcd, 18 },
0439 {0xce, 0x90},
0440
0441 {0xc4, 209 },
0442 {0xc5, 118 },
0443 {0xc7, 32 },
0444 {0xcf, 0x06},
0445 {0x09, 0x01},
0446 {0x0a, 0x02},
0447 {0x0b, 0x01},
0448 {0x40, 0x03},
0449 {0x80, 0x82},
0450 {0x81, 0x12},
0451 {0x82, 0x08},
0452
0453 {0xd0, 0x0f},
0454 {0xd1, 0x01},
0455 };
0456
0457 static void chips_hw_init(struct fb_info *p)
0458 {
0459 int i;
0460
0461 for (i = 0; i < ARRAY_SIZE(chips_init_xr); ++i)
0462 write_xr(chips_init_xr[i].addr, chips_init_xr[i].data);
0463 write_xr(0x81, 0x12);
0464 write_xr(0x82, 0x08);
0465 write_xr(0x20, 0x00);
0466 for (i = 0; i < ARRAY_SIZE(chips_init_sr); ++i)
0467 write_sr(chips_init_sr[i].addr, chips_init_sr[i].data);
0468 for (i = 0; i < ARRAY_SIZE(chips_init_gr); ++i)
0469 write_gr(chips_init_gr[i].addr, chips_init_gr[i].data);
0470 for (i = 0; i < ARRAY_SIZE(chips_init_ar); ++i)
0471 write_ar(chips_init_ar[i].addr, chips_init_ar[i].data);
0472
0473 writeb(0x20, mmio_base + 0x780);
0474 for (i = 0; i < ARRAY_SIZE(chips_init_cr); ++i)
0475 write_cr(chips_init_cr[i].addr, chips_init_cr[i].data);
0476 for (i = 0; i < ARRAY_SIZE(chips_init_fr); ++i)
0477 write_fr(chips_init_fr[i].addr, chips_init_fr[i].data);
0478 }
0479
0480 static const struct fb_fix_screeninfo asiliantfb_fix = {
0481 .id = "Asiliant 69000",
0482 .type = FB_TYPE_PACKED_PIXELS,
0483 .visual = FB_VISUAL_PSEUDOCOLOR,
0484 .accel = FB_ACCEL_NONE,
0485 .line_length = 640,
0486 .smem_len = 0x200000,
0487 };
0488
0489 static const struct fb_var_screeninfo asiliantfb_var = {
0490 .xres = 640,
0491 .yres = 480,
0492 .xres_virtual = 640,
0493 .yres_virtual = 480,
0494 .bits_per_pixel = 8,
0495 .red = { .length = 8 },
0496 .green = { .length = 8 },
0497 .blue = { .length = 8 },
0498 .height = -1,
0499 .width = -1,
0500 .vmode = FB_VMODE_NONINTERLACED,
0501 .pixclock = 39722,
0502 .left_margin = 48,
0503 .right_margin = 16,
0504 .upper_margin = 33,
0505 .lower_margin = 10,
0506 .hsync_len = 96,
0507 .vsync_len = 2,
0508 };
0509
0510 static int init_asiliant(struct fb_info *p, unsigned long addr)
0511 {
0512 int err;
0513
0514 p->fix = asiliantfb_fix;
0515 p->fix.smem_start = addr;
0516 p->var = asiliantfb_var;
0517 p->fbops = &asiliantfb_ops;
0518 p->flags = FBINFO_DEFAULT;
0519
0520 err = fb_alloc_cmap(&p->cmap, 256, 0);
0521 if (err) {
0522 printk(KERN_ERR "C&T 69000 fb failed to alloc cmap memory\n");
0523 return err;
0524 }
0525
0526 err = register_framebuffer(p);
0527 if (err < 0) {
0528 printk(KERN_ERR "C&T 69000 framebuffer failed to register\n");
0529 fb_dealloc_cmap(&p->cmap);
0530 return err;
0531 }
0532
0533 fb_info(p, "Asiliant 69000 frame buffer (%dK RAM detected)\n",
0534 p->fix.smem_len / 1024);
0535
0536 writeb(0xff, mmio_base + 0x78c);
0537 chips_hw_init(p);
0538 return 0;
0539 }
0540
0541 static int asiliantfb_pci_init(struct pci_dev *dp,
0542 const struct pci_device_id *ent)
0543 {
0544 unsigned long addr, size;
0545 struct fb_info *p;
0546 int err;
0547
0548 if ((dp->resource[0].flags & IORESOURCE_MEM) == 0)
0549 return -ENODEV;
0550 addr = pci_resource_start(dp, 0);
0551 size = pci_resource_len(dp, 0);
0552 if (addr == 0)
0553 return -ENODEV;
0554 if (!request_mem_region(addr, size, "asiliantfb"))
0555 return -EBUSY;
0556
0557 p = framebuffer_alloc(sizeof(u32) * 16, &dp->dev);
0558 if (!p) {
0559 release_mem_region(addr, size);
0560 return -ENOMEM;
0561 }
0562 p->pseudo_palette = p->par;
0563 p->par = NULL;
0564
0565 p->screen_base = ioremap(addr, 0x800000);
0566 if (p->screen_base == NULL) {
0567 release_mem_region(addr, size);
0568 framebuffer_release(p);
0569 return -ENOMEM;
0570 }
0571
0572 pci_write_config_dword(dp, 4, 0x02800083);
0573 writeb(3, p->screen_base + 0x400784);
0574
0575 err = init_asiliant(p, addr);
0576 if (err) {
0577 iounmap(p->screen_base);
0578 release_mem_region(addr, size);
0579 framebuffer_release(p);
0580 return err;
0581 }
0582
0583 pci_set_drvdata(dp, p);
0584 return 0;
0585 }
0586
0587 static void asiliantfb_remove(struct pci_dev *dp)
0588 {
0589 struct fb_info *p = pci_get_drvdata(dp);
0590
0591 unregister_framebuffer(p);
0592 fb_dealloc_cmap(&p->cmap);
0593 iounmap(p->screen_base);
0594 release_mem_region(pci_resource_start(dp, 0), pci_resource_len(dp, 0));
0595 framebuffer_release(p);
0596 }
0597
0598 static const struct pci_device_id asiliantfb_pci_tbl[] = {
0599 { PCI_VENDOR_ID_CT, PCI_DEVICE_ID_CT_69000, PCI_ANY_ID, PCI_ANY_ID },
0600 { 0 }
0601 };
0602
0603 MODULE_DEVICE_TABLE(pci, asiliantfb_pci_tbl);
0604
0605 static struct pci_driver asiliantfb_driver = {
0606 .name = "asiliantfb",
0607 .id_table = asiliantfb_pci_tbl,
0608 .probe = asiliantfb_pci_init,
0609 .remove = asiliantfb_remove,
0610 };
0611
0612 static int __init asiliantfb_init(void)
0613 {
0614 if (fb_get_options("asiliantfb", NULL))
0615 return -ENODEV;
0616
0617 return pci_register_driver(&asiliantfb_driver);
0618 }
0619
0620 module_init(asiliantfb_init);
0621
0622 static void __exit asiliantfb_exit(void)
0623 {
0624 pci_unregister_driver(&asiliantfb_driver);
0625 }
0626
0627 MODULE_LICENSE("GPL");