6 #define VERSION ((0<<8)|10)
13 #include <api_drv_video.h>
14 #include <lib/keyvalue.h>
15 #include <options.h> // ARM Arch
18 #define ABS(a) ((a)>0?(a):-(a))
22 int Tegra2Vid_Install(char **Arguments);
23 void Tegra2Vid_Uninstall();
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);
30 int Tegra2Vid_int_SetMode(int Mode);
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
39 tDevFS_Driver gTegra2Vid_DriverStruct = {
41 {.Type = &gTegra2Vid_NodeType}
44 tPAddr gTegra2Vid_PhysBase = TEGRA2VID_BASE;
45 int gbTegra2Vid_IsVersatile = 1;
46 // -- KeyVal parse rules
47 const tKeyVal_ParseRules gTegra2Vid_KeyValueParser = {
50 {"Base", "P", &gTegra2Vid_PhysBase},
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;
62 tDrvUtil_Video_BufInfo gTegra2Vid_DrvUtil_BufInfo;
63 tVideo_IOCtl_Pos gTegra2Vid_CursorPos;
68 int Tegra2Vid_Install(char **Arguments)
70 // return MODULE_ERR_NOTNEEDED;
71 // KeyVal_Parse(&gTegra2Vid_KeyValueParser, Arguments);
73 gpTegra2Vid_IOMem = (void*)MM_MapHWPages(gTegra2Vid_PhysBase, 256/4);
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]);
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]);
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;
112 giTegra2Vid_FramebufferSize =
113 (gpTegra2Vid_IOMem[DC_WIN_A_SIZE_0]&0xFFFF)
114 *(gpTegra2Vid_IOMem[DC_WIN_A_SIZE_0]>>16)*4;
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
121 memset(gpTegra2Vid_Framebuffer, 0xFF, 0x1000);
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;
132 // Tegra2Vid_int_SetMode(4);
134 DevFS_AddDevice( &gTegra2Vid_DriverStruct );
140 * \brief Clean up resources for driver unloading
142 void Tegra2Vid_Uninstall()
147 * \brief Read from the framebuffer
149 size_t Tegra2Vid_Read(tVFS_Node *node, off_t off, size_t len, void *buffer)
155 * \brief Write to the framebuffer
157 size_t Tegra2Vid_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer)
159 gTegra2Vid_DrvUtil_BufInfo.BufferFormat = giTegra2Vid_BufferMode;
160 return DrvUtil_Video_WriteLFB(&gTegra2Vid_DrvUtil_BufInfo, Offset, Length, Buffer);
163 const char *csaTegra2Vid_IOCtls[] = {DRV_IOCTLNAMES, DRV_VIDEO_IOCTLNAMES, NULL};
166 * \brief Handle messages to the device
168 int Tegra2Vid_IOCtl(tVFS_Node *Node, int ID, void *Data)
171 ENTER("pNode iID pData", Node, ID, Data);
175 BASE_IOCTLS(DRV_TYPE_VIDEO, "PL110", VERSION, csaTegra2Vid_IOCtls);
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 );
185 case VIDEO_IOCTL_GETSETMODE:
190 if( !CheckMem(Data, sizeof(int)) )
193 newMode = *(int*)Data;
195 if(newMode < 0 || newMode >= ciTegra2Vid_ModeCount)
198 if(newMode != giTegra2Vid_CurrentMode)
200 giTegra2Vid_CurrentMode = newMode;
201 Tegra2Vid_int_SetMode( newMode );
204 ret = giTegra2Vid_CurrentMode;
207 case VIDEO_IOCTL_FINDMODE:
209 tVideo_IOCtl_Mode *mode = Data;
210 int closest=0, closestArea, reqArea = 0;
211 if(!Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Mode)))
213 if( mode->bpp != 32 )
215 if( mode->flags != 0 )
225 for( int i = 0; i < ciTegra2Vid_ModeCount; i ++ )
228 if(mode->width == caTegra2Vid_Modes[i].W && mode->height == caTegra2Vid_Modes[i].H) {
234 area = caTegra2Vid_Modes[i].W * caTegra2Vid_Modes[i].H;
236 reqArea = mode->width * mode->height;
240 else if( ABS(area - reqArea) < ABS(closestArea - reqArea) ) {
251 mode->width = caTegra2Vid_Modes[mode->id].W;
252 mode->height = caTegra2Vid_Modes[mode->id].H;
256 case VIDEO_IOCTL_MODEINFO:
258 tVideo_IOCtl_Mode *mode = Data;
259 if(!Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Mode)))
261 if(mode->id < 0 || mode->id >= ciTegra2Vid_ModeCount)
267 mode->width = caTegra2Vid_Modes[mode->id].W;
268 mode->height = caTegra2Vid_Modes[mode->id].H;
274 case VIDEO_IOCTL_SETCURSOR:
275 if( !Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Pos)) )
278 DrvUtil_Video_RemoveCursor( &gTegra2Vid_DrvUtil_BufInfo );
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
288 DrvUtil_Video_DrawCursor(
289 &gTegra2Vid_DrvUtil_BufInfo,
290 gTegra2Vid_CursorPos.x,
291 gTegra2Vid_CursorPos.y
308 int Tegra2Vid_int_SetMode(int Mode)
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;
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;
323 Log_Debug("Tegra2Vid", "Mode %i (%ix%i) selected", Mode, w, h);
325 if( !gpTegra2Vid_Framebuffer || w*h*4 != giTegra2Vid_FramebufferSize )
327 if( gpTegra2Vid_Framebuffer )
329 // TODO: Free framebuffer for reallocation
332 giTegra2Vid_FramebufferSize = w*h*4;
334 gpTegra2Vid_Framebuffer = (void*)MM_AllocDMA(
335 (giTegra2Vid_FramebufferSize + PAGE_SIZE-1) / PAGE_SIZE,
337 &gTegra2Vid_FramebufferPhys
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
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