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
17 #define ABS(a) ((a)>0?(a):-(a))
\r
19 // === PROTOTYPES ===
\r
21 int Tegra2Vid_Install(char **Arguments);
\r
22 void Tegra2Vid_Uninstall();
\r
25 Uint64 Tegra2Vid_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer);
\r
26 Uint64 Tegra2Vid_Write(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer);
\r
27 int Tegra2Vid_IOCtl(tVFS_Node *node, int id, void *data);
\r
29 int Tegra2Vid_int_SetResolution(int W, int H);
\r
32 MODULE_DEFINE(0, VERSION, PL110, Tegra2Vid_Install, NULL, NULL);
\r
33 tDevFS_Driver gTegra2Vid_DriverStruct = {
\r
36 .Read = Tegra2Vid_Read,
\r
37 .Write = Tegra2Vid_Write,
\r
38 .IOCtl = Tegra2Vid_IOCtl
\r
42 tPAddr gTegra2Vid_PhysBase = Tegra2Vid_BASE;
\r
43 int gbTegra2Vid_IsVersatile = 1;
\r
44 // -- KeyVal parse rules
\r
45 const tKeyVal_ParseRules gTegra2Vid_KeyValueParser = {
\r
48 {"Base", "P", &gTegra2Vid_PhysBase},
\r
49 {"IsVersatile", "i", &gbTegra2Vid_IsVersatile},
\r
54 int giTegra2Vid_CurrentMode = 0;
\r
55 int giTegra2Vid_BufferMode;
\r
56 int giTegra2Vid_Width = 640;
\r
57 int giTegra2Vid_Height = 480;
\r
58 size_t giTegra2Vid_FramebufferSize;
\r
59 Uint8 *gpTegra2Vid_IOMem;
\r
60 tPAddr gTegra2Vid_FramebufferPhys;
\r
61 void *gpTegra2Vid_Framebuffer;
\r
63 tDrvUtil_Video_BufInfo gTegra2Vid_DrvUtil_BufInfo;
\r
64 tVideo_IOCtl_Pos gTegra2Vid_CursorPos;
\r
69 int Tegra2Vid_Install(char **Arguments)
\r
71 // KeyVal_Parse(&gTegra2Vid_KeyValueParser, Arguments);
\r
73 gpTegra2Vid_IOMem = (void*)MM_MapHWPages(gTegra2Vid_PhysBase, 1);
\r
75 Tegra2Vid_int_SetResolution(caTegra2Vid_Modes[0].W, caTegra2Vid_Modes[0].H);
\r
77 DevFS_AddDevice( &gTegra2Vid_DriverStruct );
\r
83 * \brief Clean up resources for driver unloading
\r
85 void Tegra2Vid_Uninstall()
\r
90 * \brief Read from the framebuffer
\r
92 Uint64 Tegra2Vid_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer)
\r
98 * \brief Write to the framebuffer
\r
100 Uint64 Tegra2Vid_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
\r
102 gTegra2Vid_DrvUtil_BufInfo.BufferFormat = giTegra2Vid_BufferMode;
\r
103 return DrvUtil_Video_WriteLFB(&gTegra2Vid_DrvUtil_BufInfo, Offset, Length, Buffer);
\r
106 const char *csaTegra2Vid_IOCtls[] = {DRV_IOCTLNAMES, DRV_VIDEO_IOCTLNAMES, NULL};
\r
109 * \brief Handle messages to the device
\r
111 int Tegra2Vid_IOCtl(tVFS_Node *Node, int ID, void *Data)
\r
114 ENTER("pNode iID pData", Node, ID, Data);
\r
118 BASE_IOCTLS(DRV_TYPE_VIDEO, "PL110", VERSION, csaTegra2Vid_IOCtls);
\r
120 case VIDEO_IOCTL_SETBUFFORMAT:
\r
121 DrvUtil_Video_RemoveCursor( &gTegra2Vid_DrvUtil_BufInfo );
\r
122 ret = giTegra2Vid_BufferMode;
\r
123 if(Data) giTegra2Vid_BufferMode = *(int*)Data;
\r
124 if(gTegra2Vid_DrvUtil_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)
\r
125 DrvUtil_Video_SetCursor( &gTegra2Vid_DrvUtil_BufInfo, &gDrvUtil_TextModeCursor );
\r
128 case VIDEO_IOCTL_GETSETMODE:
\r
133 if( !CheckMem(Data, sizeof(int)) )
\r
134 LEAVE_RET('i', -1);
\r
136 newMode = *(int*)Data;
\r
138 if(newMode < 0 || newMode >= ciTegra2Vid_ModeCount)
\r
139 LEAVE_RET('i', -1);
\r
141 if(newMode != giTegra2Vid_CurrentMode)
\r
143 giTegra2Vid_CurrentMode = newMode;
\r
144 Tegra2Vid_int_SetResolution( caTegra2Vid_Modes[newMode].W, caTegra2Vid_Modes[newMode].H );
\r
147 ret = giTegra2Vid_CurrentMode;
\r
150 case VIDEO_IOCTL_FINDMODE:
\r
152 tVideo_IOCtl_Mode *mode = Data;
\r
153 int closest, closestArea, reqArea = 0;
\r
154 if(!Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Mode)))
\r
155 LEAVE_RET('i', -1);
\r
156 if( mode->bpp != 32 )
\r
158 if( mode->flags != 0 )
\r
163 for( int i = 0; i < ciTegra2Vid_ModeCount; i ++ )
\r
166 if(mode->width == caTegra2Vid_Modes[i].W && mode->height == caTegra2Vid_Modes[i].H) {
\r
172 area = caTegra2Vid_Modes[i].W * caTegra2Vid_Modes[i].H;
\r
174 reqArea = mode->width * mode->height;
\r
176 closestArea = area;
\r
178 else if( ABS(area - reqArea) < ABS(closestArea - reqArea) ) {
\r
180 closestArea = area;
\r
186 mode->id = closest;
\r
189 mode->width = caTegra2Vid_Modes[mode->id].W;
\r
190 mode->height = caTegra2Vid_Modes[mode->id].H;
\r
194 case VIDEO_IOCTL_MODEINFO:
\r
196 tVideo_IOCtl_Mode *mode = Data;
\r
197 if(!Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Mode)))
\r
198 LEAVE_RET('i', -1);
\r
199 if(mode->id < 0 || mode->id >= ciTegra2Vid_ModeCount)
\r
205 mode->width = caTegra2Vid_Modes[mode->id].W;
\r
206 mode->height = caTegra2Vid_Modes[mode->id].H;
\r
212 case VIDEO_IOCTL_SETCURSOR:
\r
213 if( !Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Pos)) )
\r
214 LEAVE_RET('i', -1);
\r
216 DrvUtil_Video_RemoveCursor( &gTegra2Vid_DrvUtil_BufInfo );
\r
218 gTegra2Vid_CursorPos = *(tVideo_IOCtl_Pos*)Data;
\r
219 if(gTegra2Vid_DrvUtil_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)
\r
220 DrvUtil_Video_DrawCursor(
\r
221 &gTegra2Vid_DrvUtil_BufInfo,
\r
222 gTegra2Vid_CursorPos.x*giVT_CharWidth,
\r
223 gTegra2Vid_CursorPos.y*giVT_CharHeight
\r
226 DrvUtil_Video_DrawCursor(
\r
227 &gTegra2Vid_DrvUtil_BufInfo,
\r
228 gTegra2Vid_CursorPos.x,
\r
229 gTegra2Vid_CursorPos.y
\r
247 * \brief Set the LCD controller resolution
\r
248 * \param W Width (aligned to 16 pixels, cipped to 1024)
\r
249 * \param H Height (clipped to 768)
\r
250 * \return Boolean failure
\r
252 int Tegra2Vid_int_SetResolution(int W, int H)
\r
254 W = (W + 15) & ~0xF;
\r
255 if(W <= 0 || H <= 0) {
\r
256 Log_Warning("PL110", "Attempted to set invalid resolution (%ix%i)", W, H);
\r
259 if(W > 1024) W = 1920;
\r
260 if(H > 768) H = 1080;
\r
262 gpTegra2Vid_IOMem->DCWinAPos = 0;
\r
263 gpTegra2Vid_IOMem->DCWinASize = (H << 16) | W;
\r
265 if( gpTegra2Vid_Framebuffer ) {
\r
266 MM_UnmapHWPages((tVAddr)gpTegra2Vid_Framebuffer, (giTegra2Vid_FramebufferSize+0xFFF)>>12);
\r
268 giTegra2Vid_FramebufferSize = W*H*4;
\r
270 gpTegra2Vid_Framebuffer = (void*)MM_AllocDMA( (giTegra2Vid_FramebufferSize+0xFFF)>>12, 32, &gTegra2Vid_FramebufferPhys );
\r
271 gpTegra2Vid_IOMem->LCDUPBase = gTegra2Vid_FramebufferPhys;
\r
272 gpTegra2Vid_IOMem->LCDLPBase = 0;
\r
274 // Power on, BGR mode, ???, ???, enabled
\r
275 Uint32 controlWord = (1 << 11)|(1 << 8)|(1 << 5)|(5 << 1)|1;
\r
276 // According to qemu, the Versatile version has these two the wrong
\r
278 if( gbTegra2Vid_IsVersatile )
\r
280 gpTegra2Vid_IOMem->LCDIMSC = controlWord; // Actually LCDControl
\r
281 gpTegra2Vid_IOMem->LCDControl = 0; // Actually LCDIMSC
\r
285 gpTegra2Vid_IOMem->LCDIMSC = 0;
\r
286 gpTegra2Vid_IOMem->LCDControl = controlWord;
\r
289 giTegra2Vid_Width = W;
\r
290 giTegra2Vid_Height = H;
\r
292 // Update the DrvUtil buffer info
\r
293 gTegra2Vid_DrvUtil_BufInfo.Framebuffer = gpTegra2Vid_Framebuffer;
\r
294 gTegra2Vid_DrvUtil_BufInfo.Pitch = W * 4;
\r
295 gTegra2Vid_DrvUtil_BufInfo.Width = W;
\r
296 gTegra2Vid_DrvUtil_BufInfo.Height = H;
\r
297 gTegra2Vid_DrvUtil_BufInfo.Depth = 32;
\r
302 int Tegra2_int_SetMode(int Mode)
\r
304 *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_FRONT_PORTCH_0) = (gaTegra2Modes[Mode].VFP << 16) | gaTegra2Modes[Mode].HFP;
\r
305 *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_SYNC_WIDTH_0) = (gaTegra2Modes[Mode].HS << 16) | gaTegra2Modes[Mode].HS;
\r
306 *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_BACK_PORTCH_0) = (gaTegra2Modes[Mode].VBP << 16) | gaTegra2Modes[Mode].HBP;
\r
307 *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_DISP_ACTIVE_0) = (gaTegra2Modes[Mode].VA << 16) | gaTegra2Modes[Mode].HA;
\r
309 *(Uint32*)(gpTegra2Vid_IOMem + DC_WIN_A_POSITION_0) = 0;
\r
310 *(Uint32*)(gpTegra2Vid_IOMem + DC_WIN_A_SIZE_0) = (gaTegra2Modes[Mode].VA << 16) | gaTegra2Modes[Mode].HA;
\r
311 *(Uint8*)(gpTegra2Vid_IOMem + DC_WIN_A_COLOR_DEPTH_0) = 12; // Could be 13 (BGR/RGB)
\r
312 *(Uint32*)(gpTegra2Vid_IOMem + DC_WIN_A_PRESCALED_SIZE_0) = (gaTegra2Modes[Mode].VA << 16) | gaTegra2Modes[Mode].HA;
\r