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

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