--- /dev/null
+/**\r
+ * main.c\r
+ * - Driver core\r
+ */\r
+#define DEBUG 0\r
+#define VERSION ((0<<8)|10)\r
+#include <acess.h>\r
+#include <errno.h>\r
+#include <modules.h>\r
+#include <vfs.h>\r
+#include <fs_devfs.h>\r
+#include <drv_pci.h>\r
+#include <api_drv_video.h>\r
+#include <lib/keyvalue.h>\r
+#include <options.h> // ARM Arch\r
+\r
+#define ABS(a) ((a)>0?(a):-(a))\r
+\r
+// === PROTOTYPES ===\r
+// Driver\r
+ int Tegra2Vid_Install(char **Arguments);\r
+void Tegra2Vid_Uninstall();\r
+// Internal\r
+// Filesystem\r
+Uint64 Tegra2Vid_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer);\r
+Uint64 Tegra2Vid_Write(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer);\r
+ int Tegra2Vid_IOCtl(tVFS_Node *node, int id, void *data);\r
+// -- Internals\r
+ int Tegra2Vid_int_SetResolution(int W, int H);\r
+\r
+// === GLOBALS ===\r
+MODULE_DEFINE(0, VERSION, PL110, Tegra2Vid_Install, NULL, NULL);\r
+tDevFS_Driver gTegra2Vid_DriverStruct = {\r
+ NULL, "PL110",\r
+ {\r
+ .Read = Tegra2Vid_Read,\r
+ .Write = Tegra2Vid_Write,\r
+ .IOCtl = Tegra2Vid_IOCtl\r
+ }\r
+};\r
+// -- Options\r
+tPAddr gTegra2Vid_PhysBase = Tegra2Vid_BASE;\r
+ int gbTegra2Vid_IsVersatile = 1;\r
+// -- KeyVal parse rules\r
+const tKeyVal_ParseRules gTegra2Vid_KeyValueParser = {\r
+ NULL,\r
+ {\r
+ {"Base", "P", &gTegra2Vid_PhysBase},\r
+ {"IsVersatile", "i", &gbTegra2Vid_IsVersatile},\r
+ {NULL, NULL, NULL}\r
+ }\r
+};\r
+// -- Driver state\r
+ int giTegra2Vid_CurrentMode = 0;\r
+ int giTegra2Vid_BufferMode;\r
+ int giTegra2Vid_Width = 640;\r
+ int giTegra2Vid_Height = 480;\r
+size_t giTegra2Vid_FramebufferSize;\r
+Uint8 *gpTegra2Vid_IOMem;\r
+tPAddr gTegra2Vid_FramebufferPhys;\r
+void *gpTegra2Vid_Framebuffer;\r
+// -- Misc\r
+tDrvUtil_Video_BufInfo gTegra2Vid_DrvUtil_BufInfo;\r
+tVideo_IOCtl_Pos gTegra2Vid_CursorPos;\r
+\r
+// === CODE ===\r
+/**\r
+ */\r
+int Tegra2Vid_Install(char **Arguments)\r
+{\r
+// KeyVal_Parse(&gTegra2Vid_KeyValueParser, Arguments);\r
+ \r
+ gpTegra2Vid_IOMem = (void*)MM_MapHWPages(gTegra2Vid_PhysBase, 1);\r
+\r
+ Tegra2Vid_int_SetResolution(caTegra2Vid_Modes[0].W, caTegra2Vid_Modes[0].H);\r
+\r
+ DevFS_AddDevice( &gTegra2Vid_DriverStruct );\r
+\r
+ return 0;\r
+}\r
+\r
+/**\r
+ * \brief Clean up resources for driver unloading\r
+ */\r
+void Tegra2Vid_Uninstall()\r
+{\r
+}\r
+\r
+/**\r
+ * \brief Read from the framebuffer\r
+ */\r
+Uint64 Tegra2Vid_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer)\r
+{\r
+ return 0;\r
+}\r
+\r
+/**\r
+ * \brief Write to the framebuffer\r
+ */\r
+Uint64 Tegra2Vid_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)\r
+{\r
+ gTegra2Vid_DrvUtil_BufInfo.BufferFormat = giTegra2Vid_BufferMode;\r
+ return DrvUtil_Video_WriteLFB(&gTegra2Vid_DrvUtil_BufInfo, Offset, Length, Buffer);\r
+}\r
+\r
+const char *csaTegra2Vid_IOCtls[] = {DRV_IOCTLNAMES, DRV_VIDEO_IOCTLNAMES, NULL};\r
+\r
+/**\r
+ * \brief Handle messages to the device\r
+ */\r
+int Tegra2Vid_IOCtl(tVFS_Node *Node, int ID, void *Data)\r
+{\r
+ int ret = -2;\r
+ ENTER("pNode iID pData", Node, ID, Data);\r
+ \r
+ switch(ID)\r
+ {\r
+ BASE_IOCTLS(DRV_TYPE_VIDEO, "PL110", VERSION, csaTegra2Vid_IOCtls);\r
+\r
+ case VIDEO_IOCTL_SETBUFFORMAT:\r
+ DrvUtil_Video_RemoveCursor( &gTegra2Vid_DrvUtil_BufInfo );\r
+ ret = giTegra2Vid_BufferMode;\r
+ if(Data) giTegra2Vid_BufferMode = *(int*)Data;\r
+ if(gTegra2Vid_DrvUtil_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)\r
+ DrvUtil_Video_SetCursor( &gTegra2Vid_DrvUtil_BufInfo, &gDrvUtil_TextModeCursor );\r
+ break;\r
+ \r
+ case VIDEO_IOCTL_GETSETMODE:\r
+ if(Data)\r
+ {\r
+ int newMode;\r
+ \r
+ if( !CheckMem(Data, sizeof(int)) )\r
+ LEAVE_RET('i', -1);\r
+ \r
+ newMode = *(int*)Data;\r
+ \r
+ if(newMode < 0 || newMode >= ciTegra2Vid_ModeCount)\r
+ LEAVE_RET('i', -1);\r
+\r
+ if(newMode != giTegra2Vid_CurrentMode)\r
+ {\r
+ giTegra2Vid_CurrentMode = newMode;\r
+ Tegra2Vid_int_SetResolution( caTegra2Vid_Modes[newMode].W, caTegra2Vid_Modes[newMode].H );\r
+ }\r
+ }\r
+ ret = giTegra2Vid_CurrentMode;\r
+ break;\r
+ \r
+ case VIDEO_IOCTL_FINDMODE:\r
+ {\r
+ tVideo_IOCtl_Mode *mode = Data;\r
+ int closest, closestArea, reqArea = 0;\r
+ if(!Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Mode)))\r
+ LEAVE_RET('i', -1);\r
+ if( mode->bpp != 32 )\r
+ LEAVE_RET('i', 0);\r
+ if( mode->flags != 0 )\r
+ LEAVE_RET('i', 0);\r
+\r
+ ret = 0;\r
+\r
+ for( int i = 0; i < ciTegra2Vid_ModeCount; i ++ )\r
+ {\r
+ int area;\r
+ if(mode->width == caTegra2Vid_Modes[i].W && mode->height == caTegra2Vid_Modes[i].H) {\r
+ mode->id = i;\r
+ ret = 1;\r
+ break;\r
+ }\r
+ \r
+ area = caTegra2Vid_Modes[i].W * caTegra2Vid_Modes[i].H;\r
+ if(!reqArea) {\r
+ reqArea = mode->width * mode->height;\r
+ closest = i;\r
+ closestArea = area;\r
+ }\r
+ else if( ABS(area - reqArea) < ABS(closestArea - reqArea) ) {\r
+ closest = i;\r
+ closestArea = area;\r
+ }\r
+ }\r
+ \r
+ if( ret == 0 )\r
+ {\r
+ mode->id = closest;\r
+ ret = 1;\r
+ }\r
+ mode->width = caTegra2Vid_Modes[mode->id].W;\r
+ mode->height = caTegra2Vid_Modes[mode->id].H;\r
+ break;\r
+ }\r
+ \r
+ case VIDEO_IOCTL_MODEINFO:\r
+ {\r
+ tVideo_IOCtl_Mode *mode = Data;\r
+ if(!Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Mode)))\r
+ LEAVE_RET('i', -1);\r
+ if(mode->id < 0 || mode->id >= ciTegra2Vid_ModeCount)\r
+ LEAVE_RET('i', 0);\r
+ \r
+\r
+ mode->bpp = 32;\r
+ mode->flags = 0;\r
+ mode->width = caTegra2Vid_Modes[mode->id].W;\r
+ mode->height = caTegra2Vid_Modes[mode->id].H;\r
+\r
+ ret = 1;\r
+ break;\r
+ }\r
+ \r
+ case VIDEO_IOCTL_SETCURSOR:\r
+ if( !Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Pos)) )\r
+ LEAVE_RET('i', -1);\r
+\r
+ DrvUtil_Video_RemoveCursor( &gTegra2Vid_DrvUtil_BufInfo );\r
+ \r
+ gTegra2Vid_CursorPos = *(tVideo_IOCtl_Pos*)Data;\r
+ if(gTegra2Vid_DrvUtil_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)\r
+ DrvUtil_Video_DrawCursor(\r
+ &gTegra2Vid_DrvUtil_BufInfo,\r
+ gTegra2Vid_CursorPos.x*giVT_CharWidth,\r
+ gTegra2Vid_CursorPos.y*giVT_CharHeight\r
+ );\r
+ else\r
+ DrvUtil_Video_DrawCursor(\r
+ &gTegra2Vid_DrvUtil_BufInfo,\r
+ gTegra2Vid_CursorPos.x,\r
+ gTegra2Vid_CursorPos.y\r
+ );\r
+ break;\r
+ \r
+ default:\r
+ LEAVE('i', -2);\r
+ return -2;\r
+ }\r
+ \r
+ LEAVE('i', ret);\r
+ return ret;\r
+}\r
+\r
+//\r
+//\r
+//\r
+\r
+/**\r
+ * \brief Set the LCD controller resolution\r
+ * \param W Width (aligned to 16 pixels, cipped to 1024)\r
+ * \param H Height (clipped to 768)\r
+ * \return Boolean failure\r
+ */\r
+int Tegra2Vid_int_SetResolution(int W, int H)\r
+{\r
+ W = (W + 15) & ~0xF;\r
+ if(W <= 0 || H <= 0) {\r
+ Log_Warning("PL110", "Attempted to set invalid resolution (%ix%i)", W, H);\r
+ return 1;\r
+ }\r
+ if(W > 1024) W = 1920;\r
+ if(H > 768) H = 1080;\r
+\r
+ gpTegra2Vid_IOMem->DCWinAPos = 0;\r
+ gpTegra2Vid_IOMem->DCWinASize = (H << 16) | W;\r
+\r
+ if( gpTegra2Vid_Framebuffer ) {\r
+ MM_UnmapHWPages((tVAddr)gpTegra2Vid_Framebuffer, (giTegra2Vid_FramebufferSize+0xFFF)>>12);\r
+ }\r
+ giTegra2Vid_FramebufferSize = W*H*4;\r
+\r
+ gpTegra2Vid_Framebuffer = (void*)MM_AllocDMA( (giTegra2Vid_FramebufferSize+0xFFF)>>12, 32, &gTegra2Vid_FramebufferPhys );\r
+ gpTegra2Vid_IOMem->LCDUPBase = gTegra2Vid_FramebufferPhys;\r
+ gpTegra2Vid_IOMem->LCDLPBase = 0;\r
+\r
+ // Power on, BGR mode, ???, ???, enabled\r
+ Uint32 controlWord = (1 << 11)|(1 << 8)|(1 << 5)|(5 << 1)|1;\r
+ // According to qemu, the Versatile version has these two the wrong\r
+ // way around\r
+ if( gbTegra2Vid_IsVersatile )\r
+ {\r
+ gpTegra2Vid_IOMem->LCDIMSC = controlWord; // Actually LCDControl\r
+ gpTegra2Vid_IOMem->LCDControl = 0; // Actually LCDIMSC\r
+ }\r
+ else\r
+ {\r
+ gpTegra2Vid_IOMem->LCDIMSC = 0;\r
+ gpTegra2Vid_IOMem->LCDControl = controlWord;\r
+ }\r
+\r
+ giTegra2Vid_Width = W;\r
+ giTegra2Vid_Height = H;\r
+\r
+ // Update the DrvUtil buffer info\r
+ gTegra2Vid_DrvUtil_BufInfo.Framebuffer = gpTegra2Vid_Framebuffer;\r
+ gTegra2Vid_DrvUtil_BufInfo.Pitch = W * 4;\r
+ gTegra2Vid_DrvUtil_BufInfo.Width = W;\r
+ gTegra2Vid_DrvUtil_BufInfo.Height = H;\r
+ gTegra2Vid_DrvUtil_BufInfo.Depth = 32;\r
+ \r
+ return 0;\r
+}\r
+\r
+int Tegra2_int_SetMode(int Mode)\r
+{\r
+ *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_FRONT_PORTCH_0) = (gaTegra2Modes[Mode].VFP << 16) | gaTegra2Modes[Mode].HFP; \r
+ *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_SYNC_WIDTH_0) = (gaTegra2Modes[Mode].HS << 16) | gaTegra2Modes[Mode].HS;\r
+ *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_BACK_PORTCH_0) = (gaTegra2Modes[Mode].VBP << 16) | gaTegra2Modes[Mode].HBP;\r
+ *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_DISP_ACTIVE_0) = (gaTegra2Modes[Mode].VA << 16) | gaTegra2Modes[Mode].HA;\r
+\r
+ *(Uint32*)(gpTegra2Vid_IOMem + DC_WIN_A_POSITION_0) = 0;\r
+ *(Uint32*)(gpTegra2Vid_IOMem + DC_WIN_A_SIZE_0) = (gaTegra2Modes[Mode].VA << 16) | gaTegra2Modes[Mode].HA;\r
+ *(Uint8*)(gpTegra2Vid_IOMem + DC_WIN_A_COLOR_DEPTH_0) = 12; // Could be 13 (BGR/RGB)\r
+ *(Uint32*)(gpTegra2Vid_IOMem + DC_WIN_A_PRESCALED_SIZE_0) = (gaTegra2Modes[Mode].VA << 16) | gaTegra2Modes[Mode].HA;\r
+\r
+ return 0;\r
+}\r