vgas3.c 11 KB

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