1
0

mach64.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <bio.h>
  4. #include "pci.h"
  5. #include "vga.h"
  6. /*
  7. * ATI Mach64. Some hope. Kind of like a Mach32.
  8. * No support for accelerator so can only do up to 1024x768.
  9. *
  10. * All ATI Extended Registers are addressed using the modified index
  11. * index = (0x02<<6)|(index & 0x3F);
  12. * so registers 0x00->0x3F map to 0x80->0xBF, but we will only ever
  13. * look at a few in the range 0xA0->0xBF. In this way we can stash
  14. * them in the vga->crt[] array.
  15. */
  16. enum {
  17. Configcntl = 0x6AEC, /* Configuration control */
  18. Configstat = 0x72EC, /* Configuration status */
  19. Memcntl = 0x52EC, /* Memory control */
  20. Scratch1 = 0x46EC, /* Scratch Register (BIOS info) */
  21. };
  22. typedef struct {
  23. ulong configcntl;
  24. ulong configstat;
  25. ulong memcntl;
  26. ulong scratch1;
  27. } Mach64;
  28. /*
  29. * There are a number of possible clock generator chips for these
  30. * boards. We can divide any frequency by 2 (bit<6> of b8).
  31. */
  32. typedef struct {
  33. ulong frequency;
  34. uchar be; /* <4> - bit<3> of frequency index */
  35. uchar b9; /* <1> - bit<2> of frequency index */
  36. uchar genmo; /* <3:2> - bits <1:0> of frequency index */
  37. } Pclk;
  38. enum {
  39. Npclkx = 16, /* number of clock entries per table */
  40. };
  41. /*
  42. * ATI18811-0
  43. */
  44. static Pclk ati188110[Npclkx] = {
  45. { 42950000, 0x00, 0x00, 0x00 },
  46. { 48770000, 0x00, 0x00, 0x04 },
  47. { 92400000, 0x00, 0x00, 0x08 },
  48. { 36000000, 0x00, 0x00, 0x0C },
  49. { 50350000, 0x00, 0x02, 0x00 },
  50. { 56640000, 0x00, 0x02, 0x04 },
  51. { 0, 0x00, 0x02, 0x08 },
  52. { 44900000, 0x00, 0x02, 0x0C },
  53. { 30240000, 0x10, 0x00, 0x00 },
  54. { 32000000, 0x10, 0x00, 0x04 },
  55. { 110000000, 0x10, 0x00, 0x08 },
  56. { 80000000, 0x10, 0x00, 0x0C },
  57. { 39910000, 0x10, 0x02, 0x00 },
  58. { 44900000, 0x10, 0x02, 0x04 },
  59. { 75000000, 0x10, 0x02, 0x08 },
  60. { 65000000, 0x10, 0x02, 0x0C },
  61. };
  62. /*
  63. * ATI18811-1, ATI18811-2
  64. * PCLK_TABLE = 0 in Mach64 speak.
  65. */
  66. static Pclk ati188111[Npclkx] = {
  67. { 100000000, 0x00, 0x00, 0x00 },
  68. { 126000000, 0x00, 0x00, 0x04 },
  69. { 92400000, 0x00, 0x00, 0x08 },
  70. { 36000000, 0x00, 0x00, 0x0C },
  71. { 50350000, 0x00, 0x02, 0x00 },
  72. { 56640000, 0x00, 0x02, 0x04 },
  73. { 0, 0x00, 0x02, 0x08 },
  74. { 44900000, 0x00, 0x02, 0x0C },
  75. { 135000000, 0x10, 0x00, 0x00 },
  76. { 32000000, 0x10, 0x00, 0x04 },
  77. { 110000000, 0x10, 0x00, 0x08 },
  78. { 80000000, 0x10, 0x00, 0x0C },
  79. { 39910000, 0x10, 0x02, 0x00 },
  80. { 44900000, 0x10, 0x02, 0x04 },
  81. { 75000000, 0x10, 0x02, 0x08 },
  82. { 65000000, 0x10, 0x02, 0x0C },
  83. };
  84. /*
  85. * ATI18818
  86. * The first four entries are programmable and the default
  87. * settings are either those below or those below divided by 2
  88. * (PCLK_TABLE = 1 and PCLK_TABLE = 2 respectively in Mach64
  89. * speak).
  90. */
  91. static Pclk ati18818[Npclkx] = {
  92. { 50350000, 0x00, 0x00, 0x00 },
  93. { 56640000, 0x00, 0x00, 0x04 },
  94. { 63000000, 0x00, 0x00, 0x08 },
  95. { 72000000, 0x00, 0x00, 0x0C },
  96. { 40000000, 0x00, 0x02, 0x00 },
  97. { 44900000, 0x00, 0x02, 0x04 },
  98. { 49500000, 0x00, 0x02, 0x08 },
  99. { 50000000, 0x00, 0x02, 0x0C },
  100. { 0, 0x10, 0x00, 0x00 },
  101. { 110000000, 0x10, 0x00, 0x04 },
  102. { 126000000, 0x10, 0x00, 0x08 },
  103. { 135000000, 0x10, 0x00, 0x0C },
  104. { 0, 0x10, 0x02, 0x00 },
  105. { 80000000, 0x10, 0x02, 0x04 },
  106. { 75000000, 0x10, 0x02, 0x08 },
  107. { 65000000, 0x10, 0x02, 0x0C },
  108. };
  109. static Pclk *pclkp; /* which clock chip we are using */
  110. static ulong atix; /* index to extended regsiters */
  111. static uchar
  112. atixi(uchar index)
  113. {
  114. outportb(atix, index);
  115. return inportb(atix+1);
  116. }
  117. static void
  118. atixo(uchar index, uchar data)
  119. {
  120. outportw(atix, (data<<8)|index);
  121. }
  122. static void
  123. atixinit(Vga* vga, Ctlr*)
  124. {
  125. uchar b;
  126. /*
  127. * Set the I/O address and offset for the ATI
  128. * extended registers to something we know about.
  129. */
  130. if(atix == 0){
  131. outportw(Grx, (0xCE<<8)|0x50);
  132. outportw(Grx, (0x81<<8)|0x51);
  133. atix = 0x1CE;
  134. }
  135. /*
  136. * Unlock the ATI Extended Registers.
  137. * We leave them unlocked from now on.
  138. * Why does this chip have so many
  139. * lock bits?
  140. */
  141. if((b = atixi(0xB8)) & 0x3F)
  142. atixo(0xB8, b & 0xC0);
  143. b = atixi(0xAB);
  144. atixo(0xAB, b & ~0x18);
  145. atixo(0xB4, 0x00);
  146. b = atixi(0xB9);
  147. atixo(0xB9, b & ~0x80);
  148. b = atixi(0xBE);
  149. atixo(0xBE, b|0x09);
  150. if(vga->private == 0)
  151. vga->private = alloc(sizeof(Mach64));
  152. }
  153. static void
  154. snarf(Vga* vga, Ctlr* ctlr)
  155. {
  156. int i;
  157. Mach64 *mach64;
  158. atixinit(vga, ctlr);
  159. for(i = 0xA0; i < 0xC0; i++)
  160. vga->crt[i] = atixi(i);
  161. mach64 = vga->private;
  162. mach64->configcntl = inportl(Configcntl);
  163. mach64->configstat = inportl(Configstat);
  164. mach64->memcntl = inportl(Memcntl);
  165. mach64->scratch1 = inportl(Scratch1);
  166. /*
  167. * Memory size.
  168. */
  169. switch(mach64->memcntl & 0x07){
  170. case 0:
  171. vga->vmz = 512*1024;
  172. break;
  173. case 1:
  174. vga->vmz = 1024*1024;
  175. break;
  176. case 2:
  177. vga->vmz = 2*1024*1024;
  178. break;
  179. case 3:
  180. vga->vmz = 4*1024*1024;
  181. break;
  182. case 4:
  183. vga->vmz = 6*1024*1024;
  184. break;
  185. case 5:
  186. vga->vmz = 8*1024*1024;
  187. break;
  188. }
  189. ctlr->flag |= Fsnarf;
  190. }
  191. static void
  192. init(Vga* vga, Ctlr* ctlr)
  193. {
  194. Mode *mode;
  195. int f, divisor, index;
  196. mode = vga->mode;
  197. /*
  198. * Must somehow determine which clock chip to use here.
  199. * For now, punt and assume ATI18818.
  200. */
  201. pclkp = ati18818;
  202. if(pclkp == 0)
  203. error("%s: can't determine clock chip\n", ctlr->name);
  204. if(vga->f[0] == 0)
  205. vga->f[0] = vga->mode->frequency;
  206. /*
  207. * Find a clock frequency close to what we want.
  208. * 'Close' is within 1MHz.
  209. */
  210. for(divisor = 0, index = 0; index < Npclkx; index++, divisor = 0){
  211. divisor = 1;
  212. f = pclkp[index].frequency/divisor;
  213. if(f < vga->f[0]+1000000 && f >= vga->f[0]-1000000)
  214. break;
  215. divisor = 2;
  216. f /= divisor;
  217. if(f < vga->f[0]+1000000 && f >= vga->f[0]-1000000)
  218. break;
  219. }
  220. if(divisor == 0)
  221. error("%s: no suitable clock for %lud\n",
  222. ctlr->name, vga->f[0]);
  223. vga->d[0] = divisor;
  224. vga->i[0] = index;
  225. vga->crt[0xB0] &= 0xDA;
  226. vga->crt[0xB1] &= 0x87;
  227. vga->crt[0xB5] &= 0x7E;
  228. vga->crt[0xB6] &= 0xE2;
  229. vga->crt[0xB3] &= 0xAF;
  230. vga->crt[0xA6] &= 0xFE;
  231. vga->crt[0xA7] &= 0xF4;
  232. /*
  233. * 256-colour linear addressing.
  234. */
  235. if(mode->z == 8){
  236. vga->graphics[0x05] = 0x00;
  237. vga->attribute[0x10] &= ~0x40;
  238. vga->crt[0x13] = (mode->x/8)/2;
  239. vga->crt[0x14] = 0x00;
  240. vga->crt[0x17] = 0xE3;
  241. vga->crt[0xB0] |= 0x20;
  242. vga->crt[0xB6] |= 0x04;
  243. }
  244. vga->attribute[0x11] = 0x00;
  245. vga->crt[0xB6] |= 0x01;
  246. vga->crt[0xBE] &= ~0x04;
  247. /*
  248. * Do the clock index bits.
  249. */
  250. vga->crt[0xB8] &= 0x3F;
  251. vga->crt[0xB9] &= 0xFD;
  252. vga->crt[0xBE] &= 0xE5;
  253. if(vga->d[0] == 2)
  254. vga->crt[0xB8] |= 0x40;
  255. vga->crt[0xB9] |= pclkp[vga->i[0]].b9;
  256. vga->crt[0xBE] |= pclkp[vga->i[0]].be;
  257. vga->misc |= pclkp[vga->i[0]].genmo;
  258. if(vga->mode->interlace == 'v')
  259. vga->crt[0xBE] |= 0x02;
  260. /*
  261. * Turn off 128Kb CPU address bit so
  262. * we only have a 64Kb aperture at 0xA0000.
  263. */
  264. vga->crt[0xBD] &= ~0x04;
  265. ctlr->type = mach32.name;
  266. /*
  267. * The Mach64 can only address 1Mb in VGA mode
  268. */
  269. vga->vmz = 1*1024*1024;
  270. ctlr->flag |= Finit;
  271. }
  272. static void
  273. load(Vga* vga, Ctlr* ctlr)
  274. {
  275. /*
  276. * We should probably do something here to make sure we that we
  277. * have access to all the video memory through the 64Kb VGA aperture
  278. * by disabling and linear aperture and memory boundary and then
  279. * enabling the VGA controller.
  280. * But for now, let's just assume it's ok, the Mach64 documentation
  281. * is just as clear as the Mach32 documentation.
  282. */
  283. atixo(0xB0, vga->crt[0xB0]);
  284. atixo(0xB1, vga->crt[0xB1]);
  285. atixo(0xB5, vga->crt[0xB5]);
  286. atixo(0xB6, vga->crt[0xB6]);
  287. atixo(0xB3, vga->crt[0xB3]);
  288. atixo(0xA6, vga->crt[0xA6]);
  289. atixo(0xA7, vga->crt[0xA7]);
  290. atixo(0xB8, vga->crt[0xB8]);
  291. atixo(0xB9, vga->crt[0xB9]);
  292. atixo(0xBE, vga->crt[0xBE]);
  293. vgao(MiscW, vga->misc);
  294. ctlr->flag |= Fload;
  295. }
  296. static void
  297. dump(Vga* vga, Ctlr* ctlr)
  298. {
  299. int i;
  300. Mach64 *mach64;
  301. printitem(ctlr->name, "ATIX");
  302. for(i = 0xA0; i < 0xC0; i++)
  303. printreg(vga->crt[i]);
  304. if((mach64 = vga->private) == 0)
  305. return;
  306. printitem(ctlr->name, "CONFIGCNTL");
  307. Bprint(&stdout, "%.8lux\n", mach64->configcntl);
  308. printitem(ctlr->name, "CONFIGSTAT");
  309. Bprint(&stdout, "%.8lux\n", mach64->configstat);
  310. printitem(ctlr->name, "MEMCNTL");
  311. Bprint(&stdout, "%.8lux\n", mach64->memcntl);
  312. printitem(ctlr->name, "SCRATCH1");
  313. Bprint(&stdout, "%.8lux\n", mach64->scratch1);
  314. }
  315. Ctlr mach64 = {
  316. "mach64", /* name */
  317. snarf, /* snarf */
  318. 0, /* options */
  319. init, /* init */
  320. load, /* load */
  321. dump, /* dump */
  322. };