cyblafb.c 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456
  1. /*
  2. * Frame buffer driver for Trident Cyberblade/i1 graphics core
  3. *
  4. * Copyright 2005 Knut Petersen <Knut_Petersen@t-online.de>
  5. *
  6. * CREDITS:
  7. * tridentfb.c by Jani Monoses
  8. * see files above for further credits
  9. *
  10. * TODO:
  11. *
  12. */
  13. #define CYBLAFB_DEBUG 0
  14. #include <linux/config.h>
  15. #include <linux/module.h>
  16. #include <linux/string.h>
  17. #include <linux/fb.h>
  18. #include <linux/init.h>
  19. #include <linux/pci.h>
  20. #include <asm/types.h>
  21. #include <video/cyblafb.h>
  22. #define VERSION "0.54"
  23. struct cyblafb_par {
  24. u32 pseudo_pal[16];
  25. struct fb_ops ops;
  26. };
  27. static struct fb_fix_screeninfo cyblafb_fix __devinitdata = {
  28. .id = "CyBla",
  29. .type = FB_TYPE_PACKED_PIXELS,
  30. .ypanstep = 1,
  31. .visual = FB_VISUAL_PSEUDOCOLOR,
  32. .accel = FB_ACCEL_NONE,
  33. };
  34. static char *mode __devinitdata = NULL;
  35. static int bpp __devinitdata = 8;
  36. static int ref __devinitdata = 75;
  37. static int fp __devinitdata;
  38. static int crt __devinitdata;
  39. static int memsize __devinitdata;
  40. static int vesafb __devinitdata;
  41. static int nativex;
  42. static int center;
  43. static int stretch;
  44. static int pciwb = 1;
  45. static int pcirb = 1;
  46. static int pciwr = 1;
  47. static int pcirr = 1;
  48. static int verbosity;
  49. static int displaytype;
  50. static void __iomem * io_virt; // iospace virtual memory address
  51. module_param(mode,charp,0);
  52. module_param(bpp,int,0);
  53. module_param(ref,int,0);
  54. module_param(fp,int,0);
  55. module_param(crt,int,0);
  56. module_param(nativex,int,0);
  57. module_param(center,int,0);
  58. module_param(stretch,int,0);
  59. module_param(pciwb,int,0);
  60. module_param(pcirb,int,0);
  61. module_param(pciwr,int,0);
  62. module_param(pcirr,int,0);
  63. module_param(memsize,int,0);
  64. module_param(verbosity,int,0);
  65. module_param(vesafb,int,0);
  66. //=========================================
  67. //
  68. // Port access macros for memory mapped io
  69. //
  70. //=========================================
  71. #define out8(r,v) writeb(v,io_virt+r)
  72. #define out32(r,v) writel(v,io_virt+r)
  73. #define in8(r) readb(io_virt+r)
  74. #define in32(r) readl(io_virt+r)
  75. //======================================
  76. //
  77. // Hardware access inline functions
  78. //
  79. //======================================
  80. static inline unsigned char read3X4(int reg)
  81. {
  82. out8(0x3D4,reg);
  83. return in8(0x3D5);
  84. }
  85. static inline unsigned char read3C4(int reg)
  86. {
  87. out8(0x3C4,reg);
  88. return in8(0x3C5);
  89. }
  90. static inline unsigned char read3CE(int reg)
  91. {
  92. out8(0x3CE,reg);
  93. return in8(0x3CF);
  94. }
  95. static inline void write3X4(int reg,unsigned char val)
  96. {
  97. out8(0x3D4,reg);
  98. out8(0x3D5,val);
  99. }
  100. static inline void write3C4(int reg,unsigned char val)
  101. {
  102. out8(0x3C4,reg);
  103. out8(0x3C5,val);
  104. }
  105. static inline void write3CE(int reg,unsigned char val)
  106. {
  107. out8(0x3CE,reg);
  108. out8(0x3CF,val);
  109. }
  110. static inline void write3C0(int reg,unsigned char val)
  111. {
  112. in8(0x3DA); // read to reset index
  113. out8(0x3C0,reg);
  114. out8(0x3C0,val);
  115. }
  116. //=================================================
  117. //
  118. // Enable memory mapped io and unprotect registers
  119. //
  120. //=================================================
  121. static inline void enable_mmio(void)
  122. {
  123. int tmp;
  124. outb(0x0B,0x3C4);
  125. inb(0x3C5); // Set NEW mode
  126. outb(SR0E,0x3C4); // write enable a lot of extended ports
  127. outb(0x80,0x3C5);
  128. outb(SR11,0x3C4); // write enable those extended ports that
  129. outb(0x87,0x3C5); // are not affected by SR0E_New
  130. outb(CR1E,0x3d4); // clear write protect bit for port 0x3c2
  131. tmp=inb(0x3d5) & 0xBF;
  132. outb(CR1E,0x3d4);
  133. outb(tmp,0x3d5);
  134. outb(CR39,0x3D4);
  135. outb(inb(0x3D5)|0x01,0x3D5); // Enable mmio, everything else untouched
  136. }
  137. //=================================================
  138. //
  139. // Set pixel clock VCLK1
  140. // - multipliers set elswhere
  141. // - freq in units of 0.01 MHz
  142. //
  143. //=================================================
  144. static void set_vclk(struct cyblafb_par *par, int freq)
  145. {
  146. u32 m,n,k;
  147. int f,fi,d,di;
  148. u8 lo=0,hi=0;
  149. d = 2000;
  150. k = freq >= 10000 ? 0 : freq >= 5000 ? 1 : freq >= 2500 ? 2 : 3;
  151. for(m = 0;m<64;m++)
  152. for(n = 0;n<250;n++) { // max 249 is a hardware limit for cybla/i1 !
  153. fi = (int)(((5864727*(n+8))/((m+2)*(1<<k)))>>12);
  154. if ((di = abs(fi - freq)) < d) {
  155. d = di;
  156. f = fi;
  157. lo = (u8) n;
  158. hi = (u8) ((k<<6) | m);
  159. }
  160. }
  161. write3C4(SR19,hi);
  162. write3C4(SR18,lo);
  163. if(verbosity > 1)
  164. output("pixclock = %d.%02d MHz, k/m/n %x %x %x\n",
  165. freq/100,freq%100,(hi&0xc0)>>6,hi&0x3f,lo);
  166. }
  167. //================================================
  168. //
  169. // Cyberblade specific Graphics Engine (GE) setup
  170. //
  171. //================================================
  172. static void cyblafb_setup_GE(int pitch,int bpp)
  173. {
  174. int base = (pitch>>3)<<20;
  175. switch (bpp) {
  176. case 8: base |= (0<<29); break;
  177. case 15: base |= (5<<29); break;
  178. case 16: base |= (1<<29); break;
  179. case 24:
  180. case 32: base |= (2<<29); break;
  181. }
  182. write3X4(CR36,0x90); // reset GE
  183. write3X4(CR36,0x80); // enable GE
  184. out32(GE24,1<<7); // reset all GE pointers
  185. out32(GE24,0);
  186. write3X4(CR2D,0x00); // GE Timinigs, no delays
  187. out32(GEB8,base); // Destination Stride / Buffer Base 0, p 133
  188. out32(GEBC,base); // Destination Stride / Buffer Base 1, p 133
  189. out32(GEC0,base); // Destination Stride / Buffer Base 2, p 133
  190. out32(GEC4,base); // Destination Stride / Buffer Base 3, p 133
  191. out32(GEC8,base); // Source Stride / Buffer Base 0, p 133
  192. out32(GECC,base); // Source Stride / Buffer Base 1, p 133
  193. out32(GED0,base); // Source Stride / Buffer Base 2, p 133
  194. out32(GED4,base); // Source Stride / Buffer Base 3, p 133
  195. out32(GE6C,0); // Pattern and Style, p 129, ok
  196. }
  197. //=====================================================================
  198. //
  199. // Although this is a .fb_sync function that could be enabled in
  200. // cyblafb_ops, we do not include it there. We sync immediately before
  201. // new GE operations to improve performance.
  202. //
  203. //=====================================================================
  204. static int cyblafb_sync(struct fb_info *info)
  205. {
  206. int status, i=100000;
  207. while( ((status=in32(GE20)) & 0xFA800000) && i != 0)
  208. i--;
  209. if (i == 0) {
  210. // The timeout might be caused by disabled mmio.
  211. // Cause:
  212. // - bit CR39 & 1 == 0 upon return, X trident driver bug
  213. // - kdm bug (KD_GRAPHICS not set on first switch)
  214. // - kernel design flaw (it believes in the correctness
  215. // of kdm/X
  216. // So we make sure that mmio is enabled first ...
  217. enable_mmio();
  218. // show_trace(NULL,&status);
  219. i=1000000;
  220. while( ((status=in32(GE20)) & 0xFA800000) && i != 0)
  221. i--;
  222. if (i == 0) {
  223. output("GE Timeout, status: %x\n",status);
  224. if(status & 0x80000000)
  225. output("Bresenham Engine : Busy\n");
  226. if(status & 0x40000000)
  227. output("Setup Engine : Busy\n");
  228. if(status & 0x20000000)
  229. output("SP / DPE : Busy\n");
  230. if(status & 0x10000000)
  231. output("Memory Interface : Busy\n");
  232. if(status & 0x08000000)
  233. output("Com Lst Proc : Busy\n");
  234. if(status & 0x04000000)
  235. output("Block Write : Busy\n");
  236. if(status & 0x02000000)
  237. output("Command Buffer : Full\n");
  238. if(status & 0x01000000)
  239. output("RESERVED : Busy\n");
  240. if(status & 0x00800000)
  241. output("PCI Write Buffer : Busy\n");
  242. cyblafb_setup_GE(info->var.xres,
  243. info->var.bits_per_pixel);
  244. }
  245. }
  246. return 0;
  247. }
  248. //==============================
  249. //
  250. // Cyberblade specific fillrect
  251. //
  252. //==============================
  253. static void cyblafb_fillrect(struct fb_info * info,
  254. const struct fb_fillrect *fr)
  255. {
  256. int bpp = info->var.bits_per_pixel;
  257. int col;
  258. switch (bpp) {
  259. default:
  260. case 8: col = fr->color;
  261. col |= col <<8;
  262. col |= col <<16;
  263. break;
  264. case 16: col = ((u32 *)(info->pseudo_palette))[fr->color];
  265. col |= col <<16;
  266. break;
  267. case 32: col = ((u32 *)(info->pseudo_palette))[fr->color];
  268. break;
  269. }
  270. cyblafb_sync(info);
  271. out32(GE60,col);
  272. out32(GE48,fr->rop ? 0x66:ROP_S);
  273. out32(GE44,0x20000000|1<<19|1<<4|2<<2);
  274. out32(GE08,point(fr->dx,fr->dy));
  275. out32(GE0C,point(fr->dx+fr->width-1,fr->dy+fr->height-1));
  276. }
  277. //==============================
  278. //
  279. // Cyberblade specific copyarea
  280. //
  281. //==============================
  282. static void cyblafb_copyarea(struct fb_info *info,
  283. const struct fb_copyarea *ca)
  284. {
  285. __u32 s1,s2,d1,d2;
  286. int direction;
  287. s1 = point(ca->sx,ca->sy);
  288. s2 = point(ca->sx+ca->width-1,ca->sy+ca->height-1);
  289. d1 = point(ca->dx,ca->dy);
  290. d2 = point(ca->dx+ca->width-1,ca->dy+ca->height-1);
  291. if ((ca->sy > ca->dy) || ((ca->sy == ca->dy) && (ca->sx > ca->dx)))
  292. direction = 0;
  293. else
  294. direction = 2;
  295. cyblafb_sync(info);
  296. out32(GE44,0xa0000000|1<<19|1<<2|direction);
  297. out32(GE00,direction?s2:s1);
  298. out32(GE04,direction?s1:s2);
  299. out32(GE08,direction?d2:d1);
  300. out32(GE0C,direction?d1:d2);
  301. }
  302. //=======================================================================
  303. //
  304. // Cyberblade specific imageblit
  305. //
  306. // Accelerated for the most usual case, blitting 1-bit deep character
  307. // character images. Everything else is passed to the generic imageblit.
  308. //
  309. //=======================================================================
  310. static void cyblafb_imageblit(struct fb_info *info,
  311. const struct fb_image *image)
  312. {
  313. u32 fgcol, bgcol;
  314. int i;
  315. int bpp = info->var.bits_per_pixel;
  316. int index = 0;
  317. int index_end=image->height * image->width / 8;
  318. int width_dds=image->width / 32;
  319. int width_dbs=image->width % 32;
  320. if (image->depth != 1 || bpp < 8 || bpp > 32 || bpp % 8 != 0 ||
  321. image->width % 8 != 0 || image->width == 0 || image->height == 0) {
  322. cfb_imageblit(info,image);
  323. return;
  324. }
  325. if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
  326. info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
  327. fgcol = ((u32*)(info->pseudo_palette))[image->fg_color];
  328. bgcol = ((u32*)(info->pseudo_palette))[image->bg_color];
  329. } else {
  330. fgcol = image->fg_color;
  331. bgcol = image->bg_color;
  332. }
  333. switch (bpp) {
  334. case 8:
  335. fgcol |= fgcol <<8; fgcol |= fgcol <<16;
  336. bgcol |= bgcol <<8; bgcol |= bgcol <<16;
  337. break;
  338. case 16:
  339. fgcol |= fgcol <<16;
  340. bgcol |= bgcol <<16;
  341. break;
  342. default:
  343. break;
  344. }
  345. cyblafb_sync(info);
  346. out32(GE60,fgcol);
  347. out32(GE64,bgcol);
  348. out32(GE44,0xa0000000 | 1<<20 | 1<<19);
  349. out32(GE08,point(image->dx,image->dy));
  350. out32(GE0C,point(image->dx+image->width-1,image->dy+image->height-1));
  351. while(index < index_end) {
  352. for(i=0;i<width_dds;i++) {
  353. out32(GE9C,*((u32*) ((u32)image->data + index)));
  354. index+=4;
  355. }
  356. switch(width_dbs) {
  357. case 0: break;
  358. case 8: out32(GE9C,*((u8*)((u32)image->data+index)));
  359. index+=1;
  360. break;
  361. case 16: out32(GE9C,*((u16*)((u32)image->data+index)));
  362. index+=2;
  363. break;
  364. case 24: out32(GE9C,(u32)(*((u16*)((u32)image->data+index))) |
  365. (u32)(*((u8*)((u32)image->data+index+2)))<<16);
  366. index+=3;
  367. break;
  368. }
  369. }
  370. }
  371. //==========================================================
  372. //
  373. // Check if video mode is acceptable. We change var->??? if
  374. // video mode is slightly off or return error otherwise.
  375. // info->??? must not be changed!
  376. //
  377. //==========================================================
  378. static int cyblafb_check_var(struct fb_var_screeninfo *var,
  379. struct fb_info *info)
  380. {
  381. int bpp = var->bits_per_pixel;
  382. int s,t,maxvyres;
  383. //
  384. // we try to support 8, 16, 24 and 32 bpp modes,
  385. // default to 8
  386. //
  387. // there is a 24 bpp mode, but for now we change requests to 32 bpp
  388. // (This is what tridentfb does ... will be changed in the future)
  389. //
  390. //
  391. if ( bpp % 8 != 0 || bpp < 8 || bpp >32)
  392. bpp = 8;
  393. if (bpp == 24 )
  394. bpp = var->bits_per_pixel = 32;
  395. //
  396. // interlaced modes are broken, fail if one is requested
  397. //
  398. if (var->vmode & FB_VMODE_INTERLACED)
  399. return -EINVAL;
  400. //
  401. // fail if requested resolution is higher than physical
  402. // flatpanel resolution
  403. //
  404. if ((displaytype == DISPLAY_FP) && nativex && var->xres > nativex)
  405. return -EINVAL;
  406. //
  407. // xres != xres_virtual is broken, fail if such an
  408. // unusual mode is requested
  409. //
  410. if (var->xres != var->xres_virtual)
  411. return -EINVAL;
  412. //
  413. // we do not allow vclk to exceed 230 MHz
  414. //
  415. if ((bpp==32 ? 200000000 : 100000000) / var->pixclock > 23000)
  416. return -EINVAL;
  417. //
  418. // calc max yres_virtual that would fit in memory
  419. // and max yres_virtual that could be used for scrolling
  420. // and use minimum of the results as maxvyres
  421. //
  422. // adjust vyres_virtual to maxvyres if necessary
  423. // fail if requested yres is bigger than maxvyres
  424. //
  425. s = (0x1fffff / (var->xres * bpp/8)) + var->yres;
  426. t = info->fix.smem_len / (var->xres * bpp/8);
  427. maxvyres = t < s ? t : s;
  428. if (maxvyres < var->yres_virtual)
  429. var->yres_virtual=maxvyres;
  430. if (maxvyres < var->yres)
  431. return -EINVAL;
  432. switch (bpp) {
  433. case 8:
  434. var->red.offset = 0;
  435. var->green.offset = 0;
  436. var->blue.offset = 0;
  437. var->red.length = 6;
  438. var->green.length = 6;
  439. var->blue.length = 6;
  440. break;
  441. case 16:
  442. var->red.offset = 11;
  443. var->green.offset = 5;
  444. var->blue.offset = 0;
  445. var->red.length = 5;
  446. var->green.length = 6;
  447. var->blue.length = 5;
  448. break;
  449. case 32:
  450. var->red.offset = 16;
  451. var->green.offset = 8;
  452. var->blue.offset = 0;
  453. var->red.length = 8;
  454. var->green.length = 8;
  455. var->blue.length = 8;
  456. break;
  457. default:
  458. return -EINVAL;
  459. }
  460. return 0;
  461. }
  462. //=====================================================================
  463. //
  464. // Pan the display
  465. //
  466. // The datasheets defines crt start address to be 20 bits wide and
  467. // to be programmed to CR0C, CR0D, CR1E and CR27. Actually there is
  468. // CR2B[5] as an undocumented extension bit. Epia BIOS 2.07 does use
  469. // it, so it is also safe to be used here. BTW: datasheet CR0E on page
  470. // 90 really is CR1E, the real CRE is documented on page 72.
  471. //
  472. //=====================================================================
  473. static int cyblafb_pan_display(struct fb_var_screeninfo *var,
  474. struct fb_info *info)
  475. {
  476. unsigned int offset;
  477. offset=(var->xoffset+(var->yoffset*var->xres))*var->bits_per_pixel/32;
  478. info->var.xoffset = var->xoffset;
  479. info->var.yoffset = var->yoffset;
  480. write3X4(CR0D,offset & 0xFF);
  481. write3X4(CR0C,(offset & 0xFF00) >> 8);
  482. write3X4(CR1E,(read3X4(CR1E) & 0xDF) | ((offset & 0x10000) >> 11));
  483. write3X4(CR27,(read3X4(CR27) & 0xF8) | ((offset & 0xE0000) >> 17));
  484. write3X4(CR2B,(read3X4(CR2B) & 0xDF) | ((offset & 0x100000) >> 15));
  485. return 0;
  486. }
  487. //============================================
  488. //
  489. // This will really help in case of a bug ...
  490. // dump most gaphics core registers.
  491. //
  492. //============================================
  493. static void regdump(struct cyblafb_par *par)
  494. {
  495. int i;
  496. if (verbosity < 2)
  497. return;
  498. printk("\n");
  499. for(i=0; i<=0xff; i++) {
  500. outb(i,0x3d4);
  501. printk("CR%02x=%02x ",i,inb(0x3d5));
  502. if (i%16==15)
  503. printk("\n");
  504. }
  505. outb(0x30,0x3ce);
  506. outb(inb(0x3cf) | 0x40,0x3cf);
  507. for(i=0; i<=0x1f; i++) {
  508. if (i==0 || (i>2 && i<8) || i==0x10 || i==0x11 || i==0x16) {
  509. outb(i,0x3d4);
  510. printk("CR%02x=%02x ",i,inb(0x3d5));
  511. } else
  512. printk("------- ");
  513. if (i%16==15)
  514. printk("\n");
  515. }
  516. outb(0x30,0x3ce);
  517. outb(inb(0x3cf) & 0xbf,0x3cf);
  518. printk("\n");
  519. for(i=0; i<=0x7f; i++) {
  520. outb(i,0x3ce);
  521. printk("GR%02x=%02x ",i,inb(0x3cf));
  522. if (i%16==15)
  523. printk("\n");
  524. }
  525. printk("\n");
  526. for(i=0; i<=0xff; i++) {
  527. outb(i,0x3c4);
  528. printk("SR%02x=%02x ",i,inb(0x3c5));
  529. if (i%16==15)
  530. printk("\n");
  531. }
  532. printk("\n");
  533. for(i=0; i <= 0x1F; i++) {
  534. inb(0x3da); // next access is index!
  535. outb(i,0x3c0);
  536. printk("AR%02x=%02x ",i,inb(0x3c1));
  537. if (i%16==15)
  538. printk("\n");
  539. }
  540. printk("\n");
  541. inb(0x3DA); // reset internal flag to 3c0 index
  542. outb(0x20,0x3C0); // enable attr
  543. return;
  544. }
  545. //======================================
  546. //
  547. // Set hardware to requested video mode
  548. //
  549. //======================================
  550. static int cyblafb_set_par(struct fb_info *info)
  551. {
  552. struct cyblafb_par *par = info->par;
  553. u32
  554. htotal,hdispend,hsyncstart,hsyncend,hblankstart,hblankend,preendfetch,
  555. vtotal,vdispend,vsyncstart,vsyncend,vblankstart,vblankend;
  556. struct fb_var_screeninfo *var = &info->var;
  557. int bpp = var->bits_per_pixel;
  558. int i;
  559. if (verbosity > 0)
  560. output("Switching to new mode: "
  561. "fbset -g %d %d %d %d %d -t %d %d %d %d %d %d %d\n",
  562. var->xres,var->yres,var->xres_virtual,
  563. var->yres_virtual,var->bits_per_pixel,var->pixclock,
  564. var->left_margin,var->right_margin,var->upper_margin,
  565. var->lower_margin,var->hsync_len,var->vsync_len);
  566. htotal = (var->xres + var->left_margin + var->right_margin +
  567. var->hsync_len) / 8 - 5;
  568. hdispend = var->xres/8 - 1;
  569. hsyncstart = (var->xres + var->right_margin)/8;
  570. hsyncend = var->hsync_len/8;
  571. hblankstart = hdispend + 1;
  572. hblankend = htotal + 3; // should be htotal + 5, bios does it this way
  573. preendfetch = ((var->xres >> 3) + 1) * ((bpp+1) >> 3);
  574. vtotal = var->yres + var->upper_margin + var->lower_margin +
  575. var->vsync_len - 2;
  576. vdispend = var->yres - 1;
  577. vsyncstart = var->yres + var->lower_margin;
  578. vblankstart = var->yres;
  579. vblankend = vtotal; // should be vtotal + 2, but bios does it this way
  580. vsyncend = var->vsync_len;
  581. enable_mmio(); // necessary! ... check X ...
  582. write3X4(CR11,read3X4(CR11) & 0x7F); // unlock cr00 .. cr07
  583. write3CE(GR30,8);
  584. if ((displaytype == DISPLAY_FP) && var->xres < nativex) {
  585. // stretch or center ?
  586. out8(0x3C2,0xEB);
  587. write3CE(GR30,read3CE(GR30) | 0x81); // shadow mode on
  588. if (center) {
  589. write3CE(GR52,(read3CE(GR52) & 0x7C) | 0x80);
  590. write3CE(GR53,(read3CE(GR53) & 0x7C) | 0x80);
  591. }
  592. else if (stretch) {
  593. write3CE(GR5D,0);
  594. write3CE(GR52,(read3CE(GR52) & 0x7C) | 1);
  595. write3CE(GR53,(read3CE(GR53) & 0x7C) | 1);
  596. }
  597. } else {
  598. out8(0x3C2,0x2B);
  599. write3CE(GR30,8);
  600. }
  601. //
  602. // Setup CRxx regs
  603. //
  604. write3X4(CR00,htotal & 0xFF);
  605. write3X4(CR01,hdispend & 0xFF);
  606. write3X4(CR02,hblankstart & 0xFF);
  607. write3X4(CR03,hblankend & 0x1F);
  608. write3X4(CR04,hsyncstart & 0xFF);
  609. write3X4(CR05,(hsyncend & 0x1F) | ((hblankend & 0x20)<<2));
  610. write3X4(CR06,vtotal & 0xFF);
  611. write3X4(CR07,(vtotal & 0x100) >> 8 |
  612. (vdispend & 0x100) >> 7 |
  613. (vsyncstart & 0x100) >> 6 |
  614. (vblankstart & 0x100) >> 5 |
  615. 0x10 |
  616. (vtotal & 0x200) >> 4 |
  617. (vdispend & 0x200) >> 3 |
  618. (vsyncstart & 0x200) >> 2);
  619. write3X4(CR08,0);
  620. write3X4(CR09,(vblankstart & 0x200) >> 4 | 0x40 | // FIX !!!
  621. ((info->var.vmode & FB_VMODE_DOUBLE) ? 0x80 : 0));
  622. write3X4(CR0A,0); // Init to some reasonable default
  623. write3X4(CR0B,0); // Init to some reasonable default
  624. write3X4(CR0C,0); // Offset 0
  625. write3X4(CR0D,0); // Offset 0
  626. write3X4(CR0E,0); // Init to some reasonable default
  627. write3X4(CR0F,0); // Init to some reasonable default
  628. write3X4(CR10,vsyncstart & 0xFF);
  629. write3X4(CR11,(vsyncend & 0x0F));
  630. write3X4(CR12,vdispend & 0xFF);
  631. write3X4(CR13,((info->var.xres * bpp)/(4*16)) & 0xFF);
  632. write3X4(CR14,0x40); // double word mode
  633. write3X4(CR15,vblankstart & 0xFF);
  634. write3X4(CR16,vblankend & 0xFF);
  635. write3X4(CR17,0xC3);
  636. write3X4(CR18,0xFF);
  637. // CR19: needed for interlaced modes ... ignore it for now
  638. write3X4(CR1A,0x07); // Arbitration Control Counter 1
  639. write3X4(CR1B,0x07); // Arbitration Control Counter 2
  640. write3X4(CR1C,0x07); // Arbitration Control Counter 3
  641. write3X4(CR1D,0x00); // Don't know, doesn't hurt ;-)
  642. write3X4(CR1E,(info->var.vmode & FB_VMODE_INTERLACED) ? 0x84 : 0x80);
  643. // CR1F: do not set, contains BIOS info about memsize
  644. write3X4(CR20,0x20); // enabe wr buf, disable 16bit planar mode
  645. write3X4(CR21,0x20); // enable linear memory access
  646. // CR22: RO cpu latch readback
  647. // CR23: ???
  648. // CR24: RO AR flag state
  649. // CR25: RAMDAC rw timing, pclk buffer tristate control ????
  650. // CR26: ???
  651. write3X4(CR27,(vdispend & 0x400) >> 6 |
  652. (vsyncstart & 0x400) >> 5 |
  653. (vblankstart & 0x400) >> 4 |
  654. (vtotal & 0x400) >> 3 |
  655. 0x8);
  656. // CR28: ???
  657. write3X4(CR29,(read3X4(CR29) & 0xCF) |
  658. ((((info->var.xres * bpp) / (4*16)) & 0x300) >>4));
  659. write3X4(CR2A,read3X4(CR2A) | 0x40);
  660. write3X4(CR2B,(htotal & 0x100) >> 8 |
  661. (hdispend & 0x100) >> 7 |
  662. // (0x00 & 0x100) >> 6 | hinterlace para bit 8 ???
  663. (hsyncstart & 0x100) >> 5 |
  664. (hblankstart & 0x100) >> 4);
  665. // CR2C: ???
  666. // CR2D: initialized in cyblafb_setup_GE()
  667. write3X4(CR2F,0x92); // conservative, better signal quality
  668. // CR30: reserved
  669. // CR31: reserved
  670. // CR32: reserved
  671. // CR33: reserved
  672. // CR34: disabled in CR36
  673. // CR35: disabled in CR36
  674. // CR36: initialized in cyblafb_setup_GE
  675. // CR37: i2c, ignore for now
  676. write3X4(CR38,(bpp == 8) ? 0x00 : //
  677. (bpp == 16) ? 0x05 : // highcolor
  678. (bpp == 24) ? 0x29 : // packed 24bit truecolor
  679. (bpp == 32) ? 0x09 : 0); // truecolor, 16 bit pixelbus
  680. write3X4(CR39,0x01 | // MMIO enable
  681. (pcirb ? 0x02 : 0) | // pci read burst enable
  682. (pciwb ? 0x04 : 0)); // pci write burst enable
  683. write3X4(CR55,0x1F | // pci clocks * 2 for STOP# during 1st data phase
  684. (pcirr ? 0x40 : 0) | // pci read retry enable
  685. (pciwr ? 0x80 : 0)); // pci write retry enable
  686. write3X4(CR56,preendfetch >> 8 < 2 ? (preendfetch >> 8 & 0x01)|2 : 0);
  687. write3X4(CR57,preendfetch >> 8 < 2 ? preendfetch & 0xff : 0);
  688. write3X4(CR58,0x82); // Bios does this .... don't know more
  689. //
  690. // Setup SRxx regs
  691. //
  692. write3C4(SR00,3);
  693. write3C4(SR01,1); //set char clock 8 dots wide
  694. write3C4(SR02,0x0F); //enable 4 maps needed in chain4 mode
  695. write3C4(SR03,0); //no character map select
  696. write3C4(SR04,0x0E); //memory mode: ext mem, even, chain4
  697. out8(0x3C4,0x0b);
  698. in8(0x3C5); // Set NEW mode
  699. write3C4(SR0D,0x00); // test ... check
  700. set_vclk(par,(bpp==32 ? 200000000 : 100000000)/
  701. info->var.pixclock); //SR18,SR19
  702. //
  703. // Setup GRxx regs
  704. //
  705. write3CE(GR00,0x00); // test ... check
  706. write3CE(GR01,0x00); // test ... check
  707. write3CE(GR02,0x00); // test ... check
  708. write3CE(GR03,0x00); // test ... check
  709. write3CE(GR04,0x00); // test ... check
  710. write3CE(GR05,0x40); // no CGA compat,allow 256 col
  711. write3CE(GR06,0x05); // graphics mode
  712. write3CE(GR07,0x0F); // planes?
  713. write3CE(GR08,0xFF); // test ... check
  714. write3CE(GR0F,(bpp==32)?0x1A:0x12); // div vclk by 2 if 32bpp, chain4
  715. write3CE(GR20,0xC0); // test ... check
  716. write3CE(GR2F,0xA0); // PCLK = VCLK, no skew,
  717. //
  718. // Setup ARxx regs
  719. //
  720. for(i = 0;i < 0x10;i++) // set AR00 .. AR0f
  721. write3C0(i,i);
  722. write3C0(AR10,0x41); // graphics mode and support 256 color modes
  723. write3C0(AR12,0x0F); // planes
  724. write3C0(AR13,0); // horizontal pel panning
  725. in8(0x3DA); // reset internal flag to 3c0 index
  726. out8(0x3C0,0x20); // enable attr
  727. //
  728. // Setup hidden RAMDAC command register
  729. //
  730. in8(0x3C8); // these reads are
  731. in8(0x3C6); // necessary to
  732. in8(0x3C6); // unmask the RAMDAC
  733. in8(0x3C6); // command reg, otherwise
  734. in8(0x3C6); // we would write the pixelmask reg!
  735. out8(0x3C6,(bpp == 8) ? 0x00 : // 256 colors
  736. (bpp == 15) ? 0x10 : //
  737. (bpp == 16) ? 0x30 : // hicolor
  738. (bpp == 24) ? 0xD0 : // truecolor
  739. (bpp == 32) ? 0xD0 : 0); // truecolor
  740. in8(0x3C8);
  741. //
  742. // GR31 is not mentioned in the datasheet
  743. //
  744. if (displaytype == DISPLAY_FP)
  745. write3CE(GR31,(read3CE(GR31) & 0x8F) |
  746. ((info->var.yres > 1024) ? 0x50 :
  747. (info->var.yres > 768) ? 0x30 :
  748. (info->var.yres > 600) ? 0x20 :
  749. (info->var.yres > 480) ? 0x10 : 0));
  750. info->fix.visual = (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR
  751. : FB_VISUAL_TRUECOLOR;
  752. info->fix.line_length = info->var.xres * (bpp >> 3);
  753. info->cmap.len = (bpp == 8) ? 256: 16;
  754. //
  755. // init acceleration engine
  756. //
  757. cyblafb_setup_GE(info->var.xres,info->var.bits_per_pixel);
  758. regdump(par);
  759. return 0;
  760. }
  761. //========================
  762. //
  763. // Set one color register
  764. //
  765. //========================
  766. static int cyblafb_setcolreg(unsigned regno, unsigned red, unsigned green,
  767. unsigned blue, unsigned transp,
  768. struct fb_info *info)
  769. {
  770. int bpp = info->var.bits_per_pixel;
  771. if (regno >= info->cmap.len)
  772. return 1;
  773. if (bpp == 8) {
  774. out8(0x3C6,0xFF);
  775. out8(0x3C8,regno);
  776. out8(0x3C9,red>>10);
  777. out8(0x3C9,green>>10);
  778. out8(0x3C9,blue>>10);
  779. } else if (bpp == 16) // RGB 565
  780. ((u32*)info->pseudo_palette)[regno] =
  781. (red & 0xF800) |
  782. ((green & 0xFC00) >> 5) |
  783. ((blue & 0xF800) >> 11);
  784. else if (bpp == 32) // ARGB 8888
  785. ((u32*)info->pseudo_palette)[regno] =
  786. ((transp & 0xFF00) <<16) |
  787. ((red & 0xFF00) << 8) |
  788. ((green & 0xFF00)) |
  789. ((blue & 0xFF00)>>8);
  790. return 0;
  791. }
  792. //==========================================================
  793. //
  794. // Try blanking the screen. For flat panels it does nothing
  795. //
  796. //==========================================================
  797. static int cyblafb_blank(int blank_mode, struct fb_info *info)
  798. {
  799. unsigned char PMCont,DPMSCont;
  800. if (displaytype == DISPLAY_FP)
  801. return 0;
  802. out8(0x83C8,0x04); // DPMS Control
  803. PMCont = in8(0x83C6) & 0xFC;
  804. DPMSCont = read3CE(GR23) & 0xFC;
  805. switch (blank_mode)
  806. {
  807. case FB_BLANK_UNBLANK: // Screen: On, HSync: On, VSync: On
  808. case FB_BLANK_NORMAL: // Screen: Off, HSync: On, VSync: On
  809. PMCont |= 0x03;
  810. DPMSCont |= 0x00;
  811. break;
  812. case FB_BLANK_HSYNC_SUSPEND: // Screen: Off, HSync: Off, VSync: On
  813. PMCont |= 0x02;
  814. DPMSCont |= 0x01;
  815. break;
  816. case FB_BLANK_VSYNC_SUSPEND: // Screen: Off, HSync: On, VSync: Off
  817. PMCont |= 0x02;
  818. DPMSCont |= 0x02;
  819. break;
  820. case FB_BLANK_POWERDOWN: // Screen: Off, HSync: Off, VSync: Off
  821. PMCont |= 0x00;
  822. DPMSCont |= 0x03;
  823. break;
  824. }
  825. write3CE(GR23,DPMSCont);
  826. out8(0x83C8,4);
  827. out8(0x83C6,PMCont);
  828. //
  829. // let fbcon do a softblank for us
  830. //
  831. return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0;
  832. }
  833. static struct fb_ops cyblafb_ops __devinitdata = {
  834. .owner = THIS_MODULE,
  835. .fb_setcolreg = cyblafb_setcolreg,
  836. .fb_pan_display = cyblafb_pan_display,
  837. .fb_blank = cyblafb_blank,
  838. .fb_check_var = cyblafb_check_var,
  839. .fb_set_par = cyblafb_set_par,
  840. .fb_fillrect = cyblafb_fillrect,
  841. .fb_copyarea= cyblafb_copyarea,
  842. .fb_imageblit = cyblafb_imageblit,
  843. .fb_cursor = soft_cursor,
  844. };
  845. //==========================================================================
  846. //
  847. // getstartupmode() decides about the inital video mode
  848. //
  849. // There is no reason to use modedb, a lot of video modes there would
  850. // need altered timings to display correctly. So I decided that it is much
  851. // better to provide a limited optimized set of modes plus the option of
  852. // using the mode in effect at startup time (might be selected using the
  853. // vga=??? paramter). After that the user might use fbset to select any
  854. // mode he likes, check_var will not try to alter geometry parameters as
  855. // it would be necessary otherwise.
  856. //
  857. //==========================================================================
  858. static int __devinit getstartupmode(struct fb_info *info)
  859. {
  860. u32 htotal,hdispend,hsyncstart,hsyncend,hblankstart,hblankend,
  861. vtotal,vdispend,vsyncstart,vsyncend,vblankstart,vblankend,
  862. cr00,cr01,cr02,cr03,cr04,cr05,cr2b,
  863. cr06,cr07,cr09,cr10,cr11,cr12,cr15,cr16,cr27,
  864. cr38,
  865. sr0d,sr18,sr19,
  866. gr0f,
  867. fi,pxclkdiv,vclkdiv,tmp,i;
  868. struct modus {
  869. int xres; int yres; int vyres; int bpp; int pxclk;
  870. int left_margin; int right_margin; int upper_margin;
  871. int lower_margin; int hsync_len; int vsync_len;
  872. } modedb[5] = {
  873. { 0, 0, 8000, 0, 0, 0, 0, 0, 0, 0, 0},
  874. { 640, 480, 3756, 0, 0, -40, 24, 17, 0, 216, 3},
  875. { 800, 600, 3221, 0, 0, 96, 24, 14, 0, 136, 11},
  876. {1024, 768, 2815, 0, 0, 144, 24, 29, 0, 120, 3},
  877. {1280, 1024, 2662, 0, 0, 232, 16, 39, 0, 160, 3}
  878. };
  879. outb(0x00,0x3d4); cr00=inb(0x3d5); outb(0x01,0x3d4); cr01=inb(0x3d5);
  880. outb(0x02,0x3d4); cr02=inb(0x3d5); outb(0x03,0x3d4); cr03=inb(0x3d5);
  881. outb(0x04,0x3d4); cr04=inb(0x3d5); outb(0x05,0x3d4); cr05=inb(0x3d5);
  882. outb(0x06,0x3d4); cr06=inb(0x3d5); outb(0x07,0x3d4); cr07=inb(0x3d5);
  883. outb(0x09,0x3d4); cr09=inb(0x3d5); outb(0x10,0x3d4); cr10=inb(0x3d5);
  884. outb(0x11,0x3d4); cr11=inb(0x3d5); outb(0x12,0x3d4); cr12=inb(0x3d5);
  885. outb(0x15,0x3d4); cr15=inb(0x3d5); outb(0x16,0x3d4); cr16=inb(0x3d5);
  886. outb(0x27,0x3d4); cr27=inb(0x3d5); outb(0x2b,0x3d4); cr2b=inb(0x3d5);
  887. outb(0x38,0x3d4); cr38=inb(0x3d5); outb(0x0b,0x3c4); inb(0x3c5);
  888. outb(0x0d,0x3c4); sr0d=inb(0x3c5); outb(0x18,0x3c4); sr18=inb(0x3c5);
  889. outb(0x19,0x3c4); sr19=inb(0x3c5); outb(0x0f,0x3ce); gr0f=inb(0x3cf);
  890. htotal = cr00 | (cr2b & 0x01) << 8;
  891. hdispend = cr01 | (cr2b & 0x02) << 7;
  892. hblankstart = cr02 | (cr2b & 0x10) << 4;
  893. hblankend = (cr03 & 0x1f) | (cr05 & 0x80) >> 2;
  894. hsyncstart = cr04 | (cr2b & 0x08) << 5;
  895. hsyncend = cr05 & 0x1f;
  896. modedb[0].xres = hblankstart * 8;
  897. modedb[0].hsync_len = hsyncend * 8;
  898. modedb[0].right_margin = hsyncstart * 8 - modedb[0].xres;
  899. modedb[0].left_margin = (htotal + 5) * 8 - modedb[0].xres -
  900. modedb[0].right_margin - modedb[0].hsync_len;
  901. vtotal = cr06 | (cr07 & 0x01) << 8 | (cr07 & 0x20) << 4
  902. | (cr27 & 0x80) << 3;
  903. vdispend = cr12 | (cr07 & 0x02) << 7 | (cr07 & 0x40) << 3
  904. | (cr27 & 0x10) << 6;
  905. vsyncstart = cr10 | (cr07 & 0x04) << 6 | (cr07 & 0x80) << 2
  906. | (cr27 & 0x20) << 5;
  907. vsyncend = cr11 & 0x0f;
  908. vblankstart = cr15 | (cr07 & 0x08) << 5 | (cr09 & 0x20) << 4
  909. | (cr27 & 0x40) << 4;
  910. vblankend = cr16;
  911. modedb[0].yres = vdispend + 1;
  912. modedb[0].vsync_len = vsyncend;
  913. modedb[0].lower_margin = vsyncstart - modedb[0].yres;
  914. modedb[0].upper_margin = vtotal - modedb[0].yres -
  915. modedb[0].lower_margin - modedb[0].vsync_len + 2;
  916. tmp = cr38 & 0x3c;
  917. modedb[0].bpp = tmp == 0 ? 8 : tmp == 4 ? 16 : tmp == 28 ? 24 :
  918. tmp == 8 ? 32 : 8;
  919. fi = ((5864727*(sr18+8))/(((sr19&0x3f)+2)*(1<<((sr19&0xc0)>>6))))>>12;
  920. pxclkdiv = ((gr0f & 0x08) >> 3 | (gr0f & 0x40) >> 5) + 1;
  921. tmp = sr0d & 0x06;
  922. vclkdiv = tmp == 0 ? 2 : tmp == 2 ? 4 : tmp == 4 ? 8 : 3; // * 2 !
  923. modedb[0].pxclk = ((100000000 * pxclkdiv * vclkdiv) >> 1) / fi;
  924. if (verbosity > 0)
  925. output("detected startup mode: "
  926. "fbset -g %d %d %d ??? %d -t %d %d %d %d %d %d %d\n",
  927. modedb[0].xres,modedb[0].yres,modedb[0].xres,
  928. modedb[0].bpp,modedb[0].pxclk,modedb[0].left_margin,
  929. modedb[0].right_margin,modedb[0].upper_margin,
  930. modedb[0].lower_margin,modedb[0].hsync_len,
  931. modedb[0].vsync_len);
  932. //
  933. // We use this goto target in case of a failed check_var. No, I really
  934. // do not want to do it in another way!
  935. //
  936. tryagain:
  937. i = (mode == NULL) ? 0 :
  938. !strncmp(mode,"640x480",7) ? 1 :
  939. !strncmp(mode,"800x600",7) ? 2 :
  940. !strncmp(mode,"1024x768",8) ? 3 :
  941. !strncmp(mode,"1280x1024",9) ? 4 : 0;
  942. ref = (ref < 50) ? 50 : (ref > 85) ? 85 : ref;
  943. if(i==0) {
  944. info->var.pixclock = modedb[i].pxclk;
  945. info->var.bits_per_pixel = modedb[i].bpp;
  946. } else {
  947. info->var.pixclock = (100000000 /
  948. ((modedb[i].left_margin + modedb[i].xres +
  949. modedb[i].right_margin + modedb[i].hsync_len
  950. ) * (
  951. modedb[i].upper_margin + modedb[i].yres +
  952. modedb[i].lower_margin + modedb[i].vsync_len
  953. ) *
  954. ref / 10000
  955. ));
  956. info->var.bits_per_pixel = bpp;
  957. }
  958. info->var.left_margin = modedb[i].left_margin;
  959. info->var.right_margin = modedb[i].right_margin;
  960. info->var.xres = modedb[i].xres;
  961. info->var.xres_virtual = modedb[i].xres;
  962. info->var.xoffset = 0;
  963. info->var.hsync_len = modedb[i].hsync_len;
  964. info->var.upper_margin = modedb[i].upper_margin;
  965. info->var.yres = modedb[i].yres;
  966. info->var.yres_virtual = modedb[i].vyres;
  967. info->var.yoffset = 0;
  968. info->var.lower_margin = modedb[i].lower_margin;
  969. info->var.vsync_len = modedb[i].vsync_len;
  970. info->var.sync = 0;
  971. info->var.vmode = FB_VMODE_NONINTERLACED;
  972. if(cyblafb_check_var(&info->var,info)) {
  973. // 640x480-8@75 should really never fail. One case would
  974. // be fp == 1 and nativex < 640 ... give up then
  975. if(i==1 && bpp == 8 && ref == 75){
  976. output("Can't find a valid mode :-(\n");
  977. return -EINVAL;
  978. }
  979. // Our detected mode is unlikely to fail. If it does,
  980. // try 640x480-8@75 ...
  981. if(i==0) {
  982. mode="640x480";
  983. bpp=8;
  984. ref=75;
  985. output("Detected mode failed check_var! "
  986. "Trying 640x480-8@75\n");
  987. goto tryagain;
  988. }
  989. // A specified video mode failed for some reason.
  990. // Try the startup mode first
  991. output("Specified mode '%s' failed check! "
  992. "Falling back to startup mode.\n",mode);
  993. mode=NULL;
  994. goto tryagain;
  995. }
  996. return 0;
  997. }
  998. //========================================================
  999. //
  1000. // Detect activated memory size. Undefined values require
  1001. // memsize parameter.
  1002. //
  1003. //========================================================
  1004. static unsigned int __devinit get_memsize(void)
  1005. {
  1006. unsigned char tmp;
  1007. unsigned int k;
  1008. if (memsize)
  1009. k = memsize * Kb;
  1010. else {
  1011. tmp = read3X4(CR1F) & 0x0F;
  1012. switch (tmp) {
  1013. case 0x03: k = 1 * Mb; break;
  1014. case 0x07: k = 2 * Mb; break;
  1015. case 0x0F: k = 4 * Mb; break;
  1016. case 0x04: k = 8 * Mb; break;
  1017. default:
  1018. k = 1 * Mb;
  1019. output("Unknown memory size code %x in CR1F."
  1020. " We default to 1 Mb for now, please"
  1021. " do provide a memsize parameter!\n",
  1022. tmp);
  1023. }
  1024. }
  1025. if (verbosity > 0)
  1026. output("framebuffer size = %d Kb\n",k/Kb);
  1027. return k;
  1028. }
  1029. //=========================================================
  1030. //
  1031. // Detect if a flat panel monitor connected to the special
  1032. // interface is active. Override is possible by fp and crt
  1033. // parameters.
  1034. //
  1035. //=========================================================
  1036. static unsigned int __devinit get_displaytype(void)
  1037. {
  1038. if (fp)
  1039. return DISPLAY_FP;
  1040. if (crt)
  1041. return DISPLAY_CRT;
  1042. return (read3CE(GR33) & 0x10)?DISPLAY_FP:DISPLAY_CRT;
  1043. }
  1044. //=====================================
  1045. //
  1046. // Get native resolution of flat panel
  1047. //
  1048. //=====================================
  1049. static int __devinit get_nativex(void)
  1050. {
  1051. int x,y,tmp;
  1052. if (nativex)
  1053. return nativex;
  1054. tmp = (read3CE(GR52) >> 4) & 3;
  1055. switch (tmp) {
  1056. case 0: x = 1280; y = 1024; break;
  1057. case 2: x = 1024; y = 768; break;
  1058. case 3: x = 800; y = 600; break;
  1059. case 4: x = 1400; y = 1050; break;
  1060. case 1:
  1061. default: x = 640; y = 480; break;
  1062. }
  1063. if (verbosity > 0)
  1064. output("%dx%d flat panel found\n",x,y);
  1065. return x;
  1066. }
  1067. static int __devinit cybla_pci_probe(struct pci_dev * dev,
  1068. const struct pci_device_id * id)
  1069. {
  1070. struct fb_info *info;
  1071. struct cyblafb_par *par;
  1072. info = framebuffer_alloc(sizeof(struct cyblafb_par),&dev->dev);
  1073. if (!info)
  1074. goto errout_alloc;
  1075. par = info->par;
  1076. par->ops = cyblafb_ops;
  1077. info->fix = cyblafb_fix;
  1078. info->fbops = &par->ops;
  1079. info->fix = cyblafb_fix;
  1080. if (pci_enable_device(dev)) {
  1081. output("could not enable device!\n");
  1082. goto errout_enable;
  1083. }
  1084. // might already be requested by vga console or vesafb,
  1085. // so we do care about success
  1086. request_region(0x3c0,32,"cyblafb");
  1087. //
  1088. // Graphics Engine Registers
  1089. //
  1090. request_region(GEBase,0x100,"cyblafb");
  1091. regdump(par);
  1092. enable_mmio();
  1093. // setup MMIO region
  1094. info->fix.mmio_start = pci_resource_start(dev,1);
  1095. info->fix.mmio_len = 0x20000;
  1096. if (!request_mem_region(info->fix.mmio_start,
  1097. info->fix.mmio_len,"cyblafb")) {
  1098. output("request_mem_region failed for mmio region!\n");
  1099. goto errout_mmio_reqmem;
  1100. }
  1101. io_virt = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len);
  1102. if (!io_virt) {
  1103. output("ioremap failed for mmio region\n");
  1104. goto errout_mmio_remap;
  1105. }
  1106. // setup framebuffer memory ... might already be requested
  1107. // by vesafb. Not to fail in case of an unsuccessful request
  1108. // is useful for the development cycle
  1109. info->fix.smem_start = pci_resource_start(dev,0);
  1110. info->fix.smem_len = get_memsize();
  1111. if (!request_mem_region(info->fix.smem_start,
  1112. info->fix.smem_len,"cyblafb")) {
  1113. output("request_mem_region failed for smem region!\n");
  1114. if (!vesafb)
  1115. goto errout_smem_req;
  1116. }
  1117. info->screen_base = ioremap_nocache(info->fix.smem_start,
  1118. info->fix.smem_len);
  1119. if (!info->screen_base) {
  1120. output("ioremap failed for smem region\n");
  1121. goto errout_smem_remap;
  1122. }
  1123. displaytype = get_displaytype();
  1124. if(displaytype == DISPLAY_FP)
  1125. nativex = get_nativex();
  1126. //
  1127. // FBINFO_HWACCEL_YWRAP .... does not work (could be made to work?)
  1128. // FBINFO_PARTIAL_PAN_OK .... is not ok
  1129. // FBINFO_READS_FAST .... is necessary for optimal scrolling
  1130. //
  1131. info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN
  1132. | FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT
  1133. | FBINFO_HWACCEL_IMAGEBLIT | FBINFO_READS_FAST;
  1134. info->pseudo_palette = par->pseudo_pal;
  1135. if(getstartupmode(info))
  1136. goto errout_findmode;
  1137. fb_alloc_cmap(&info->cmap,256,0);
  1138. if (register_framebuffer(info)) {
  1139. output("Could not register CyBla framebuffer\n");
  1140. goto errout_register;
  1141. }
  1142. pci_set_drvdata(dev,info);
  1143. //
  1144. // normal exit and error paths
  1145. //
  1146. return 0;
  1147. errout_register:
  1148. errout_findmode:
  1149. iounmap(info->screen_base);
  1150. errout_smem_remap:
  1151. release_mem_region(info->fix.smem_start,
  1152. info->fix.smem_len);
  1153. errout_smem_req:
  1154. iounmap(io_virt);
  1155. errout_mmio_remap:
  1156. release_mem_region(info->fix.mmio_start,
  1157. info->fix.mmio_len);
  1158. errout_mmio_reqmem:
  1159. // release_region(0x3c0,32);
  1160. errout_enable:
  1161. framebuffer_release(info);
  1162. errout_alloc:
  1163. output("CyblaFB version %s aborting init.\n",VERSION);
  1164. return -ENODEV;
  1165. }
  1166. static void __devexit cybla_pci_remove(struct pci_dev *dev)
  1167. {
  1168. struct fb_info *info = pci_get_drvdata(dev);
  1169. unregister_framebuffer(info);
  1170. iounmap(io_virt);
  1171. iounmap(info->screen_base);
  1172. release_mem_region(info->fix.smem_start,info->fix.smem_len);
  1173. release_mem_region(info->fix.mmio_start,info->fix.mmio_len);
  1174. fb_dealloc_cmap(&info->cmap);
  1175. framebuffer_release(info);
  1176. output("CyblaFB version %s normal exit.\n",VERSION);
  1177. }
  1178. //
  1179. // List of boards that we are trying to support
  1180. //
  1181. static struct pci_device_id cybla_devices[] = {
  1182. {PCI_VENDOR_ID_TRIDENT,CYBERBLADEi1,PCI_ANY_ID,PCI_ANY_ID,0,0,0},
  1183. {0,}
  1184. };
  1185. MODULE_DEVICE_TABLE(pci,cybla_devices);
  1186. static struct pci_driver cyblafb_pci_driver = {
  1187. .name = "cyblafb",
  1188. .id_table = cybla_devices,
  1189. .probe = cybla_pci_probe,
  1190. .remove = __devexit_p(cybla_pci_remove)
  1191. };
  1192. //=============================================================
  1193. //
  1194. // kernel command line example:
  1195. //
  1196. // video=cyblafb:1280x1024,bpp=16,ref=50 ...
  1197. //
  1198. // modprobe command line example:
  1199. //
  1200. // modprobe cyblafb mode=1280x1024 bpp=16 ref=50 ...
  1201. //
  1202. //=============================================================
  1203. static int __devinit cyblafb_init(void)
  1204. {
  1205. #ifndef MODULE
  1206. char *options = NULL;
  1207. char *opt;
  1208. if (fb_get_options("cyblafb",&options))
  1209. return -ENODEV;
  1210. if (options && *options)
  1211. while((opt = strsep(&options,",")) != NULL ) {
  1212. if (!*opt) continue;
  1213. else if (!strncmp(opt,"bpp=",4))
  1214. bpp = simple_strtoul(opt+4,NULL,0);
  1215. else if (!strncmp(opt,"ref=",4))
  1216. ref = simple_strtoul(opt+4,NULL,0);
  1217. else if (!strncmp(opt,"fp",2))
  1218. displaytype = DISPLAY_FP;
  1219. else if (!strncmp(opt,"crt",3))
  1220. displaytype = DISPLAY_CRT;
  1221. else if (!strncmp(opt,"nativex=",8))
  1222. nativex = simple_strtoul(opt+8,NULL,0);
  1223. else if (!strncmp(opt,"center",6))
  1224. center = 1;
  1225. else if (!strncmp(opt,"stretch",7))
  1226. stretch = 1;
  1227. else if (!strncmp(opt,"pciwb=",6))
  1228. pciwb = simple_strtoul(opt+6,NULL,0);
  1229. else if (!strncmp(opt,"pcirb=",6))
  1230. pcirb = simple_strtoul(opt+6,NULL,0);
  1231. else if (!strncmp(opt,"pciwr=",6))
  1232. pciwr = simple_strtoul(opt+6,NULL,0);
  1233. else if (!strncmp(opt,"pcirr=",6))
  1234. pcirr = simple_strtoul(opt+6,NULL,0);
  1235. else if (!strncmp(opt,"memsize=",8))
  1236. memsize = simple_strtoul(opt+8,NULL,0);
  1237. else if (!strncmp(opt,"verbosity=",10))
  1238. verbosity = simple_strtoul(opt+10,NULL,0);
  1239. else if (!strncmp(opt,"vesafb",6))
  1240. vesafb = 1;
  1241. else
  1242. mode = opt;
  1243. }
  1244. #endif
  1245. output("CyblaFB version %s initializing\n",VERSION);
  1246. return pci_module_init(&cyblafb_pci_driver);
  1247. }
  1248. static void __exit cyblafb_exit(void)
  1249. {
  1250. pci_unregister_driver(&cyblafb_pci_driver);
  1251. }
  1252. module_init(cyblafb_init);
  1253. module_exit(cyblafb_exit);
  1254. MODULE_AUTHOR("Knut Petersen <knut_petersen@t-online.de>");
  1255. MODULE_DESCRIPTION("Framebuffer driver for Cyberblade/i1 graphics core");
  1256. MODULE_LICENSE("GPL");