vgamach64xx.c 28 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250
  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. char Eunsupportedformat[] = "unsupported video format";
  14. char Enotconfigured[] = "device not configured";
  15. #define SCALE_ZERO_EXTEND 0x0
  16. #define SCALE_DYNAMIC 0x1
  17. #define SCALE_RED_TEMP_6500K 0x0
  18. #define SCALE_RED_TEMP_9800K 0x2
  19. #define SCALE_HORZ_BLEND 0x0
  20. #define SCALE_HORZ_REP 0x4
  21. #define SCALE_VERT_BLEND 0x0
  22. #define SCALE_VERT_REP 0x8
  23. #define SCALE_BANDWIDTH_NORMAL 0x0
  24. #define SCALE_BANDWIDTH_EXCEEDED 0x4000000
  25. #define SCALE_BANDWIDTH_RESET 0x4000000
  26. #define SCALE_CLK_ACTIVITY 0x0
  27. #define SCALE_CLK_CONTINUOUS 0x20000000
  28. #define OVERLAY_DISABLE 0x0
  29. #define OVERLAY_ENABLE 0x40000000
  30. #define SCALE_DISABLE 0x0
  31. #define SCALE_ENABLE 0x80000000
  32. #define SCALER_FRAME_READ_MODE_FULL 0x0
  33. #define SCALER_BUF_MODE_SINGLE 0x0
  34. #define SCALER_BUF_MODE_DOUBLE 0x40000
  35. #define SCALER_BUF_NEXT_0 0x0
  36. #define SCALER_BUF_NEXT_1 0x80000
  37. #define SCALER_BUF_STATUS_0 0x0
  38. #define SCALER_BUF_STATUS_1 0x100000
  39. #define OVERLAY_MIX_G_CMP 0x0
  40. #define OVERLAY_MIX_ALWAYS_G 0x100
  41. #define OVERLAY_MIX_ALWAYS_V 0x200
  42. #define OVERLAY_MIX_NOT_G 0x300
  43. #define OVERLAY_MIX_NOT_V 0x400
  44. #define OVERLAY_MIX_G_XOR_V 0x500
  45. #define OVERLAY_MIX_NOT_G_XOR_V 0x600
  46. #define OVERLAY_MIX_V_CMP 0x700
  47. #define OVERLAY_MIX_NOT_G_OR_NOT_V 0x800
  48. #define OVERLAY_MIX_G_OR_NOT_V 0x900
  49. #define OVERLAY_MIX_NOT_G_OR_V 0xA00
  50. #define OVERLAY_MIX_G_OR_V 0xB00
  51. #define OVERLAY_MIX_G_AND_V 0xC00
  52. #define OVERLAY_MIX_NOT_G_AND_V 0xD00
  53. #define OVERLAY_MIX_G_AND_NOT_V 0xE00
  54. #define OVERLAY_MIX_NOT_G_AND_NOT_V 0xF00
  55. #define OVERLAY_EXCLUSIVE_NORMAL 0x0
  56. #define OVERLAY_EXCLUSIVE_V_ONLY 0x80000000
  57. #define VIDEO_IN_8BPP 0x2
  58. #define VIDEO_IN_16BPP 0x4
  59. #define VIDEO_IN_32BPP 0x6
  60. #define VIDEO_IN_VYUY422 0xB /*16 bpp */
  61. #define VIDEO_IN_YVYU422 0xC /* 16 bpp */
  62. #define SCALE_IN_15BPP 0x30000 /* aRGB 1555 */
  63. #define SCALE_IN_16BPP 0x40000 /* RGB 565 */
  64. #define SCALE_IN_32BPP 0x60000 /* aRGB 8888 */
  65. #define SCALE_IN_YUV9 0x90000 /* planar */
  66. #define SCALE_IN_YUV12 0xA0000 /* planar */
  67. #define SCALE_IN_VYUY422 0xB0000 /* 16 bpp */
  68. #define SCALE_IN_YVYU422 0xC0000 /* 16 bpp */
  69. #define HOST_YUV_APERTURE_UPPER 0x0
  70. #define HOST_YUV_APERTURE_LOWER 0x20000000
  71. #define HOST_MEM_MODE_Y 0x40000000
  72. #define HOST_MEM_MODE_U 0x80000000
  73. #define HOST_MEM_MODE_V 0xC0000000
  74. #define HOST_MEM_MODE_NORMAL HOST_YUV_APERTURE_UPPER
  75. static Chan *ovl_chan; /* Channel of controlling process */
  76. static int ovl_width; /* Width of input overlay buffer */
  77. static int ovl_height; /* Height of input overlay buffer */
  78. static int ovl_format; /* Overlay format */
  79. static ulong ovl_fib; /* Frame in bytes */
  80. enum {
  81. VTGTB1S1 = 0x01, // Asic description for VTB1S1 and GTB1S1.
  82. VT4GTIIC = 0x3A, // asic descr for VT4 and RAGE IIC
  83. GTB1U1 = 0x19, // Asic description for GTB1U1.
  84. GTB1S2 = 0x41, // Asic description for GTB1S2.
  85. GTB2U1 = 0x1A,
  86. GTB2U2 = 0x5A,
  87. GTB2U3 = 0x9A,
  88. GTIIIC1U1 = 0x1B, // 3D RAGE PRO asic descrp.
  89. GTIIIC1U2 = 0x5B, // 3D RAGE PRO asic descrp.
  90. GTIIIC2U1 = 0x1C, // 3D RAGE PRO asic descrp.
  91. GTIIIC2U2 = 0x5C, // 3D RAGE PRO asic descrp.
  92. GTIIIC2U3 = 0x7C, // 3D RAGE PRO asic descrp.
  93. GTBC = 0x3A, // 3D RAGE IIC asic descrp.
  94. LTPRO = 0x9C, // 3D RAGE LT PRO
  95. };
  96. /*
  97. * ATI Mach64(CT|ET|G*|V*|L*).
  98. */
  99. typedef struct Mach64types Mach64types;
  100. struct Mach64types {
  101. ushort m64_id; /* Chip ID */
  102. int m64_vtgt; /* Is this a VT or GT chipset? */
  103. ulong m64_ovlclock; /* Max. overlay clock frequency */
  104. int m64_pro; /* Is this a PRO? */
  105. };
  106. static ulong mach64refclock;
  107. static Mach64types *mach64type;
  108. static int mach64revb; /* Revision B or greater? */
  109. static ulong mach64overlay; /* Overlay buffer */
  110. static Mach64types mach64s[] = {
  111. ('C'<<8)|'T', 0, 1350000, /*?*/ 0, /* 4354: CT */
  112. ('E'<<8)|'T', 0, 1350000, /*?*/ 0, /* 4554: ET */
  113. ('G'<<8)|'B', 1, 1250000, 1, /* 4742: 264GT PRO */
  114. ('G'<<8)|'D', 1, 1250000, 1, /* 4744: 264GT PRO */
  115. ('G'<<8)|'I', 1, 1250000, 1, /* 4749: 264GT PRO */
  116. ('G'<<8)|'M', 0, 1350000, 0, /* 474D: Rage XL */
  117. ('G'<<8)|'P', 1, 1250000, 1, /* 4750: 264GT PRO */
  118. ('G'<<8)|'Q', 1, 1250000, 1, /* 4751: 264GT PRO */
  119. ('G'<<8)|'R', 1, 1250000, 1, /* 4752: */
  120. ('G'<<8)|'T', 1, 800000, 0, /* 4754: 264GT[B] */
  121. ('G'<<8)|'U', 1, 1000000, 0, /* 4755: 264GT DVD */
  122. ('G'<<8)|'V', 1, 1000000, 0, /* 4756: Rage2C */
  123. ('G'<<8)|'Z', 1, 1000000, 0, /* 475A: Rage2C */
  124. ('V'<<8)|'T', 1, 800000, 0, /* 5654: 264VT/GT/VTB */
  125. ('V'<<8)|'U', 1, 800000, 0, /* 5655: 264VT3 */
  126. ('V'<<8)|'V', 1, 1000000, 0, /* 5656: 264VT4 */
  127. ('L'<<8)|'B', 0, 1350000, 1, /* 4C42: Rage LTPro AGP */
  128. ('L'<<8)|'I', 0, 1350000, 0, /* 4C49: Rage LTPro AGP */
  129. ('L'<<8)|'M', 0, 1350000, 0, /* 4C4D: Rage Mobility */
  130. ('L'<<8)|'P', 0, 1350000, 1, /* 4C50: 264LT PRO */
  131. };
  132. static int hwfill(VGAscr*, Rectangle, ulong);
  133. static int hwscroll(VGAscr*, Rectangle, Rectangle);
  134. static void initengine(VGAscr*);
  135. static Pcidev*
  136. mach64xxpci(void)
  137. {
  138. Pcidev *p;
  139. int i;
  140. if((p = pcimatch(nil, 0x1002, 0)) == nil)
  141. return nil;
  142. for (i = 0; i != nelem(mach64s); i++)
  143. if (mach64s[i].m64_id == p->did) {
  144. mach64type = &mach64s[i];
  145. return p;
  146. }
  147. return nil;
  148. }
  149. static void
  150. mach64xxenable(VGAscr* scr)
  151. {
  152. Pcidev *p;
  153. /*
  154. * Only once, can't be disabled for now.
  155. */
  156. if(scr->io)
  157. return;
  158. if(p = mach64xxpci()){
  159. scr->id = p->did;
  160. /*
  161. * The CT doesn't always have the I/O base address
  162. * in the PCI base registers. There is a way to find
  163. * it via the vendor-specific PCI config space but
  164. * this will do for now.
  165. */
  166. scr->io = p->mem[1].bar & ~0x03;
  167. if(scr->io == 0)
  168. scr->io = 0x2EC;
  169. }
  170. }
  171. static ulong
  172. mach64xxlinear(VGAscr* scr, int* size, int* align)
  173. {
  174. ulong aperture, osize, oaperture;
  175. int i, oapsize, wasupamem;
  176. Pcidev *p;
  177. osize = *size;
  178. oaperture = scr->aperture;
  179. oapsize = scr->apsize;
  180. wasupamem = scr->isupamem;
  181. if(p = mach64xxpci()){
  182. for(i=0; i<nelem(p->mem); i++){
  183. if(p->mem[i].size >= *size
  184. && ((p->mem[i].bar & ~0x0F) & (*align-1)) == 0)
  185. break;
  186. }
  187. if(i >= nelem(p->mem)){
  188. print("vgamach64xx: aperture not found\n");
  189. return 0;
  190. }
  191. aperture = p->mem[i].bar & ~0x0F;
  192. *size = p->mem[i].size;
  193. }
  194. else
  195. aperture = 0;
  196. if(wasupamem)
  197. upafree(oaperture, oapsize);
  198. scr->isupamem = 0;
  199. aperture = upamalloc(aperture, *size, *align);
  200. if(aperture == 0){
  201. if(wasupamem && upamalloc(oaperture, oapsize, 0))
  202. scr->isupamem = 1;
  203. }
  204. else
  205. scr->isupamem = 1;
  206. scr->mmio = KADDR(aperture+osize-0x400);
  207. if(oaperture && oaperture != aperture)
  208. print("warning (BUG): redefinition of aperture does not change mach64mmio segment\n");
  209. addvgaseg("mach64mmio", aperture+osize-BY2PG, BY2PG);
  210. addvgaseg("mach64screen", aperture, osize);
  211. return aperture;
  212. }
  213. enum {
  214. CrtcOffPitch = 0x05,
  215. CrtcGenCtl = 0x07,
  216. CurClr0 = 0x0B, /* I/O Select */
  217. CurClr1 = 0x0C,
  218. CurOffset = 0x0D,
  219. CurHVposn = 0x0E,
  220. CurHVoff = 0x0F,
  221. BusCntl = 0x13,
  222. GenTestCntl = 0x19,
  223. CrtcHsyncDis = 0x04,
  224. CrtcVsyncDis = 0x08,
  225. ContextMask = 0x100, /* not accessible via I/O */
  226. FifoStat,
  227. GuiStat,
  228. DpFrgdClr,
  229. DpBkgdClr,
  230. DpWriteMask,
  231. DpMix,
  232. DpPixWidth,
  233. DpSrc,
  234. ClrCmpCntl,
  235. GuiTrajCntl,
  236. ScLeftRight,
  237. ScTopBottom,
  238. DstOffPitch,
  239. DstYX,
  240. DstHeightWidth,
  241. DstCntl,
  242. DstHeight,
  243. DstBresErr,
  244. DstBresInc,
  245. DstBresDec,
  246. SrcCntl,
  247. SrcHeight1Width1,
  248. SrcHeight2Width2,
  249. SrcYX,
  250. SrcWidth1,
  251. SrcYXstart,
  252. HostCntl,
  253. PatReg0,
  254. PatReg1,
  255. PatCntl,
  256. ScBottom,
  257. ScLeft,
  258. ScRight,
  259. ScTop,
  260. ClrCmpClr,
  261. ClrCmpMask,
  262. DpChainMask,
  263. SrcOffPitch,
  264. LcdIndex,
  265. LcdData,
  266. ClockCntl,
  267. OverlayScaleCntl,
  268. ConfigChipId,
  269. Buf0Pitch,
  270. ScalerBuf0Pitch,
  271. CaptureConfig,
  272. OverlayKeyCntl,
  273. ScalerColourCntl,
  274. ScalerHCoef0,
  275. ScalerHCoef1,
  276. ScalerHCoef2,
  277. ScalerHCoef3,
  278. ScalerHCoef4,
  279. VideoFormat,
  280. Buf0Offset,
  281. ScalerBuf0Offset,
  282. CrtcGenCntl,
  283. OverlayScaleInc,
  284. OverlayYX,
  285. OverlayYXEnd,
  286. ScalerHeightWidth,
  287. HTotalDisp,
  288. VTotalDisp,
  289. };
  290. enum {
  291. LCD_ConfigPanel = 0,
  292. LCD_GenCtrl,
  293. LCD_DstnCntl,
  294. LCD_HfbPitchAddr,
  295. LCD_HorzStretch,
  296. LCD_VertStretch,
  297. LCD_ExtVertStretch,
  298. LCD_LtGio,
  299. LCD_PowerMngmnt,
  300. LCD_ZvgPio,
  301. Nlcd,
  302. };
  303. #define Bank1 (-0x100) /* 1KB */
  304. static int mmoffset[] = {
  305. [HTotalDisp] 0x00,
  306. [VTotalDisp] 0x02,
  307. [CrtcOffPitch] 0x05,
  308. [CrtcGenCntl] 0x07,
  309. [CurClr0] 0x18,
  310. [CurClr1] 0x19,
  311. [CurOffset] 0x1A,
  312. [CurHVposn] 0x1B,
  313. [CurHVoff] 0x1C,
  314. [ClockCntl] 0x24,
  315. [BusCntl] 0x28,
  316. [LcdIndex] 0x29,
  317. [LcdData] 0x2A,
  318. [GenTestCntl] 0x34,
  319. [ConfigChipId] 0x38,
  320. [DstOffPitch] 0x40,
  321. [DstYX] 0x43,
  322. [DstHeight] 0x45,
  323. [DstHeightWidth] 0x46,
  324. [DstBresErr] 0x49,
  325. [DstBresInc] 0x4A,
  326. [DstBresDec] 0x4B,
  327. [DstCntl] 0x4C,
  328. [SrcOffPitch] 0x60,
  329. [SrcYX] 0x63,
  330. [SrcWidth1] 0x64,
  331. [SrcYXstart] 0x69,
  332. [SrcHeight1Width1] 0x66,
  333. [SrcHeight2Width2] 0x6C,
  334. [SrcCntl] 0x6D,
  335. [HostCntl] 0x90,
  336. [PatReg0] 0xA0,
  337. [PatReg1] 0xA1,
  338. [PatCntl] 0xA2,
  339. [ScLeft] 0xA8,
  340. [ScRight] 0xA9,
  341. [ScLeftRight] 0xAA,
  342. [ScTop] 0xAB,
  343. [ScBottom] 0xAC,
  344. [ScTopBottom] 0xAD,
  345. [DpBkgdClr] 0xB0,
  346. [DpFrgdClr] 0xB1,
  347. [DpWriteMask] 0xB2,
  348. [DpChainMask] 0xB3,
  349. [DpPixWidth] 0xB4,
  350. [DpMix] 0xB5,
  351. [DpSrc] 0xB6,
  352. [ClrCmpClr] 0xC0,
  353. [ClrCmpMask] 0xC1,
  354. [ClrCmpCntl] 0xC2,
  355. [FifoStat] 0xC4,
  356. [ContextMask] 0xC8,
  357. [GuiTrajCntl] 0xCC,
  358. [GuiStat] 0xCE,
  359. /* Bank1 */
  360. [OverlayYX] Bank1 + 0x00,
  361. [OverlayYXEnd] Bank1 + 0x01,
  362. [OverlayKeyCntl] Bank1 + 0x06,
  363. [OverlayScaleInc] Bank1 + 0x08,
  364. [OverlayScaleCntl] Bank1 + 0x09,
  365. [ScalerHeightWidth] Bank1 + 0x0A,
  366. [ScalerBuf0Offset] Bank1 + 0x0D,
  367. [ScalerBuf0Pitch] Bank1 + 0x0F,
  368. [VideoFormat] Bank1 + 0x12,
  369. [CaptureConfig] Bank1 + 0x14,
  370. [Buf0Offset] Bank1 + 0x20,
  371. [Buf0Pitch] Bank1 + 0x23,
  372. [ScalerColourCntl] Bank1 + 0x54,
  373. [ScalerHCoef0] Bank1 + 0x55,
  374. [ScalerHCoef1] Bank1 + 0x56,
  375. [ScalerHCoef2] Bank1 + 0x57,
  376. [ScalerHCoef3] Bank1 + 0x58,
  377. [ScalerHCoef4] Bank1 + 0x59,
  378. };
  379. static ulong
  380. ior32(VGAscr* scr, int r)
  381. {
  382. if(scr->io == 0x2EC || scr->io == 0x1C8)
  383. return inl((r<<10)+scr->io);
  384. if(r >= 0x100 && scr->mmio != nil)
  385. return scr->mmio[mmoffset[r]];
  386. return inl((mmoffset[r]<<2)+scr->io);
  387. }
  388. static void
  389. iow32(VGAscr* scr, int r, ulong l)
  390. {
  391. if(scr->io == 0x2EC || scr->io == 0x1C8)
  392. outl(((r)<<10)+scr->io, l);
  393. else if(r >= 0x100 && scr->mmio != nil)
  394. scr->mmio[mmoffset[r]] = l;
  395. else
  396. outl((mmoffset[r]<<2)+scr->io, l);
  397. }
  398. static ulong
  399. lcdr32(VGAscr *scr, ulong r)
  400. {
  401. ulong or;
  402. or = ior32(scr, LcdIndex);
  403. iow32(scr, LcdIndex, (or&~0x0F) | (r&0x0F));
  404. return ior32(scr, LcdData);
  405. }
  406. static void
  407. lcdw32(VGAscr *scr, ulong r, ulong v)
  408. {
  409. ulong or;
  410. or = ior32(scr, LcdIndex);
  411. iow32(scr, LcdIndex, (or&~0x0F) | (r&0x0F));
  412. iow32(scr, LcdData, v);
  413. }
  414. static void
  415. mach64xxcurdisable(VGAscr* scr)
  416. {
  417. ulong r;
  418. r = ior32(scr, GenTestCntl);
  419. iow32(scr, GenTestCntl, r & ~0x80);
  420. }
  421. static void
  422. mach64xxcurload(VGAscr* scr, Cursor* curs)
  423. {
  424. uchar *p;
  425. int i, y;
  426. ulong c, s, m, r;
  427. /*
  428. * Disable the cursor.
  429. */
  430. r = ior32(scr, GenTestCntl);
  431. iow32(scr, GenTestCntl, r & ~0x80);
  432. p = KADDR(scr->aperture);
  433. p += scr->storage;
  434. /*
  435. * Initialise the 64x64 cursor RAM array.
  436. * The cursor mode gives the following truth table:
  437. * p1 p0 colour
  438. * 0 0 Cursor Colour 0
  439. * 0 1 Cursor Colour 1
  440. * 1 0 Transparent
  441. * 1 1 Complement
  442. * Put the cursor into the top-right of the 64x64 array.
  443. */
  444. for(y = 0; y < 16; y++){
  445. for(i = 0; i < (64-16)/8; i++){
  446. *p++ = 0xAA;
  447. *p++ = 0xAA;
  448. }
  449. c = (curs->clr[2*y]<<8)|curs->clr[y*2 + 1];
  450. s = (curs->set[2*y]<<8)|curs->set[y*2 + 1];
  451. m = 0x00000000;
  452. for(i = 0; i < 16; i++){
  453. if(s & (1<<(15-i)))
  454. m |= 0x01<<(2*i);
  455. else if(c & (1<<(15-i))){
  456. /* nothing to do */
  457. }
  458. else
  459. m |= 0x02<<(2*i);
  460. }
  461. *p++ = m;
  462. *p++ = m>>8;
  463. *p++ = m>>16;
  464. *p++ = m>>24;
  465. }
  466. memset(p, 0xAA, (64-16)*16);
  467. /*
  468. * Set the cursor hotpoint and enable the cursor.
  469. */
  470. scr->offset = curs->offset;
  471. iow32(scr, GenTestCntl, 0x80|r);
  472. }
  473. static int
  474. ptalmostinrect(Point p, Rectangle r)
  475. {
  476. return p.x>=r.min.x && p.x<=r.max.x &&
  477. p.y>=r.min.y && p.y<=r.max.y;
  478. }
  479. /*
  480. * If necessary, translate the rectangle physr
  481. * some multiple of [dx dy] so that it includes p.
  482. * Return 1 if the rectangle changed.
  483. */
  484. static int
  485. screenpan(Point p, Rectangle *physr, int dx, int dy)
  486. {
  487. int d;
  488. if(ptalmostinrect(p, *physr))
  489. return 0;
  490. if(p.y < physr->min.y){
  491. d = physr->min.y - (p.y&~(dy-1));
  492. physr->min.y -= d;
  493. physr->max.y -= d;
  494. }
  495. if(p.y > physr->max.y){
  496. d = ((p.y+dy-1)&~(dy-1)) - physr->max.y;
  497. physr->min.y += d;
  498. physr->max.y += d;
  499. }
  500. if(p.x < physr->min.x){
  501. d = physr->min.x - (p.x&~(dx-1));
  502. physr->min.x -= d;
  503. physr->max.x -= d;
  504. }
  505. if(p.x > physr->max.x){
  506. d = ((p.x+dx-1)&~(dx-1)) - physr->max.x;
  507. physr->min.x += d;
  508. physr->max.x += d;
  509. }
  510. return 1;
  511. }
  512. static int
  513. mach64xxcurmove(VGAscr* scr, Point p)
  514. {
  515. int x, xo, y, yo;
  516. int dx;
  517. ulong off, pitch;
  518. /*
  519. * If the point we want to display is outside the current
  520. * screen rectangle, pan the screen to display it.
  521. *
  522. * We have to move in 64-bit chunks.
  523. */
  524. if(scr->gscreen->depth == 24)
  525. dx = (64*3)/24;
  526. else
  527. dx = 64 / scr->gscreen->depth;
  528. if(panning && screenpan(p, &physgscreenr, dx, 1)){
  529. off = (physgscreenr.min.y*Dx(scr->gscreen->r)+physgscreenr.min.x)/dx;
  530. pitch = Dx(scr->gscreen->r)/8;
  531. iow32(scr, CrtcOffPitch, (pitch<<22)|off);
  532. }
  533. p.x -= physgscreenr.min.x;
  534. p.y -= physgscreenr.min.y;
  535. /*
  536. * Mustn't position the cursor offscreen even partially,
  537. * or it disappears. Therefore, if x or y is -ve, adjust the
  538. * cursor presets instead. If y is negative also have to
  539. * adjust the starting offset.
  540. */
  541. if((x = p.x+scr->offset.x) < 0){
  542. xo = x;
  543. x = 0;
  544. }
  545. else
  546. xo = 0;
  547. if((y = p.y+scr->offset.y) < 0){
  548. yo = y;
  549. y = 0;
  550. }
  551. else
  552. yo = 0;
  553. iow32(scr, CurHVoff, ((64-16-yo)<<16)|(64-16-xo));
  554. iow32(scr, CurOffset, scr->storage/8 + (-yo*2));
  555. iow32(scr, CurHVposn, (y<<16)|x);
  556. return 0;
  557. }
  558. static void
  559. mach64xxcurenable(VGAscr* scr)
  560. {
  561. ulong r, storage;
  562. mach64xxenable(scr);
  563. if(scr->io == 0)
  564. return;
  565. r = ior32(scr, GenTestCntl);
  566. iow32(scr, GenTestCntl, r & ~0x80);
  567. iow32(scr, CurClr0, (Pwhite<<24)|(Pwhite<<16)|(Pwhite<<8)|Pwhite);
  568. iow32(scr, CurClr1, (Pblack<<24)|(Pblack<<16)|(Pblack<<8)|Pblack);
  569. /*
  570. * Find a place for the cursor data in display memory.
  571. * Must be 64-bit aligned.
  572. */
  573. storage = (scr->gscreen->width*BY2WD*scr->gscreen->r.max.y+7)/8;
  574. iow32(scr, CurOffset, storage);
  575. scr->storage = storage*8;
  576. /*
  577. * Cursor goes in the top right corner of the 64x64 array
  578. * so the horizontal and vertical presets are 64-16.
  579. */
  580. iow32(scr, CurHVposn, (0<<16)|0);
  581. iow32(scr, CurHVoff, ((64-16)<<16)|(64-16));
  582. /*
  583. * Load, locate and enable the 64x64 cursor.
  584. */
  585. mach64xxcurload(scr, &arrow);
  586. mach64xxcurmove(scr, ZP);
  587. iow32(scr, GenTestCntl, 0x80|r);
  588. }
  589. static void
  590. waitforfifo(VGAscr *scr, int entries)
  591. {
  592. int x;
  593. x = 0;
  594. while((ior32(scr, FifoStat)&0xFF) > (0x8000>>entries) && x++ < 1000000)
  595. ;
  596. if(x >= 1000000)
  597. iprint("fifo %d stat %.8lux %.8lux scrio %.8lux mmio %p scr %p pc %luX\n", entries, ior32(scr, FifoStat), scr->mmio[mmoffset[FifoStat]], scr->io, scr->mmio, scr, getcallerpc(&scr));
  598. }
  599. static void
  600. waitforidle(VGAscr *scr)
  601. {
  602. int x;
  603. waitforfifo(scr, 16);
  604. x = 0;
  605. while((ior32(scr, GuiStat)&1) && x++ < 1000000)
  606. ;
  607. if(x >= 1000000)
  608. iprint("idle stat %.8lux %.8lux scrio %.8lux mmio %p scr %p pc %luX\n", ior32(scr, GuiStat), scr->mmio[mmoffset[GuiStat]], scr->io, scr->mmio, scr, getcallerpc(&scr));
  609. }
  610. static void
  611. resetengine(VGAscr *scr)
  612. {
  613. ulong x;
  614. x = ior32(scr, GenTestCntl);
  615. iow32(scr, GenTestCntl, x&~0x100);
  616. iow32(scr, GenTestCntl, x|0x100);
  617. iow32(scr, BusCntl, ior32(scr, BusCntl)|0x00A00000);
  618. }
  619. static void
  620. init_overlayclock(VGAscr *scr)
  621. {
  622. uchar *cc, save, pll_ref_div, pll_vclk_cntl, vclk_post_div,
  623. vclk_fb_div, ecp_div;
  624. int i;
  625. ulong dotclock;
  626. /* Taken from GLX */
  627. /* Get monitor dotclock, check for Overlay Scaler clock limit */
  628. cc = (uchar *)&scr->mmio[mmoffset[ClockCntl]];
  629. save = cc[1]; i = cc[0] & 3;
  630. cc[1] = 2<<2; pll_ref_div = cc[2];
  631. cc[1] = 5<<2; pll_vclk_cntl = cc[2];
  632. cc[1] = 6<<2; vclk_post_div = (cc[2]>>(i+i)) & 3;
  633. cc[1] = (7+i)<<2; vclk_fb_div = cc[2];
  634. dotclock = 2 * mach64refclock * vclk_fb_div /
  635. (pll_ref_div * (1 << vclk_post_div));
  636. /* ecp_div: 0=dotclock, 1=dotclock/2, 2=dotclock/4 */
  637. ecp_div = dotclock / mach64type->m64_ovlclock;
  638. if (ecp_div>2) ecp_div = 2;
  639. /* Force a scaler clock factor of 1 if refclock *
  640. * is unknown (VCLK_SRC not PLLVCLK) */
  641. if ((pll_vclk_cntl & 0x03) != 0x03)
  642. ecp_div = 0;
  643. if ((pll_vclk_cntl & 0x30) != ecp_div<<4) {
  644. cc[1] = (5<<2)|2;
  645. cc[2] = (pll_vclk_cntl&0xCF) | (ecp_div<<4);
  646. }
  647. /* Restore PLL Register Index */
  648. cc[1] = save;
  649. }
  650. static void
  651. initengine(VGAscr *scr)
  652. {
  653. ulong pitch;
  654. uchar *bios;
  655. ushort table;
  656. pitch = Dx(scr->gscreen->r)/8;
  657. if(scr->gscreen->depth == 24)
  658. pitch *= 3;
  659. resetengine(scr);
  660. waitforfifo(scr, 14);
  661. iow32(scr, ContextMask, ~0);
  662. iow32(scr, DstOffPitch, pitch<<22);
  663. iow32(scr, DstYX, 0);
  664. iow32(scr, DstHeight, 0);
  665. iow32(scr, DstBresErr, 0);
  666. iow32(scr, DstBresInc, 0);
  667. iow32(scr, DstBresDec, 0);
  668. iow32(scr, DstCntl, 0x23);
  669. iow32(scr, SrcOffPitch, pitch<<22);
  670. iow32(scr, SrcYX, 0);
  671. iow32(scr, SrcHeight1Width1, 1);
  672. iow32(scr, SrcYXstart, 0);
  673. iow32(scr, SrcHeight2Width2, 1);
  674. iow32(scr, SrcCntl, 0x01);
  675. waitforfifo(scr, 13);
  676. iow32(scr, HostCntl, 0);
  677. iow32(scr, PatReg0, 0);
  678. iow32(scr, PatReg1, 0);
  679. iow32(scr, PatCntl, 0);
  680. iow32(scr, ScLeft, 0);
  681. iow32(scr, ScTop, 0);
  682. iow32(scr, ScBottom, 0xFFFF);
  683. iow32(scr, ScRight, 0xFFFF);
  684. iow32(scr, DpBkgdClr, 0);
  685. iow32(scr, DpFrgdClr, ~0);
  686. iow32(scr, DpWriteMask, ~0);
  687. iow32(scr, DpMix, 0x70003);
  688. iow32(scr, DpSrc, 0x00010100);
  689. waitforfifo(scr, 3);
  690. iow32(scr, ClrCmpClr, 0);
  691. iow32(scr, ClrCmpMask, ~0);
  692. iow32(scr, ClrCmpCntl, 0);
  693. waitforfifo(scr, 2);
  694. switch(scr->gscreen->depth){
  695. case 8:
  696. case 24: /* [sic] */
  697. iow32(scr, DpPixWidth, 0x00020202);
  698. iow32(scr, DpChainMask, 0x8080);
  699. break;
  700. case 16:
  701. iow32(scr, DpPixWidth, 0x00040404);
  702. iow32(scr, DpChainMask, 0x8410);
  703. break;
  704. case 32:
  705. iow32(scr, DpPixWidth, 0x00060606);
  706. iow32(scr, DpChainMask, 0x8080);
  707. break;
  708. }
  709. /* Get the base freq from the BIOS */
  710. bios = KADDR(0xC000);
  711. table = *(ushort *)(bios + 0x48);
  712. table = *(ushort *)(bios + table + 0x10);
  713. switch (*(ushort *)(bios + table + 0x08)) {
  714. case 2700:
  715. mach64refclock = 270000;
  716. break;
  717. case 2863:
  718. case 2864:
  719. mach64refclock = 286363;
  720. break;
  721. case 2950:
  722. mach64refclock = 294989;
  723. break;
  724. case 1432:
  725. default:
  726. mach64refclock = 143181;
  727. break ;
  728. }
  729. /* Figure out which revision this chip is */
  730. switch ((scr->mmio[mmoffset[ConfigChipId]] >> 24) & 0xFF) {
  731. case VTGTB1S1:
  732. case GTB1U1:
  733. case GTB1S2:
  734. case GTB2U1:
  735. case GTB2U2:
  736. case GTB2U3:
  737. case GTBC:
  738. case GTIIIC1U1:
  739. case GTIIIC1U2:
  740. case GTIIIC2U1:
  741. case GTIIIC2U2:
  742. case GTIIIC2U3:
  743. case LTPRO:
  744. mach64revb = 1;
  745. break;
  746. default:
  747. mach64revb = 0;
  748. break;
  749. }
  750. waitforidle(scr);
  751. }
  752. static int
  753. mach64hwfill(VGAscr *scr, Rectangle r, ulong sval)
  754. {
  755. ulong pitch;
  756. ulong ctl;
  757. if(drawdebug)
  758. iprint("hwfill %R val %lux...\n", r, sval);
  759. /* shouldn't happen */
  760. if(scr->io == 0x2EC || scr->io == 0x1C8 || scr->io == 0)
  761. return 0;
  762. pitch = Dx(scr->gscreen->r)/8;
  763. ctl = 1|2; /* left-to-right, top-to-bottom */
  764. if(scr->gscreen->depth == 24){
  765. r.min.x *= 3;
  766. r.max.x *= 3;
  767. pitch *= 3;
  768. ctl |= (1<<7)|(((r.min.x/4)%6)<<8);
  769. }
  770. waitforfifo(scr, 11);
  771. iow32(scr, DpFrgdClr, sval);
  772. iow32(scr, DpWriteMask, 0xFFFFFFFF);
  773. iow32(scr, DpMix, 0x00070003);
  774. iow32(scr, DpSrc, 0x00000111);
  775. iow32(scr, ClrCmpCntl, 0x00000000);
  776. iow32(scr, ScLeftRight, 0x1FFF0000);
  777. iow32(scr, ScTopBottom, 0x1FFF0000);
  778. iow32(scr, DstOffPitch, pitch<<22);
  779. iow32(scr, DstCntl, ctl);
  780. iow32(scr, DstYX, (r.min.x<<16)|r.min.y);
  781. iow32(scr, DstHeightWidth, (Dx(r)<<16)|Dy(r));
  782. waitforidle(scr);
  783. return 1;
  784. }
  785. static int
  786. mach64hwscroll(VGAscr *scr, Rectangle r, Rectangle sr)
  787. {
  788. ulong pitch;
  789. Point dp, sp;
  790. ulong ctl;
  791. int dx, dy;
  792. dx = Dx(r);
  793. dy = Dy(r);
  794. pitch = Dx(scr->gscreen->r)/8;
  795. if(scr->gscreen->depth == 24){
  796. dx *= 3;
  797. pitch *= 3;
  798. r.min.x *= 3;
  799. sr.min.x *= 3;
  800. }
  801. ctl = 0;
  802. if(r.min.x <= sr.min.x){
  803. ctl |= 1;
  804. dp.x = r.min.x;
  805. sp.x = sr.min.x;
  806. }else{
  807. dp.x = r.min.x+dx-1;
  808. sp.x = sr.min.x+dx-1;
  809. }
  810. if(r.min.y <= sr.min.y){
  811. ctl |= 2;
  812. dp.y = r.min.y;
  813. sp.y = sr.min.y;
  814. }else{
  815. dp.y = r.min.y+dy-1;
  816. sp.y = sr.min.y+dy-1;
  817. }
  818. if(scr->gscreen->depth == 24)
  819. ctl |= (1<<7)|(((dp.x/4)%6)<<8);
  820. waitforfifo(scr, 6);
  821. iow32(scr, ScLeftRight, 0x1FFF0000);
  822. iow32(scr, ScTopBottom, 0x1FFF0000);
  823. iow32(scr, DpWriteMask, 0xFFFFFFFF);
  824. iow32(scr, DpMix, 0x00070003);
  825. iow32(scr, DpSrc, 0x00000300);
  826. iow32(scr, ClrCmpCntl, 0x00000000);
  827. waitforfifo(scr, 8);
  828. iow32(scr, SrcOffPitch, pitch<<22);
  829. iow32(scr, SrcCntl, 0x00000000);
  830. iow32(scr, SrcYX, (sp.x<<16)|sp.y);
  831. iow32(scr, SrcWidth1, dx);
  832. iow32(scr, DstOffPitch, pitch<<22);
  833. iow32(scr, DstCntl, ctl);
  834. iow32(scr, DstYX, (dp.x<<16)|dp.y);
  835. iow32(scr, DstHeightWidth, (dx<<16)|dy);
  836. waitforidle(scr);
  837. return 1;
  838. }
  839. /*
  840. * This should work, but doesn't.
  841. * It messes up the screen timings for some reason.
  842. */
  843. static void
  844. mach64blank(VGAscr *scr, int blank)
  845. {
  846. ulong ctl;
  847. ctl = ior32(scr, CrtcGenCtl) & ~(CrtcHsyncDis|CrtcVsyncDis);
  848. if(blank)
  849. ctl |= CrtcHsyncDis|CrtcVsyncDis;
  850. iow32(scr, CrtcGenCtl, ctl);
  851. }
  852. /*
  853. * We squirrel away whether the LCD and/or CRT were
  854. * on when we were called to blank the screen, and
  855. * restore the old state. If we are called to blank the
  856. * screen when it is already blank, we don't update the state.
  857. * Such a call sequence should not happen, though.
  858. *
  859. * We could try forcing the chip into power management
  860. * mode instead, but I'm not sure how that would interact
  861. * with screen updates going on while the screen is blanked.
  862. */
  863. static void
  864. mach64lcdblank(VGAscr *scr, int blank)
  865. {
  866. static int crtlcd;
  867. ulong x;
  868. if(blank) {
  869. x = lcdr32(scr, LCD_GenCtrl);
  870. if(x & 3) {
  871. crtlcd = x & 3;
  872. lcdw32(scr, LCD_GenCtrl, x&~3);
  873. }
  874. } else {
  875. if(crtlcd == 0)
  876. crtlcd = 2; /* lcd only */
  877. x = lcdr32(scr, LCD_GenCtrl);
  878. lcdw32(scr, LCD_GenCtrl, x | crtlcd);
  879. }
  880. }
  881. static void
  882. mach64xxdrawinit(VGAscr *scr)
  883. {
  884. if(scr->io > 0x2FF){
  885. initengine(scr);
  886. scr->fill = mach64hwfill;
  887. scr->scroll = mach64hwscroll;
  888. }
  889. /* scr->blank = mach64blank; */
  890. switch(scr->id){
  891. default:
  892. break;
  893. case ('L'<<8)|'B': /* 4C42: Rage 3D LTPro */
  894. case ('L'<<8)|'I': /* 4C49: Rage 3D LTPro */
  895. case ('L'<<8)|'M': /* 4C4D: Rage Mobility */
  896. case ('L'<<8)|'P': /* 4C50: Rage 3D LTPro */
  897. scr->blank = mach64lcdblank;
  898. hwblank = 1;
  899. break;
  900. }
  901. }
  902. static void
  903. ovl_configure(VGAscr *scr, Chan *c, char **field)
  904. {
  905. int w, h;
  906. char *format;
  907. w = (int)strtol(field[1], nil, 0);
  908. h = (int)strtol(field[2], nil, 0);
  909. format = field[3];
  910. if (c != ovl_chan)
  911. error(Einuse);
  912. if (strcmp(format, "YUYV"))
  913. error(Eunsupportedformat);
  914. ovl_width = w;
  915. ovl_height = h;
  916. ovl_fib = w * h * sizeof(ushort);
  917. waitforidle(scr);
  918. scr->mmio[mmoffset[BusCntl]] |= 0x08000000; /* Enable regblock 1 */
  919. scr->mmio[mmoffset[OverlayScaleCntl]] =
  920. SCALE_ZERO_EXTEND|SCALE_RED_TEMP_6500K|
  921. SCALE_HORZ_BLEND|SCALE_VERT_BLEND;
  922. scr->mmio[mmoffset[!mach64revb? Buf0Pitch: ScalerBuf0Pitch]] = w;
  923. scr->mmio[mmoffset[CaptureConfig]] =
  924. SCALER_FRAME_READ_MODE_FULL|
  925. SCALER_BUF_MODE_SINGLE|
  926. SCALER_BUF_NEXT_0;
  927. scr->mmio[mmoffset[OverlayKeyCntl]] = !mach64revb?
  928. OVERLAY_MIX_ALWAYS_V|(OVERLAY_EXCLUSIVE_NORMAL << 28):
  929. 0x011;
  930. if (mach64type->m64_pro) {
  931. waitforfifo(scr, 6);
  932. /* set the scaler co-efficient registers */
  933. scr->mmio[mmoffset[ScalerColourCntl]] =
  934. (0x00) | (0x10 << 8) | (0x10 << 16);
  935. scr->mmio[mmoffset[ScalerHCoef0]] =
  936. (0x00) | (0x20 << 8);
  937. scr->mmio[mmoffset[ScalerHCoef1]] =
  938. (0x0D) | (0x20 << 8) | (0x06 << 16) | (0x0D << 24);
  939. scr->mmio[mmoffset[ScalerHCoef2]] =
  940. (0x0D) | (0x1C << 8) | (0x0A << 16) | (0x0D << 24);
  941. scr->mmio[mmoffset[ScalerHCoef3]] =
  942. (0x0C) | (0x1A << 8) | (0x0E << 16) | (0x0C << 24);
  943. scr->mmio[mmoffset[ScalerHCoef4]] =
  944. (0x0C) | (0x14 << 8) | (0x14 << 16) | (0x0C << 24);
  945. }
  946. waitforfifo(scr, 3);
  947. scr->mmio[mmoffset[VideoFormat]] = SCALE_IN_YVYU422 |
  948. (!mach64revb? 0xC: 0);
  949. if (mach64overlay == 0)
  950. mach64overlay = scr->storage + 64 * 64 * sizeof(uchar);
  951. scr->mmio[mmoffset[!mach64revb? Buf0Offset: ScalerBuf0Offset]] =
  952. mach64overlay;
  953. }
  954. static void
  955. ovl_enable(VGAscr *scr, Chan *c, char **field)
  956. {
  957. int x, y, w, h;
  958. long h_inc, v_inc;
  959. x = (int)strtol(field[1], nil, 0);
  960. y = (int)strtol(field[2], nil, 0);
  961. w = (int)strtol(field[3], nil, 0);
  962. h = (int)strtol(field[4], nil, 0);
  963. if (x < 0 || x + w > physgscreenr.max.x ||
  964. y < 0 || y + h > physgscreenr.max.y)
  965. error(Ebadarg);
  966. if (c != ovl_chan)
  967. error(Einuse);
  968. if (scr->mmio[mmoffset[CrtcGenCntl]] & 1) { /* double scan enable */
  969. y *= 2;
  970. h *= 2;
  971. }
  972. waitforfifo(scr, 2);
  973. scr->mmio[mmoffset[OverlayYX]] =
  974. ((x & 0xFFFF) << 16) | (y & 0xFFFF);
  975. scr->mmio[mmoffset[OverlayYXEnd]] =
  976. (((x + w) & 0xFFFF) << 16) | ((y + h) & 0xFFFF);
  977. h_inc = (ovl_width << 12) / (w >> 1); /* ??? */
  978. v_inc = (ovl_height << 12) / h;
  979. waitforfifo(scr, 2);
  980. scr->mmio[mmoffset[OverlayScaleInc]] =
  981. ((h_inc & 0xFFFF) << 16) | (v_inc & 0xFFFF);
  982. scr->mmio[mmoffset[ScalerHeightWidth]] =
  983. ((ovl_width & 0xFFFF) << 16) | (ovl_height & 0xFFFF);
  984. waitforidle(scr);
  985. scr->mmio[mmoffset[OverlayScaleCntl]] |=
  986. (SCALE_ENABLE|OVERLAY_ENABLE);
  987. }
  988. static void
  989. ovl_status(VGAscr *scr, Chan *, char **field)
  990. {
  991. pprint("%s: %s %.4uX, VT/GT %s, PRO %s, ovlclock %d, rev B %s, refclock %ld\n",
  992. scr->dev->name, field[0], mach64type->m64_id,
  993. mach64type->m64_vtgt? "yes": "no",
  994. mach64type->m64_pro? "yes": "no",
  995. mach64type->m64_ovlclock,
  996. mach64revb? "yes": "no",
  997. mach64refclock);
  998. pprint("%s: storage @%.8luX, aperture @%8.ulX, ovl buf @%.8ulX\n",
  999. scr->dev->name, scr->storage, scr->aperture,
  1000. mach64overlay);
  1001. }
  1002. static void
  1003. ovl_openctl(VGAscr *, Chan *c, char **)
  1004. {
  1005. if (ovl_chan)
  1006. error(Einuse);
  1007. ovl_chan = c;
  1008. }
  1009. static void
  1010. ovl_closectl(VGAscr *scr, Chan *c, char **)
  1011. {
  1012. if (c != ovl_chan) return;
  1013. waitforidle(scr);
  1014. scr->mmio[mmoffset[OverlayScaleCntl]] &=
  1015. ~(SCALE_ENABLE|OVERLAY_ENABLE);
  1016. ovl_chan = nil;
  1017. ovl_width = ovl_height = ovl_fib = 0;
  1018. }
  1019. enum
  1020. {
  1021. CMclosectl,
  1022. CMconfigure,
  1023. CMenable,
  1024. CMopenctl,
  1025. CMstatus,
  1026. };
  1027. static void (*ovl_cmds[])(VGAscr *, Chan *, char **) =
  1028. {
  1029. [CMclosectl] ovl_closectl,
  1030. [CMconfigure] ovl_configure,
  1031. [CMenable] ovl_enable,
  1032. [CMopenctl] ovl_openctl,
  1033. [CMstatus] ovl_status,
  1034. };
  1035. static Cmdtab mach64xxcmd[] =
  1036. {
  1037. CMclosectl, "closectl", 1,
  1038. CMconfigure, "configure", 4,
  1039. CMenable, "enable", 5,
  1040. CMopenctl, "openctl", 1,
  1041. CMstatus, "status", 1,
  1042. };
  1043. static void
  1044. mach64xxovlctl(VGAscr *scr, Chan *c, void *a, int n)
  1045. {
  1046. Cmdbuf *cb;
  1047. Cmdtab *ct;
  1048. if(!mach64type->m64_vtgt)
  1049. error(Enodev);
  1050. if(!scr->overlayinit){
  1051. scr->overlayinit = 1;
  1052. init_overlayclock(scr);
  1053. }
  1054. cb = parsecmd(a, n);
  1055. if(waserror()){
  1056. free(cb);
  1057. nexterror();
  1058. }
  1059. ct = lookupcmd(cb, mach64xxcmd, nelem(mach64xxcmd));
  1060. ovl_cmds[ct->index](scr, c, cb->f);
  1061. poperror();
  1062. free(cb);
  1063. }
  1064. static int
  1065. mach64xxovlwrite(VGAscr *scr, void *a, int len, vlong offs)
  1066. {
  1067. uchar *src;
  1068. int _len;
  1069. if (ovl_chan == nil) return len; /* Acts as a /dev/null */
  1070. /* Calculate the destination address */
  1071. _len = len;
  1072. src = (uchar *)a;
  1073. while (len > 0) {
  1074. ulong _offs;
  1075. int nb;
  1076. _offs = (ulong)(offs % ovl_fib);
  1077. nb = (_offs + len > ovl_fib)? ovl_fib - _offs: len;
  1078. memmove((uchar *)KADDR(scr->aperture + mach64overlay + _offs),
  1079. src, nb);
  1080. offs += nb;
  1081. src += nb;
  1082. len -= nb;
  1083. }
  1084. return _len;
  1085. }
  1086. VGAdev vgamach64xxdev = {
  1087. "mach64xx",
  1088. mach64xxenable, /* enable */
  1089. 0, /* disable */
  1090. 0, /* page */
  1091. mach64xxlinear, /* linear */
  1092. mach64xxdrawinit, /* drawinit */
  1093. 0,
  1094. mach64xxovlctl, /* overlay control */
  1095. mach64xxovlwrite, /* write the overlay */
  1096. };
  1097. VGAcur vgamach64xxcur = {
  1098. "mach64xxhwgc",
  1099. mach64xxcurenable, /* enable */
  1100. mach64xxcurdisable, /* disable */
  1101. mach64xxcurload, /* load */
  1102. mach64xxcurmove, /* move */
  1103. 1 /* doespanning */
  1104. };