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 // Integrator
\r
51 } caPL110_Modes[] = {
\r
56 const int ciPL110_ModeCount = sizeof(caPL110_Modes)/sizeof(caPL110_Modes[0]);
\r
58 // === PROTOTYPES ===
\r
60 int PL110_Install(char **Arguments);
\r
61 void PL110_Uninstall();
\r
64 Uint64 PL110_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer);
\r
65 Uint64 PL110_Write(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer);
\r
66 int PL110_IOCtl(tVFS_Node *node, int id, void *data);
\r
68 int PL110_int_SetResolution(int W, int H);
\r
71 MODULE_DEFINE(0, VERSION, PL110, PL110_Install, NULL, NULL);
\r
72 tDevFS_Driver gPL110_DriverStruct = {
\r
76 .Write = PL110_Write,
\r
77 .IOCtl = PL110_IOCtl
\r
81 tPAddr gPL110_PhysBase = PL110_BASE;
\r
82 // -- KeyVal parse rules
\r
83 const tKeyVal_ParseRules gPL110_KeyValueParser = {
\r
86 {"Base", "P", &gPL110_PhysBase},
\r
91 int giPL110_CurrentMode = 0;
\r
92 int giPL110_BufferMode;
\r
93 int giPL110_Width = 640;
\r
94 int giPL110_Height = 480;
\r
95 size_t giPL110_FramebufferSize;
\r
96 tPL110 *gpPL110_IOMem;
\r
97 tPAddr gPL110_FramebufferPhys;
\r
98 void *gpPL110_Framebuffer;
\r
100 tDrvUtil_Video_BufInfo gPL110_DrvUtil_BufInfo;
\r
105 int PL110_Install(char **Arguments)
\r
107 // KeyVal_Parse(&gPL110_KeyValueParser, Arguments);
\r
109 gpPL110_IOMem = (void*)MM_MapHWPages(gPL110_PhysBase, 1);
\r
111 PL110_int_SetResolution(caPL110_Modes[0].W, caPL110_Modes[0].H);
\r
113 DevFS_AddDevice( &gPL110_DriverStruct );
\r
119 * \brief Clean up resources for driver unloading
\r
121 void PL110_Uninstall()
\r
126 * \brief Read from the framebuffer
\r
128 Uint64 PL110_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer)
\r
134 * \brief Write to the framebuffer
\r
136 Uint64 PL110_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
\r
138 return DrvUtil_Video_WriteLFB(giPL110_BufferMode, &gPL110_DrvUtil_BufInfo, Offset, Length, Buffer);
\r
141 const char *csaPL110_IOCtls[] = {DRV_IOCTLNAMES, DRV_VIDEO_IOCTLNAMES, NULL};
\r
144 * \brief Handle messages to the device
\r
146 int PL110_IOCtl(tVFS_Node *Node, int ID, void *Data)
\r
149 ENTER("pNode iID pData", Node, ID, Data);
\r
153 BASE_IOCTLS(DRV_TYPE_VIDEO, "PL110", VERSION, csaPL110_IOCtls);
\r
155 case VIDEO_IOCTL_SETBUFFORMAT:
\r
156 ret = giPL110_BufferMode;
\r
157 if(Data) giPL110_BufferMode = *(int*)Data;
\r
160 case VIDEO_IOCTL_GETSETMODE:
\r
165 if( !CheckMem(Data, sizeof(int)) )
\r
166 LEAVE_RET('i', -1);
\r
168 newMode = *(int*)Data;
\r
170 if(newMode < 0 || newMode >= ciPL110_ModeCount)
\r
171 LEAVE_RET('i', -1);
\r
173 if(newMode != giPL110_CurrentMode)
\r
175 giPL110_CurrentMode = newMode;
\r
176 PL110_int_SetResolution( caPL110_Modes[newMode].W, caPL110_Modes[newMode].H );
\r
179 ret = giPL110_CurrentMode;
\r
182 case VIDEO_IOCTL_FINDMODE:
\r
184 tVideo_IOCtl_Mode *mode = Data;
\r
185 int closest, closestArea, reqArea = 0;
\r
186 if(!Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Mode)))
\r
187 LEAVE_RET('i', -1);
\r
188 if( mode->bpp != 32 )
\r
190 if( mode->flags != 0 )
\r
195 for( int i = 0; i < ciPL110_ModeCount; i ++ )
\r
198 if(mode->width == caPL110_Modes[i].W && mode->height == caPL110_Modes[i].H) {
\r
204 area = caPL110_Modes[i].W * caPL110_Modes[i].H;
\r
206 reqArea = mode->width * mode->height;
\r
208 closestArea = area;
\r
210 else if( ABS(area - reqArea) < ABS(closestArea - reqArea) ) {
\r
212 closestArea = area;
\r
218 mode->id = closest;
\r
221 mode->width = caPL110_Modes[mode->id].W;
\r
222 mode->height = caPL110_Modes[mode->id].H;
\r
226 case VIDEO_IOCTL_MODEINFO:
\r
228 tVideo_IOCtl_Mode *mode = Data;
\r
229 if(!Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Mode)))
\r
230 LEAVE_RET('i', -1);
\r
231 if(mode->id < 0 || mode->id >= ciPL110_ModeCount)
\r
237 mode->width = caPL110_Modes[mode->id].W;
\r
238 mode->height = caPL110_Modes[mode->id].H;
\r
244 case VIDEO_IOCTL_SETCURSOR: break;
\r
261 int PL110_int_SetResolution(int W, int H)
\r
264 if(W > 1024) W = 1024;
\r
265 if(H > 768) H = 768;
\r
267 gpPL110_IOMem->LCDTiming0 = ((W/16)-1) << 2;
\r
268 gpPL110_IOMem->LCDTiming1 = H-1;
\r
269 gpPL110_IOMem->LCDTiming2 = (14 << 27);
\r
270 gpPL110_IOMem->LCDTiming3 = 0;
\r
272 if( gpPL110_Framebuffer ) {
\r
273 MM_UnmapHWPages((tVAddr)gpPL110_Framebuffer, (giPL110_FramebufferSize+0xFFF)>>12);
\r
275 giPL110_FramebufferSize = W*H*4;
\r
277 gpPL110_Framebuffer = (void*)MM_AllocDMA( (giPL110_FramebufferSize+0xFFF)>>12, 32, &gPL110_FramebufferPhys );
\r
278 gpPL110_IOMem->LCDUPBase = gPL110_FramebufferPhys;
\r
279 gpPL110_IOMem->LCDLPBase = 0;
\r
281 gpPL110_IOMem->LCDIMSC = 0;
\r
282 gpPL110_IOMem->LCDControl = (1 << 11)|(1 << 5)|(5<<1)|1;
\r
285 giPL110_Height = H;
\r
287 // Update the DrvUtil buffer info
\r
288 gPL110_DrvUtil_BufInfo.Framebuffer = gpPL110_Framebuffer;
\r
289 gPL110_DrvUtil_BufInfo.Pitch = W * 4;
\r
290 gPL110_DrvUtil_BufInfo.Width = W;
\r
291 gPL110_DrvUtil_BufInfo.Height = H;
\r
292 gPL110_DrvUtil_BufInfo.Depth = 32;
\r