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

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