Merge branch 'master' of git.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 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 #if 0
120         gpTegra2Vid_IOMem[DC_WIN_A_WIN_OPTIONS_0] = (1 << 30);
121         gpTegra2Vid_IOMem[DC_WIN_A_COLOR_DEPTH_0] = 12; // Could be 13 (BGR/RGB)
122         gpTegra2Vid_IOMem[DC_WIN_A_PRESCALED_SIZE_0] = gpTegra2Vid_IOMem[DC_WIN_A_SIZE_0];
123         gpTegra2Vid_IOMem[DC_WIN_A_LINE_STRIDE_0] =
124                 gTegra2Vid_DrvUtil_BufInfo.Pitch =
125                 1680*4;
126         gTegra2Vid_DrvUtil_BufInfo.Depth = 32;
127         gTegra2Vid_DrvUtil_BufInfo.Width = 1680;
128         gTegra2Vid_DrvUtil_BufInfo.Height = 1050;
129 #else
130         gpTegra2Vid_IOMem[DC_WIN_A_COLOR_DEPTH_0] = 13; // Could be 13 (BGR/RGB)
131         gpTegra2Vid_IOMem[DC_WIN_A_LINE_STRIDE_0] =
132                 gTegra2Vid_DrvUtil_BufInfo.Pitch = 1024*4;
133         gTegra2Vid_DrvUtil_BufInfo.Depth = 32;
134         gTegra2Vid_DrvUtil_BufInfo.Width = 1024;
135         gTegra2Vid_DrvUtil_BufInfo.Height = 768;
136         gTegra2Vid_DrvUtil_BufInfo.Framebuffer = gpTegra2Vid_Framebuffer;
137 #endif
138         gpTegra2Vid_IOMem[DC_CMD_STATE_CONTROL_0] = WIN_A_ACT_REQ;
139
140
141 //      Tegra2Vid_int_SetMode(4);
142
143         DevFS_AddDevice( &gTegra2Vid_DriverStruct );
144
145         return 0;
146 }
147
148 /**
149  * \brief Clean up resources for driver unloading
150  */
151 void Tegra2Vid_Uninstall()
152 {
153 }
154
155 /**
156  * \brief Read from the framebuffer
157  */
158 size_t Tegra2Vid_Read(tVFS_Node *node, off_t off, size_t len, void *buffer)
159 {
160         return 0;
161 }
162
163 /**
164  * \brief Write to the framebuffer
165  */
166 size_t Tegra2Vid_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer)
167 {
168         gTegra2Vid_DrvUtil_BufInfo.BufferFormat = giTegra2Vid_BufferMode;
169         return DrvUtil_Video_WriteLFB(&gTegra2Vid_DrvUtil_BufInfo, Offset, Length, Buffer);
170 }
171
172 const char *csaTegra2Vid_IOCtls[] = {DRV_IOCTLNAMES, DRV_VIDEO_IOCTLNAMES, NULL};
173
174 /**
175  * \brief Handle messages to the device
176  */
177 int Tegra2Vid_IOCtl(tVFS_Node *Node, int ID, void *Data)
178 {
179          int    ret = -2;
180         ENTER("pNode iID pData", Node, ID, Data);
181         
182         switch(ID)
183         {
184         BASE_IOCTLS(DRV_TYPE_VIDEO, "PL110", VERSION, csaTegra2Vid_IOCtls);
185
186         case VIDEO_IOCTL_SETBUFFORMAT:
187                 DrvUtil_Video_RemoveCursor( &gTegra2Vid_DrvUtil_BufInfo );
188                 ret = giTegra2Vid_BufferMode;
189                 if(Data)        giTegra2Vid_BufferMode = *(int*)Data;
190                 if(gTegra2Vid_DrvUtil_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)
191                         DrvUtil_Video_SetCursor( &gTegra2Vid_DrvUtil_BufInfo, &gDrvUtil_TextModeCursor );
192                 break;
193         
194         case VIDEO_IOCTL_GETSETMODE:
195                 if(Data)
196                 {
197                          int    newMode;
198                         
199                         if( !CheckMem(Data, sizeof(int)) )
200                                 LEAVE_RET('i', -1);
201                         
202                         newMode = *(int*)Data;
203                         
204                         if(newMode < 0 || newMode >= ciTegra2Vid_ModeCount)
205                                 LEAVE_RET('i', -1);
206
207                         if(newMode != giTegra2Vid_CurrentMode)
208                         {
209                                 giTegra2Vid_CurrentMode = newMode;
210                                 Tegra2Vid_int_SetMode( newMode );
211                         }
212                 }
213                 ret = giTegra2Vid_CurrentMode;
214                 break;
215         
216         case VIDEO_IOCTL_FINDMODE:
217                 {
218                 tVideo_IOCtl_Mode *mode = Data;
219                  int    closest=0, closestArea, reqArea = 0;
220                 if(!Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Mode)))
221                         LEAVE_RET('i', -1);
222                 if( mode->bpp != 32 )
223                         LEAVE_RET('i', 0);
224                 if( mode->flags != 0 )
225                         LEAVE_RET('i', 0);
226
227                 // DEBUG!!!
228                 mode->width = 1024;
229                 mode->height = 768;
230                 break;
231
232                 ret = 0;
233
234                 for( int i = 0; i < ciTegra2Vid_ModeCount; i ++ )
235                 {
236                          int    area;
237                         if(mode->width == caTegra2Vid_Modes[i].W && mode->height == caTegra2Vid_Modes[i].H) {
238                                 mode->id = i;
239                                 ret = 1;
240                                 break;
241                         }
242                         
243                         area = caTegra2Vid_Modes[i].W * caTegra2Vid_Modes[i].H;
244                         if(!reqArea) {
245                                 reqArea = mode->width * mode->height;
246                                 closest = i;
247                                 closestArea = area;
248                         }
249                         else if( ABS(area - reqArea) < ABS(closestArea - reqArea) ) {
250                                 closest = i;
251                                 closestArea = area;
252                         }
253                 }
254                 
255                 if( ret == 0 )
256                 {
257                         mode->id = closest;
258                         ret = 1;
259                 }
260                 mode->width = caTegra2Vid_Modes[mode->id].W;
261                 mode->height = caTegra2Vid_Modes[mode->id].H;
262                 break;
263                 }
264         
265         case VIDEO_IOCTL_MODEINFO:
266                 {
267                 tVideo_IOCtl_Mode *mode = Data;
268                 if(!Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Mode)))
269                         LEAVE_RET('i', -1);
270                 if(mode->id < 0 || mode->id >= ciTegra2Vid_ModeCount)
271                         LEAVE_RET('i', 0);
272                 
273
274                 mode->bpp = 32;
275                 mode->flags = 0;
276                 mode->width = caTegra2Vid_Modes[mode->id].W;
277                 mode->height = caTegra2Vid_Modes[mode->id].H;
278
279                 ret = 1;
280                 break;
281                 }
282         
283         case VIDEO_IOCTL_SETCURSOR:
284                 if( !Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Pos)) )
285                         LEAVE_RET('i', -1);
286
287                 DrvUtil_Video_RemoveCursor( &gTegra2Vid_DrvUtil_BufInfo );
288                 
289                 gTegra2Vid_CursorPos = *(tVideo_IOCtl_Pos*)Data;
290                 if(gTegra2Vid_DrvUtil_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)
291                         DrvUtil_Video_DrawCursor(
292                                 &gTegra2Vid_DrvUtil_BufInfo,
293                                 gTegra2Vid_CursorPos.x*giVT_CharWidth,
294                                 gTegra2Vid_CursorPos.y*giVT_CharHeight
295                                 );
296                 else
297                         DrvUtil_Video_DrawCursor(
298                                 &gTegra2Vid_DrvUtil_BufInfo,
299                                 gTegra2Vid_CursorPos.x,
300                                 gTegra2Vid_CursorPos.y
301                                 );
302                 break;
303         
304         default:
305                 LEAVE('i', -2);
306                 return -2;
307         }
308         
309         LEAVE('i', ret);
310         return ret;
311 }
312
313 //
314 //
315 //
316
317 int Tegra2Vid_int_SetMode(int Mode)
318 {
319         const struct sTegra2_Disp_Mode  *mode = &caTegra2Vid_Modes[Mode];
320          int    w = mode->W, h = mode->H;       // Horizontal/Vertical Active
321         gpTegra2Vid_IOMem[DC_DISP_FRONT_PORCH_0] = (mode->VFP << 16) | mode->HFP; 
322         gpTegra2Vid_IOMem[DC_DISP_SYNC_WIDTH_0]  = (mode->HS << 16)  | mode->HS;
323         gpTegra2Vid_IOMem[DC_DISP_BACK_PORCH_0]  = (mode->VBP << 16) | mode->HBP;
324         gpTegra2Vid_IOMem[DC_DISP_DISP_ACTIVE_0] = (mode->H << 16)   | mode->W;
325
326         gpTegra2Vid_IOMem[DC_WIN_A_POSITION_0] = 0;
327         gpTegra2Vid_IOMem[DC_WIN_A_SIZE_0] = (h << 16) | w;
328         gpTegra2Vid_IOMem[DC_DISP_DISP_COLOR_CONTROL_0] = 0x8;  // BASE888
329         gpTegra2Vid_IOMem[DC_WIN_A_COLOR_DEPTH_0] = 12; // Could be 13 (BGR/RGB)
330         gpTegra2Vid_IOMem[DC_WIN_A_PRESCALED_SIZE_0] = (h << 16) | w;
331
332         Log_Debug("Tegra2Vid", "Mode %i (%ix%i) selected", Mode, w, h);
333
334         if( !gpTegra2Vid_Framebuffer || w*h*4 != giTegra2Vid_FramebufferSize )
335         {
336                 if( gpTegra2Vid_Framebuffer )
337                 {
338                         // TODO: Free framebuffer for reallocation
339                 }
340
341                 giTegra2Vid_FramebufferSize = w*h*4;            
342
343                 // TODO: Does this need RAM or unmapped space?
344                 gpTegra2Vid_Framebuffer = (void*)MM_AllocDMA(
345                         (giTegra2Vid_FramebufferSize + PAGE_SIZE-1) / PAGE_SIZE,
346                         32,
347                         &gTegra2Vid_FramebufferPhys
348                         );
349                 // TODO: Catch allocation failures
350                 Log_Debug("Tegra2Vid", "0x%x byte framebuffer at %p (%P phys)",
351                                 giTegra2Vid_FramebufferSize,
352                                 gpTegra2Vid_Framebuffer,
353                                 gTegra2Vid_FramebufferPhys
354                                 );
355                 
356                 // Tell hardware
357                 gpTegra2Vid_IOMem[DC_WINBUF_A_START_ADDR_0] = gTegra2Vid_FramebufferPhys;
358                 gpTegra2Vid_IOMem[DC_WINBUF_A_ADDR_V_OFFSET_0] = 0;     // Y offset
359                 gpTegra2Vid_IOMem[DC_WINBUF_A_ADDR_H_OFFSET_0] = 0;     // X offset
360         }
361
362         gpTegra2Vid_IOMem[DC_CMD_STATE_CONTROL_0] = WIN_A_ACT_REQ;
363         
364         return 0;
365 }

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