cyblafb.c 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457
  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. const char *p = image->data + index;
  353. for(i=0;i<width_dds;i++) {
  354. out32(GE9C,*(u32*)p);
  355. p+=4;
  356. index+=4;
  357. }
  358. switch(width_dbs) {
  359. case 0: break;
  360. case 8: out32(GE9C,*(u8*)p);
  361. index+=1;
  362. break;
  363. case 16: out32(GE9C,*(u16*)p);
  364. index+=2;
  365. break;
  366. case 24: out32(GE9C,*(u16*)p | *(u8*)(p+2)<<16);
  367. index+=3;
  368. break;
  369. }
  370. }
  371. }
  372. //==========================================================
  373. //
  374. // Check if video mode is acceptable. We change var->??? if
  375. // video mode is slightly off or return error otherwise.
  376. // info->??? must not be changed!
  377. //
  378. //==========================================================
  379. static int cyblafb_check_var(struct fb_var_screeninfo *var,
  380. struct fb_info *info)
  381. {
  382. int bpp = var->bits_per_pixel;
  383. int s,t,maxvyres;
  384. //
  385. // we try to support 8, 16, 24 and 32 bpp modes,
  386. // default to 8
  387. //
  388. // there is a 24 bpp mode, but for now we change requests to 32 bpp
  389. // (This is what tridentfb does ... will be changed in the future)
  390. //
  391. //
  392. if ( bpp % 8 != 0 || bpp < 8 || bpp >32)
  393. bpp = 8;
  394. if (bpp == 24 )
  395. bpp = var->bits_per_pixel = 32;
  396. //
  397. // interlaced modes are broken, fail if one is requested
  398. //
  399. if (var->vmode & FB_VMODE_INTERLACED)
  400. return -EINVAL;
  401. //
  402. // fail if requested resolution is higher than physical
  403. // flatpanel resolution
  404. //
  405. if ((displaytype == DISPLAY_FP) && nativex && var->xres > nativex)
  406. return -EINVAL;
  407. //
  408. // xres != xres_virtual is broken, fail if such an
  409. // unusual mode is requested
  410. //
  411. if (var->xres != var->xres_virtual)
  412. return -EINVAL;
  413. //
  414. // we do not allow vclk to exceed 230 MHz
  415. //
  416. if ((bpp==32 ? 200000000 : 100000000) / var->pixclock > 23000)
  417. return -EINVAL;
  418. //
  419. // calc max yres_virtual that would fit in memory
  420. // and max yres_virtual that could be used for scrolling
  421. // and use minimum of the results as maxvyres
  422. //
  423. // adjust vyres_virtual to maxvyres if necessary
  424. // fail if requested yres is bigger than maxvyres
  425. //
  426. s = (0x1fffff / (var->xres * bpp/8)) + var->yres;
  427. t = info->fix.smem_len / (var->xres * bpp/8);
  428. maxvyres = t < s ? t : s;
  429. if (maxvyres < var->yres_virtual)
  430. var->yres_virtual=maxvyres;
  431. if (maxvyres < var->yres)
  432. return -EINVAL;
  433. switch (bpp) {
  434. case 8:
  435. var->red.offset = 0;
  436. var->green.offset = 0;
  437. var->blue.offset = 0;
  438. var->red.length = 6;
  439. var->green.length = 6;
  440. var->blue.length = 6;
  441. break;
  442. case 16:
  443. var->red.offset = 11;
  444. var->green.offset = 5;
  445. var->blue.offset = 0;
  446. var->red.length = 5;
  447. var->green.length = 6;
  448. var->blue.length = 5;
  449. break;
  450. case 32:
  451. var->red.offset = 16;
  452. var->green.offset = 8;
  453. var->blue.offset = 0;
  454. var->red.length = 8;
  455. var->green.length = 8;
  456. var->blue.length = 8;
  457. break;
  458. default:
  459. return -EINVAL;
  460. }
  461. return 0;
  462. }
  463. //=====================================================================
  464. //
  465. // Pan the display
  466. //
  467. // The datasheets defines crt start address to be 20 bits wide and
  468. // to be programmed to CR0C, CR0D, CR1E and CR27. Actually there is
  469. // CR2B[5] as an undocumented extension bit. Epia BIOS 2.07 does use
  470. // it, so it is also safe to be used here. BTW: datasheet CR0E on page
  471. // 90 really is CR1E, the real CRE is documented on page 72.
  472. //
  473. //=====================================================================
  474. static int cyblafb_pan_display(struct fb_var_screeninfo *var,
  475. struct fb_info *info)
  476. {
  477. unsigned int offset;
  478. offset=(var->xoffset+(var->yoffset*var->xres))*var->bits_per_pixel/32;
  479. info->var.xoffset = var->xoffset;
  480. info->var.yoffset = var->yoffset;
  481. write3X4(CR0D,offset & 0xFF);
  482. write3X4(CR0C,(offset & 0xFF00) >> 8);
  483. write3X4(CR1E,(read3X4(CR1E) & 0xDF) | ((offset & 0x10000) >> 11));
  484. write3X4(CR27,(read3X4(CR27) & 0xF8) | ((offset & 0xE0000) >> 17));
  485. write3X4(CR2B,(read3X4(CR2B) & 0xDF) | ((offset & 0x100000) >> 15));
  486. return 0;
  487. }
  488. //============================================
  489. //
  490. // This will really help in case of a bug ...
  491. // dump most gaphics core registers.
  492. //
  493. //============================================
  494. static void regdump(struct cyblafb_par *par)
  495. {
  496. int i;
  497. if (verbosity < 2)
  498. return;
  499. printk("\n");
  500. for(i=0; i<=0xff; i++) {
  501. outb(i,0x3d4);
  502. printk("CR%02x=%02x ",i,inb(0x3d5));
  503. if (i%16==15)
  504. printk("\n");
  505. }
  506. outb(0x30,0x3ce);
  507. outb(inb(0x3cf) | 0x40,0x3cf);
  508. for(i=0; i<=0x1f; i++) {
  509. if (i==0 || (i>2 && i<8) || i==0x10 || i==0x11 || i==0x16) {
  510. outb(i,0x3d4);
  511. printk("CR%02x=%02x ",i,inb(0x3d5));
  512. } else
  513. printk("------- ");
  514. if (i%16==15)
  515. printk("\n");
  516. }
  517. outb(0x30,0x3ce);
  518. outb(inb(0x3cf) & 0xbf,0x3cf);
  519. printk("\n");
  520. for(i=0; i<=0x7f; i++) {
  521. outb(i,0x3ce);
  522. printk("GR%02x=%02x ",i,inb(0x3cf));
  523. if (i%16==15)
  524. printk("\n");
  525. }
  526. printk("\n");
  527. for(i=0; i<=0xff; i++) {
  528. outb(i,0x3c4);
  529. printk("SR%02x=%02x ",i,inb(0x3c5));
  530. if (i%16==15)
  531. printk("\n");
  532. }
  533. printk("\n");
  534. for(i=0; i <= 0x1F; i++) {
  535. inb(0x3da); // next access is index!
  536. outb(i,0x3c0);
  537. printk("AR%02x=%02x ",i,inb(0x3c1));
  538. if (i%16==15)
  539. printk("\n");
  540. }
  541. printk("\n");
  542. inb(0x3DA); // reset internal flag to 3c0 index
  543. outb(0x20,0x3C0); // enable attr
  544. return;
  545. }
  546. //======================================
  547. //
  548. // Set hardware to requested video mode
  549. //
  550. //======================================
  551. static int cyblafb_set_par(struct fb_info *info)
  552. {
  553. struct cyblafb_par *par = info->par;
  554. u32
  555. htotal,hdispend,hsyncstart,hsyncend,hblankstart,hblankend,preendfetch,
  556. vtotal,vdispend,vsyncstart,vsyncend,vblankstart,vblankend;
  557. struct fb_var_screeninfo *var = &info->var;
  558. int bpp = var->bits_per_pixel;
  559. int i;
  560. if (verbosity > 0)
  561. output("Switching to new mode: "
  562. "fbset -g %d %d %d %d %d -t %d %d %d %d %d %d %d\n",
  563. var->xres,var->yres,var->xres_virtual,
  564. var->yres_virtual,var->bits_per_pixel,var->pixclock,
  565. var->left_margin,var->right_margin,var->upper_margin,
  566. var->lower_margin,var->hsync_len,var->vsync_len);
  567. htotal = (var->xres + var->left_margin + var->right_margin +
  568. var->hsync_len) / 8 - 5;
  569. hdispend = var->xres/8 - 1;
  570. hsyncstart = (var->xres + var->right_margin)/8;
  571. hsyncend = var->hsync_len/8;
  572. hblankstart = hdispend + 1;
  573. hblankend = htotal + 3; // should be htotal + 5, bios does it this way
  574. preendfetch = ((var->xres >> 3) + 1) * ((bpp+1) >> 3);
  575. vtotal = var->yres + var->upper_margin + var->lower_margin +
  576. var->vsync_len - 2;
  577. vdispend = var->yres - 1;
  578. vsyncstart = var->yres + var->lower_margin;
  579. vblankstart = var->yres;
  580. vblankend = vtotal; // should be vtotal + 2, but bios does it this way
  581. vsyncend = var->vsync_len;
  582. enable_mmio(); // necessary! ... check X ...
  583. write3X4(CR11,read3X4(CR11) & 0x7F); // unlock cr00 .. cr07
  584. write3CE(GR30,8);
  585. if ((displaytype == DISPLAY_FP) && var->xres < nativex) {
  586. // stretch or center ?
  587. out8(0x3C2,0xEB);
  588. write3CE(GR30,read3CE(GR30) | 0x81); // shadow mode on
  589. if (center) {
  590. write3CE(GR52,(read3CE(GR52) & 0x7C) | 0x80);
  591. write3CE(GR53,(read3CE(GR53) & 0x7C) | 0x80);
  592. }
  593. else if (stretch) {
  594. write3CE(GR5D,0);
  595. write3CE(GR52,(read3CE(GR52) & 0x7C) | 1);
  596. write3CE(GR53,(read3CE(GR53) & 0x7C) | 1);
  597. }
  598. } else {
  599. out8(0x3C2,0x2B);
  600. write3CE(GR30,8);
  601. }
  602. //
  603. // Setup CRxx regs
  604. //
  605. write3X4(CR00,htotal & 0xFF);
  606. write3X4(CR01,hdispend & 0xFF);
  607. write3X4(CR02,hblankstart & 0xFF);
  608. write3X4(CR03,hblankend & 0x1F);
  609. write3X4(CR04,hsyncstart & 0xFF);
  610. write3X4(CR05,(hsyncend & 0x1F) | ((hblankend & 0x20)<<2));
  611. write3X4(CR06,vtotal & 0xFF);
  612. write3X4(CR07,(vtotal & 0x100) >> 8 |
  613. (vdispend & 0x100) >> 7 |
  614. (vsyncstart & 0x100) >> 6 |
  615. (vblankstart & 0x100) >> 5 |
  616. 0x10 |
  617. (vtotal & 0x200) >> 4 |
  618. (vdispend & 0x200) >> 3 |
  619. (vsyncstart & 0x200) >> 2);
  620. write3X4(CR08,0);
  621. write3X4(CR09,(vblankstart & 0x200) >> 4 | 0x40 | // FIX !!!
  622. ((info->var.vmode & FB_VMODE_DOUBLE) ? 0x80 : 0));
  623. write3X4(CR0A,0); // Init to some reasonable default
  624. write3X4(CR0B,0); // Init to some reasonable default
  625. write3X4(CR0C,0); // Offset 0
  626. write3X4(CR0D,0); // Offset 0
  627. write3X4(CR0E,0); // Init to some reasonable default
  628. write3X4(CR0F,0); // Init to some reasonable default
  629. write3X4(CR10,vsyncstart & 0xFF);
  630. write3X4(CR11,(vsyncend & 0x0F));
  631. write3X4(CR12,vdispend & 0xFF);
  632. write3X4(CR13,((info->var.xres * bpp)/(4*16)) & 0xFF);
  633. write3X4(CR14,0x40); // double word mode
  634. write3X4(CR15,vblankstart & 0xFF);
  635. write3X4(CR16,vblankend & 0xFF);
  636. write3X4(CR17,0xC3);
  637. write3X4(CR18,0xFF);
  638. // CR19: needed for interlaced modes ... ignore it for now
  639. write3X4(CR1A,0x07); // Arbitration Control Counter 1
  640. write3X4(CR1B,0x07); // Arbitration Control Counter 2
  641. write3X4(CR1C,0x07); // Arbitration Control Counter 3
  642. write3X4(CR1D,0x00); // Don't know, doesn't hurt ;-)
  643. write3X4(CR1E,(info->var.vmode & FB_VMODE_INTERLACED) ? 0x84 : 0x80);
  644. // CR1F: do not set, contains BIOS info about memsize
  645. write3X4(CR20,0x20); // enabe wr buf, disable 16bit planar mode
  646. write3X4(CR21,0x20); // enable linear memory access
  647. // CR22: RO cpu latch readback
  648. // CR23: ???
  649. // CR24: RO AR flag state
  650. // CR25: RAMDAC rw timing, pclk buffer tristate control ????
  651. // CR26: ???
  652. write3X4(CR27,(vdispend & 0x400) >> 6 |
  653. (vsyncstart & 0x400) >> 5 |
  654. (vblankstart & 0x400) >> 4 |
  655. (vtotal & 0x400) >> 3 |
  656. 0x8);
  657. // CR28: ???
  658. write3X4(CR29,(read3X4(CR29) & 0xCF) |
  659. ((((info->var.xres * bpp) / (4*16)) & 0x300) >>4));
  660. write3X4(CR2A,read3X4(CR2A) | 0x40);
  661. write3X4(CR2B,(htotal & 0x100) >> 8 |
  662. (hdispend & 0x100) >> 7 |
  663. // (0x00 & 0x100) >> 6 | hinterlace para bit 8 ???
  664. (hsyncstart & 0x100) >> 5 |
  665. (hblankstart & 0x100) >> 4);
  666. // CR2C: ???
  667. // CR2D: initialized in cyblafb_setup_GE()
  668. write3X4(CR2F,0x92); // conservative, better signal quality
  669. // CR30: reserved
  670. // CR31: reserved
  671. // CR32: reserved
  672. // CR33: reserved
  673. // CR34: disabled in CR36
  674. // CR35: disabled in CR36
  675. // CR36: initialized in cyblafb_setup_GE
  676. // CR37: i2c, ignore for now
  677. write3X4(CR38,(bpp == 8) ? 0x00 : //
  678. (bpp == 16) ? 0x05 : // highcolor
  679. (bpp == 24) ? 0x29 : // packed 24bit truecolor
  680. (bpp == 32) ? 0x09 : 0); // truecolor, 16 bit pixelbus
  681. write3X4(CR39,0x01 | // MMIO enable
  682. (pcirb ? 0x02 : 0) | // pci read burst enable
  683. (pciwb ? 0x04 : 0)); // pci write burst enable
  684. write3X4(CR55,0x1F | // pci clocks * 2 for STOP# during 1st data phase
  685. (pcirr ? 0x40 : 0) | // pci read retry enable
  686. (pciwr ? 0x80 : 0)); // pci write retry enable
  687. write3X4(CR56,preendfetch >> 8 < 2 ? (preendfetch >> 8 & 0x01)|2 : 0);
  688. write3X4(CR57,preendfetch >> 8 < 2 ? preendfetch & 0xff : 0);
  689. write3X4(CR58,0x82); // Bios does this .... don't know more
  690. //
  691. // Setup SRxx regs
  692. //
  693. write3C4(SR00,3);
  694. write3C4(SR01,1); //set char clock 8 dots wide
  695. write3C4(SR02,0x0F); //enable 4 maps needed in chain4 mode
  696. write3C4(SR03,0); //no character map select
  697. write3C4(SR04,0x0E); //memory mode: ext mem, even, chain4
  698. out8(0x3C4,0x0b);
  699. in8(0x3C5); // Set NEW mode
  700. write3C4(SR0D,0x00); // test ... check
  701. set_vclk(par,(bpp==32 ? 200000000 : 100000000)/
  702. info->var.pixclock); //SR18,SR19
  703. //
  704. // Setup GRxx regs
  705. //
  706. write3CE(GR00,0x00); // test ... check
  707. write3CE(GR01,0x00); // test ... check
  708. write3CE(GR02,0x00); // test ... check
  709. write3CE(GR03,0x00); // test ... check
  710. write3CE(GR04,0x00); // test ... check
  711. write3CE(GR05,0x40); // no CGA compat,allow 256 col
  712. write3CE(GR06,0x05); // graphics mode
  713. write3CE(GR07,0x0F); // planes?
  714. write3CE(GR08,0xFF); // test ... check
  715. write3CE(GR0F,(bpp==32)?0x1A:0x12); // div vclk by 2 if 32bpp, chain4
  716. write3CE(GR20,0xC0); // test ... check
  717. write3CE(GR2F,0xA0); // PCLK = VCLK, no skew,
  718. //
  719. // Setup ARxx regs
  720. //
  721. for(i = 0;i < 0x10;i++) // set AR00 .. AR0f
  722. write3C0(i,i);
  723. write3C0(AR10,0x41); // graphics mode and support 256 color modes
  724. write3C0(AR12,0x0F); // planes
  725. write3C0(AR13,0); // horizontal pel panning
  726. in8(0x3DA); // reset internal flag to 3c0 index
  727. out8(0x3C0,0x20); // enable attr
  728. //
  729. // Setup hidden RAMDAC command register
  730. //
  731. in8(0x3C8); // these reads are
  732. in8(0x3C6); // necessary to
  733. in8(0x3C6); // unmask the RAMDAC
  734. in8(0x3C6); // command reg, otherwise
  735. in8(0x3C6); // we would write the pixelmask reg!
  736. out8(0x3C6,(bpp == 8) ? 0x00 : // 256 colors
  737. (bpp == 15) ? 0x10 : //
  738. (bpp == 16) ? 0x30 : // hicolor
  739. (bpp == 24) ? 0xD0 : // truecolor
  740. (bpp == 32) ? 0xD0 : 0); // truecolor
  741. in8(0x3C8);
  742. //
  743. // GR31 is not mentioned in the datasheet
  744. //
  745. if (displaytype == DISPLAY_FP)
  746. write3CE(GR31,(read3CE(GR31) & 0x8F) |
  747. ((info->var.yres > 1024) ? 0x50 :
  748. (info->var.yres > 768) ? 0x30 :
  749. (info->var.yres > 600) ? 0x20 :
  750. (info->var.yres > 480) ? 0x10 : 0));
  751. info->fix.visual = (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR
  752. : FB_VISUAL_TRUECOLOR;
  753. info->fix.line_length = info->var.xres * (bpp >> 3);
  754. info->cmap.len = (bpp == 8) ? 256: 16;
  755. //
  756. // init acceleration engine
  757. //
  758. cyblafb_setup_GE(info->var.xres,info->var.bits_per_pixel);
  759. regdump(par);
  760. return 0;
  761. }
  762. //========================
  763. //
  764. // Set one color register
  765. //
  766. //========================
  767. static int cyblafb_setcolreg(unsigned regno, unsigned red, unsigned green,
  768. unsigned blue, unsigned transp,
  769. struct fb_info *info)
  770. {
  771. int bpp = info->var.bits_per_pixel;
  772. if (regno >= info->cmap.len)
  773. return 1;
  774. if (bpp == 8) {
  775. out8(0x3C6,0xFF);
  776. out8(0x3C8,regno);
  777. out8(0x3C9,red>>10);
  778. out8(0x3C9,green>>10);
  779. out8(0x3C9,blue>>10);
  780. } else if (bpp == 16) // RGB 565
  781. ((u32*)info->pseudo_palette)[regno] =
  782. (red & 0xF800) |
  783. ((green & 0xFC00) >> 5) |
  784. ((blue & 0xF800) >> 11);
  785. else if (bpp == 32) // ARGB 8888
  786. ((u32*)info->pseudo_palette)[regno] =
  787. ((transp & 0xFF00) <<16) |
  788. ((red & 0xFF00) << 8) |
  789. ((green & 0xFF00)) |
  790. ((blue & 0xFF00)>>8);
  791. return 0;
  792. }
  793. //==========================================================
  794. //
  795. // Try blanking the screen. For flat panels it does nothing
  796. //
  797. //==========================================================
  798. static int cyblafb_blank(int blank_mode, struct fb_info *info)
  799. {
  800. unsigned char PMCont,DPMSCont;
  801. if (displaytype == DISPLAY_FP)
  802. return 0;
  803. out8(0x83C8,0x04); // DPMS Control
  804. PMCont = in8(0x83C6) & 0xFC;
  805. DPMSCont = read3CE(GR23) & 0xFC;
  806. switch (blank_mode)
  807. {
  808. case FB_BLANK_UNBLANK: // Screen: On, HSync: On, VSync: On
  809. case FB_BLANK_NORMAL: // Screen: Off, HSync: On, VSync: On
  810. PMCont |= 0x03;
  811. DPMSCont |= 0x00;
  812. break;
  813. case FB_BLANK_HSYNC_SUSPEND: // Screen: Off, HSync: Off, VSync: On
  814. PMCont |= 0x02;
  815. DPMSCont |= 0x01;
  816. break;
  817. case FB_BLANK_VSYNC_SUSPEND: // Screen: Off, HSync: On, VSync: Off
  818. PMCont |= 0x02;
  819. DPMSCont |= 0x02;
  820. break;
  821. case FB_BLANK_POWERDOWN: // Screen: Off, HSync: Off, VSync: Off
  822. PMCont |= 0x00;
  823. DPMSCont |= 0x03;
  824. break;
  825. }
  826. write3CE(GR23,DPMSCont);
  827. out8(0x83C8,4);
  828. out8(0x83C6,PMCont);
  829. //
  830. // let fbcon do a softblank for us
  831. //
  832. return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0;
  833. }
  834. static struct fb_ops cyblafb_ops __devinitdata = {
  835. .owner = THIS_MODULE,
  836. .fb_setcolreg = cyblafb_setcolreg,
  837. .fb_pan_display = cyblafb_pan_display,
  838. .fb_blank = cyblafb_blank,
  839. .fb_check_var = cyblafb_check_var,
  840. .fb_set_par = cyblafb_set_par,
  841. .fb_fillrect = cyblafb_fillrect,
  842. .fb_copyarea= cyblafb_copyarea,
  843. .fb_imageblit = cyblafb_imageblit,
  844. .fb_cursor = soft_cursor,
  845. };
  846. //==========================================================================
  847. //
  848. // getstartupmode() decides about the inital video mode
  849. //
  850. // There is no reason to use modedb, a lot of video modes there would
  851. // need altered timings to display correctly. So I decided that it is much
  852. // better to provide a limited optimized set of modes plus the option of
  853. // using the mode in effect at startup time (might be selected using the
  854. // vga=??? paramter). After that the user might use fbset to select any
  855. // mode he likes, check_var will not try to alter geometry parameters as
  856. // it would be necessary otherwise.
  857. //
  858. //==========================================================================
  859. static int __devinit getstartupmode(struct fb_info *info)
  860. {
  861. u32 htotal,hdispend,hsyncstart,hsyncend,hblankstart,hblankend,
  862. vtotal,vdispend,vsyncstart,vsyncend,vblankstart,vblankend,
  863. cr00,cr01,cr02,cr03,cr04,cr05,cr2b,
  864. cr06,cr07,cr09,cr10,cr11,cr12,cr15,cr16,cr27,
  865. cr38,
  866. sr0d,sr18,sr19,
  867. gr0f,
  868. fi,pxclkdiv,vclkdiv,tmp,i;
  869. struct modus {
  870. int xres; int yres; int vyres; int bpp; int pxclk;
  871. int left_margin; int right_margin; int upper_margin;
  872. int lower_margin; int hsync_len; int vsync_len;
  873. } modedb[5] = {
  874. { 0, 0, 8000, 0, 0, 0, 0, 0, 0, 0, 0},
  875. { 640, 480, 3756, 0, 0, -40, 24, 17, 0, 216, 3},
  876. { 800, 600, 3221, 0, 0, 96, 24, 14, 0, 136, 11},
  877. {1024, 768, 2815, 0, 0, 144, 24, 29, 0, 120, 3},
  878. {1280, 1024, 2662, 0, 0, 232, 16, 39, 0, 160, 3}
  879. };
  880. outb(0x00,0x3d4); cr00=inb(0x3d5); outb(0x01,0x3d4); cr01=inb(0x3d5);
  881. outb(0x02,0x3d4); cr02=inb(0x3d5); outb(0x03,0x3d4); cr03=inb(0x3d5);
  882. outb(0x04,0x3d4); cr04=inb(0x3d5); outb(0x05,0x3d4); cr05=inb(0x3d5);
  883. outb(0x06,0x3d4); cr06=inb(0x3d5); outb(0x07,0x3d4); cr07=inb(0x3d5);
  884. outb(0x09,0x3d4); cr09=inb(0x3d5); outb(0x10,0x3d4); cr10=inb(0x3d5);
  885. outb(0x11,0x3d4); cr11=inb(0x3d5); outb(0x12,0x3d4); cr12=inb(0x3d5);
  886. outb(0x15,0x3d4); cr15=inb(0x3d5); outb(0x16,0x3d4); cr16=inb(0x3d5);
  887. outb(0x27,0x3d4); cr27=inb(0x3d5); outb(0x2b,0x3d4); cr2b=inb(0x3d5);
  888. outb(0x38,0x3d4); cr38=inb(0x3d5); outb(0x0b,0x3c4); inb(0x3c5);
  889. outb(0x0d,0x3c4); sr0d=inb(0x3c5); outb(0x18,0x3c4); sr18=inb(0x3c5);
  890. outb(0x19,0x3c4); sr19=inb(0x3c5); outb(0x0f,0x3ce); gr0f=inb(0x3cf);
  891. htotal = cr00 | (cr2b & 0x01) << 8;
  892. hdispend = cr01 | (cr2b & 0x02) << 7;
  893. hblankstart = cr02 | (cr2b & 0x10) << 4;
  894. hblankend = (cr03 & 0x1f) | (cr05 & 0x80) >> 2;
  895. hsyncstart = cr04 | (cr2b & 0x08) << 5;
  896. hsyncend = cr05 & 0x1f;
  897. modedb[0].xres = hblankstart * 8;
  898. modedb[0].hsync_len = hsyncend * 8;
  899. modedb[0].right_margin = hsyncstart * 8 - modedb[0].xres;
  900. modedb[0].left_margin = (htotal + 5) * 8 - modedb[0].xres -
  901. modedb[0].right_margin - modedb[0].hsync_len;
  902. vtotal = cr06 | (cr07 & 0x01) << 8 | (cr07 & 0x20) << 4
  903. | (cr27 & 0x80) << 3;
  904. vdispend = cr12 | (cr07 & 0x02) << 7 | (cr07 & 0x40) << 3
  905. | (cr27 & 0x10) << 6;
  906. vsyncstart = cr10 | (cr07 & 0x04) << 6 | (cr07 & 0x80) << 2
  907. | (cr27 & 0x20) << 5;
  908. vsyncend = cr11 & 0x0f;
  909. vblankstart = cr15 | (cr07 & 0x08) << 5 | (cr09 & 0x20) << 4
  910. | (cr27 & 0x40) << 4;
  911. vblankend = cr16;
  912. modedb[0].yres = vdispend + 1;
  913. modedb[0].vsync_len = vsyncend;
  914. modedb[0].lower_margin = vsyncstart - modedb[0].yres;
  915. modedb[0].upper_margin = vtotal - modedb[0].yres -
  916. modedb[0].lower_margin - modedb[0].vsync_len + 2;
  917. tmp = cr38 & 0x3c;
  918. modedb[0].bpp = tmp == 0 ? 8 : tmp == 4 ? 16 : tmp == 28 ? 24 :
  919. tmp == 8 ? 32 : 8;
  920. fi = ((5864727*(sr18+8))/(((sr19&0x3f)+2)*(1<<((sr19&0xc0)>>6))))>>12;
  921. pxclkdiv = ((gr0f & 0x08) >> 3 | (gr0f & 0x40) >> 5) + 1;
  922. tmp = sr0d & 0x06;
  923. vclkdiv = tmp == 0 ? 2 : tmp == 2 ? 4 : tmp == 4 ? 8 : 3; // * 2 !
  924. modedb[0].pxclk = ((100000000 * pxclkdiv * vclkdiv) >> 1) / fi;
  925. if (verbosity > 0)
  926. output("detected startup mode: "
  927. "fbset -g %d %d %d ??? %d -t %d %d %d %d %d %d %d\n",
  928. modedb[0].xres,modedb[0].yres,modedb[0].xres,
  929. modedb[0].bpp,modedb[0].pxclk,modedb[0].left_margin,
  930. modedb[0].right_margin,modedb[0].upper_margin,
  931. modedb[0].lower_margin,modedb[0].hsync_len,
  932. modedb[0].vsync_len);
  933. //
  934. // We use this goto target in case of a failed check_var. No, I really
  935. // do not want to do it in another way!
  936. //
  937. tryagain:
  938. i = (mode == NULL) ? 0 :
  939. !strncmp(mode,"640x480",7) ? 1 :
  940. !strncmp(mode,"800x600",7) ? 2 :
  941. !strncmp(mode,"1024x768",8) ? 3 :
  942. !strncmp(mode,"1280x1024",9) ? 4 : 0;
  943. ref = (ref < 50) ? 50 : (ref > 85) ? 85 : ref;
  944. if(i==0) {
  945. info->var.pixclock = modedb[i].pxclk;
  946. info->var.bits_per_pixel = modedb[i].bpp;
  947. } else {
  948. info->var.pixclock = (100000000 /
  949. ((modedb[i].left_margin + modedb[i].xres +
  950. modedb[i].right_margin + modedb[i].hsync_len
  951. ) * (
  952. modedb[i].upper_margin + modedb[i].yres +
  953. modedb[i].lower_margin + modedb[i].vsync_len
  954. ) *
  955. ref / 10000
  956. ));
  957. info->var.bits_per_pixel = bpp;
  958. }
  959. info->var.left_margin = modedb[i].left_margin;
  960. info->var.right_margin = modedb[i].right_margin;
  961. info->var.xres = modedb[i].xres;
  962. info->var.xres_virtual = modedb[i].xres;
  963. info->var.xoffset = 0;
  964. info->var.hsync_len = modedb[i].hsync_len;
  965. info->var.upper_margin = modedb[i].upper_margin;
  966. info->var.yres = modedb[i].yres;
  967. info->var.yres_virtual = modedb[i].vyres;
  968. info->var.yoffset = 0;
  969. info->var.lower_margin = modedb[i].lower_margin;
  970. info->var.vsync_len = modedb[i].vsync_len;
  971. info->var.sync = 0;
  972. info->var.vmode = FB_VMODE_NONINTERLACED;
  973. if(cyblafb_check_var(&info->var,info)) {
  974. // 640x480-8@75 should really never fail. One case would
  975. // be fp == 1 and nativex < 640 ... give up then
  976. if(i==1 && bpp == 8 && ref == 75){
  977. output("Can't find a valid mode :-(\n");
  978. return -EINVAL;
  979. }
  980. // Our detected mode is unlikely to fail. If it does,
  981. // try 640x480-8@75 ...
  982. if(i==0) {
  983. mode="640x480";
  984. bpp=8;
  985. ref=75;
  986. output("Detected mode failed check_var! "
  987. "Trying 640x480-8@75\n");
  988. goto tryagain;
  989. }
  990. // A specified video mode failed for some reason.
  991. // Try the startup mode first
  992. output("Specified mode '%s' failed check! "
  993. "Falling back to startup mode.\n",mode);
  994. mode=NULL;
  995. goto tryagain;
  996. }
  997. return 0;
  998. }
  999. //========================================================
  1000. //
  1001. // Detect activated memory size. Undefined values require
  1002. // memsize parameter.
  1003. //
  1004. //========================================================
  1005. static unsigned int __devinit get_memsize(void)
  1006. {
  1007. unsigned char tmp;
  1008. unsigned int k;
  1009. if (memsize)
  1010. k = memsize * Kb;
  1011. else {
  1012. tmp = read3X4(CR1F) & 0x0F;
  1013. switch (tmp) {
  1014. case 0x03: k = 1 * Mb; break;
  1015. case 0x07: k = 2 * Mb; break;
  1016. case 0x0F: k = 4 * Mb; break;
  1017. case 0x04: k = 8 * Mb; break;
  1018. default:
  1019. k = 1 * Mb;
  1020. output("Unknown memory size code %x in CR1F."
  1021. " We default to 1 Mb for now, please"
  1022. " do provide a memsize parameter!\n",
  1023. tmp);
  1024. }
  1025. }
  1026. if (verbosity > 0)
  1027. output("framebuffer size = %d Kb\n",k/Kb);
  1028. return k;
  1029. }
  1030. //=========================================================
  1031. //
  1032. // Detect if a flat panel monitor connected to the special
  1033. // interface is active. Override is possible by fp and crt
  1034. // parameters.
  1035. //
  1036. //=========================================================
  1037. static unsigned int __devinit get_displaytype(void)
  1038. {
  1039. if (fp)
  1040. return DISPLAY_FP;
  1041. if (crt)
  1042. return DISPLAY_CRT;
  1043. return (read3CE(GR33) & 0x10)?DISPLAY_FP:DISPLAY_CRT;
  1044. }
  1045. //=====================================
  1046. //
  1047. // Get native resolution of flat panel
  1048. //
  1049. //=====================================
  1050. static int __devinit get_nativex(void)
  1051. {
  1052. int x,y,tmp;
  1053. if (nativex)
  1054. return nativex;
  1055. tmp = (read3CE(GR52) >> 4) & 3;
  1056. switch (tmp) {
  1057. case 0: x = 1280; y = 1024; break;
  1058. case 2: x = 1024; y = 768; break;
  1059. case 3: x = 800; y = 600; break;
  1060. case 4: x = 1400; y = 1050; break;
  1061. case 1:
  1062. default: x = 640; y = 480; break;
  1063. }
  1064. if (verbosity > 0)
  1065. output("%dx%d flat panel found\n",x,y);
  1066. return x;
  1067. }
  1068. static int __devinit cybla_pci_probe(struct pci_dev * dev,
  1069. const struct pci_device_id * id)
  1070. {
  1071. struct fb_info *info;
  1072. struct cyblafb_par *par;
  1073. info = framebuffer_alloc(sizeof(struct cyblafb_par),&dev->dev);
  1074. if (!info)
  1075. goto errout_alloc;
  1076. par = info->par;
  1077. par->ops = cyblafb_ops;
  1078. info->fix = cyblafb_fix;
  1079. info->fbops = &par->ops;
  1080. info->fix = cyblafb_fix;
  1081. if (pci_enable_device(dev)) {
  1082. output("could not enable device!\n");
  1083. goto errout_enable;
  1084. }
  1085. // might already be requested by vga console or vesafb,
  1086. // so we do care about success
  1087. request_region(0x3c0,32,"cyblafb");
  1088. //
  1089. // Graphics Engine Registers
  1090. //
  1091. request_region(GEBase,0x100,"cyblafb");
  1092. regdump(par);
  1093. enable_mmio();
  1094. // setup MMIO region
  1095. info->fix.mmio_start = pci_resource_start(dev,1);
  1096. info->fix.mmio_len = 0x20000;
  1097. if (!request_mem_region(info->fix.mmio_start,
  1098. info->fix.mmio_len,"cyblafb")) {
  1099. output("request_mem_region failed for mmio region!\n");
  1100. goto errout_mmio_reqmem;
  1101. }
  1102. io_virt = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len);
  1103. if (!io_virt) {
  1104. output("ioremap failed for mmio region\n");
  1105. goto errout_mmio_remap;
  1106. }
  1107. // setup framebuffer memory ... might already be requested
  1108. // by vesafb. Not to fail in case of an unsuccessful request
  1109. // is useful for the development cycle
  1110. info->fix.smem_start = pci_resource_start(dev,0);
  1111. info->fix.smem_len = get_memsize();
  1112. if (!request_mem_region(info->fix.smem_start,
  1113. info->fix.smem_len,"cyblafb")) {
  1114. output("request_mem_region failed for smem region!\n");
  1115. if (!vesafb)
  1116. goto errout_smem_req;
  1117. }
  1118. info->screen_base = ioremap_nocache(info->fix.smem_start,
  1119. info->fix.smem_len);
  1120. if (!info->screen_base) {
  1121. output("ioremap failed for smem region\n");
  1122. goto errout_smem_remap;
  1123. }
  1124. displaytype = get_displaytype();
  1125. if(displaytype == DISPLAY_FP)
  1126. nativex = get_nativex();
  1127. //
  1128. // FBINFO_HWACCEL_YWRAP .... does not work (could be made to work?)
  1129. // FBINFO_PARTIAL_PAN_OK .... is not ok
  1130. // FBINFO_READS_FAST .... is necessary for optimal scrolling
  1131. //
  1132. info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN
  1133. | FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT
  1134. | FBINFO_HWACCEL_IMAGEBLIT | FBINFO_READS_FAST;
  1135. info->pseudo_palette = par->pseudo_pal;
  1136. if(getstartupmode(info))
  1137. goto errout_findmode;
  1138. fb_alloc_cmap(&info->cmap,256,0);
  1139. if (register_framebuffer(info)) {
  1140. output("Could not register CyBla framebuffer\n");
  1141. goto errout_register;
  1142. }
  1143. pci_set_drvdata(dev,info);
  1144. //
  1145. // normal exit and error paths
  1146. //
  1147. return 0;
  1148. errout_register:
  1149. errout_findmode:
  1150. iounmap(info->screen_base);
  1151. errout_smem_remap:
  1152. release_mem_region(info->fix.smem_start,
  1153. info->fix.smem_len);
  1154. errout_smem_req:
  1155. iounmap(io_virt);
  1156. errout_mmio_remap:
  1157. release_mem_region(info->fix.mmio_start,
  1158. info->fix.mmio_len);
  1159. errout_mmio_reqmem:
  1160. // release_region(0x3c0,32);
  1161. errout_enable:
  1162. framebuffer_release(info);
  1163. errout_alloc:
  1164. output("CyblaFB version %s aborting init.\n",VERSION);
  1165. return -ENODEV;
  1166. }
  1167. static void __devexit cybla_pci_remove(struct pci_dev *dev)
  1168. {
  1169. struct fb_info *info = pci_get_drvdata(dev);
  1170. unregister_framebuffer(info);
  1171. iounmap(io_virt);
  1172. iounmap(info->screen_base);
  1173. release_mem_region(info->fix.smem_start,info->fix.smem_len);
  1174. release_mem_region(info->fix.mmio_start,info->fix.mmio_len);
  1175. fb_dealloc_cmap(&info->cmap);
  1176. framebuffer_release(info);
  1177. output("CyblaFB version %s normal exit.\n",VERSION);
  1178. }
  1179. //
  1180. // List of boards that we are trying to support
  1181. //
  1182. static struct pci_device_id cybla_devices[] = {
  1183. {PCI_VENDOR_ID_TRIDENT,CYBERBLADEi1,PCI_ANY_ID,PCI_ANY_ID,0,0,0},
  1184. {0,}
  1185. };
  1186. MODULE_DEVICE_TABLE(pci,cybla_devices);
  1187. static struct pci_driver cyblafb_pci_driver = {
  1188. .name = "cyblafb",
  1189. .id_table = cybla_devices,
  1190. .probe = cybla_pci_probe,
  1191. .remove = __devexit_p(cybla_pci_remove)
  1192. };
  1193. //=============================================================
  1194. //
  1195. // kernel command line example:
  1196. //
  1197. // video=cyblafb:1280x1024,bpp=16,ref=50 ...
  1198. //
  1199. // modprobe command line example:
  1200. //
  1201. // modprobe cyblafb mode=1280x1024 bpp=16 ref=50 ...
  1202. //
  1203. //=============================================================
  1204. static int __devinit cyblafb_init(void)
  1205. {
  1206. #ifndef MODULE
  1207. char *options = NULL;
  1208. char *opt;
  1209. if (fb_get_options("cyblafb",&options))
  1210. return -ENODEV;
  1211. if (options && *options)
  1212. while((opt = strsep(&options,",")) != NULL ) {
  1213. if (!*opt) continue;
  1214. else if (!strncmp(opt,"bpp=",4))
  1215. bpp = simple_strtoul(opt+4,NULL,0);
  1216. else if (!strncmp(opt,"ref=",4))
  1217. ref = simple_strtoul(opt+4,NULL,0);
  1218. else if (!strncmp(opt,"fp",2))
  1219. displaytype = DISPLAY_FP;
  1220. else if (!strncmp(opt,"crt",3))
  1221. displaytype = DISPLAY_CRT;
  1222. else if (!strncmp(opt,"nativex=",8))
  1223. nativex = simple_strtoul(opt+8,NULL,0);
  1224. else if (!strncmp(opt,"center",6))
  1225. center = 1;
  1226. else if (!strncmp(opt,"stretch",7))
  1227. stretch = 1;
  1228. else if (!strncmp(opt,"pciwb=",6))
  1229. pciwb = simple_strtoul(opt+6,NULL,0);
  1230. else if (!strncmp(opt,"pcirb=",6))
  1231. pcirb = simple_strtoul(opt+6,NULL,0);
  1232. else if (!strncmp(opt,"pciwr=",6))
  1233. pciwr = simple_strtoul(opt+6,NULL,0);
  1234. else if (!strncmp(opt,"pcirr=",6))
  1235. pcirr = simple_strtoul(opt+6,NULL,0);
  1236. else if (!strncmp(opt,"memsize=",8))
  1237. memsize = simple_strtoul(opt+8,NULL,0);
  1238. else if (!strncmp(opt,"verbosity=",10))
  1239. verbosity = simple_strtoul(opt+10,NULL,0);
  1240. else if (!strncmp(opt,"vesafb",6))
  1241. vesafb = 1;
  1242. else
  1243. mode = opt;
  1244. }
  1245. #endif
  1246. output("CyblaFB version %s initializing\n",VERSION);
  1247. return pci_module_init(&cyblafb_pci_driver);
  1248. }
  1249. static void __exit cyblafb_exit(void)
  1250. {
  1251. pci_unregister_driver(&cyblafb_pci_driver);
  1252. }
  1253. module_init(cyblafb_init);
  1254. module_exit(cyblafb_exit);
  1255. MODULE_AUTHOR("Knut Petersen <knut_petersen@t-online.de>");
  1256. MODULE_DESCRIPTION("Framebuffer driver for Cyberblade/i1 graphics core");
  1257. MODULE_LICENSE("GPL");