32 #include <linux/module.h>
33 #include <linux/kernel.h>
34 #include <linux/errno.h>
35 #include <linux/string.h>
42 #include <linux/pci.h>
46 static const unsigned Fref = 14318180;
48 #define mmio_base (p->screen_base + 0x400000)
50 #define mm_write_ind(num, val, ap, dp) do { \
51 writeb((num), mmio_base + (ap)); writeb((val), mmio_base + (dp)); \
58 #define write_xr(num, val) mm_write_xr(p, num, val)
64 #define write_fr(num, val) mm_write_fr(p, num, val)
70 #define write_cr(num, val) mm_write_cr(p, num, val)
76 #define write_gr(num, val) mm_write_gr(p, num, val)
82 #define write_sr(num, val) mm_write_sr(p, num, val)
89 #define write_ar(num, val) mm_write_ar(p, num, val)
94 static int asiliantfb_set_par(
struct fb_info *
info);
98 static struct fb_ops asiliantfb_ops = {
100 .fb_check_var = asiliantfb_check_var,
101 .fb_set_par = asiliantfb_set_par,
102 .fb_setcolreg = asiliantfb_setcolreg,
110 static void asiliant_calc_dclk2(
u32 *ppixclock,
u8 *dclk2_m,
u8 *dclk2_n,
u8 *dclk2_div)
112 unsigned pixclock = *ppixclock;
113 unsigned Ftarget = 1000000 * (1000000 / pixclock);
115 unsigned best_error = 0xffffffff;
116 unsigned best_m = 0xffffffff,
123 ratio = 1000000 / pixclock;
124 remainder = 1000000 % pixclock;
125 Ftarget = 1000000 * ratio + (1000000 * remainder) / pixclock;
127 while (Ftarget < 100000000) {
132 ratio = Ftarget / Fref;
133 remainder = Ftarget % Fref;
137 for (n = 3; n <= 257; n++) {
138 unsigned m = n * ratio + (n * remainder) / Fref;
141 if (m >= 3 && m <= 257) {
142 unsigned new_error = Ftarget * n >= Fref * m ?
143 ((Ftarget *
n) - (Fref * m)) : ((Fref * m) - (Ftarget *
n));
144 if (new_error < best_error) {
147 best_error = new_error;
151 else if (m <= 1028) {
154 unsigned new_error = Ftarget * n >= Fref * (m & ~3) ?
155 ((Ftarget * n) - (Fref * (m & ~3))) : ((Fref * (m & ~3)) - (Ftarget * n));
156 if (new_error < best_error) {
159 best_error = new_error;
167 *dclk2_m = best_m - 2;
168 *dclk2_n = best_n - 2;
170 *ppixclock = pixclock;
174 static void asiliant_set_timing(
struct fb_info *
p)
176 unsigned hd = p->
var.xres / 8;
177 unsigned hs = (p->
var.xres + p->
var.right_margin) / 8;
178 unsigned he = (p->
var.xres + p->
var.right_margin + p->
var.hsync_len) / 8;
179 unsigned ht = (p->
var.left_margin + p->
var.xres + p->
var.right_margin + p->
var.hsync_len) / 8;
180 unsigned vd = p->
var.yres;
181 unsigned vs = p->
var.yres + p->
var.lower_margin;
182 unsigned ve = p->
var.yres + p->
var.lower_margin + p->
var.vsync_len;
183 unsigned vt = p->
var.upper_margin + p->
var.yres + p->
var.lower_margin + p->
var.vsync_len;
184 unsigned wd = (p->
var.xres_virtual * ((p->
var.bits_per_pixel+7)/8)) / 8;
186 if ((p->
var.xres == 640) && (p->
var.yres == 480) && (p->
var.pixclock == 39722)) {
196 write_cr(0x03, ((ht - 1) & 0x1f) | 0x80);
198 write_cr(0x05, (((ht - 1) & 0x20) <<2) | (he & 0x1f));
206 write_cr(0x32, ((vs - 1) >> 8) & 0xf);
207 write_cr(0x11, ((ve - 1) & 0x0f) | 0x80);
209 write_cr(0x31, ((vd - 1) & 0xf00) >> 8);
213 write_cr(0x33, ((vs - 1) >> 8) & 0xf);
214 write_cr(0x38, ((ht - 5) & 0x100) >> 8);
218 if (p->
var.xres == 640) {
228 unsigned long Ftarget,
ratio, remainder;
231 remainder = 1000000 % var->
pixclock;
232 Ftarget = 1000000 * ratio + (1000000 * remainder) / var->
pixclock;
236 if (Ftarget > 220000000 || Ftarget < 3125000) {
237 printk(
KERN_ERR "asiliantfb dotclock must be between 3.125 and 220MHz\n");
244 var->
red.offset = 16;
245 var->
green.offset = 8;
246 var->
blue.offset = 0;
247 var->
red.length = var->
blue.length = var->
green.length = 8;
249 switch (var->
red.offset) {
251 var->
green.length = 6;
254 var->
green.length = 5;
259 var->
green.offset = 5;
260 var->
blue.offset = 0;
261 var->
red.length = var->
blue.length = 5;
263 var->
red.offset = var->
green.offset = var->
blue.offset = 0;
264 var->
red.length = var->
green.length = var->
blue.length = 8;
269 static int asiliantfb_set_par(
struct fb_info *p)
276 asiliant_calc_dclk2(&p->
var.pixclock, &dclk2_m, &dclk2_n, &dclk2_div);
279 if (p->
var.bits_per_pixel == 24) {
283 }
else if (p->
var.bits_per_pixel == 16) {
284 if (p->
var.red.offset == 11)
290 }
else if (p->
var.bits_per_pixel == 8) {
296 p->
fix.line_length = p->
var.xres * (p->
var.bits_per_pixel >> 3);
302 asiliant_set_timing(p);
323 switch(p->
var.red.offset) {
326 ((red & 0xf8) << 7) |
327 ((green & 0xf8) << 2) |
328 ((blue & 0xf8) >> 3);
332 ((red & 0xf8) << 8) |
333 ((green & 0xfc) << 3) |
334 ((blue & 0xf8) >> 3);
464 write_sr(chips_init_sr[i].addr, chips_init_sr[i].data);
466 write_gr(chips_init_gr[i].addr, chips_init_gr[i].data);
468 write_ar(chips_init_ar[i].addr, chips_init_ar[i].data);
472 write_cr(chips_init_cr[i].addr, chips_init_cr[i].data);
474 write_fr(chips_init_fr[i].addr, chips_init_fr[i].data);
478 .id =
"Asiliant 69000",
483 .smem_len = 0x200000,
492 .red = { .length = 8 },
493 .green = { .length = 8 },
494 .blue = { .length = 8 },
511 p->
fix = asiliantfb_fix;
513 p->
var = asiliantfb_var;
514 p->
fbops = &asiliantfb_ops;
530 printk(
KERN_INFO "fb%d: Asiliant 69000 frame buffer (%dK RAM detected)\n",
531 p->
node, p->
fix.smem_len / 1024);
569 pci_write_config_dword(dp, 4, 0x02800083);
572 err = init_asiliant(p, addr);
580 pci_set_drvdata(dp, p);
586 struct fb_info *p = pci_get_drvdata(dp);
592 pci_set_drvdata(dp,
NULL);
596 static struct pci_device_id asiliantfb_pci_tbl[] __devinitdata = {
603 static struct pci_driver asiliantfb_driver = {
604 .name =
"asiliantfb",
605 .id_table = asiliantfb_pci_tbl,
606 .probe = asiliantfb_pci_init,
610 static int __init asiliantfb_init(
void)
615 return pci_register_driver(&asiliantfb_driver);
620 static void __exit asiliantfb_exit(
void)