Sorting source tree a bit
[tpg/acess2.git] / KernelLand / Modules / Display / PL110 / main.c
diff --git a/KernelLand/Modules/Display/PL110/main.c b/KernelLand/Modules/Display/PL110/main.c
new file mode 100644 (file)
index 0000000..c3b6e52
--- /dev/null
@@ -0,0 +1,345 @@
+/**\r
+ * Acess2 ARM PrimeCell Colour LCD Controller (PL110) Driver\r
+ * - By John Hodge (thePowersGang)\r
+ *\r
+ * main.c\r
+ * - Driver core\r
+ *\r
+ *\r
+ * NOTE: The PL110 is set to 24bpp, but these are stored as 32-bit words.\r
+ *       This corresponds to the Acess 32bpp mode, as the Acess 24bpp is packed\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
+// === TYPEDEFS ===\r
+typedef struct sPL110  tPL110;\r
+\r
+struct sPL110\r
+{\r
+       Uint32  LCDTiming0;\r
+       Uint32  LCDTiming1;\r
+       Uint32  LCDTiming2;\r
+       Uint32  LCDTiming3;\r
+       \r
+       Uint32  LCDUPBase;\r
+       Uint32  LCDLPBase;\r
+       Uint32  LCDIMSC;\r
+       Uint32  LCDControl;\r
+       Uint32  LCDRIS;\r
+       Uint32  LCDMIS;\r
+       Uint32  LCDICR;\r
+       Uint32  LCDUPCurr;\r
+       Uint32  LCDLPCurr;\r
+};\r
+\r
+#ifndef PL110_BASE\r
+#define PL110_BASE     0x10020000      // Integrator\r
+#endif\r
+\r
+// === CONSTANTS ===\r
+const struct {\r
+       short W, H;\r
+}      caPL110_Modes[] = {\r
+       {640,480},\r
+       {800,600},\r
+       {1024,768}      // MAX\r
+};\r
+const int      ciPL110_ModeCount = sizeof(caPL110_Modes)/sizeof(caPL110_Modes[0]);\r
+\r
+// === PROTOTYPES ===\r
+// Driver\r
+ int   PL110_Install(char **Arguments);\r
+void   PL110_Uninstall();\r
+// Internal\r
+// Filesystem\r
+Uint64 PL110_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer);\r
+Uint64 PL110_Write(tVFS_Node *node, Uint64 off, Uint64 len, const void *buffer);\r
+ int   PL110_IOCtl(tVFS_Node *node, int id, void *data);\r
+// -- Internals\r
+ int   PL110_int_SetResolution(int W, int H);\r
+\r
+// === GLOBALS ===\r
+MODULE_DEFINE(0, VERSION, PL110, PL110_Install, NULL, NULL);\r
+tVFS_NodeType  gPL110_DevNodeType = {\r
+       .Read = PL110_Read,\r
+       .Write = PL110_Write,\r
+       .IOCtl = PL110_IOCtl\r
+       };\r
+tDevFS_Driver  gPL110_DriverStruct = {\r
+       NULL, "PL110",\r
+       {.Type = &gPL110_DevNodeType}\r
+};\r
+// -- Options\r
+tPAddr gPL110_PhysBase = PL110_BASE;\r
+ int   gbPL110_IsVersatile = 1;\r
+// -- KeyVal parse rules\r
+const tKeyVal_ParseRules       gPL110_KeyValueParser = {\r
+       NULL,\r
+       {\r
+               {"Base", "P", &gPL110_PhysBase},\r
+               {"IsVersatile", "i", &gbPL110_IsVersatile},\r
+               {NULL, NULL, NULL}\r
+       }\r
+};\r
+// -- Driver state\r
+ int   giPL110_CurrentMode = 0;\r
+ int   giPL110_BufferMode;\r
+ int   giPL110_Width = 640;\r
+ int   giPL110_Height = 480;\r
+size_t giPL110_FramebufferSize;\r
+tPL110 *gpPL110_IOMem;\r
+tPAddr gPL110_FramebufferPhys;\r
+void   *gpPL110_Framebuffer;\r
+// -- Misc\r
+tDrvUtil_Video_BufInfo gPL110_DrvUtil_BufInfo;\r
+tVideo_IOCtl_Pos       gPL110_CursorPos;\r
+\r
+// === CODE ===\r
+/**\r
+ */\r
+int PL110_Install(char **Arguments)\r
+{\r
+//     KeyVal_Parse(&gPL110_KeyValueParser, Arguments);\r
+       \r
+       gpPL110_IOMem = (void*)MM_MapHWPages(gPL110_PhysBase, 1);\r
+\r
+       PL110_int_SetResolution(caPL110_Modes[0].W, caPL110_Modes[0].H);\r
+\r
+       DevFS_AddDevice( &gPL110_DriverStruct );\r
+\r
+       return 0;\r
+}\r
+\r
+/**\r
+ * \brief Clean up resources for driver unloading\r
+ */\r
+void PL110_Uninstall()\r
+{\r
+}\r
+\r
+/**\r
+ * \brief Read from the framebuffer\r
+ */\r
+Uint64 PL110_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 PL110_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)\r
+{\r
+       gPL110_DrvUtil_BufInfo.BufferFormat = giPL110_BufferMode;\r
+       return DrvUtil_Video_WriteLFB(&gPL110_DrvUtil_BufInfo, Offset, Length, Buffer);\r
+}\r
+\r
+const char *csaPL110_IOCtls[] = {DRV_IOCTLNAMES, DRV_VIDEO_IOCTLNAMES, NULL};\r
+\r
+/**\r
+ * \brief Handle messages to the device\r
+ */\r
+int PL110_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, csaPL110_IOCtls);\r
+\r
+       case VIDEO_IOCTL_SETBUFFORMAT:\r
+               DrvUtil_Video_RemoveCursor( &gPL110_DrvUtil_BufInfo );\r
+               ret = giPL110_BufferMode;\r
+               if(Data)        giPL110_BufferMode = *(int*)Data;\r
+               if(gPL110_DrvUtil_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)\r
+                       DrvUtil_Video_SetCursor( &gPL110_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 >= ciPL110_ModeCount)\r
+                               LEAVE_RET('i', -1);\r
+\r
+                       if(newMode != giPL110_CurrentMode)\r
+                       {\r
+                               giPL110_CurrentMode = newMode;\r
+                               PL110_int_SetResolution( caPL110_Modes[newMode].W, caPL110_Modes[newMode].H );\r
+                       }\r
+               }\r
+               ret = giPL110_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 < ciPL110_ModeCount; i ++ )\r
+               {\r
+                        int    area;\r
+                       if(mode->width == caPL110_Modes[i].W && mode->height == caPL110_Modes[i].H) {\r
+                               mode->id = i;\r
+                               ret = 1;\r
+                               break;\r
+                       }\r
+                       \r
+                       area = caPL110_Modes[i].W * caPL110_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 = caPL110_Modes[mode->id].W;\r
+               mode->height = caPL110_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 >= ciPL110_ModeCount)\r
+                       LEAVE_RET('i', 0);\r
+               \r
+\r
+               mode->bpp = 32;\r
+               mode->flags = 0;\r
+               mode->width = caPL110_Modes[mode->id].W;\r
+               mode->height = caPL110_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( &gPL110_DrvUtil_BufInfo );\r
+               \r
+               gPL110_CursorPos = *(tVideo_IOCtl_Pos*)Data;\r
+               if(gPL110_DrvUtil_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)\r
+                       DrvUtil_Video_DrawCursor(\r
+                               &gPL110_DrvUtil_BufInfo,\r
+                               gPL110_CursorPos.x*giVT_CharWidth,\r
+                               gPL110_CursorPos.y*giVT_CharHeight\r
+                               );\r
+               else\r
+                       DrvUtil_Video_DrawCursor(\r
+                               &gPL110_DrvUtil_BufInfo,\r
+                               gPL110_CursorPos.x,\r
+                               gPL110_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 PL110_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 = 1024;\r
+       if(H > 768)     H = 768;\r
+\r
+       gpPL110_IOMem->LCDTiming0 = ((W/16)-1) << 2;\r
+       gpPL110_IOMem->LCDTiming1 = H-1;\r
+       gpPL110_IOMem->LCDTiming2 = (14 << 27);\r
+       gpPL110_IOMem->LCDTiming3 = 0;\r
+\r
+       if( gpPL110_Framebuffer ) {\r
+               MM_UnmapHWPages((tVAddr)gpPL110_Framebuffer, (giPL110_FramebufferSize+0xFFF)>>12);\r
+       }\r
+       giPL110_FramebufferSize = W*H*4;\r
+\r
+       gpPL110_Framebuffer = (void*)MM_AllocDMA( (giPL110_FramebufferSize+0xFFF)>>12, 32, &gPL110_FramebufferPhys );\r
+       gpPL110_IOMem->LCDUPBase = gPL110_FramebufferPhys;\r
+       gpPL110_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( gbPL110_IsVersatile )\r
+       {\r
+               gpPL110_IOMem->LCDIMSC = controlWord;   // Actually LCDControl\r
+               gpPL110_IOMem->LCDControl = 0;  // Actually LCDIMSC\r
+       }\r
+       else\r
+       {\r
+               gpPL110_IOMem->LCDIMSC = 0;\r
+               gpPL110_IOMem->LCDControl = controlWord;\r
+       }\r
+\r
+       giPL110_Width = W;\r
+       giPL110_Height = H;\r
+\r
+       // Update the DrvUtil buffer info\r
+       gPL110_DrvUtil_BufInfo.Framebuffer = gpPL110_Framebuffer;\r
+       gPL110_DrvUtil_BufInfo.Pitch = W * 4;\r
+       gPL110_DrvUtil_BufInfo.Width = W;\r
+       gPL110_DrvUtil_BufInfo.Height = H;\r
+       gPL110_DrvUtil_BufInfo.Depth = 32;\r
+       \r
+       return 0;\r
+}\r

UCC git Repository :: git.ucc.asn.au