mach64xx.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <bio.h>
  4. #include "pci.h"
  5. #include "vga.h"
  6. /*
  7. * ATI Mach64 family.
  8. */
  9. enum {
  10. HTotalDisp,
  11. HSyncStrtWid,
  12. VTotalDisp,
  13. VSyncStrtWid,
  14. VlineCrntVline,
  15. OffPitch,
  16. IntCntl,
  17. CrtcGenCntl,
  18. OvrClr,
  19. OvrWidLR,
  20. OvrWidTB,
  21. CurClr0,
  22. CurClr1,
  23. CurOffset,
  24. CurHVposn,
  25. CurHVoff,
  26. ScratchReg0,
  27. ScratchReg1, /* Scratch Register (BIOS info) */
  28. ClockCntl,
  29. BusCntl,
  30. MemCntl,
  31. ExtMemCntl,
  32. MemVgaWpSel,
  33. MemVgaRpSel,
  34. DacRegs,
  35. DacCntl,
  36. GenTestCntl,
  37. ConfigCntl, /* Configuration control */
  38. ConfigChipId,
  39. ConfigStat0, /* Configuration status 0 */
  40. ConfigStat1, /* Configuration status 1 */
  41. ConfigStat2,
  42. DspConfig, /* Rage */
  43. DspOnOff, /* Rage */
  44. DpBkgdClr,
  45. DpChainMsk,
  46. DpFrgdClr,
  47. DpMix,
  48. DpPixWidth,
  49. DpSrc,
  50. DpWriteMsk,
  51. LcdIndex,
  52. LcdData,
  53. Nreg,
  54. TvIndex = 0x1D,
  55. TvData = 0x27,
  56. LCD_ConfigPanel = 0,
  57. LCD_GenCtrl,
  58. LCD_DstnCntl,
  59. LCD_HfbPitchAddr,
  60. LCD_HorzStretch,
  61. LCD_VertStretch,
  62. LCD_ExtVertStretch,
  63. LCD_LtGio,
  64. LCD_PowerMngmnt,
  65. LCD_ZvgPio,
  66. Nlcd,
  67. };
  68. static char* iorname[Nreg] = {
  69. "HTotalDisp",
  70. "HSyncStrtWid",
  71. "VTotalDisp",
  72. "VSyncStrtWid",
  73. "VlineCrntVline",
  74. "OffPitch",
  75. "IntCntl",
  76. "CrtcGenCntl",
  77. "OvrClr",
  78. "OvrWidLR",
  79. "OvrWidTB",
  80. "CurClr0",
  81. "CurClr1",
  82. "CurOffset",
  83. "CurHVposn",
  84. "CurHVoff",
  85. "ScratchReg0",
  86. "ScratchReg1",
  87. "ClockCntl",
  88. "BusCntl",
  89. "MemCntl",
  90. "ExtMemCntl",
  91. "MemVgaWpSel",
  92. "MemVgaRpSel",
  93. "DacRegs",
  94. "DacCntl",
  95. "GenTestCntl",
  96. "ConfigCntl",
  97. "ConfigChipId",
  98. "ConfigStat0",
  99. "ConfigStat1",
  100. "ConfigStat2",
  101. "DspConfig",
  102. "DspOnOff",
  103. "DpBkgdClr",
  104. "DpChainMsk",
  105. "DpFrgdClr",
  106. "DpMix",
  107. "DpPixWidth",
  108. "DpSrc",
  109. "DpWriteMsk",
  110. "LcdIndex",
  111. "LcdData",
  112. };
  113. static char* lcdname[Nlcd] = {
  114. "LCD ConfigPanel",
  115. "LCD GenCntl",
  116. "LCD DstnCntl",
  117. "LCD HfbPitchAddr",
  118. "LCD HorzStretch",
  119. "LCD VertStretch",
  120. "LCD ExtVertStretch",
  121. "LCD LtGio",
  122. "LCD PowerMngmnt",
  123. "LCD ZvgPio"
  124. };
  125. /*
  126. * Crummy hack: all io register offsets
  127. * here get IOREG or'ed in, so that we can
  128. * tell the difference between an uninitialized
  129. * array entry and HTotalDisp.
  130. */
  131. enum {
  132. IOREG = 0x10000,
  133. };
  134. static ushort ioregs[Nreg] = {
  135. [HTotalDisp] IOREG|0x0000,
  136. [HSyncStrtWid] IOREG|0x0100,
  137. [VTotalDisp] IOREG|0x0200,
  138. [VSyncStrtWid] IOREG|0x0300,
  139. [VlineCrntVline] IOREG|0x0400,
  140. [OffPitch] IOREG|0x0500,
  141. [IntCntl] IOREG|0x0600,
  142. [CrtcGenCntl] IOREG|0x0700,
  143. [OvrClr] IOREG|0x0800,
  144. [OvrWidLR] IOREG|0x0900,
  145. [OvrWidTB] IOREG|0x0A00,
  146. [CurClr0] IOREG|0x0B00,
  147. [CurClr1] IOREG|0x0C00,
  148. [CurOffset] IOREG|0x0D00,
  149. [CurHVposn] IOREG|0x0E00,
  150. [CurHVoff] IOREG|0x0F00,
  151. [ScratchReg0] IOREG|0x1000,
  152. [ScratchReg1] IOREG|0x1100,
  153. [ClockCntl] IOREG|0x1200,
  154. [BusCntl] IOREG|0x1300,
  155. [MemCntl] IOREG|0x1400,
  156. [MemVgaWpSel] IOREG|0x1500,
  157. [MemVgaRpSel] IOREG|0x1600,
  158. [DacRegs] IOREG|0x1700,
  159. [DacCntl] IOREG|0x1800,
  160. [GenTestCntl] IOREG|0x1900,
  161. [ConfigCntl] IOREG|0x1A00,
  162. [ConfigChipId] IOREG|0x1B00,
  163. [ConfigStat0] IOREG|0x1C00,
  164. [ConfigStat1] IOREG|0x1D00,
  165. /* [GpIo] IOREG|0x1E00, */
  166. /* [HTotalDisp] IOREG|0x1F00, duplicate, says XFree86 */
  167. };
  168. static ushort pciregs[Nreg] = {
  169. [HTotalDisp] 0x00,
  170. [HSyncStrtWid] 0x01,
  171. [VTotalDisp] 0x02,
  172. [VSyncStrtWid] 0x03,
  173. [VlineCrntVline] 0x04,
  174. [OffPitch] 0x05,
  175. [IntCntl] 0x06,
  176. [CrtcGenCntl] 0x07,
  177. [DspConfig] 0x08,
  178. [DspOnOff] 0x09,
  179. [OvrClr] 0x10,
  180. [OvrWidLR] 0x11,
  181. [OvrWidTB] 0x12,
  182. [CurClr0] 0x18,
  183. [CurClr1] 0x19,
  184. [CurOffset] 0x1A,
  185. [CurHVposn] 0x1B,
  186. [CurHVoff] 0x1C,
  187. [ScratchReg0] 0x20,
  188. [ScratchReg1] 0x21,
  189. [ClockCntl] 0x24,
  190. [BusCntl] 0x28,
  191. [LcdIndex] 0x29,
  192. [LcdData] 0x2A,
  193. [ExtMemCntl] 0x2B,
  194. [MemCntl] 0x2C,
  195. [MemVgaWpSel] 0x2D,
  196. [MemVgaRpSel] 0x2E,
  197. [DacRegs] 0x30,
  198. [DacCntl] 0x31,
  199. [GenTestCntl] 0x34,
  200. [ConfigCntl] 0x37,
  201. [ConfigChipId] 0x38,
  202. [ConfigStat0] 0x39,
  203. [ConfigStat1] 0x25, /* rsc: was 0x3A, but that's not what the LT manual says */
  204. [ConfigStat2] 0x26,
  205. [DpBkgdClr] 0xB0,
  206. [DpChainMsk] 0xB3,
  207. [DpFrgdClr] 0xB1,
  208. [DpMix] 0xB5,
  209. [DpPixWidth] 0xB4,
  210. [DpSrc] 0xB6,
  211. [DpWriteMsk] 0xB2,
  212. };
  213. enum {
  214. PLLm = 0x02,
  215. PLLp = 0x06,
  216. PLLn0 = 0x07,
  217. PLLn1 = 0x08,
  218. PLLn2 = 0x09,
  219. PLLn3 = 0x0A,
  220. PLLx = 0x0B, /* external divisor (Rage) */
  221. Npll = 32,
  222. Ntv = 1, /* actually 256, but not used */
  223. };
  224. typedef struct Mach64xx Mach64xx;
  225. struct Mach64xx {
  226. ulong io;
  227. Pcidev* pci;
  228. int bigmem;
  229. int lcdon;
  230. int lcdpanelid;
  231. ulong reg[Nreg];
  232. ulong lcd[Nlcd];
  233. ulong tv[Ntv];
  234. uchar pll[Npll];
  235. ulong (*ior32)(Mach64xx*, int);
  236. void (*iow32)(Mach64xx*, int, ulong);
  237. };
  238. static ulong
  239. portior32(Mach64xx* mp, int r)
  240. {
  241. if((ioregs[r] & IOREG) == 0)
  242. return ~0;
  243. return inportl(((ioregs[r] & ~IOREG)<<2)+mp->io);
  244. }
  245. static void
  246. portiow32(Mach64xx* mp, int r, ulong l)
  247. {
  248. if((ioregs[r] & IOREG) == 0)
  249. return;
  250. outportl(((ioregs[r] & ~IOREG)<<2)+mp->io, l);
  251. }
  252. static ulong
  253. pciior32(Mach64xx* mp, int r)
  254. {
  255. return inportl((pciregs[r]<<2)+mp->io);
  256. }
  257. static void
  258. pciiow32(Mach64xx* mp, int r, ulong l)
  259. {
  260. outportl((pciregs[r]<<2)+mp->io, l);
  261. }
  262. static uchar
  263. pllr(Mach64xx* mp, int r)
  264. {
  265. int io;
  266. if(mp->ior32 == portior32)
  267. io = ((ioregs[ClockCntl]&~IOREG)<<2)+mp->io;
  268. else
  269. io = (pciregs[ClockCntl]<<2)+mp->io;
  270. outportb(io+1, r<<2);
  271. return inportb(io+2);
  272. }
  273. static void
  274. pllw(Mach64xx* mp, int r, uchar b)
  275. {
  276. int io;
  277. if(mp->ior32 == portior32)
  278. io = ((ioregs[ClockCntl]&~IOREG)<<2)+mp->io;
  279. else
  280. io = (pciregs[ClockCntl]<<2)+mp->io;
  281. outportb(io+1, (r<<2)|0x02);
  282. outportb(io+2, b);
  283. }
  284. static ulong
  285. lcdr32(Mach64xx *mp, ulong r)
  286. {
  287. ulong or;
  288. or = mp->ior32(mp, LcdIndex);
  289. mp->iow32(mp, LcdIndex, (or&~0x0F) | (r&0x0F));
  290. return mp->ior32(mp, LcdData);
  291. }
  292. static void
  293. lcdw32(Mach64xx *mp, ulong r, ulong v)
  294. {
  295. ulong or;
  296. or = mp->ior32(mp, LcdIndex);
  297. mp->iow32(mp, LcdIndex, (or&~0x0F) | (r&0x0F));
  298. mp->iow32(mp, LcdData, v);
  299. }
  300. static ulong
  301. tvr32(Mach64xx *mp, ulong r)
  302. {
  303. outportb(mp->io+(TvIndex<<2), r&0x0F);
  304. return inportl(mp->io+(TvData<<2));
  305. }
  306. static void
  307. tvw32(Mach64xx *mp, ulong r, ulong v)
  308. {
  309. outportb(mp->io+(TvIndex<<2), r&0x0F);
  310. outportl(mp->io+(TvData<<2), v);
  311. }
  312. static int smallmem[] = {
  313. 512*1024, 1024*1024, 2*1024*1024, 4*1024*1024,
  314. 6*1024*1024, 8*1024*1024, 12*1024*1024, 16*1024*1024,
  315. };
  316. static int bigmem[] = {
  317. 512*1024, 2*512*1024, 3*512*1024, 4*512*1024,
  318. 5*512*1024, 6*512*1024, 7*512*1024, 8*512*1024,
  319. 5*1024*1024, 6*1024*1024, 7*1024*1024, 8*1024*1024,
  320. 10*1024*1024, 12*1024*1024, 14*1024*1024, 16*1024*1024,
  321. };
  322. static void
  323. snarf(Vga* vga, Ctlr* ctlr)
  324. {
  325. Mach64xx *mp;
  326. int i;
  327. ulong v;
  328. if(vga->private == nil){
  329. vga->private = alloc(sizeof(Mach64xx));
  330. mp = vga->private;
  331. mp->io = 0x2EC;
  332. mp->ior32 = portior32;
  333. mp->iow32 = portiow32;
  334. mp->pci = pcimatch(0, 0x1002, 0);
  335. if (mp->pci) {
  336. if(v = mp->pci->mem[1].bar & ~0x3) {
  337. mp->io = v;
  338. mp->ior32 = pciior32;
  339. mp->iow32 = pciiow32;
  340. }
  341. }
  342. }
  343. mp = vga->private;
  344. for(i = 0; i < Nreg; i++)
  345. mp->reg[i] = mp->ior32(mp, i);
  346. for(i = 0; i < Npll; i++)
  347. mp->pll[i] = pllr(mp, i);
  348. switch(mp->reg[ConfigChipId] & 0xFFFF){
  349. default:
  350. mp->lcdpanelid = 0;
  351. break;
  352. case ('L'<<8)|'B': /* 4C42: Rage LTPro AGP */
  353. case ('L'<<8)|'I': /* 4C49: Rage 3D LTPro */
  354. case ('L'<<8)|'M': /* 4C4D: Rage Mobility */
  355. case ('L'<<8)|'P': /* 4C50: Rage 3D LTPro */
  356. for(i = 0; i < Nlcd; i++)
  357. mp->lcd[i] = lcdr32(mp, i);
  358. if(mp->lcd[LCD_GenCtrl] & 0x02)
  359. mp->lcdon = 1;
  360. mp->lcdpanelid = ((mp->reg[ConfigStat2]>>14) & 0x1F);
  361. break;
  362. }
  363. /*
  364. * Check which memory size map we are using.
  365. */
  366. mp->bigmem = 0;
  367. switch(mp->reg[ConfigChipId] & 0xFFFF){
  368. case ('G'<<8)|'B': /* 4742: 264GT PRO */
  369. case ('G'<<8)|'D': /* 4744: 264GT PRO */
  370. case ('G'<<8)|'I': /* 4749: 264GT PRO */
  371. case ('G'<<8)|'M': /* 474D: Rage XL */
  372. case ('G'<<8)|'P': /* 4750: 264GT PRO */
  373. case ('G'<<8)|'Q': /* 4751: 264GT PRO */
  374. case ('G'<<8)|'R': /* 4752: */
  375. case ('G'<<8)|'U': /* 4755: 264GT DVD */
  376. case ('G'<<8)|'V': /* 4756: Rage2C */
  377. case ('G'<<8)|'Z': /* 475A: Rage2C */
  378. case ('V'<<8)|'U': /* 5655: 264VT3 */
  379. case ('V'<<8)|'V': /* 5656: 264VT4 */
  380. case ('L'<<8)|'B': /* 4C42: Rage LTPro AGP */
  381. case ('L'<<8)|'I': /* 4C49: Rage 3D LTPro */
  382. case ('L'<<8)|'M': /* 4C4D: Rage Mobility */
  383. case ('L'<<8)|'P': /* 4C50: Rage 3D LTPro */
  384. mp->bigmem = 1;
  385. break;
  386. case ('G'<<8)|'T': /* 4754: 264GT[B] */
  387. case ('V'<<8)|'T': /* 5654: 264VT/GT/VTB */
  388. /*
  389. * Only the VTB and GTB use the new memory encoding,
  390. * and they are identified by a nonzero ChipVersion,
  391. * apparently.
  392. */
  393. if((mp->reg[ConfigChipId] >> 24) & 0x7)
  394. mp->bigmem = 1;
  395. break;
  396. }
  397. /*
  398. * Memory size and aperture. It's recommended
  399. * to use an 8Mb aperture on a 16Mb boundary.
  400. */
  401. if(mp->bigmem)
  402. vga->vmz = bigmem[mp->reg[MemCntl] & 0x0F];
  403. else
  404. vga->vmz = smallmem[mp->reg[MemCntl] & 0x07];
  405. vga->vma = 16*1024*1024;
  406. switch(mp->reg[ConfigCntl]&0x3){
  407. case 0:
  408. vga->apz = 16*1024*1024; /* empirical -rsc */
  409. break;
  410. case 1:
  411. vga->apz = 4*1024*1024;
  412. break;
  413. case 2:
  414. vga->apz = 8*1024*1024;
  415. break;
  416. case 3:
  417. vga->apz = 2*1024*1024; /* empirical: mach64GX -rsc */
  418. break;
  419. }
  420. ctlr->flag |= Fsnarf;
  421. }
  422. static void
  423. options(Vga*, Ctlr* ctlr)
  424. {
  425. ctlr->flag |= Hlinear|Foptions;
  426. }
  427. static void
  428. clock(Vga* vga, Ctlr* ctlr)
  429. {
  430. int clk, m, n, p;
  431. double f, q;
  432. Mach64xx *mp;
  433. mp = vga->private;
  434. /*
  435. * Don't compute clock timings for LCD panels.
  436. * Just use what's already there. We can't just use
  437. * the frequency in the vgadb for this because
  438. * the frequency being programmed into the PLLs
  439. * is not the frequency being used to compute the DSP
  440. * settings. The DSP-relevant frequency is the one
  441. * we keep in /lib/vgadb.
  442. */
  443. if(mp->lcdon){
  444. clk = mp->reg[ClockCntl] & 0x03;
  445. n = mp->pll[7+clk];
  446. p = (mp->pll[6]>>(clk*2)) & 0x03;
  447. p |= (mp->pll[11]>>(2+clk)) & 0x04;
  448. switch(p){
  449. case 0:
  450. case 1:
  451. case 2:
  452. case 3:
  453. p = 1<<p;
  454. break;
  455. case 4+0:
  456. p = 3;
  457. break;
  458. case 4+2:
  459. p = 6;
  460. break;
  461. case 4+3:
  462. p = 12;
  463. break;
  464. default:
  465. case 4+1:
  466. p = -1;
  467. break;
  468. }
  469. m = mp->pll[PLLm];
  470. f = (2.0*RefFreq*n)/(m*p) + 0.5;
  471. vga->m[0] = m;
  472. vga->p[0] = p;
  473. vga->n[0] = n;
  474. vga->f[0] = f;
  475. return;
  476. }
  477. if(vga->f[0] == 0)
  478. vga->f[0] = vga->mode->frequency;
  479. f = vga->f[0];
  480. /*
  481. * To generate a specific output frequency, the reference (m),
  482. * feedback (n), and post dividers (p) must be loaded with the
  483. * appropriate divide-down ratios. In the following r is the
  484. * XTALIN frequency (usually RefFreq) and t is the target frequency
  485. * (vga->f).
  486. *
  487. * Use the maximum reference divider left by the BIOS for now,
  488. * otherwise MCLK might be a concern. It can be calculated as
  489. * follows:
  490. * Upper Limit of PLL Lock Range
  491. * Minimum PLLREFCLK = -----------------------------
  492. * (2*255)
  493. *
  494. * XTALIN
  495. * m = Floor[-----------------]
  496. * Minimum PLLREFCLK
  497. *
  498. * For an upper limit of 135MHz and XTALIN of 14.318MHz m
  499. * would be 54.
  500. */
  501. m = mp->pll[PLLm];
  502. vga->m[0] = m;
  503. /*
  504. * The post divider may be 1, 2, 4 or 8 and is determined by
  505. * calculating
  506. * t*m
  507. * q = -----
  508. * (2*r)
  509. * and using the result to look-up p.
  510. */
  511. q = (f*m)/(2*RefFreq);
  512. if(ctlr->flag&Uenhanced){
  513. if(q > 255 || q < 10.6666666667)
  514. error("%s: vclk %lud out of range\n", ctlr->name, vga->f[0]);
  515. if(q > 127.5)
  516. p = 1;
  517. else if(q > 85)
  518. p = 2;
  519. else if(q > 63.75)
  520. p = 3;
  521. else if(q > 42.5)
  522. p = 4;
  523. else if(q > 31.875)
  524. p = 6;
  525. else if(q > 21.25)
  526. p = 8;
  527. else
  528. p = 12;
  529. }else{
  530. if(q > 255 || q < 16)
  531. error("%s: vclk %lud out of range\n", ctlr->name, vga->f[0]);
  532. if(q >= 127.5)
  533. p = 1;
  534. else if(q >= 63.5)
  535. p = 2;
  536. else if(q >= 31.5)
  537. p = 4;
  538. else
  539. p = 8;
  540. }
  541. vga->p[0] = p;
  542. /*
  543. * The feedback divider should be kept in the range 0x80 to 0xFF
  544. * and is found from
  545. * n = q*p
  546. * rounded to the nearest whole number.
  547. */
  548. vga->n[0] = (q*p)+0.5;
  549. }
  550. typedef struct Meminfo Meminfo;
  551. struct Meminfo {
  552. int latency;
  553. int latch;
  554. int trp; /* filled in from card */
  555. int trcd; /* filled in from card */
  556. int tcrd; /* filled in from card */
  557. int tras; /* filled in from card */
  558. };
  559. enum {
  560. Mdram,
  561. Medo,
  562. Msdram,
  563. Mwram,
  564. };
  565. /*
  566. * The manuals and documentation are silent on which settings
  567. * to use for Mwdram, or how to tell which to use.
  568. */
  569. static Meminfo meminfo[] = {
  570. [Mdram] { 1, 0 },
  571. [Medo] { 1, 2 },
  572. [Msdram] { 3, 1 },
  573. [Mwram] { 1, 3 }, /* non TYPE_A */
  574. };
  575. static ushort looplatencytab[2][2] = {
  576. { 8, 6 }, /* DRAM: ≤1M, > 1M */
  577. { 9, 8 }, /* SDRAM: ≤1M, > 1M */
  578. };
  579. static ushort cyclesperqwordtab[2][2] = {
  580. { 3, 2 }, /* DRAM: ≤1M, > 1M */
  581. { 2, 1 }, /* SDRAM: ≤1M, > 1M */
  582. };
  583. static int memtype[] = {
  584. -1, /* disable memory access */
  585. Mdram, /* basic DRAM */
  586. Medo, /* EDO */
  587. Medo, /* hyper page DRAM or EDO */
  588. Msdram, /* SDRAM */
  589. Msdram, /* SGRAM */
  590. Mwram,
  591. Mwram
  592. };
  593. /*
  594. * Calculate various memory parameters so that the card
  595. * fetches the right bytes at the right time. I don't claim to
  596. * understand the actual calculations very well.
  597. *
  598. * This is remarkably useful on laptops, since knowledge of
  599. * x lets us find the frequency that the screen is really running
  600. * at, which is not necessarily in the VCLKs.
  601. */
  602. static void
  603. setdsp(Vga* vga, Ctlr*)
  604. {
  605. Mach64xx *mp;
  606. Meminfo *mem;
  607. ushort table, memclk, memtyp;
  608. int i, prec, xprec, fprec;
  609. ulong t;
  610. double pw, x, fifosz, fifoon, fifooff;
  611. ushort dspon, dspoff;
  612. int afifosz, lat, ncycle, pfc, rcc;
  613. mp = vga->private;
  614. /*
  615. * Get video ram configuration from BIOS and chip
  616. */
  617. table = *(ushort*)readbios(sizeof table, 0xc0048);
  618. trace("rom table offset %uX\n", table);
  619. table = *(ushort*)readbios(sizeof table, 0xc0000+table+16);
  620. trace("freq table offset %uX\n", table);
  621. memclk = *(ushort*)readbios(sizeof memclk, 0xc0000+table+18);
  622. trace("memclk %ud\n", memclk);
  623. memtyp = memtype[mp->reg[ConfigStat0]&07];
  624. mem = &meminfo[memtyp];
  625. /*
  626. * First we need to calculate x, the number of
  627. * XCLKs that one QWORD occupies in the display FIFO.
  628. *
  629. * For some reason, x gets stretched out if LCD stretching
  630. * is turned on.
  631. */
  632. x = ((double)memclk*640000.0) /
  633. ((double)vga->mode->frequency * (double)vga->mode->z);
  634. if(mp->lcd[LCD_HorzStretch] & (1<<31))
  635. x *= 4096.0 / (double)(mp->lcd[LCD_HorzStretch] & 0xFFFF);
  636. trace("memclk %d... x %f...", memclk, x);
  637. /*
  638. * We have 14 bits to specify x in. Decide where to
  639. * put the decimal (err, binary) point by counting how
  640. * many significant bits are in the integer portion of x.
  641. */
  642. t = x;
  643. for(i=31; i>=0; i--)
  644. if(t & (1<<i))
  645. break;
  646. xprec = i+1;
  647. trace("t %lud... xprec %d...", t, xprec);
  648. /*
  649. * The maximum FIFO size is the number of XCLKs per QWORD
  650. * multiplied by 32, for some reason. We have 11 bits to
  651. * specify fifosz.
  652. */
  653. fifosz = x * 32.0;
  654. trace("fifosz %f...", fifosz);
  655. t = fifosz;
  656. for(i=31; i>=0; i--)
  657. if(t & (1<<i))
  658. break;
  659. fprec = i+1;
  660. trace("fprec %d...", fprec);
  661. /*
  662. * Precision is specified as 3 less than the number of bits
  663. * in the integer part of x, and 5 less than the number of bits
  664. * in the integer part of fifosz.
  665. *
  666. * It is bounded by zero and seven.
  667. */
  668. prec = (xprec-3 > fprec-5) ? xprec-3 : fprec-5;
  669. if(prec < 0)
  670. prec = 0;
  671. if(prec > 7)
  672. prec = 7;
  673. xprec = prec+3;
  674. fprec = prec+5;
  675. trace("prec %d...", prec);
  676. /*
  677. * Actual fifo size
  678. */
  679. afifosz = (1<<fprec) / x;
  680. if(afifosz > 32)
  681. afifosz = 32;
  682. fifooff = ceil(x*(afifosz-1));
  683. /*
  684. * I am suspicious of this table, lifted from ATI docs,
  685. * because it doesn't agree with the Windows drivers.
  686. * We always get 0x0A for lat+2 while Windows uses 0x08.
  687. */
  688. lat = looplatencytab[memtyp > 1][vga->vmz > 1*1024*1024];
  689. trace("afifosz %d...fifooff %f...", afifosz, fifooff);
  690. /*
  691. * Page fault clock
  692. */
  693. t = mp->reg[MemCntl];
  694. mem->trp = (t>>8)&3; /* RAS precharge time */
  695. mem->trcd = (t>>10)&3; /* RAS to CAS delay */
  696. mem->tcrd = (t>>12)&1; /* CAS to RAS delay */
  697. mem->tras = (t>>16)&7; /* RAS low minimum pulse width */
  698. pfc = mem->trp + 1 + mem->trcd + 1 + mem->tcrd;
  699. trace("pfc %d...", pfc);
  700. /*
  701. * Maximum random access cycle clock.
  702. */
  703. ncycle = cyclesperqwordtab[memtyp > 1][vga->vmz > 1*1024*1024];
  704. rcc = mem->trp + 1 + mem->tras + 1;
  705. if(rcc < pfc+ncycle)
  706. rcc = pfc+ncycle;
  707. trace("rcc %d...", rcc);
  708. fifoon = (rcc > floor(x)) ? rcc : floor(x);
  709. fifoon += (3.0 * rcc) - 1 + pfc + ncycle;
  710. trace("fifoon %f...\n", fifoon);
  711. /*
  712. * Now finally put the bits together.
  713. * x is stored in a 14 bit field with xprec bits of integer.
  714. */
  715. pw = x * (1<<(14-xprec));
  716. mp->reg[DspConfig] = (ulong)pw | (((lat+2)&0xF)<<16) | ((prec&7)<<20);
  717. /*
  718. * These are stored in an 11 bit field with fprec bits of integer.
  719. */
  720. dspon = (ushort)fifoon << (11-fprec);
  721. dspoff = (ushort)fifooff << (11-fprec);
  722. mp->reg[DspOnOff] = ((dspon&0x7ff) << 16) | (dspoff&0x7ff);
  723. }
  724. static void
  725. init(Vga* vga, Ctlr* ctlr)
  726. {
  727. Mode *mode;
  728. Mach64xx *mp;
  729. int p, x, y;
  730. mode = vga->mode;
  731. if((mode->x > 640 || mode->y > 480) && mode->z == 1)
  732. error("%s: no support for 1-bit mode other than 640x480x1\n",
  733. ctlr->name);
  734. mp = vga->private;
  735. if(mode->z > 8 && mp->pci == nil)
  736. error("%s: no support for >8-bit color without PCI\n",
  737. ctlr->name);
  738. /*
  739. * Check for Rage chip
  740. */
  741. switch (mp->reg[ConfigChipId]&0xffff) {
  742. case ('G'<<8)|'B': /* 4742: 264GT PRO */
  743. case ('G'<<8)|'D': /* 4744: 264GT PRO */
  744. case ('G'<<8)|'I': /* 4749: 264GT PRO */
  745. case ('G'<<8)|'M': /* 474D: Rage XL */
  746. case ('G'<<8)|'P': /* 4750: 264GT PRO */
  747. case ('G'<<8)|'Q': /* 4751: 264GT PRO */
  748. case ('G'<<8)|'R': /* 4752: */
  749. case ('G'<<8)|'U': /* 4755: 264GT DVD */
  750. case ('G'<<8)|'V': /* 4756: Rage2C */
  751. case ('G'<<8)|'Z': /* 475A: Rage2C */
  752. case ('V'<<8)|'U': /* 5655: 264VT3 */
  753. case ('V'<<8)|'V': /* 5656: 264VT4 */
  754. case ('G'<<8)|'T': /* 4754: 264GT[B] */
  755. case ('V'<<8)|'T': /* 5654: 264VT/GT/VTB */
  756. case ('L'<<8)|'B': /* 4C42: Rage LTPro AGP */
  757. case ('L'<<8)|'I': /* 4C49: 264LT PRO */
  758. case ('L'<<8)|'M': /* 4C4D: Rage Mobility */
  759. case ('L'<<8)|'P': /* 4C50: 264LT PRO */
  760. ctlr->flag |= Uenhanced;
  761. break;
  762. }
  763. /*
  764. * Always use VCLK2.
  765. */
  766. clock(vga, ctlr);
  767. mp->pll[PLLn2] = vga->n[0];
  768. mp->pll[PLLp] &= ~(0x03<<(2*2));
  769. switch(vga->p[0]){
  770. case 1:
  771. case 3:
  772. p = 0;
  773. break;
  774. case 2:
  775. p = 1;
  776. break;
  777. case 4:
  778. case 6:
  779. p = 2;
  780. break;
  781. case 8:
  782. case 12:
  783. p = 3;
  784. break;
  785. default:
  786. p = 3;
  787. break;
  788. }
  789. mp->pll[PLLp] |= p<<(2*2);
  790. if ((1<<p) != vga->p[0])
  791. mp->pll[PLLx] |= 1<<(4+2);
  792. else
  793. mp->pll[PLLx] &= ~(1<<(4+2));
  794. mp->reg[ClockCntl] = 2;
  795. mp->reg[ConfigCntl] = 0;
  796. mp->reg[CrtcGenCntl] = 0x02000000|(mp->reg[CrtcGenCntl] & ~0x01400700);
  797. switch(mode->z){
  798. default:
  799. case 1:
  800. mp->reg[CrtcGenCntl] |= 0x00000100;
  801. mp->reg[DpPixWidth] = 0x00000000;
  802. break;
  803. case 8:
  804. mp->reg[CrtcGenCntl] |= 0x01000200;
  805. mp->reg[DpPixWidth] = 0x00020202;
  806. break;
  807. case 15:
  808. mp->reg[CrtcGenCntl] |= 0x01000300;
  809. mp->reg[DpPixWidth] = 0x00030303;
  810. break;
  811. case 16:
  812. mp->reg[CrtcGenCntl] |= 0x01000400;
  813. mp->reg[DpPixWidth] = 0x00040404;
  814. break;
  815. case 24:
  816. mp->reg[CrtcGenCntl] |= 0x01000500;
  817. mp->reg[DpPixWidth] = 0x00050505;
  818. break;
  819. case 32:
  820. mp->reg[CrtcGenCntl] |= 0x01000600;
  821. mp->reg[DpPixWidth] = 0x00060606;
  822. break;
  823. }
  824. mp->reg[HTotalDisp] = (((mode->x>>3)-1)<<16)|((mode->ht>>3)-1);
  825. mp->reg[HSyncStrtWid] = (((mode->ehs - mode->shs)>>3)<<16)
  826. |((mode->shs>>3)-1);
  827. if(mode->hsync == '-')
  828. mp->reg[HSyncStrtWid] |= 0x00200000;
  829. mp->reg[VTotalDisp] = ((mode->y-1)<<16)|(mode->vt-1);
  830. mp->reg[VSyncStrtWid] = ((mode->vre - mode->vrs)<<16)|(mode->vrs-1);
  831. if(mode->vsync == '-')
  832. mp->reg[VSyncStrtWid] |= 0x00200000;
  833. mp->reg[IntCntl] = 0;
  834. /*
  835. * This used to set it to (mode->x/(8*2))<<22 for depths < 8,
  836. * but from the manual that seems wrong to me. -rsc
  837. */
  838. mp->reg[OffPitch] = (vga->virtx/8)<<22;
  839. mp->reg[OvrClr] = Pblack;
  840. if(vga->linear && mode->z != 1)
  841. ctlr->flag |= Ulinear;
  842. /*
  843. * Heuristic fiddling on LT PRO.
  844. * Do this before setdsp so the stretching is right.
  845. */
  846. if(mp->lcdon){
  847. /* use non-shadowed registers */
  848. mp->lcd[LCD_GenCtrl] &= ~0x00000404;
  849. mp->lcd[LCD_ConfigPanel] |= 0x00004000;
  850. mp->lcd[LCD_VertStretch] = 0;
  851. y = ((mp->lcd[LCD_ExtVertStretch]>>11) & 0x7FF)+1;
  852. if(mode->y < y){
  853. x = (mode->y*1024)/y;
  854. mp->lcd[LCD_VertStretch] = 0xC0000000|x;
  855. }
  856. mp->lcd[LCD_ExtVertStretch] &= ~0x00400400;
  857. /*
  858. * The x value doesn't seem to be available on all
  859. * chips so intuit it from the y value which seems to
  860. * be reliable.
  861. */
  862. mp->lcd[LCD_HorzStretch] &= ~0xC00000FF;
  863. x = (mp->lcd[LCD_HorzStretch]>>20) & 0xFF;
  864. if(x == 0){
  865. switch(y){
  866. default:
  867. break;
  868. case 480:
  869. x = 640;
  870. break;
  871. case 600:
  872. x = 800;
  873. break;
  874. case 768:
  875. x = 1024;
  876. break;
  877. case 1024:
  878. x = 1280;
  879. break;
  880. }
  881. }
  882. else
  883. x = (x+1)*8;
  884. if(mode->x < x){
  885. x = (mode->x*4096)/x;
  886. mp->lcd[LCD_HorzStretch] |= 0xC0000000|x;
  887. }
  888. }
  889. if(ctlr->flag&Uenhanced)
  890. setdsp(vga, ctlr);
  891. ctlr->flag |= Finit;
  892. }
  893. static void
  894. load(Vga* vga, Ctlr* ctlr)
  895. {
  896. Mach64xx *mp;
  897. int i;
  898. mp = vga->private;
  899. /*
  900. * Unlock the CRTC and LCD registers.
  901. */
  902. mp->iow32(mp, CrtcGenCntl, mp->ior32(mp, CrtcGenCntl)&~0x00400000);
  903. if(mp->lcdon)
  904. lcdw32(mp, LCD_GenCtrl, mp->lcd[LCD_GenCtrl]|0x80000000);
  905. /*
  906. * Always use an aperture on a 16Mb boundary.
  907. */
  908. if(ctlr->flag & Ulinear)
  909. mp->reg[ConfigCntl] = ((vga->vmb/(4*1024*1024))<<4)|0x02;
  910. mp->iow32(mp, ConfigCntl, mp->reg[ConfigCntl]);
  911. mp->iow32(mp, GenTestCntl, 0);
  912. mp->iow32(mp, GenTestCntl, 0x100);
  913. if((ctlr->flag&Uenhanced) == 0)
  914. mp->iow32(mp, MemCntl, mp->reg[MemCntl] & ~0x70000);
  915. mp->iow32(mp, BusCntl, mp->reg[BusCntl]);
  916. mp->iow32(mp, HTotalDisp, mp->reg[HTotalDisp]);
  917. mp->iow32(mp, HSyncStrtWid, mp->reg[HSyncStrtWid]);
  918. mp->iow32(mp, VTotalDisp, mp->reg[VTotalDisp]);
  919. mp->iow32(mp, VSyncStrtWid, mp->reg[VSyncStrtWid]);
  920. mp->iow32(mp, IntCntl, mp->reg[IntCntl]);
  921. mp->iow32(mp, OffPitch, mp->reg[OffPitch]);
  922. if(mp->lcdon){
  923. for(i=0; i<Nlcd; i++)
  924. lcdw32(mp, i, mp->lcd[i]);
  925. }
  926. mp->iow32(mp, GenTestCntl, mp->reg[GenTestCntl]);
  927. mp->iow32(mp, ConfigCntl, mp->reg[ConfigCntl]);
  928. mp->iow32(mp, CrtcGenCntl, mp->reg[CrtcGenCntl]);
  929. mp->iow32(mp, OvrClr, mp->reg[OvrClr]);
  930. mp->iow32(mp, OvrWidLR, mp->reg[OvrWidLR]);
  931. mp->iow32(mp, OvrWidTB, mp->reg[OvrWidTB]);
  932. if(ctlr->flag&Uenhanced){
  933. mp->iow32(mp, DacRegs, mp->reg[DacRegs]);
  934. mp->iow32(mp, DacCntl, mp->reg[DacCntl]);
  935. mp->iow32(mp, CrtcGenCntl, mp->reg[CrtcGenCntl]&~0x02000000);
  936. mp->iow32(mp, DspOnOff, mp->reg[DspOnOff]);
  937. mp->iow32(mp, DspConfig, mp->reg[DspConfig]);
  938. mp->iow32(mp, CrtcGenCntl, mp->reg[CrtcGenCntl]);
  939. pllw(mp, PLLx, mp->pll[PLLx]);
  940. }
  941. pllw(mp, PLLn2, mp->pll[PLLn2]);
  942. pllw(mp, PLLp, mp->pll[PLLp]);
  943. pllw(mp, PLLn3, mp->pll[PLLn3]);
  944. mp->iow32(mp, ClockCntl, mp->reg[ClockCntl]);
  945. mp->iow32(mp, ClockCntl, 0x40|mp->reg[ClockCntl]);
  946. mp->iow32(mp, DpPixWidth, mp->reg[DpPixWidth]);
  947. if(vga->mode->z > 8){
  948. int sh, i;
  949. /*
  950. * We need to initialize the palette, since the DACs use it
  951. * in true color modes. First see if the card supports an
  952. * 8-bit DAC.
  953. */
  954. mp->iow32(mp, DacCntl, mp->reg[DacCntl] | 0x100);
  955. if(mp->ior32(mp, DacCntl)&0x100){
  956. /* card appears to support it */
  957. vgactlw("palettedepth", "8");
  958. mp->reg[DacCntl] |= 0x100;
  959. }
  960. if(mp->reg[DacCntl] & 0x100)
  961. sh = 0; /* 8-bit DAC */
  962. else
  963. sh = 2; /* 6-bit DAC */
  964. for(i=0; i<256; i++)
  965. setpalette(i, i>>sh, i>>sh, i>>sh);
  966. }
  967. ctlr->flag |= Fload;
  968. }
  969. static void
  970. pixelclock(Vga* vga, Ctlr* ctlr)
  971. {
  972. Mach64xx *mp;
  973. ushort table, s;
  974. int memclk, ref_freq, ref_divider, min_freq, max_freq;
  975. int feedback, nmult, pd, post, value;
  976. int clock;
  977. /*
  978. * Find the pixel clock from the BIOS and current
  979. * settings. Lifted from the ATI-supplied example code.
  980. * The clocks stored in the BIOS table are in kHz/10.
  981. *
  982. * This is the clock LCDs use in vgadb to set the DSP
  983. * values.
  984. */
  985. mp = vga->private;
  986. /*
  987. * GetPLLInfo()
  988. */
  989. table = *(ushort*)readbios(sizeof table, 0xc0048);
  990. trace("rom table offset %uX\n", table);
  991. table = *(ushort*)readbios(sizeof table, 0xc0000+table+16);
  992. trace("freq table offset %uX\n", table);
  993. s = *(ushort*)readbios(sizeof s, 0xc0000+table+18);
  994. memclk = s*10000;
  995. trace("memclk %ud\n", memclk);
  996. s = *(ushort*)readbios(sizeof s, 0xc0000+table+8);
  997. ref_freq = s*10000;
  998. trace("ref_freq %ud\n", ref_freq);
  999. s = *(ushort*)readbios(sizeof s, 0xc0000+table+10);
  1000. ref_divider = s;
  1001. trace("ref_divider %ud\n", ref_divider);
  1002. s = *(ushort*)readbios(sizeof s, 0xc0000+table+2);
  1003. min_freq = s*10000;
  1004. trace("min_freq %ud\n", min_freq);
  1005. s = *(ushort*)readbios(sizeof s, 0xc0000+table+4);
  1006. max_freq = s*10000;
  1007. trace("max_freq %ud\n", max_freq);
  1008. /*
  1009. * GetDivider()
  1010. */
  1011. pd = mp->pll[PLLp] & 0x03;
  1012. value = (mp->pll[PLLx] & 0x10)>>2;
  1013. trace("pd %uX value %uX (|%d)\n", pd, value, value|pd);
  1014. value |= pd;
  1015. post = 0;
  1016. switch(value){
  1017. case 0:
  1018. post = 1;
  1019. break;
  1020. case 1:
  1021. post = 2;
  1022. break;
  1023. case 2:
  1024. post = 4;
  1025. break;
  1026. case 3:
  1027. post = 8;
  1028. break;
  1029. case 4:
  1030. post = 3;
  1031. break;
  1032. case 5:
  1033. post = 0;
  1034. break;
  1035. case 6:
  1036. post = 6;
  1037. break;
  1038. case 7:
  1039. post = 12;
  1040. break;
  1041. }
  1042. trace("post = %d\n", post);
  1043. feedback = mp->pll[PLLn0];
  1044. if(mp->pll[PLLx] & 0x08)
  1045. nmult = 4;
  1046. else
  1047. nmult = 2;
  1048. clock = (ref_freq/10000)*nmult*feedback;
  1049. clock /= ref_divider*post;
  1050. clock *= 10000;
  1051. Bprint(&stdout, "%s pixel clock = %ud\n", ctlr->name, clock);
  1052. }
  1053. static void dumpmach64bios(Mach64xx*);
  1054. static void
  1055. dump(Vga* vga, Ctlr* ctlr)
  1056. {
  1057. Mach64xx *mp;
  1058. int i, m, n, p;
  1059. double f;
  1060. static int first = 1;
  1061. if((mp = vga->private) == 0)
  1062. return;
  1063. Bprint(&stdout, "%s pci %p io %lux %s\n", ctlr->name,
  1064. mp->pci, mp->io, mp->ior32 == pciior32 ? "pciregs" : "ioregs");
  1065. if(mp->pci)
  1066. Bprint(&stdout, "%s ccru %ux\n", ctlr->name, mp->pci->ccru);
  1067. for(i = 0; i < Nreg; i++)
  1068. Bprint(&stdout, "%s %-*s%.8luX\n",
  1069. ctlr->name, 20, iorname[i], mp->reg[i]);
  1070. printitem(ctlr->name, "PLL");
  1071. for(i = 0; i < Npll; i++)
  1072. printreg(mp->pll[i]);
  1073. Bprint(&stdout, "\n");
  1074. switch(mp->reg[ConfigChipId] & 0xFFFF){
  1075. default:
  1076. break;
  1077. case ('L'<<8)|'B': /* 4C42: Rage LTPro AGP */
  1078. case ('L'<<8)|'I': /* 4C49: Rage 3D LTPro */
  1079. case ('L'<<8)|'M': /* 4C4D: Rage Mobility */
  1080. case ('L'<<8)|'P': /* 4C50: Rage 3D LTPro */
  1081. for(i = 0; i < Nlcd; i++)
  1082. Bprint(&stdout, "%s %-*s%.8luX\n",
  1083. ctlr->name, 20, lcdname[i], mp->lcd[i]);
  1084. break;
  1085. }
  1086. /*
  1087. * (2*r*n)
  1088. * f = -------
  1089. * (m*p)
  1090. */
  1091. m = mp->pll[2];
  1092. for(i = 0; i < 4; i++){
  1093. n = mp->pll[7+i];
  1094. p = (mp->pll[6]>>(i*2)) & 0x03;
  1095. p |= (mp->pll[11]>>(2+i)) & 0x04;
  1096. switch(p){
  1097. case 0:
  1098. case 1:
  1099. case 2:
  1100. case 3:
  1101. p = 1<<p;
  1102. break;
  1103. case 4+0:
  1104. p = 3;
  1105. break;
  1106. case 4+2:
  1107. p = 6;
  1108. break;
  1109. case 4+3:
  1110. p = 12;
  1111. break;
  1112. default:
  1113. case 4+1:
  1114. p = -1;
  1115. break;
  1116. }
  1117. if(m*p == 0)
  1118. Bprint(&stdout, "unknown VCLK%d\n", i);
  1119. else {
  1120. f = (2.0*RefFreq*n)/(m*p) + 0.5;
  1121. Bprint(&stdout, "%s VCLK%d\t%ud\n", ctlr->name, i, (int)f);
  1122. }
  1123. }
  1124. pixelclock(vga, ctlr);
  1125. if(first) {
  1126. first = 0;
  1127. dumpmach64bios(mp);
  1128. }
  1129. }
  1130. enum {
  1131. ClockFixed=0,
  1132. ClockIcs2595,
  1133. ClockStg1703,
  1134. ClockCh8398,
  1135. ClockInternal,
  1136. ClockAtt20c408,
  1137. ClockIbmrgb514
  1138. };
  1139. /*
  1140. * mostly derived from the xfree86 probe routines.
  1141. */
  1142. static void
  1143. dumpmach64bios(Mach64xx *mp)
  1144. {
  1145. int i, romtable, clocktable, freqtable, lcdtable, lcdpanel;
  1146. uchar bios[0x1000];
  1147. memmove(bios, readbios(sizeof bios, 0xC0000), sizeof bios);
  1148. /* find magic string */
  1149. for(i=0; i<1024; i++)
  1150. if(strncmp((char*)bios+i, " 761295520", 10) == 0)
  1151. break;
  1152. if(i==1024) {
  1153. Bprint(&stdout, "no ATI bios found\n");
  1154. return;
  1155. }
  1156. /* this is horribly endian dependent. sorry. */
  1157. romtable = *(ushort*)(bios+0x48);
  1158. if(romtable+0x12 > sizeof(bios)) {
  1159. Bprint(&stdout, "couldn't find ATI rom table\n");
  1160. return;
  1161. }
  1162. clocktable = *(ushort*)(bios+romtable+0x10);
  1163. if(clocktable+0x0C > sizeof(bios)) {
  1164. Bprint(&stdout, "couldn't find ATI clock table\n");
  1165. return;
  1166. }
  1167. freqtable = *(ushort*)(bios-2);
  1168. if(freqtable+0x20 > sizeof(bios)) {
  1169. Bprint(&stdout, "couldn't find ATI frequency table\n");
  1170. return;
  1171. }
  1172. Bprint(&stdout, "ATI BIOS rom 0x%x freq 0x%x clock 0x%x\n", romtable, freqtable, clocktable);
  1173. Bprint(&stdout, "clocks:");
  1174. for(i=0; i<16; i++)
  1175. Bprint(&stdout, " %d", *(ushort*)(bios+freqtable+2*i));
  1176. Bprint(&stdout, "\n");
  1177. Bprint(&stdout, "programmable clock: %d\n", bios[clocktable]);
  1178. Bprint(&stdout, "clock to program: %d\n", bios[clocktable+6]);
  1179. if(*(ushort*)(bios+clocktable+8) != 1430) {
  1180. Bprint(&stdout, "reference numerator: %d\n", *(ushort*)(bios+clocktable+8)*10);
  1181. Bprint(&stdout, "reference denominator: 1\n");
  1182. } else {
  1183. Bprint(&stdout, "default reference numerator: 157500\n");
  1184. Bprint(&stdout, "default reference denominator: 11\n");
  1185. }
  1186. switch(bios[clocktable]) {
  1187. case ClockIcs2595:
  1188. Bprint(&stdout, "ics2595\n");
  1189. Bprint(&stdout, "reference divider: %d\n", *(ushort*)(bios+clocktable+0x0A));
  1190. break;
  1191. case ClockStg1703:
  1192. Bprint(&stdout, "stg1703\n");
  1193. break;
  1194. case ClockCh8398:
  1195. Bprint(&stdout, "ch8398\n");
  1196. break;
  1197. case ClockInternal:
  1198. Bprint(&stdout, "internal clock\n");
  1199. Bprint(&stdout, "reference divider in plls\n");
  1200. break;
  1201. case ClockAtt20c408:
  1202. Bprint(&stdout, "att 20c408\n");
  1203. break;
  1204. case ClockIbmrgb514:
  1205. Bprint(&stdout, "ibm rgb514\n");
  1206. Bprint(&stdout, "clock to program = 7\n");
  1207. break;
  1208. default:
  1209. Bprint(&stdout, "unknown clock\n");
  1210. break;
  1211. }
  1212. USED(mp);
  1213. if(1 || mp->lcdpanelid) {
  1214. lcdtable = *(ushort*)(bios+0x78);
  1215. if(lcdtable+5 > sizeof bios || lcdtable+bios[lcdtable+5] > sizeof bios) {
  1216. Bprint(&stdout, "can't find lcd bios table\n");
  1217. goto NoLcd;
  1218. }
  1219. lcdpanel = *(ushort*)(bios+lcdtable+0x0A);
  1220. if(lcdpanel+0x1D > sizeof bios /*|| bios[lcdpanel] != mp->lcdpanelid*/) {
  1221. Bprint(&stdout, "can't find lcd bios table0\n");
  1222. goto NoLcd;
  1223. }
  1224. Bprint(&stdout, "panelid %d x %d y %d\n", bios[lcdpanel], *(ushort*)(bios+lcdpanel+0x19), *(ushort*)(bios+lcdpanel+0x1B));
  1225. }
  1226. NoLcd:;
  1227. }
  1228. Ctlr mach64xx = {
  1229. "mach64xx", /* name */
  1230. snarf, /* snarf */
  1231. 0, /* options */
  1232. init, /* init */
  1233. load, /* load */
  1234. dump, /* dump */
  1235. };
  1236. Ctlr mach64xxhwgc = {
  1237. "mach64xxhwgc", /* name */
  1238. 0, /* snarf */
  1239. 0, /* options */
  1240. 0, /* init */
  1241. 0, /* load */
  1242. 0, /* dump */
  1243. };