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

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