2 * Acess2 VIA Video Driver
8 * NOTE: Based off the UniChrome driver for X, http://unichrome.sourceforge.net/
9 * - OGPM_UniChrome_ProII_R108a_Part1_Core_2D.pdf
16 #include <api_drv_video.h>
20 #define VERSION VER2(0,1)
23 const struct sVGA_Timings
25 int HFP, HSync, HDisplay, HBP;
26 int VFP, VSync, VDisplay, VBP;
28 {40, 128, 800, 88, 1, 4, 600, 23}, // SVGA @ 60Hz
29 {24, 136, 1024, 160, 3, 6, 768, 29}, // XGA @ 60Hz
30 {38, 112, 1280, 248, 1, 3, 1024, 38} // 1280x1024 @ 60Hz
32 const Uint16 caVIAVideo_CardIDs[][2] = {
33 {0x1106, 0x3108}, // minuet (unk chip, PCIDB says "VIA/S3G UniChrome Pro IGP (Integrated Video Adapter)")
34 {0x1106, 0x3157}, // CX700/VX700 (S3 UniChrome Pro) - serenade
35 //{0x1106, 0x1122}, // VX800
36 //{0x1106, 0x5122}, // VX855
37 //{0x1106, 0x7122}, // VX900
39 const int ciVIAVideo_NumCardIDs = sizeof(caVIAVideo_CardIDs)/sizeof(caVIAVideo_CardIDs[0]);
42 int VIAVideo_Initialise(char **Arguments);
43 void VIAVideo_Cleanup(void);
45 size_t VIAVideo_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer);
46 int VIAVideo_IOCtl(tVFS_Node *Node, int ID, void *Data);
48 void VIAVideo_int_SetMode(const struct sVGA_Timings *Timings, int Depth);
49 void VIAVideo_int_ResetCRTC(int Index, BOOL Reset);
51 static void _SRMask(int Reg, Uint8 Byte, Uint8 Mask);
52 static void _CRMask(int Reg, Uint8 Byte, Uint8 Mask);
55 MODULE_DEFINE(0, VERSION, VIAVideo, VIAVideo_Initialise, VIAVideo_Cleanup, NULL);
56 tVFS_NodeType gVIAVideo_NodeType = {
57 .Write = VIAVideo_Write,
58 .IOCtl = VIAVideo_IOCtl
60 tDevFS_Driver gVIAVideo_DriverStruct = {
62 {.Type = &gVIAVideo_NodeType}
64 int giVIAVideo_DriverID;
65 tVIAVideo_Dev gVIAVideo_Info;
68 int VIAVideo_Initialise(char **Arguments)
72 for( int i = 0; i < ciVIAVideo_NumCardIDs; i ++ )
74 count += PCI_CountDevices(caVIAVideo_CardIDs[i][0], caVIAVideo_CardIDs[i][1]);
76 if(count == 0) return MODULE_ERR_NOTNEEDED;
79 for( int i = 0; i < ciVIAVideo_NumCardIDs; i ++ )
81 const Uint16 *dev_ids = caVIAVideo_CardIDs[i];
82 for( int id = 0; (id = PCI_GetDevice(dev_ids[0], dev_ids[1], id)) != -1; id ++ )
85 Log_Log("VIAVideo", "BAR0 = 0x%x", PCI_GetBAR(id, 0));
86 Log_Log("VIAVideo", "BAR1 = 0x%x", PCI_GetBAR(id, 1));
87 //Log_Log("VIAVideo", "BAR2 = 0x%x", PCI_GetBAR(id, 2));
88 //Log_Log("VIAVideo", "BAR3 = 0x%x", PCI_GetBAR(id, 3));
89 //Log_Log("VIAVideo", "BAR4 = 0x%x", PCI_GetBAR(id, 4));
90 //Log_Log("VIAVideo", "BAR5 = 0x%x", PCI_GetBAR(id, 5));
92 // Ignore multiple cards
93 if( gVIAVideo_Info.FramebufferPhys ) continue ;
95 gVIAVideo_Info.FramebufferPhys = PCI_GetBAR(id, 0);
96 gVIAVideo_Info.MMIOPhys = PCI_GetBAR(id, 1);
98 gVIAVideo_Info.Framebuffer = (void*)MM_MapHWPages(
99 gVIAVideo_Info.FramebufferPhys, (1024*768*4)/PAGE_SIZE
104 tmp = PCI_ConfigRead(id, 0xA1, 1);
105 Uint32 vidram = (1 << ((tmp & 0x70) >> 4)) * 4096;
106 Log_Debug("VIAVideo", "0x%x bytes of video ram?", vidram);
109 // Enable Framebuffer
110 _SRMask(0x02, 0x0F, 0xFF); /* Enable writing to all VGA memory planes */
111 _SRMask(0x04, 0x0E, 0xFF); /* Enable Extended VGA memory */
112 _SRMask(0x1A, 0x08, 0x08); /* Enable Extended Memory access */
114 gVIAVideo_Info.BufInfo.Framebuffer = gVIAVideo_Info.Framebuffer;
115 gVIAVideo_Info.BufInfo.Pitch = 1024*4;
116 gVIAVideo_Info.BufInfo.Width = 1024;
117 gVIAVideo_Info.BufInfo.Height = 768;
118 gVIAVideo_Info.BufInfo.Depth = 32;
122 VIAVideo_int_SetMode( &csaTimings[1], 32 );
123 for( int i = 0; i < 768; i ++ )
125 Uint32 *scanline = gVIAVideo_Info.Framebuffer + i * 0x1000;
126 for( int j = 0; j < 200; j ++ )
128 scanline[j] = 0xFFA06000;
134 giVIAVideo_DriverID = DevFS_AddDevice( &gVIAVideo_DriverStruct );
135 if(giVIAVideo_DriverID == -1) return MODULE_ERR_MISC;
137 return MODULE_ERR_OK;
140 void VIAVideo_Cleanup(void)
145 size_t VIAVideo_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer)
148 return DrvUtil_Video_WriteLFB(&gVIAVideo_Info.BufInfo, Offset, Length, Buffer);
152 if( Offset >= gVIAVideo_Info.FBSize )
154 if( Length > gVIAVideo_Info.FBSize )
155 Length = gVIAVideo_Info.FBSize;
156 if( Offset + Length > gVIAVideo_Info.FBSize )
157 Length = gVIAVideo_Info.FBSize - Offset;
159 memcpy( (Uint8*)gVIAVideo_Info.Framebuffer + Offset, Buffer, Length );
165 int VIAVideo_IOCtl(tVFS_Node *Node, int ID, void *Data)
171 void VIAVideo_int_SetMode(const struct sVGA_Timings *Timings, int Depth)
176 _CRMask(0x36, 0x30, 0x30); // CRT Off (TODO: Others)
177 // VQ Disable (optional?)
180 _CRMask(0x17, 0x00, 0x80);
183 VIAVideo_int_ResetCRTC(0, TRUE);
185 // -- Set framebuffer --
186 // Set colour depth bits
187 // VGASRMask(Crtc, 0x15, {0x00,0x14,0x0C}[Depth=8,16,24/32], 0x1C)
189 case 8: _SRMask(0x15, 0x00, 0x1C); break;
190 case 16: _SRMask(0x15, 0x14, 0x1C); break; // 565 16-bit
191 case 24: _SRMask(0x15, 0x0C, 0x1C); break;
192 case 32: _SRMask(0x15, 0x0C, 0x1C); break;
197 int pitch = Timings->HDisplay * (Depth/8) / 8;
198 // (Pitch/8) -> CR13 + CR35&0xE0
199 _CRMask(0x13, pitch, 0xFF);
200 _CRMask(0x35, (pitch>>8)<<5, 0xE0);
202 // - Set frame origin? (->FrameSet(Crtc, X, Y))
203 // DWORD Offset in memory
204 // Stored in CR0D + CR0C + CR34 + CR48&0x03
205 Uint32 start_addr = 0; // Video address (29 bits)
206 _CRMask(0x0D, (start_addr >> 0)&0xFF, 0xFF);
207 _CRMask(0x0C, (start_addr >> 8)&0xFF, 0xFF);
208 _CRMask(0x34, (start_addr >>16)&0xFF, 0xFF);
209 _CRMask(0x34, (start_addr >>24)&0x1F, 0xFF);
211 // -- Set CRTC Mode --
213 // - VGA Represents the signal cycle as Display, Blank with Sync anywhere in that
214 // - Hence, I program the blanking as HBP, Sync, HFP (with the sync in the blanking area)
217 // VGAMiscMask(Crtc, (HSyncEnabled ? 0x40 : 0x00), 0x40);
218 // VGAMiscMask(Crtc, (VSyncEnabled ? 0x80 : 0x00), 0x80);
219 // HTotal: CR00 + CR36&0x08 = /8-5
220 temp = (Timings->HFP + Timings->HSync + Timings->HDisplay + Timings->HBP) / 8 - 5;
221 _CRMask(0x00, temp, 0xFF);
222 _CRMask(0x36, (temp>>8)<<3, 0x08);
223 // HDisplay: CR01 = /8-1
224 temp = Timings->HDisplay / 8 - 1;
225 _CRMask(0x01, temp, 0xFF);
226 // HBlank Start: CR02 = /8-1
227 temp = (Timings->HDisplay) / 8 - 1;
228 _CRMask(0x02, temp, 0xFF);
229 // HBlank End: CR03&0x1F + CR05&0x80 + CR33&0x20 = /8-1
230 temp = (Timings->HBP + Timings->HSync + Timings->HFP) / 8 - 1;
231 if( temp >> 7 ) Log_Error("VIA", "HBlank End doesn't fit (%i not 7 bits)", temp);
232 _CRMask(0x03, temp, 0x1F);
233 _CRMask(0x05, (temp>>5)<<7, 0x80);
234 _CRMask(0x33, (temp>>6)<<5, 0x20);
235 // HSync Start: CR04 + CR33&0x10 = /8
236 temp = (Timings->HDisplay + Timings->HBP) / 8;
237 _CRMask(0x04, temp, 0xFF);
238 _CRMask(0x33, (temp>>8)<<4, 0x10);
239 // HSync End: CR05&0x1F = /8
240 temp = (Timings->HSync) / 8;
241 _CRMask(0x05, temp, 0x1F);
242 // VTotal: CR06 + CR07&0x01 + CR07&0x20 + CR35&0x01 = -2
243 temp = (Timings->VFP + Timings->VBP + Timings->VSync + Timings->VDisplay) - 2;
244 _CRMask(0x06, temp, 0xFF);
245 _CRMask(0x07, (temp>>8)<<0, 0x01);
246 _CRMask(0x07, (temp>>9)<<5, 0x20);
247 _CRMask(0x35, (temp>>10)<<0, 0x01);
248 // VDisplay: CR12 + CR07&0x02 + CR07&0x40 + CR35&0x04 = -1
249 temp = (Timings->VDisplay) - 1;
250 _CRMask(0x12, temp, 0xFF);
251 _CRMask(0x07, (temp>>8)<<1, 0x02);
252 _CRMask(0x07, (temp>>9)<<6, 0x40);
253 _CRMask(0x07, (temp>>10)<<2, 0x04);
254 // 0: CR0C + CR0D + CD34 + CR48&0x03 ("Primary starting address")
256 _CRMask(0x0C, temp, 0xFF);
257 _CRMask(0x0D, (temp>>8), 0xFF);
258 _CRMask(0x34, (temp>>16), 0xFF);
259 _CRMask(0x48, (temp>>24), 0x03);
260 // VSyncStart: CR10 + CR07&0x04 + CR07&0x80 + CR35&0x02
261 temp = (Timings->VDisplay + Timings->HBP);
262 _CRMask(0x10, temp, 0xFF);
263 _CRMask(0x07, (temp>>8)<<2, 0x04);
264 _CRMask(0x07, (temp>>9)<<7, 0x80);
265 _CRMask(0x35, (temp>>10)<<1, 0x02);
266 // VSyncEnd: CR11&0x0F
267 temp = (Timings->VSync);
268 _CRMask(0x11, temp, 0x0F);
269 // 0x3FFF: CR18 + CR07&0x10 + CR09&0x40 + CR33&0x06 + CR35&0x10 ("line compare")
271 _CRMask(0x18, temp, 0xFF);
272 _CRMask(0x07, (temp>>8)<<4, 0x10);
273 _CRMask(0x09, (temp>>9)<<6, 0x40);
274 _CRMask(0x33, (temp>>10)<<1, 0x06);
275 _CRMask(0x35, (temp>>12)<<4, 0x10);
276 // 0: CR09&0x1F ("Maximum scanline")
278 _CRMask(0x09, temp, 0x1F);
279 // 0: Cursor location
281 _CRMask(0x14, temp, 0xFF);
282 // VBlankStart: CR15 + CR07&0x08 + CR09&0x20 + CR35&0x08 = -1
283 temp = (Timings->VDisplay) - 1;
284 _CRMask(0x15, temp, 0xFF);
285 _CRMask(0x07, (temp>>8)<<3, 0x08);
286 _CRMask(0x09, (temp>>9)<<5, 0x20);
287 _CRMask(0x35, (temp>>10)<<3, 0x08);
288 // VBlankEnd: CR16 = -1
289 temp = (Timings->VBP + Timings->VSync + Timings->VFP) - 1;
290 _CRMask(0x16, temp, 0xFF);
291 // 0: CR08 (Preset Row Scan Register)
292 _CRMask(0x08, 0, 0xFF);
294 _CRMask(0x32, 0, 0xFF);
296 _CRMask(0x33, 0, 0xC8);
300 // Some magic? (Not Simultaneous)
301 _CRMask(0x6B, 0x00, 0x08);
303 // Disable CRTC reset
304 VIAVideo_int_ResetCRTC(0, FALSE);
306 // Some other magic? (VGA - Lock registers?)
307 _CRMask(0x17, 0x80, 0x80);
309 _CRMask(0x36, 0x00, 0x30); // CRT On (TODO: Others)
312 void VIAVideo_int_ResetCRTC(int Index, BOOL Reset)
314 // VGASRMask(Crtc, 0x00, (Reset ? 0x00 : 0x02), 0x02);
315 _SRMask(0x00, (Reset ? 0x00 : 0x02), 0x02);
318 void _SRMask(int Reg, Uint8 Byte, Uint8 Mask)
322 if(Mask != 0xFF) cv = inb(0x3C5) & ~Mask;
327 void _CRMask(int Reg, Uint8 Byte, Uint8 Mask)
331 if(Mask != 0xFF) cv = inb(0x3D5) & ~Mask;