Modules/Tegra2Vid - Misc
[tpg/acess2.git] / KernelLand / Modules / Display / Tegra2Vid / main.c
1 /**
2  * main.c
3  * - Driver core
4  */
5 #define DEBUG   0
6 #define DUMP_REGISTERS  1
7 #define VERSION ((0<<8)|10)
8 #include <acess.h>
9 #include <errno.h>
10 #include <modules.h>
11 #include <vfs.h>
12 #include <fs_devfs.h>
13 #include <drv_pci.h>
14 #include <api_drv_video.h>
15 #include <lib/keyvalue.h>
16 #include <options.h>    // ARM Arch
17 #include "tegra2.h"
18
19 #define ABS(a)  ((a)>0?(a):-(a))
20
21 // === PROTOTYPES ===
22 // Driver
23  int    Tegra2Vid_Install(char **Arguments);
24 void    Tegra2Vid_Uninstall();
25 // Internal
26 // Filesystem
27 size_t  Tegra2Vid_Read(tVFS_Node *node, off_t off, size_t len, void *buffer, Uint Flags);
28 size_t  Tegra2Vid_Write(tVFS_Node *node, off_t off, size_t len, const void *buffer, Uint Flags);
29  int    Tegra2Vid_IOCtl(tVFS_Node *node, int id, void *data);
30 // -- Internals
31  int    Tegra2Vid_int_SetMode(int Mode);
32
33 // === GLOBALS ===
34 MODULE_DEFINE(0, VERSION, Tegra2Vid, Tegra2Vid_Install, NULL, NULL);
35 tVFS_NodeType   gTegra2Vid_NodeType = {
36         .Read = Tegra2Vid_Read,
37         .Write = Tegra2Vid_Write,
38         .IOCtl = Tegra2Vid_IOCtl
39         };
40 tDevFS_Driver   gTegra2Vid_DriverStruct = {
41         NULL, "Tegra2Vid",
42         {.Type = &gTegra2Vid_NodeType}
43 };
44 // -- Options
45 tPAddr  gTegra2Vid_PhysBase = TEGRA2VID_BASE;
46  int    gbTegra2Vid_IsVersatile = 1;
47 // -- KeyVal parse rules
48 const tKeyVal_ParseRules        gTegra2Vid_KeyValueParser = {
49         NULL,
50         {
51                 {"Base", "P", &gTegra2Vid_PhysBase},
52                 {NULL, NULL, NULL}
53         }
54 };
55 // -- Driver state
56  int    giTegra2Vid_CurrentMode = 0;
57  int    giTegra2Vid_BufferMode;
58 size_t  giTegra2Vid_FramebufferSize;
59 Uint32  *gpTegra2Vid_IOMem;
60 tPAddr  gTegra2Vid_FramebufferPhys;
61 void    *gpTegra2Vid_Framebuffer;
62 void    *gpTegra2Vid_Cursor;
63 // -- Misc
64 tDrvUtil_Video_BufInfo  gTegra2Vid_DrvUtil_BufInfo;
65 tVideo_IOCtl_Pos        gTegra2Vid_CursorPos;
66
67 // === CODE ===
68 inline void _dumpreg(int i)
69 {
70         Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x (%s)", i, gpTegra2Vid_IOMem[i],
71                 (csaTegra2Vid_RegisterNames[i] ? csaTegra2Vid_RegisterNames[i] : "-"));
72 }
73 #define DUMPREGS(s,e)   do{for(int ii=(s);ii<=(e);ii++) _dumpreg(ii);}while(0)
74
75 void Tegra2Vid_int_DumpRegisters(void)
76 {
77         Log_Debug("Tegra2Vid", "Display CMD Registers");
78         DUMPREGS(0x000, 0x01A); // 00 -- 1A :: CMD (block 1)
79         DUMPREGS(0x028, 0x043); // 28 -- 43 :: CMD (block 2)
80         for( int i = 0x028; i <= 0x043; i ++ )  _dumpreg(i);
81         Log_Debug("Tegra2Vid", "Display COM Registers");
82         for( int i = 0x300; i <= 0x329; i ++ )  _dumpreg(i);
83         Log_Debug("Tegra2Vid", "Display DISP Registers");
84         for( int i = 0x400; i <= 0x446; i ++ )  _dumpreg(i);
85         for( int i = 0x480; i <= 0x484; i ++ )  _dumpreg(i);
86         for( int i = 0x4C0; i <= 0x4C1; i ++ )  _dumpreg(i);
87         Log_Debug("Tegra2Vid", "WINC_A Registers");
88         for( int i = 0x700; i <= 0x714; i ++ )  _dumpreg(i);
89         Log_Debug("Tegra2Vid", "WINBUF_A");
90         for( int i = 0x800; i <= 0x80A; i ++ )  _dumpreg(i);
91 }
92
93 /**
94  */
95 int Tegra2Vid_Install(char **Arguments)
96 {
97 //      return MODULE_ERR_NOTNEEDED;
98 //      KeyVal_Parse(&gTegra2Vid_KeyValueParser, Arguments);
99
100         gpTegra2Vid_IOMem = (void*)MM_MapHWPages(gTegra2Vid_PhysBase, 256/4);
101
102         #if DUMP_REGISTERS
103 //      Tegra2Vid_int_DumpRegisters();
104         #endif
105
106         // HACK!!!
107 #if 0
108         {
109                 int     w = 1680, h = 1050;
110                 gpTegra2Vid_IOMem[DC_DISP_DISP_ACTIVE_0] = (h << 16) | w;
111                 gpTegra2Vid_IOMem[DC_WIN_A_SIZE_0] = (h << 16) | w;
112                 gpTegra2Vid_IOMem[DC_WIN_A_PRESCALED_SIZE_0] = (h << 16) | w;
113         }
114 #endif
115
116 #if 0
117         // Map the original framebuffer into memory and write to it (tests the original state)
118         giTegra2Vid_FramebufferSize =
119                 (gpTegra2Vid_IOMem[DC_WIN_A_SIZE_0]&0xFFFF)
120                 *(gpTegra2Vid_IOMem[DC_WIN_A_SIZE_0]>>16)*4;
121
122         Log_Debug("Tegra2Vid", "giTegra2Vid_FramebufferSize = 0x%x", giTegra2Vid_FramebufferSize);
123         gpTegra2Vid_Framebuffer = (void*)MM_MapHWPages(
124                 gpTegra2Vid_IOMem[DC_WINBUF_A_START_ADDR_0],
125                 (giTegra2Vid_FramebufferSize+PAGE_SIZE-1)/PAGE_SIZE
126                 );
127         Log_Debug("Tegra2Vid", "gpTegra2Vid_Framebuffer = %p", gpTegra2Vid_Framebuffer);
128         memset(gpTegra2Vid_Framebuffer, 0xFF, giTegra2Vid_FramebufferSize);
129 #endif
130
131 #if 0
132         gpTegra2Vid_IOMem[DC_WIN_A_WIN_OPTIONS_0] = (1 << 30);
133         gpTegra2Vid_IOMem[DC_WIN_A_COLOR_DEPTH_0] = 12; // Could be 13 (BGR/RGB)
134         gpTegra2Vid_IOMem[DC_WIN_A_PRESCALED_SIZE_0] = gpTegra2Vid_IOMem[DC_WIN_A_SIZE_0];
135         gpTegra2Vid_IOMem[DC_WIN_A_LINE_STRIDE_0] =
136                 gTegra2Vid_DrvUtil_BufInfo.Pitch =
137                 1680*4;
138         gTegra2Vid_DrvUtil_BufInfo.Depth = 32;
139         gTegra2Vid_DrvUtil_BufInfo.Width = 1680;
140         gTegra2Vid_DrvUtil_BufInfo.Height = 1050;
141         gpTegra2Vid_IOMem[DC_CMD_STATE_CONTROL_0] = WIN_A_ACT_REQ;
142 #elif 0
143         gpTegra2Vid_IOMem[DC_WIN_A_COLOR_DEPTH_0] = 13; // Could be 13 (BGR/RGB)
144         gpTegra2Vid_IOMem[DC_WIN_A_LINE_STRIDE_0] =
145                 gTegra2Vid_DrvUtil_BufInfo.Pitch = 1024*4;
146         gTegra2Vid_DrvUtil_BufInfo.Depth = 32;
147         gTegra2Vid_DrvUtil_BufInfo.Width = 1024;
148         gTegra2Vid_DrvUtil_BufInfo.Height = 768;
149         gTegra2Vid_DrvUtil_BufInfo.Framebuffer = gpTegra2Vid_Framebuffer;
150         gpTegra2Vid_IOMem[DC_CMD_STATE_CONTROL_0] = WIN_A_ACT_REQ;
151 #endif
152
153         gpTegra2Vid_Cursor = (void*)MM_AllocDMA(1, 26, NULL);
154         Log_Debug("Tegra2Vid", "gpTegra2Vid_Cursor = %p", gpTegra2Vid_Cursor);
155
156         Tegra2Vid_int_SetMode(0);
157
158         DevFS_AddDevice( &gTegra2Vid_DriverStruct );
159
160         return 0;
161 }
162
163 /**
164  * \brief Clean up resources for driver unloading
165  */
166 void Tegra2Vid_Uninstall()
167 {
168 }
169
170 /**
171  * \brief Read from the framebuffer
172  */
173 size_t Tegra2Vid_Read(tVFS_Node *node, off_t off, size_t len, void *buffer, Uint Flags)
174 {
175         return 0;
176 }
177
178 /**
179  * \brief Write to the framebuffer
180  */
181 size_t Tegra2Vid_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer, Uint Flags)
182 {
183         gTegra2Vid_DrvUtil_BufInfo.BufferFormat = giTegra2Vid_BufferMode;
184         return DrvUtil_Video_WriteLFB(&gTegra2Vid_DrvUtil_BufInfo, Offset, Length, Buffer);
185 }
186
187 const char *csaTegra2Vid_IOCtls[] = {DRV_IOCTLNAMES, DRV_VIDEO_IOCTLNAMES, NULL};
188
189 /**
190  * \brief Handle messages to the device
191  */
192 int Tegra2Vid_IOCtl(tVFS_Node *Node, int ID, void *Data)
193 {
194          int    ret = -2;
195         ENTER("pNode iID pData", Node, ID, Data);
196         
197         switch(ID)
198         {
199         BASE_IOCTLS(DRV_TYPE_VIDEO, "PL110", VERSION, csaTegra2Vid_IOCtls);
200
201         case VIDEO_IOCTL_SETBUFFORMAT:
202                 DrvUtil_Video_RemoveCursor( &gTegra2Vid_DrvUtil_BufInfo );
203                 ret = giTegra2Vid_BufferMode;
204                 if(Data)        giTegra2Vid_BufferMode = *(int*)Data;
205                 if(gTegra2Vid_DrvUtil_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)
206                         DrvUtil_Video_SetCursor( &gTegra2Vid_DrvUtil_BufInfo, &gDrvUtil_TextModeCursor );
207                 break;
208         
209         case VIDEO_IOCTL_GETSETMODE:
210                 if(Data)
211                 {
212                          int    newMode;
213                         
214                         if( !CheckMem(Data, sizeof(int)) )
215                                 LEAVE_RET('i', -1);
216                         
217                         newMode = *(int*)Data;
218                         
219                         if(newMode < 0 || newMode >= ciTegra2Vid_ModeCount)
220                                 LEAVE_RET('i', -1);
221
222                         if(newMode != giTegra2Vid_CurrentMode)
223                         {
224                                 giTegra2Vid_CurrentMode = newMode;
225                                 Tegra2Vid_int_SetMode( newMode );
226                         }
227                 }
228                 ret = giTegra2Vid_CurrentMode;
229                 break;
230         
231         case VIDEO_IOCTL_FINDMODE:
232                 {
233                 tVideo_IOCtl_Mode *mode = Data;
234                  int    closest=0, closestArea, reqArea = 0;
235                 if(!Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Mode)))
236                         LEAVE_RET('i', -1);
237                 if( mode->bpp != 32 )
238                         LEAVE_RET('i', 0);
239                 if( mode->flags != 0 )
240                         LEAVE_RET('i', 0);
241
242                 // DEBUG!!!
243                 mode->id = 1;   mode->width = 1680;     mode->height = 1050;
244                 mode->id = 0;   mode->width = 1024;     mode->height = 768;
245
246                 // DEBUG!
247                 for( int i = 0x800; i <= 0x80A; i ++ )  _dumpreg(i);
248                 break;
249
250                 ret = 0;
251
252                 for( int i = 0; i < ciTegra2Vid_ModeCount; i ++ )
253                 {
254                          int    area;
255                         if(mode->width == caTegra2Vid_Modes[i].W
256                         && mode->height == caTegra2Vid_Modes[i].H) {
257                                 mode->id = i;
258                                 ret = 1;
259                                 break;
260                         }
261                         
262                         area = caTegra2Vid_Modes[i].W * caTegra2Vid_Modes[i].H;
263                         if(!reqArea) {
264                                 reqArea = mode->width * mode->height;
265                                 closest = i;
266                                 closestArea = area;
267                         }
268                         else if( ABS(area - reqArea) < ABS(closestArea - reqArea) ) {
269                                 closest = i;
270                                 closestArea = area;
271                         }
272                 }
273                 
274                 if( ret == 0 )
275                 {
276                         mode->id = closest;
277                         ret = 1;
278                 }
279                 mode->width = caTegra2Vid_Modes[mode->id].W;
280                 mode->height = caTegra2Vid_Modes[mode->id].H;
281                 break;
282                 }
283         
284         case VIDEO_IOCTL_MODEINFO:
285                 {
286                 tVideo_IOCtl_Mode *mode = Data;
287                 if(!Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Mode)))
288                         LEAVE_RET('i', -1);
289                 if(mode->id < 0 || mode->id >= ciTegra2Vid_ModeCount)
290                         LEAVE_RET('i', 0);
291                 
292
293                 mode->bpp = 32;
294                 mode->flags = 0;
295                 mode->width = caTegra2Vid_Modes[mode->id].W;
296                 mode->height = caTegra2Vid_Modes[mode->id].H;
297
298                 ret = 1;
299                 break;
300                 }
301         
302         case VIDEO_IOCTL_SETCURSOR:
303                 if( !Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Pos)) )
304                         LEAVE_RET('i', -1);
305
306                 DrvUtil_Video_RemoveCursor( &gTegra2Vid_DrvUtil_BufInfo );
307                 
308                 gTegra2Vid_CursorPos = *(tVideo_IOCtl_Pos*)Data;
309                 // TODO: Set DC_DISP_CURSOR_POSITION_0
310                 // TODO: Set DC_DISP_CURSOR_FOREGROUND_0 etc from image?
311                 if(gTegra2Vid_DrvUtil_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)
312                         DrvUtil_Video_DrawCursor(
313                                 &gTegra2Vid_DrvUtil_BufInfo,
314                                 gTegra2Vid_CursorPos.x*giVT_CharWidth,
315                                 gTegra2Vid_CursorPos.y*giVT_CharHeight
316                                 );
317                 else
318                         DrvUtil_Video_DrawCursor(
319                                 &gTegra2Vid_DrvUtil_BufInfo,
320                                 gTegra2Vid_CursorPos.x,
321                                 gTegra2Vid_CursorPos.y
322                                 );
323                 break;
324         
325         default:
326                 LEAVE('i', -2);
327                 return -2;
328         }
329         
330         LEAVE('i', ret);
331         return ret;
332 }
333
334 //
335 //
336 //
337
338 int Tegra2Vid_int_SetMode(int Mode)
339 {
340         const struct sTegra2_Disp_Mode  *mode = &caTegra2Vid_Modes[Mode];
341          int    w = mode->W, h = mode->H;       // Horizontal/Vertical Active
342         gpTegra2Vid_IOMem[DC_DISP_REF_TO_SYNC_0] = (1 << 16) | 11;      // TODO: <--
343         gpTegra2Vid_IOMem[DC_DISP_SYNC_WIDTH_0]  = (mode->HS << 16)  | mode->HS;
344         gpTegra2Vid_IOMem[DC_DISP_BACK_PORCH_0]  = (mode->VBP << 16) | mode->HBP;
345         gpTegra2Vid_IOMem[DC_DISP_DISP_ACTIVE_0] = (mode->H << 16)   | mode->W;
346         gpTegra2Vid_IOMem[DC_DISP_FRONT_PORCH_0] = (mode->VFP << 16) | mode->HFP; 
347
348         gpTegra2Vid_IOMem[DC_DISP_DISP_COLOR_CONTROL_0] = 0x8;  // BASE888 - TODO: useful?
349         gpTegra2Vid_IOMem[DC_WIN_A_POSITION_0] = 0;
350         gpTegra2Vid_IOMem[DC_WIN_A_SIZE_0] = (h << 16) | w;
351         gpTegra2Vid_IOMem[DC_WIN_A_COLOR_DEPTH_0] = 12; // Could be 13 (BGR/RGB)
352         gpTegra2Vid_IOMem[DC_WIN_A_PRESCALED_SIZE_0] = (h << 16) | w;
353         gpTegra2Vid_IOMem[DC_WIN_A_LINE_STRIDE_0] = w * 4;
354         gpTegra2Vid_IOMem[DC_WIN_A_DV_CONTROL_0] = 0;
355         
356         gpTegra2Vid_IOMem[DC_DISP_BORDER_COLOR_0] = 0x70F010;
357
358         Log_Debug("Tegra2Vid", "Mode %i (%ix%i) selected", Mode, w, h);
359
360         if( !gpTegra2Vid_Framebuffer || w*h*4 != giTegra2Vid_FramebufferSize )
361         {
362                 if( gpTegra2Vid_Framebuffer )
363                 {
364                         // TODO: Free framebuffer for reallocation
365                         Log_Error("Tegra2Vid", "TODO: Free existing framebuffer");
366                 }
367
368                 giTegra2Vid_FramebufferSize = w*h*4;            
369
370                 // Uses RAM I think
371                 gpTegra2Vid_Framebuffer = (void*)MM_AllocDMA(
372                         (giTegra2Vid_FramebufferSize + PAGE_SIZE-1) / PAGE_SIZE,
373                         32,
374                         &gTegra2Vid_FramebufferPhys
375                         );
376                 if( !gpTegra2Vid_Framebuffer ) {
377                         Log_Error("Tegra2Vid", "Can't allocate pages for 0x%x byte framebuffer",
378                                 giTegra2Vid_FramebufferSize);
379                         return -1;
380                 }
381                 Log_Debug("Tegra2Vid", "0x%x byte framebuffer at %p (%P phys)",
382                                 giTegra2Vid_FramebufferSize,
383                                 gpTegra2Vid_Framebuffer,
384                                 gTegra2Vid_FramebufferPhys
385                                 );
386                 
387                 // Tell hardware
388                 gpTegra2Vid_IOMem[DC_WINBUF_A_START_ADDR_0] = gTegra2Vid_FramebufferPhys;
389                 gpTegra2Vid_IOMem[DC_WINBUF_A_ADDR_V_OFFSET_0] = 0;     // Y offset
390                 gpTegra2Vid_IOMem[DC_WINBUF_A_ADDR_H_OFFSET_0] = 0;     // X offset
391         }
392
393         gpTegra2Vid_IOMem[DC_CMD_STATE_CONTROL_0] = WIN_A_ACT_REQ;
394         gpTegra2Vid_IOMem[DC_CMD_STATE_CONTROL_0] = GEN_ACT_REQ;
395         
396         // DEBUG!
397         for( int i = 0x800; i <= 0x80A; i ++ )  _dumpreg(i);
398         
399         return 0;
400 }

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