Modules/VGA - Start on a generic VGA driver (VGA driver, and library for derivatives)
[tpg/acess2.git] / KernelLand / Modules / Display / VIAVideo / main.c
1 /*
2  * Acess2 VIA Video Driver
3  * - By John Hodge
4  * 
5  * main.c
6  * - Driver core
7  *
8  * NOTE: Based off the UniChrome driver for X, http://unichrome.sourceforge.net/
9  * - OGPM_UniChrome_ProII_R108a_Part1_Core_2D.pdf
10  */
11 #define DEBUG   0
12 #include <acess.h>
13 #include <fs_devfs.h>
14 #include <drv_pci.h>
15 #include <modules.h>
16 #include <api_drv_video.h>
17 #include <timers.h>
18 #include "common.h"
19
20 #define VERSION VER2(0,1)
21
22 // === CONSTANTS ===
23 const struct sVGA_Timings
24 {
25          int    HFP, HSync, HDisplay, HBP;
26          int    VFP, VSync, VDisplay, VBP;
27 } csaTimings[] = {
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
31 };
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
38 };
39 const int       ciVIAVideo_NumCardIDs = sizeof(caVIAVideo_CardIDs)/sizeof(caVIAVideo_CardIDs[0]);
40
41 // === PROTOTYPES ===
42  int    VIAVideo_Initialise(char **Arguments);
43 void    VIAVideo_Cleanup(void);
44
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);
47
48 void    VIAVideo_int_SetMode(const struct sVGA_Timings *Timings, int Depth);
49 void    VIAVideo_int_ResetCRTC(int Index, BOOL Reset);
50
51 static void     _SRMask(int Reg, Uint8 Byte, Uint8 Mask);
52 static void     _CRMask(int Reg, Uint8 Byte, Uint8 Mask);
53
54 // === GLOBALS ===
55 MODULE_DEFINE(0, VERSION, VIAVideo, VIAVideo_Initialise, VIAVideo_Cleanup, NULL);
56 tVFS_NodeType   gVIAVideo_NodeType = {
57         .Write = VIAVideo_Write,
58         .IOCtl = VIAVideo_IOCtl
59         };
60 tDevFS_Driver   gVIAVideo_DriverStruct = {
61         NULL, "VIAVideo",
62         {.Type = &gVIAVideo_NodeType}
63         };
64  int    giVIAVideo_DriverID;
65 tVIAVideo_Dev   gVIAVideo_Info;
66
67 // === CODE ===
68 int VIAVideo_Initialise(char **Arguments)
69 {
70          int    count = 0;
71         
72         for( int i = 0; i < ciVIAVideo_NumCardIDs; i ++ )
73         {
74                 count += PCI_CountDevices(caVIAVideo_CardIDs[i][0], caVIAVideo_CardIDs[i][1]);
75         }
76         if(count == 0)  return MODULE_ERR_NOTNEEDED;
77         
78
79         for( int i = 0; i < ciVIAVideo_NumCardIDs; i ++ )
80         {
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 ++ )
83                 {
84                         // TODO: Support MMIO
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));
91                         
92                         // Ignore multiple cards
93                         if( gVIAVideo_Info.FramebufferPhys )    continue ;
94                         
95                         gVIAVideo_Info.FramebufferPhys = PCI_GetBAR(id, 0);
96                         gVIAVideo_Info.MMIOPhys = PCI_GetBAR(id, 1);
97                         
98                         gVIAVideo_Info.Framebuffer = (void*)MM_MapHWPages(
99                                 gVIAVideo_Info.FramebufferPhys, (1024*768*4)/PAGE_SIZE
100                                 );
101                         // TODO: Map MMIO
102
103                         Uint8   tmp;
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);
107
108
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 */
113
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;
119                 }
120         }
121
122         VIAVideo_int_SetMode( &csaTimings[1], 32 );
123         for( int i = 0; i < 768; i ++ )
124         {
125                 Uint32  *scanline = gVIAVideo_Info.Framebuffer + i * 0x1000;
126                 for( int j = 0; j < 200; j ++ )
127                 {
128                         scanline[j] = 0xFFA06000;
129                 }
130                 Time_Delay(500);
131         }
132
133         // Install Device
134         giVIAVideo_DriverID = DevFS_AddDevice( &gVIAVideo_DriverStruct );
135         if(giVIAVideo_DriverID == -1)   return MODULE_ERR_MISC;
136
137         return MODULE_ERR_OK;
138 }
139
140 void VIAVideo_Cleanup(void)
141 {
142         return ;
143 }
144
145 size_t VIAVideo_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer)
146 {
147         #if 0
148         return DrvUtil_Video_WriteLFB(&gVIAVideo_Info.BufInfo, Offset, Length, Buffer);
149         #endif
150         return 0;
151         #if 0
152         if( Offset >= gVIAVideo_Info.FBSize )
153                 return 0;
154         if( Length > gVIAVideo_Info.FBSize )
155                 Length = gVIAVideo_Info.FBSize;
156         if( Offset + Length > gVIAVideo_Info.FBSize )
157                 Length = gVIAVideo_Info.FBSize - Offset;
158         
159         memcpy( (Uint8*)gVIAVideo_Info.Framebuffer + Offset, Buffer, Length );
160         
161         return Length;
162         #endif
163 }
164
165 int VIAVideo_IOCtl(tVFS_Node *Node, int ID, void *Data)
166 {
167         return 0;
168 }
169
170 // --- Modeset!
171 void VIAVideo_int_SetMode(const struct sVGA_Timings *Timings, int Depth)
172 {
173          int    temp;
174
175         // Disable power
176         _CRMask(0x36, 0x30, 0x30);      // CRT Off (TODO: Others)
177         // VQ Disable (optional?)
178         
179         // Unlock registers
180         _CRMask(0x17, 0x00, 0x80);
181         
182         // Reset CRTC1
183         VIAVideo_int_ResetCRTC(0, TRUE);
184         
185         // -- Set framebuffer --
186         // Set colour depth bits
187         // VGASRMask(Crtc, 0x15, {0x00,0x14,0x0C}[Depth=8,16,24/32], 0x1C)
188         switch(Depth) {
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;
193         default:        return ;
194         }
195         // Set line length
196         {
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);
201         }
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);
210
211         // -- Set CRTC Mode --
212         // NOTES:
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)
215
216         // Set mode
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")
255         temp = 0;
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")
270         temp = 0x3FFF;
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")
277         temp = 0;
278         _CRMask(0x09, temp, 0x1F);
279         // 0: Cursor location
280         temp = 0;
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);
293         // 0:  CR32 (???)
294         _CRMask(0x32, 0, 0xFF);
295         // 0:  CR33&0xC8
296         _CRMask(0x33, 0, 0xC8);
297
298         // Set scaling?
299
300         // Some magic? (Not Simultaneous)
301         _CRMask(0x6B, 0x00, 0x08);
302
303         // Disable CRTC reset
304         VIAVideo_int_ResetCRTC(0, FALSE);
305
306         // Some other magic? (VGA - Lock registers?)
307         _CRMask(0x17, 0x80, 0x80);
308                 
309         _CRMask(0x36, 0x00, 0x30);      // CRT On (TODO: Others)
310 }
311
312 void VIAVideo_int_ResetCRTC(int Index, BOOL Reset)
313 {
314         // VGASRMask(Crtc, 0x00, (Reset ? 0x00 : 0x02), 0x02);
315         _SRMask(0x00, (Reset ? 0x00 : 0x02), 0x02);
316 }
317
318 void _SRMask(int Reg, Uint8 Byte, Uint8 Mask)
319 {
320         Uint8   cv = 0;
321         outb(0x3C4, Reg);
322         if(Mask != 0xFF)        cv = inb(0x3C5) & ~Mask;
323         cv |= Byte & Mask;
324         outb(0x3C5, cv);
325 }
326
327 void _CRMask(int Reg, Uint8 Byte, Uint8 Mask)
328 {
329         Uint8   cv = 0;
330         outb(0x3D4, Reg);
331         if(Mask != 0xFF)        cv = inb(0x3D5) & ~Mask;
332         cv |= Byte & Mask;
333         outb(0x3D5, cv);
334 }
335

UCC git Repository :: git.ucc.asn.au