6 #define VERSION ((0<<8)|10)
\r
11 #include <fs_devfs.h>
\r
12 #include <drv_pci.h>
\r
13 #include <api_drv_video.h>
\r
14 #include <lib/keyvalue.h>
\r
15 #include <options.h> // ARM Arch
\r
18 #define ABS(a) ((a)>0?(a):-(a))
\r
20 // === PROTOTYPES ===
\r
22 int Tegra2Vid_Install(char **Arguments);
\r
23 void Tegra2Vid_Uninstall();
\r
26 Uint64 Tegra2Vid_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer);
\r
27 Uint64 Tegra2Vid_Write(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer);
\r
28 int Tegra2Vid_IOCtl(tVFS_Node *node, int id, void *data);
\r
30 int Tegra2Vid_int_SetMode(int Mode);
\r
33 MODULE_DEFINE(0, VERSION, Tegra2Vid, Tegra2Vid_Install, NULL, NULL);
\r
34 tDevFS_Driver gTegra2Vid_DriverStruct = {
\r
37 .Read = Tegra2Vid_Read,
\r
38 .Write = Tegra2Vid_Write,
\r
39 .IOCtl = Tegra2Vid_IOCtl
\r
43 tPAddr gTegra2Vid_PhysBase = TEGRA2VID_BASE;
\r
44 int gbTegra2Vid_IsVersatile = 1;
\r
45 // -- KeyVal parse rules
\r
46 const tKeyVal_ParseRules gTegra2Vid_KeyValueParser = {
\r
49 {"Base", "P", &gTegra2Vid_PhysBase},
\r
54 int giTegra2Vid_CurrentMode = 0;
\r
55 int giTegra2Vid_BufferMode;
\r
56 size_t giTegra2Vid_FramebufferSize;
\r
57 Uint32 *gpTegra2Vid_IOMem;
\r
58 tPAddr gTegra2Vid_FramebufferPhys;
\r
59 void *gpTegra2Vid_Framebuffer;
\r
61 tDrvUtil_Video_BufInfo gTegra2Vid_DrvUtil_BufInfo;
\r
62 tVideo_IOCtl_Pos gTegra2Vid_CursorPos;
\r
67 int Tegra2Vid_Install(char **Arguments)
\r
69 return MODULE_ERR_NOTNEEDED;
\r
70 // KeyVal_Parse(&gTegra2Vid_KeyValueParser, Arguments);
\r
72 gpTegra2Vid_IOMem = (void*)MM_MapHWPages(gTegra2Vid_PhysBase, 256/4);
\r
74 Log_Debug("Tegra2Vid", "Display CMD Registers");
\r
75 for( int i = 0x000; i <= 0x01A; i ++ )
\r
76 Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);
\r
77 for( int i = 0x028; i <= 0x043; i ++ )
\r
78 Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);
\r
79 Log_Debug("Tegra2Vid", "Display COM Registers");
\r
80 for( int i = 0x300; i <= 0x329; i ++ )
\r
81 Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);
\r
82 Log_Debug("Tegra2Vid", "Display DISP Registers");
\r
83 for( int i = 0x400; i <= 0x446; i ++ )
\r
84 Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);
\r
85 for( int i = 0x480; i <= 0x484; i ++ )
\r
86 Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);
\r
87 for( int i = 0x4C0; i <= 0x4C1; i ++ )
\r
88 Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);
\r
90 Log_Debug("Tegra2Vid", "WINC_A Registers");
\r
91 for( int i = 0x700; i <= 0x714; i ++ )
\r
92 Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);
\r
93 Log_Debug("Tegra2Vid", "WINBUF_A");
\r
94 for( int i = 0x800; i <= 0x80A; i ++ )
\r
95 Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);
\r
101 // int w = 1980, h = 1080;
\r
102 // gpTegra2Vid_IOMem[DC_DISP_DISP_ACTIVE_0] = (h << 16) | w;
\r
103 // gpTegra2Vid_IOMem[DC_WIN_A_SIZE_0] = (h << 16) | w;
\r
104 // gpTegra2Vid_IOMem[DC_WIN_A_PRESCALED_SIZE_0] = (h << 16) | w;
\r
107 giTegra2Vid_FramebufferSize =
\r
108 (gpTegra2Vid_IOMem[DC_WIN_A_SIZE_0]&0xFFFF)
\r
109 *(gpTegra2Vid_IOMem[DC_WIN_A_SIZE_0]>>16)*4;
\r
111 Log_Debug("Tegra2Vid", "giTegra2Vid_FramebufferSize = 0x%x", giTegra2Vid_FramebufferSize);
\r
112 gpTegra2Vid_Framebuffer = MM_MapHWPages(
\r
113 gpTegra2Vid_IOMem[DC_WINBUF_A_START_ADDR_0],
\r
114 (giTegra2Vid_FramebufferSize+PAGE_SIZE-1)/PAGE_SIZE
\r
116 memset(gpTegra2Vid_Framebuffer, 0xFF, 0x1000);
\r
118 gpTegra2Vid_IOMem[DC_WIN_A_WIN_OPTIONS_0] &= ~0x40;
\r
119 gpTegra2Vid_IOMem[DC_WIN_A_COLOR_DEPTH_0] = 12; // Could be 13 (BGR/RGB)
\r
120 gTegra2Vid_DrvUtil_BufInfo.Width = 1024;
\r
121 gTegra2Vid_DrvUtil_BufInfo.Height = 768;
\r
122 gTegra2Vid_DrvUtil_BufInfo.Pitch = 1024*4;
\r
123 gTegra2Vid_DrvUtil_BufInfo.Depth = 32;
\r
124 gTegra2Vid_DrvUtil_BufInfo.Framebuffer = gpTegra2Vid_Framebuffer;
\r
127 // Tegra2Vid_int_SetMode(4);
\r
129 DevFS_AddDevice( &gTegra2Vid_DriverStruct );
\r
135 * \brief Clean up resources for driver unloading
\r
137 void Tegra2Vid_Uninstall()
\r
142 * \brief Read from the framebuffer
\r
144 Uint64 Tegra2Vid_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer)
\r
150 * \brief Write to the framebuffer
\r
152 Uint64 Tegra2Vid_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
\r
154 gTegra2Vid_DrvUtil_BufInfo.BufferFormat = giTegra2Vid_BufferMode;
\r
155 return DrvUtil_Video_WriteLFB(&gTegra2Vid_DrvUtil_BufInfo, Offset, Length, Buffer);
\r
158 const char *csaTegra2Vid_IOCtls[] = {DRV_IOCTLNAMES, DRV_VIDEO_IOCTLNAMES, NULL};
\r
161 * \brief Handle messages to the device
\r
163 int Tegra2Vid_IOCtl(tVFS_Node *Node, int ID, void *Data)
\r
166 ENTER("pNode iID pData", Node, ID, Data);
\r
170 BASE_IOCTLS(DRV_TYPE_VIDEO, "PL110", VERSION, csaTegra2Vid_IOCtls);
\r
172 case VIDEO_IOCTL_SETBUFFORMAT:
\r
173 DrvUtil_Video_RemoveCursor( &gTegra2Vid_DrvUtil_BufInfo );
\r
174 ret = giTegra2Vid_BufferMode;
\r
175 if(Data) giTegra2Vid_BufferMode = *(int*)Data;
\r
176 if(gTegra2Vid_DrvUtil_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)
\r
177 DrvUtil_Video_SetCursor( &gTegra2Vid_DrvUtil_BufInfo, &gDrvUtil_TextModeCursor );
\r
180 case VIDEO_IOCTL_GETSETMODE:
\r
185 if( !CheckMem(Data, sizeof(int)) )
\r
186 LEAVE_RET('i', -1);
\r
188 newMode = *(int*)Data;
\r
190 if(newMode < 0 || newMode >= ciTegra2Vid_ModeCount)
\r
191 LEAVE_RET('i', -1);
\r
193 if(newMode != giTegra2Vid_CurrentMode)
\r
195 giTegra2Vid_CurrentMode = newMode;
\r
196 Tegra2Vid_int_SetMode( newMode );
\r
199 ret = giTegra2Vid_CurrentMode;
\r
202 case VIDEO_IOCTL_FINDMODE:
\r
204 tVideo_IOCtl_Mode *mode = Data;
\r
205 int closest, closestArea, reqArea = 0;
\r
206 if(!Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Mode)))
\r
207 LEAVE_RET('i', -1);
\r
208 if( mode->bpp != 32 )
\r
210 if( mode->flags != 0 )
\r
215 for( int i = 0; i < ciTegra2Vid_ModeCount; i ++ )
\r
218 if(mode->width == caTegra2Vid_Modes[i].W && mode->height == caTegra2Vid_Modes[i].H) {
\r
224 area = caTegra2Vid_Modes[i].W * caTegra2Vid_Modes[i].H;
\r
226 reqArea = mode->width * mode->height;
\r
228 closestArea = area;
\r
230 else if( ABS(area - reqArea) < ABS(closestArea - reqArea) ) {
\r
232 closestArea = area;
\r
238 mode->id = closest;
\r
241 mode->width = caTegra2Vid_Modes[mode->id].W;
\r
242 mode->height = caTegra2Vid_Modes[mode->id].H;
\r
246 case VIDEO_IOCTL_MODEINFO:
\r
248 tVideo_IOCtl_Mode *mode = Data;
\r
249 if(!Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Mode)))
\r
250 LEAVE_RET('i', -1);
\r
251 if(mode->id < 0 || mode->id >= ciTegra2Vid_ModeCount)
\r
257 mode->width = caTegra2Vid_Modes[mode->id].W;
\r
258 mode->height = caTegra2Vid_Modes[mode->id].H;
\r
264 case VIDEO_IOCTL_SETCURSOR:
\r
265 if( !Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Pos)) )
\r
266 LEAVE_RET('i', -1);
\r
268 DrvUtil_Video_RemoveCursor( &gTegra2Vid_DrvUtil_BufInfo );
\r
270 gTegra2Vid_CursorPos = *(tVideo_IOCtl_Pos*)Data;
\r
271 if(gTegra2Vid_DrvUtil_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)
\r
272 DrvUtil_Video_DrawCursor(
\r
273 &gTegra2Vid_DrvUtil_BufInfo,
\r
274 gTegra2Vid_CursorPos.x*giVT_CharWidth,
\r
275 gTegra2Vid_CursorPos.y*giVT_CharHeight
\r
278 DrvUtil_Video_DrawCursor(
\r
279 &gTegra2Vid_DrvUtil_BufInfo,
\r
280 gTegra2Vid_CursorPos.x,
\r
281 gTegra2Vid_CursorPos.y
\r
298 int Tegra2Vid_int_SetMode(int Mode)
\r
300 const struct sTegra2_Disp_Mode *mode = &caTegra2Vid_Modes[Mode];
\r
301 int w = mode->W, h = mode->H; // Horizontal/Vertical Active
\r
302 *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_FRONT_PORCH_0) = (mode->VFP << 16) | mode->HFP;
\r
303 *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_SYNC_WIDTH_0) = (mode->HS << 16) | mode->HS;
\r
304 *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_BACK_PORCH_0) = (mode->VBP << 16) | mode->HBP;
\r
305 *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_DISP_ACTIVE_0) = (mode->H << 16) | mode->W;
\r
307 *(Uint32*)(gpTegra2Vid_IOMem + DC_WIN_A_POSITION_0) = 0;
\r
308 *(Uint32*)(gpTegra2Vid_IOMem + DC_WIN_A_SIZE_0) = (h << 16) | w;
\r
309 *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_DISP_COLOR_CONTROL_0) = 0x8; // BASE888
\r
310 *(Uint32*)(gpTegra2Vid_IOMem + DC_WIN_A_COLOR_DEPTH_0) = 12; // Could be 13 (BGR/RGB)
\r
311 *(Uint32*)(gpTegra2Vid_IOMem + DC_WIN_A_PRESCALED_SIZE_0) = (h << 16) | w;
\r
313 Log_Debug("Tegra2Vid", "Mode %i (%ix%i) selected", Mode, w, h);
\r
315 if( !gpTegra2Vid_Framebuffer || w*h*4 != giTegra2Vid_FramebufferSize )
\r
317 if( gpTegra2Vid_Framebuffer )
\r
319 // TODO: Free framebuffer for reallocation
\r
322 giTegra2Vid_FramebufferSize = w*h*4;
\r
324 gpTegra2Vid_Framebuffer = (void*)MM_AllocDMA(
\r
325 (giTegra2Vid_FramebufferSize + PAGE_SIZE-1) / PAGE_SIZE,
\r
327 &gTegra2Vid_FramebufferPhys
\r
329 // TODO: Catch allocation failures
\r
330 Log_Debug("Tegra2Vid", "0x%x byte framebuffer at %p (%P phys)",
\r
331 giTegra2Vid_FramebufferSize,
\r
332 gpTegra2Vid_Framebuffer,
\r
333 gTegra2Vid_FramebufferPhys
\r
337 *(Uint32*)(gpTegra2Vid_IOMem + DC_WINBUF_A_START_ADDR_0) = gTegra2Vid_FramebufferPhys;
\r
338 *(Uint32*)(gpTegra2Vid_IOMem + DC_WINBUF_A_ADDR_V_OFFSET_0) = 0; // Y offset
\r
339 *(Uint32*)(gpTegra2Vid_IOMem + DC_WINBUF_A_ADDR_H_OFFSET_0) = 0; // X offset
\r