vgas3.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619
  1. #include "u.h"
  2. #include "../port/lib.h"
  3. #include "mem.h"
  4. #include "dat.h"
  5. #include "fns.h"
  6. #include "io.h"
  7. #include "../port/error.h"
  8. #define Image IMAGE
  9. #include <draw.h>
  10. #include <memdraw.h>
  11. #include <cursor.h>
  12. #include "screen.h"
  13. enum {
  14. PCIS3 = 0x5333, /* PCI VID */
  15. SAVAGE3D = 0x8A20, /* PCI DID */
  16. SAVAGE3DMV = 0x8A21,
  17. SAVAGE4 = 0x8A22,
  18. PROSAVAGEP = 0x8A25,
  19. PROSAVAGEK = 0x8A26,
  20. PROSAVAGE8 = 0x8D04,
  21. SAVAGEMXMV = 0x8C10,
  22. SAVAGEMX = 0x8C11,
  23. SAVAGEIXMV = 0x8C12,
  24. SAVAGEIX = 0x8C13,
  25. SUPERSAVAGEIXC16 = 0x8C2E,
  26. SAVAGE2000 = 0x9102,
  27. VIRGE = 0x5631,
  28. VIRGEGX2 = 0x8A10,
  29. VIRGEDXGX = 0x8A01,
  30. VIRGEVX = 0x883D,
  31. VIRGEMX = 0x8C01,
  32. VIRGEMXP = 0x8C03,
  33. AURORA64VPLUS = 0x8812,
  34. };
  35. static int
  36. s3pageset(VGAscr* scr, int page)
  37. {
  38. uchar crt35, crt51;
  39. int opage;
  40. crt35 = vgaxi(Crtx, 0x35);
  41. if(scr->gscreen->depth >= 8){
  42. /*
  43. * The S3 registers need to be unlocked for this.
  44. * Let's hope they are already:
  45. * vgaxo(Crtx, 0x38, 0x48);
  46. * vgaxo(Crtx, 0x39, 0xA0);
  47. *
  48. * The page is 6 bits, the lower 4 bits in Crt35<3:0>,
  49. * the upper 2 in Crt51<3:2>.
  50. */
  51. vgaxo(Crtx, 0x35, page & 0x0F);
  52. crt51 = vgaxi(Crtx, 0x51);
  53. vgaxo(Crtx, 0x51, (crt51 & ~0x0C)|((page & 0x30)>>2));
  54. opage = ((crt51 & 0x0C)<<2)|(crt35 & 0x0F);
  55. }
  56. else{
  57. vgaxo(Crtx, 0x35, (page<<2) & 0x0C);
  58. opage = (crt35>>2) & 0x03;
  59. }
  60. return opage;
  61. }
  62. static void
  63. s3page(VGAscr* scr, int page)
  64. {
  65. int id;
  66. id = (vgaxi(Crtx, 0x2D)<<8)|vgaxi(Crtx, 0x2E);
  67. switch(id){
  68. case VIRGEGX2:
  69. break;
  70. default:
  71. lock(&scr->devlock);
  72. s3pageset(scr, page);
  73. unlock(&scr->devlock);
  74. break;
  75. }
  76. }
  77. static ulong
  78. s3linear(VGAscr* scr, int* size, int* align)
  79. {
  80. char *mmioname;
  81. ulong aperture, oaperture, mmiobase, mmiosize;
  82. int i, id, j, osize, oapsize, wasupamem;
  83. Pcidev *p;
  84. osize = *size;
  85. oaperture = scr->aperture;
  86. oapsize = scr->apsize;
  87. wasupamem = scr->isupamem;
  88. mmiosize = 0;
  89. mmiobase = 0;
  90. mmioname = nil;
  91. /*
  92. * S3 makes cards other than display controllers, so
  93. * look for the first S3 display controller (device class 3)
  94. * and not one of their sound cards.
  95. */
  96. p = nil;
  97. while(p = pcimatch(p, PCIS3, 0)){
  98. if(p->ccrb == 0x03)
  99. break;
  100. }
  101. if(p != nil){
  102. for(i=0; i<nelem(p->mem); i++){
  103. if(p->mem[i].size >= *size
  104. && ((p->mem[i].bar & ~0x0F) & (*align-1)) == 0)
  105. break;
  106. }
  107. if(i >= nelem(p->mem)){
  108. print("vgas3: aperture not found\n");
  109. return 0;
  110. }
  111. aperture = p->mem[i].bar & ~0x0F;
  112. *size = p->mem[i].size;
  113. id = (vgaxi(Crtx, 0x2D)<<8)|vgaxi(Crtx, 0x2E);
  114. switch(id){ /* find mmio */
  115. case SAVAGE4:
  116. case PROSAVAGEP:
  117. case PROSAVAGEK:
  118. case PROSAVAGE8:
  119. case SUPERSAVAGEIXC16:
  120. /*
  121. * We could assume that the MMIO registers
  122. * will be in the screen segment and just use
  123. * that, but PCI software is allowed to move them
  124. * if it feels like it, so we look for an aperture of
  125. * the right size; only the first 512k actually means
  126. * anything. The S3 engineers overestimated how
  127. * much space they would need in the first design.
  128. */
  129. for(j=0; j<nelem(p->mem); j++){
  130. if(i == j)
  131. continue;
  132. if(p->mem[j].size==512*1024 || p->mem[j].size==16*1024*1024){
  133. mmiobase = p->mem[j].bar & ~0x0F;
  134. mmiosize = 512*1024;
  135. scr->mmio = (ulong*)upamalloc(mmiobase, mmiosize, 0);
  136. mmioname = "savagemmio";
  137. break;
  138. }
  139. }
  140. if(mmiosize == 0){
  141. print("savage4: mmio not found\n");
  142. return 0;
  143. }
  144. }
  145. }else
  146. aperture = 0;
  147. if(wasupamem)
  148. upafree(oaperture, oapsize);
  149. scr->isupamem = 0;
  150. aperture = upamalloc(aperture, *size, *align);
  151. if(aperture == 0){
  152. if(wasupamem && upamalloc(oaperture, oapsize, 0))
  153. scr->isupamem = 1;
  154. }
  155. else
  156. scr->isupamem = 1;
  157. if(oaperture && oaperture != aperture)
  158. print("warning (BUG): redefinition of aperture does not change s3screen segment\n");
  159. addvgaseg("s3screen", aperture, osize);
  160. if(mmiosize)
  161. addvgaseg(mmioname, mmiobase, mmiosize);
  162. return aperture;
  163. }
  164. static void
  165. s3vsyncactive(void)
  166. {
  167. /*
  168. * Hardware cursor information is fetched from display memory
  169. * during the horizontal blank active time. The 80x chips may hang
  170. * if the cursor is turned on or off during this period.
  171. */
  172. while((vgai(Status1) & 0x08) == 0)
  173. ;
  174. }
  175. static void
  176. s3disable(VGAscr*)
  177. {
  178. uchar crt45;
  179. /*
  180. * Turn cursor off.
  181. */
  182. crt45 = vgaxi(Crtx, 0x45) & 0xFE;
  183. s3vsyncactive();
  184. vgaxo(Crtx, 0x45, crt45);
  185. }
  186. static void
  187. s3load(VGAscr* scr, Cursor* curs)
  188. {
  189. uchar *p;
  190. int id, dolock, opage, x, y;
  191. /*
  192. * Disable the cursor and
  193. * set the pointer to the two planes.
  194. */
  195. s3disable(scr);
  196. opage = 0;
  197. p = KADDR(scr->aperture);
  198. id = (vgaxi(Crtx, 0x2D)<<8)|vgaxi(Crtx, 0x2E);
  199. switch(id){
  200. case VIRGE:
  201. case VIRGEDXGX:
  202. case VIRGEGX2:
  203. case VIRGEVX:
  204. case SAVAGEMXMV:
  205. case SAVAGEIXMV:
  206. case SAVAGE4:
  207. case PROSAVAGEP:
  208. case PROSAVAGEK:
  209. case PROSAVAGE8:
  210. case SUPERSAVAGEIXC16:
  211. dolock = 0;
  212. p += scr->storage;
  213. break;
  214. default:
  215. dolock = 1;
  216. lock(&scr->devlock);
  217. opage = s3pageset(scr, scr->storage>>16);
  218. p += (scr->storage & 0xFFFF);
  219. break;
  220. }
  221. /*
  222. * The cursor is set in Microsoft Windows format (the ViRGE/GX2 doesn't
  223. * support the X11 format) which gives the following truth table:
  224. * and xor colour
  225. * 0 0 background colour
  226. * 0 1 foreground colour
  227. * 1 0 current screen pixel
  228. * 1 1 NOT current screen pixel
  229. * Put the cursor into the top-left of the 64x64 array.
  230. *
  231. * The cursor pattern in memory is interleaved words of
  232. * AND and XOR patterns.
  233. */
  234. for(y = 0; y < 64; y++){
  235. for(x = 0; x < 64/8; x += 2){
  236. if(x < 16/8 && y < 16){
  237. *p++ = ~(curs->clr[2*y + x]|curs->set[2*y + x]);
  238. *p++ = ~(curs->clr[2*y + x+1]|curs->set[2*y + x+1]);
  239. *p++ = curs->set[2*y + x];
  240. *p++ = curs->set[2*y + x+1];
  241. }
  242. else {
  243. *p++ = 0xFF;
  244. *p++ = 0xFF;
  245. *p++ = 0x00;
  246. *p++ = 0x00;
  247. }
  248. }
  249. }
  250. if(dolock){
  251. s3pageset(scr, opage);
  252. unlock(&scr->devlock);
  253. }
  254. /*
  255. * Save the cursor hotpoint and enable the cursor.
  256. */
  257. scr->offset = curs->offset;
  258. s3vsyncactive();
  259. vgaxo(Crtx, 0x45, 0x01);
  260. }
  261. static int
  262. s3move(VGAscr* scr, Point p)
  263. {
  264. int x, xo, y, yo;
  265. /*
  266. * Mustn't position the cursor offscreen even partially,
  267. * or it disappears. Therefore, if x or y is -ve, adjust the
  268. * cursor offset instead.
  269. * There seems to be a bug in that if the offset is 1, the
  270. * cursor doesn't disappear off the left edge properly, so
  271. * round it up to be even.
  272. */
  273. if((x = p.x+scr->offset.x) < 0){
  274. xo = -x;
  275. xo = ((xo+1)/2)*2;
  276. x = 0;
  277. }
  278. else
  279. xo = 0;
  280. if((y = p.y+scr->offset.y) < 0){
  281. yo = -y;
  282. y = 0;
  283. }
  284. else
  285. yo = 0;
  286. vgaxo(Crtx, 0x46, (x>>8) & 0x07);
  287. vgaxo(Crtx, 0x47, x & 0xFF);
  288. vgaxo(Crtx, 0x49, y & 0xFF);
  289. vgaxo(Crtx, 0x4E, xo);
  290. vgaxo(Crtx, 0x4F, yo);
  291. vgaxo(Crtx, 0x48, (y>>8) & 0x07);
  292. s3vsyncactive();
  293. return 0;
  294. }
  295. static void
  296. s3enable(VGAscr* scr)
  297. {
  298. int i;
  299. ulong storage;
  300. s3disable(scr);
  301. /*
  302. * Cursor colours. Set both the CR0[EF] and the colour
  303. * stack in case we are using a 16-bit RAMDAC.
  304. */
  305. vgaxo(Crtx, 0x0E, Pwhite);
  306. vgaxo(Crtx, 0x0F, Pblack);
  307. vgaxi(Crtx, 0x45);
  308. for(i = 0; i < 3; i++)
  309. vgaxo(Crtx, 0x4A, Pblack);
  310. vgaxi(Crtx, 0x45);
  311. for(i = 0; i < 3; i++)
  312. vgaxo(Crtx, 0x4B, Pwhite);
  313. /*
  314. * Find a place for the cursor data in display memory.
  315. * Must be on a 1024-byte boundary.
  316. */
  317. storage = (scr->gscreen->width*BY2WD*scr->gscreen->r.max.y+1023)/1024;
  318. vgaxo(Crtx, 0x4C, storage>>8);
  319. vgaxo(Crtx, 0x4D, storage & 0xFF);
  320. storage *= 1024;
  321. scr->storage = storage;
  322. /*
  323. * Load, locate and enable the cursor
  324. * in Microsoft Windows format.
  325. */
  326. s3load(scr, &arrow);
  327. s3move(scr, ZP);
  328. vgaxo(Crtx, 0x55, vgaxi(Crtx, 0x55) & ~0x10);
  329. s3vsyncactive();
  330. vgaxo(Crtx, 0x45, 0x01);
  331. }
  332. /*
  333. * The manual gives byte offsets, but we want ulong offsets, hence /4.
  334. */
  335. enum {
  336. SrcBase = 0xA4D4/4,
  337. DstBase = 0xA4D8/4,
  338. Stride = 0xA4E4/4,
  339. FgrdData = 0xA4F4/4,
  340. WidthHeight = 0xA504/4,
  341. SrcXY = 0xA508/4,
  342. DestXY = 0xA50C/4,
  343. Command = 0xA500/4,
  344. SubStat = 0x8504/4,
  345. FifoStat = 0x850C/4,
  346. };
  347. /*
  348. * Wait for writes to VGA memory via linear aperture to flush.
  349. */
  350. enum {Maxloop = 1<<24};
  351. struct {
  352. ulong linear;
  353. ulong fifo;
  354. ulong idle;
  355. ulong lineartimeout;
  356. ulong fifotimeout;
  357. ulong idletimeout;
  358. } waitcount;
  359. static void
  360. waitforlinearfifo(VGAscr *scr)
  361. {
  362. ulong *mmio;
  363. long x;
  364. static ulong nwaitforlinearfifo;
  365. ulong mask, val;
  366. switch(scr->id){
  367. default:
  368. panic("unknown scr->id in s3 waitforlinearfifo");
  369. case 0x8A01: /* ViRGE/[DG]X. XFree86 says no waiting necessary */
  370. return;
  371. case 0x5631: /* ViRGE */
  372. case 0x883D: /* ViRGE/VX */
  373. mask = 0x0F<<6;
  374. val = 0x08<<6;
  375. break;
  376. case 0x8A10: /* ViRGE/GX2 */
  377. mask = 0x1F<<6;
  378. val = 0x10<<6;
  379. break;
  380. }
  381. mmio = scr->mmio;
  382. x = 0;
  383. while((mmio[FifoStat]&mask) != val && x++ < Maxloop)
  384. waitcount.linear++;
  385. if(x >= Maxloop)
  386. waitcount.lineartimeout++;
  387. }
  388. static void
  389. waitforfifo(VGAscr *scr, int entries)
  390. {
  391. ulong *mmio;
  392. long x;
  393. static ulong nwaitforfifo;
  394. mmio = scr->mmio;
  395. x = 0;
  396. while((mmio[SubStat]&0x1F00) < ((entries+2)<<8) && x++ < Maxloop)
  397. waitcount.fifo++;
  398. if(x >= Maxloop)
  399. waitcount.fifotimeout++;
  400. }
  401. static void
  402. waitforidle(VGAscr *scr)
  403. {
  404. ulong *mmio;
  405. long x;
  406. mmio = scr->mmio;
  407. x = 0;
  408. while((mmio[SubStat]&0x3F00) != 0x3000 && x++ < Maxloop)
  409. waitcount.idle++;
  410. if(x >= Maxloop)
  411. waitcount.idletimeout++;
  412. }
  413. static int
  414. hwscroll(VGAscr *scr, Rectangle r, Rectangle sr)
  415. {
  416. enum { Bitbltop = 0xCC }; /* copy source */
  417. ulong *mmio;
  418. ulong cmd, stride;
  419. Point dp, sp;
  420. int did, d;
  421. d = scr->gscreen->depth;
  422. did = (d-8)/8;
  423. cmd = 0x00000020|(Bitbltop<<17)|(did<<2);
  424. stride = Dx(scr->gscreen->r)*d/8;
  425. if(r.min.x <= sr.min.x){
  426. cmd |= 1<<25;
  427. dp.x = r.min.x;
  428. sp.x = sr.min.x;
  429. }else{
  430. dp.x = r.max.x-1;
  431. sp.x = sr.max.x-1;
  432. }
  433. if(r.min.y <= sr.min.y){
  434. cmd |= 1<<26;
  435. dp.y = r.min.y;
  436. sp.y = sr.min.y;
  437. }else{
  438. dp.y = r.max.y-1;
  439. sp.y = sr.max.y-1;
  440. }
  441. mmio = scr->mmio;
  442. waitforlinearfifo(scr);
  443. waitforfifo(scr, 7);
  444. mmio[SrcBase] = scr->aperture;
  445. mmio[DstBase] = scr->aperture;
  446. mmio[Stride] = (stride<<16)|stride;
  447. mmio[WidthHeight] = ((Dx(r)-1)<<16)|Dy(r);
  448. mmio[SrcXY] = (sp.x<<16)|sp.y;
  449. mmio[DestXY] = (dp.x<<16)|dp.y;
  450. mmio[Command] = cmd;
  451. waitforidle(scr);
  452. return 1;
  453. }
  454. static int
  455. hwfill(VGAscr *scr, Rectangle r, ulong sval)
  456. {
  457. enum { Bitbltop = 0xCC }; /* copy source */
  458. ulong *mmio;
  459. ulong cmd, stride;
  460. int did, d;
  461. d = scr->gscreen->depth;
  462. did = (d-8)/8;
  463. cmd = 0x16000120|(Bitbltop<<17)|(did<<2);
  464. stride = Dx(scr->gscreen->r)*d/8;
  465. mmio = scr->mmio;
  466. waitforlinearfifo(scr);
  467. waitforfifo(scr, 8);
  468. mmio[SrcBase] = scr->aperture;
  469. mmio[DstBase] = scr->aperture;
  470. mmio[DstBase] = scr->aperture;
  471. mmio[Stride] = (stride<<16)|stride;
  472. mmio[FgrdData] = sval;
  473. mmio[WidthHeight] = ((Dx(r)-1)<<16)|Dy(r);
  474. mmio[DestXY] = (r.min.x<<16)|r.min.y;
  475. mmio[Command] = cmd;
  476. waitforidle(scr);
  477. return 1;
  478. }
  479. enum {
  480. CursorSyncCtl = 0x0D, /* in Seqx */
  481. VsyncHi = 0x80,
  482. VsyncLo = 0x40,
  483. HsyncHi = 0x20,
  484. HsyncLo = 0x10,
  485. };
  486. static void
  487. s3blank(VGAscr*, int blank)
  488. {
  489. uchar x;
  490. x = vgaxi(Seqx, CursorSyncCtl);
  491. x &= ~0xF0;
  492. if(blank)
  493. x |= VsyncLo | HsyncLo;
  494. vgaxo(Seqx, CursorSyncCtl, x);
  495. }
  496. static void
  497. s3drawinit(VGAscr *scr)
  498. {
  499. extern void savageinit(VGAscr*); /* vgasavage.c */
  500. ulong id;
  501. id = (vgaxi(Crtx, 0x2D)<<8)|vgaxi(Crtx, 0x2E);
  502. scr->id = id;
  503. /*
  504. * It's highly likely that other ViRGEs will work without
  505. * change to the driver, with the exception of the size of
  506. * the linear aperture memory write FIFO. Since we don't
  507. * know that size, I'm not turning them on. See waitforlinearfifo
  508. * above.
  509. */
  510. scr->blank = s3blank;
  511. /* hwblank = 1; not known to work well */
  512. switch(id){
  513. case VIRGE:
  514. case VIRGEVX:
  515. case VIRGEGX2:
  516. scr->mmio = (ulong*)(scr->aperture+0x1000000);
  517. scr->fill = hwfill;
  518. scr->scroll = hwscroll;
  519. break;
  520. case SAVAGEMXMV:
  521. case SAVAGEIXMV:
  522. scr->mmio = (ulong*)(scr->aperture+0x1000000);
  523. savageinit(scr);
  524. break;
  525. case SUPERSAVAGEIXC16:
  526. case SAVAGE4:
  527. case PROSAVAGEP:
  528. case PROSAVAGE8:
  529. case PROSAVAGEK:
  530. /* scr->mmio is set by s3linear */
  531. savageinit(scr);
  532. break;
  533. }
  534. }
  535. VGAdev vgas3dev = {
  536. "s3",
  537. 0,
  538. 0,
  539. s3page,
  540. s3linear,
  541. s3drawinit,
  542. };
  543. VGAcur vgas3cur = {
  544. "s3hwgc",
  545. s3enable,
  546. s3disable,
  547. s3load,
  548. s3move,
  549. };