6 #define DUMP_REGISTERS 1
7 #define VERSION ((0<<8)|10)
14 #include <api_drv_video.h>
15 #include <lib/keyvalue.h>
16 #include <options.h> // ARM Arch
19 #define ABS(a) ((a)>0?(a):-(a))
23 int Tegra2Vid_Install(char **Arguments);
24 void Tegra2Vid_Uninstall();
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);
31 int Tegra2Vid_int_SetMode(int Mode);
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
40 tDevFS_Driver gTegra2Vid_DriverStruct = {
42 {.Type = &gTegra2Vid_NodeType}
45 tPAddr gTegra2Vid_PhysBase = TEGRA2VID_BASE;
46 int gbTegra2Vid_IsVersatile = 1;
47 // -- KeyVal parse rules
48 const tKeyVal_ParseRules gTegra2Vid_KeyValueParser = {
51 {"Base", "P", &gTegra2Vid_PhysBase},
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;
64 tDrvUtil_Video_BufInfo gTegra2Vid_DrvUtil_BufInfo;
65 tVideo_IOCtl_Pos gTegra2Vid_CursorPos;
68 inline void _dumpreg(int i)
70 Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x (%s)", i, gpTegra2Vid_IOMem[i],
71 (csaTegra2Vid_RegisterNames[i] ? csaTegra2Vid_RegisterNames[i] : "-"));
73 #define DUMPREGS(s,e) do{for(int ii=(s);ii<=(e);ii++) _dumpreg(ii);}while(0)
75 void Tegra2Vid_int_DumpRegisters(void)
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);
95 int Tegra2Vid_Install(char **Arguments)
97 // return MODULE_ERR_NOTNEEDED;
98 // KeyVal_Parse(&gTegra2Vid_KeyValueParser, Arguments);
100 gpTegra2Vid_IOMem = (void*)MM_MapHWPages(gTegra2Vid_PhysBase, 256/4);
103 // Tegra2Vid_int_DumpRegisters();
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;
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;
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
127 Log_Debug("Tegra2Vid", "gpTegra2Vid_Framebuffer = %p", gpTegra2Vid_Framebuffer);
128 memset(gpTegra2Vid_Framebuffer, 0xFF, giTegra2Vid_FramebufferSize);
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 =
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;
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;
153 gpTegra2Vid_Cursor = (void*)MM_AllocDMA(1, 26, NULL);
154 Log_Debug("Tegra2Vid", "gpTegra2Vid_Cursor = %p", gpTegra2Vid_Cursor);
156 Tegra2Vid_int_SetMode(0);
158 DevFS_AddDevice( &gTegra2Vid_DriverStruct );
164 * \brief Clean up resources for driver unloading
166 void Tegra2Vid_Uninstall()
171 * \brief Read from the framebuffer
173 size_t Tegra2Vid_Read(tVFS_Node *node, off_t off, size_t len, void *buffer, Uint Flags)
179 * \brief Write to the framebuffer
181 size_t Tegra2Vid_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer, Uint Flags)
183 gTegra2Vid_DrvUtil_BufInfo.BufferFormat = giTegra2Vid_BufferMode;
184 return DrvUtil_Video_WriteLFB(&gTegra2Vid_DrvUtil_BufInfo, Offset, Length, Buffer);
187 const char *csaTegra2Vid_IOCtls[] = {DRV_IOCTLNAMES, DRV_VIDEO_IOCTLNAMES, NULL};
190 * \brief Handle messages to the device
192 int Tegra2Vid_IOCtl(tVFS_Node *Node, int ID, void *Data)
195 ENTER("pNode iID pData", Node, ID, Data);
199 BASE_IOCTLS(DRV_TYPE_VIDEO, "Tegra2", VERSION, csaTegra2Vid_IOCtls);
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 );
209 case VIDEO_IOCTL_GETSETMODE:
214 if( !CheckMem(Data, sizeof(int)) )
217 newMode = *(int*)Data;
219 if(newMode < 0 || newMode >= ciTegra2Vid_ModeCount)
222 if(newMode != giTegra2Vid_CurrentMode)
224 giTegra2Vid_CurrentMode = newMode;
225 Tegra2Vid_int_SetMode( newMode );
228 ret = giTegra2Vid_CurrentMode;
231 case VIDEO_IOCTL_FINDMODE:
233 tVideo_IOCtl_Mode *mode = Data;
234 int closest=0, closestArea, reqArea = 0;
235 if(!Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Mode)))
237 if( mode->bpp != 32 )
239 if( mode->flags != 0 )
243 mode->id = 1; mode->width = 1680; mode->height = 1050;
244 mode->id = 0; mode->width = 1024; mode->height = 768;
247 for( int i = 0x800; i <= 0x80A; i ++ ) _dumpreg(i);
252 for( int i = 0; i < ciTegra2Vid_ModeCount; i ++ )
255 if(mode->width == caTegra2Vid_Modes[i].W
256 && mode->height == caTegra2Vid_Modes[i].H) {
262 area = caTegra2Vid_Modes[i].W * caTegra2Vid_Modes[i].H;
264 reqArea = mode->width * mode->height;
268 else if( ABS(area - reqArea) < ABS(closestArea - reqArea) ) {
279 mode->width = caTegra2Vid_Modes[mode->id].W;
280 mode->height = caTegra2Vid_Modes[mode->id].H;
284 case VIDEO_IOCTL_MODEINFO:
286 tVideo_IOCtl_Mode *mode = Data;
287 if(!Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Mode)))
289 if(mode->id < 0 || mode->id >= ciTegra2Vid_ModeCount)
295 mode->width = caTegra2Vid_Modes[mode->id].W;
296 mode->height = caTegra2Vid_Modes[mode->id].H;
302 case VIDEO_IOCTL_SETCURSOR:
303 if( !Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Pos)) )
306 DrvUtil_Video_RemoveCursor( &gTegra2Vid_DrvUtil_BufInfo );
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
318 DrvUtil_Video_DrawCursor(
319 &gTegra2Vid_DrvUtil_BufInfo,
320 gTegra2Vid_CursorPos.x,
321 gTegra2Vid_CursorPos.y
338 int Tegra2Vid_int_SetMode(int Mode)
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;
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;
356 gpTegra2Vid_IOMem[DC_DISP_BORDER_COLOR_0] = 0x70F010;
358 Log_Debug("Tegra2Vid", "Mode %i (%ix%i) selected", Mode, w, h);
360 if( !gpTegra2Vid_Framebuffer || w*h*4 != giTegra2Vid_FramebufferSize )
362 if( gpTegra2Vid_Framebuffer )
364 // TODO: Free framebuffer for reallocation
365 Log_Error("Tegra2Vid", "TODO: Free existing framebuffer");
368 giTegra2Vid_FramebufferSize = w*h*4;
371 gpTegra2Vid_Framebuffer = (void*)MM_AllocDMA(
372 (giTegra2Vid_FramebufferSize + PAGE_SIZE-1) / PAGE_SIZE,
374 &gTegra2Vid_FramebufferPhys
376 if( !gpTegra2Vid_Framebuffer ) {
377 Log_Error("Tegra2Vid", "Can't allocate pages for 0x%x byte framebuffer",
378 giTegra2Vid_FramebufferSize);
381 Log_Debug("Tegra2Vid", "0x%x byte framebuffer at %p (%P phys)",
382 giTegra2Vid_FramebufferSize,
383 gpTegra2Vid_Framebuffer,
384 gTegra2Vid_FramebufferPhys
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
393 gpTegra2Vid_IOMem[DC_CMD_STATE_CONTROL_0] = WIN_A_ACT_REQ;
394 gpTegra2Vid_IOMem[DC_CMD_STATE_CONTROL_0] = GEN_ACT_REQ;
397 for( int i = 0x800; i <= 0x80A; i ++ ) _dumpreg(i);