2 * Acess2 ARM PrimeCell Colour LCD Controller (PL110) Driver
\r
3 * - By John Hodge (thePowersGang)
\r
9 * NOTE: The PL110 is set to 24bpp, but these are stored as 32-bit words.
\r
10 * This corresponds to the Acess 32bpp mode, as the Acess 24bpp is packed
\r
13 #define VERSION ((0<<8)|10)
\r
16 #include <modules.h>
\r
18 #include <fs_devfs.h>
\r
19 #include <drv_pci.h>
\r
20 #include <api_drv_video.h>
\r
21 #include <lib/keyvalue.h>
\r
23 #define ABS(a) ((a)>0?(a):-(a))
\r
26 typedef struct sPL110 tPL110;
\r
46 // === CONSTANTS ===
\r
47 #define PL110_BASE 0x10020000
\r
50 } caPL110_Modes[] = {
\r
55 const int ciPL110_ModeCount = sizeof(caPL110_Modes)/sizeof(caPL110_Modes[0]);
\r
57 // === PROTOTYPES ===
\r
59 int PL110_Install(char **Arguments);
\r
60 void PL110_Uninstall();
\r
63 Uint64 PL110_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer);
\r
64 Uint64 PL110_Write(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer);
\r
65 int PL110_IOCtl(tVFS_Node *node, int id, void *data);
\r
67 int PL110_int_SetResolution(int W, int H);
\r
70 MODULE_DEFINE(0, VERSION, PL110, PL110_Install, NULL, NULL);
\r
71 tDevFS_Driver gPL110_DriverStruct = {
\r
75 .Write = PL110_Write,
\r
76 .IOCtl = PL110_IOCtl
\r
80 tPAddr gPL110_PhysBase = PL110_BASE;
\r
81 // -- KeyVal parse rules
\r
82 const tKeyVal_ParseRules gPL110_KeyValueParser = {
\r
85 {"Base", "P", &gPL110_PhysBase},
\r
90 int giPL110_CurrentMode = 0;
\r
91 int giPL110_BufferMode;
\r
92 int giPL110_Width = 640;
\r
93 int giPL110_Height = 480;
\r
94 size_t giPL110_FramebufferSize;
\r
95 tPL110 *gpPL110_IOMem;
\r
96 tPAddr gPL110_FramebufferPhys;
\r
97 void *gpPL110_Framebuffer;
\r
99 tDrvUtil_Video_BufInfo gPL110_DrvUtil_BufInfo;
\r
104 int PL110_Install(char **Arguments)
\r
106 // KeyVal_Parse(&gPL110_KeyValueParser, Arguments);
\r
108 gpPL110_IOMem = (void*)MM_MapHWPages(gPL110_PhysBase, 1);
\r
110 PL110_int_SetResolution(caPL110_Modes[0].W, caPL110_Modes[0].H);
\r
112 DevFS_AddDevice( &gPL110_DriverStruct );
\r
118 * \brief Clean up resources for driver unloading
\r
120 void PL110_Uninstall()
\r
125 * \brief Read from the framebuffer
\r
127 Uint64 PL110_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer)
\r
133 * \brief Write to the framebuffer
\r
135 Uint64 PL110_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
\r
137 return DrvUtil_Video_WriteLFB(giPL110_BufferMode, &gPL110_DrvUtil_BufInfo, Offset, Length, Buffer);
\r
140 const char *csaPL110_IOCtls[] = {DRV_IOCTLNAMES, DRV_VIDEO_IOCTLNAMES, NULL};
\r
143 * \brief Handle messages to the device
\r
145 int PL110_IOCtl(tVFS_Node *Node, int ID, void *Data)
\r
148 ENTER("pNode iID pData", Node, ID, Data);
\r
152 BASE_IOCTLS(DRV_TYPE_VIDEO, "PL110", VERSION, csaPL110_IOCtls);
\r
154 case VIDEO_IOCTL_SETBUFFORMAT:
\r
155 ret = giPL110_BufferMode;
\r
156 if(Data) giPL110_BufferMode = *(int*)Data;
\r
159 case VIDEO_IOCTL_GETSETMODE:
\r
164 if( !CheckMem(Data, sizeof(int)) )
\r
165 LEAVE_RET('i', -1);
\r
167 newMode = *(int*)Data;
\r
169 if(newMode < 0 || newMode >= ciPL110_ModeCount)
\r
170 LEAVE_RET('i', -1);
\r
172 if(newMode != giPL110_CurrentMode)
\r
174 giPL110_CurrentMode = newMode;
\r
175 PL110_int_SetResolution( caPL110_Modes[newMode].W, caPL110_Modes[newMode].H );
\r
178 ret = giPL110_CurrentMode;
\r
181 case VIDEO_IOCTL_FINDMODE:
\r
183 tVideo_IOCtl_Mode *mode = Data;
\r
184 int closest, closestArea, reqArea = 0;
\r
185 if(!Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Mode)))
\r
186 LEAVE_RET('i', -1);
\r
187 if( mode->bpp != 32 )
\r
189 if( mode->flags != 0 )
\r
194 for( int i = 0; i < ciPL110_ModeCount; i ++ )
\r
197 if(mode->width == caPL110_Modes[i].W && mode->height == caPL110_Modes[i].H) {
\r
203 area = caPL110_Modes[i].W * caPL110_Modes[i].H;
\r
205 reqArea = mode->width * mode->height;
\r
207 closestArea = area;
\r
209 else if( ABS(area - reqArea) < ABS(closestArea - reqArea) ) {
\r
211 closestArea = area;
\r
217 mode->id = closest;
\r
220 mode->width = caPL110_Modes[mode->id].W;
\r
221 mode->height = caPL110_Modes[mode->id].H;
\r
225 case VIDEO_IOCTL_MODEINFO:
\r
227 tVideo_IOCtl_Mode *mode = Data;
\r
228 if(!Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Mode)))
\r
229 LEAVE_RET('i', -1);
\r
230 if(mode->id < 0 || mode->id >= ciPL110_ModeCount)
\r
236 mode->width = caPL110_Modes[mode->id].W;
\r
237 mode->height = caPL110_Modes[mode->id].H;
\r
243 case VIDEO_IOCTL_SETCURSOR: break;
\r
260 int PL110_int_SetResolution(int W, int H)
\r
263 if(W > 1024) W = 1024;
\r
264 if(H > 768) H = 768;
\r
266 gpPL110_IOMem->LCDTiming0 = ((W/16)-1) << 2;
\r
267 gpPL110_IOMem->LCDTiming1 = H-1;
\r
268 gpPL110_IOMem->LCDTiming2 = (14 << 27);
\r
269 gpPL110_IOMem->LCDTiming3 = 0;
\r
271 if( gpPL110_Framebuffer ) {
\r
272 MM_UnmapHWPages((tVAddr)gpPL110_Framebuffer, (giPL110_FramebufferSize+0xFFF)>>12);
\r
274 giPL110_FramebufferSize = W*H*4;
\r
276 gpPL110_Framebuffer = (void*)MM_AllocDMA( (giPL110_FramebufferSize+0xFFF)>>12, 32, &gPL110_FramebufferPhys );
\r
277 gpPL110_IOMem->LCDUPBase = gPL110_FramebufferPhys;
\r
278 gpPL110_IOMem->LCDLPBase = 0;
\r
280 gpPL110_IOMem->LCDIMSC = 0;
\r
281 gpPL110_IOMem->LCDControl = (1 << 11)|(1 << 5)|(5<<1)|1;
\r
284 giPL110_Height = H;
\r
286 // Update the DrvUtil buffer info
\r
287 gPL110_DrvUtil_BufInfo.Framebuffer = gpPL110_Framebuffer;
\r
288 gPL110_DrvUtil_BufInfo.Pitch = W * 4;
\r
289 gPL110_DrvUtil_BufInfo.Width = W;
\r
290 gPL110_DrvUtil_BufInfo.Height = H;
\r
291 gPL110_DrvUtil_BufInfo.Depth = 32;
\r