Modules/PL110 - Added ARM PL110 CLCD driver
[tpg/acess2.git] / Modules / Display / PL110 / main.c
1 /**\r
2  * Acess2 ARM PrimeCell Colour LCD Controller (PL110) Driver\r
3  * - By John Hodge (thePowersGang)\r
4  *\r
5  * main.c\r
6  * - Driver core\r
7  *\r
8  *\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
11  */\r
12 #define DEBUG   0\r
13 #define VERSION ((0<<8)|10)\r
14 #include <acess.h>\r
15 #include <errno.h>\r
16 #include <modules.h>\r
17 #include <vfs.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
22 \r
23 #define ABS(a)  ((a)>0?(a):-(a))\r
24 \r
25 // === TYPEDEFS ===\r
26 typedef struct sPL110   tPL110;\r
27 \r
28 struct sPL110\r
29 {\r
30         Uint32  LCDTiming0;\r
31         Uint32  LCDTiming1;\r
32         Uint32  LCDTiming2;\r
33         Uint32  LCDTiming3;\r
34         \r
35         Uint32  LCDUPBase;\r
36         Uint32  LCDLPBase;\r
37         Uint32  LCDIMSC;\r
38         Uint32  LCDControl;\r
39         Uint32  LCDRIS;\r
40         Uint32  LCDMIS;\r
41         Uint32  LCDICR;\r
42         Uint32  LCDUPCurr;\r
43         Uint32  LCDLPCurr;\r
44 };\r
45 \r
46 // === CONSTANTS ===\r
47 #define PL110_BASE      0x10020000      \r
48 const struct {\r
49         short W, H;\r
50 }       caPL110_Modes[] = {\r
51         {640,480},\r
52         {800,600},\r
53         {1024,768}      // MAX\r
54 };\r
55 const int       ciPL110_ModeCount = sizeof(caPL110_Modes)/sizeof(caPL110_Modes[0]);\r
56 \r
57 // === PROTOTYPES ===\r
58 // Driver\r
59  int    PL110_Install(char **Arguments);\r
60 void    PL110_Uninstall();\r
61 // Internal\r
62 // Filesystem\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
66 // -- Internals\r
67  int    PL110_int_SetResolution(int W, int H);\r
68 \r
69 // === GLOBALS ===\r
70 MODULE_DEFINE(0, VERSION, PL110, PL110_Install, NULL, NULL);\r
71 tDevFS_Driver   gPL110_DriverStruct = {\r
72         NULL, "PL110",\r
73         {\r
74         .Read = PL110_Read,\r
75         .Write = PL110_Write,\r
76         .IOCtl = PL110_IOCtl\r
77         }\r
78 };\r
79 // -- Options\r
80 tPAddr  gPL110_PhysBase = PL110_BASE;\r
81 // -- KeyVal parse rules\r
82 const tKeyVal_ParseRules        gPL110_KeyValueParser = {\r
83         NULL,\r
84         {\r
85                 {"Base", "P", &gPL110_PhysBase},\r
86                 {NULL, NULL, NULL}\r
87         }\r
88 };\r
89 // -- Driver state\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
98 // -- Misc\r
99 tDrvUtil_Video_BufInfo  gPL110_DrvUtil_BufInfo;\r
100 \r
101 // === CODE ===\r
102 /**\r
103  */\r
104 int PL110_Install(char **Arguments)\r
105 {\r
106 //      KeyVal_Parse(&gPL110_KeyValueParser, Arguments);\r
107         \r
108         gpPL110_IOMem = (void*)MM_MapHWPages(gPL110_PhysBase, 1);\r
109 \r
110         PL110_int_SetResolution(caPL110_Modes[0].W, caPL110_Modes[0].H);\r
111 \r
112         DevFS_AddDevice( &gPL110_DriverStruct );\r
113 \r
114         return 0;\r
115 }\r
116 \r
117 /**\r
118  * \brief Clean up resources for driver unloading\r
119  */\r
120 void PL110_Uninstall()\r
121 {\r
122 }\r
123 \r
124 /**\r
125  * \brief Read from the framebuffer\r
126  */\r
127 Uint64 PL110_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer)\r
128 {\r
129         return 0;\r
130 }\r
131 \r
132 /**\r
133  * \brief Write to the framebuffer\r
134  */\r
135 Uint64 PL110_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)\r
136 {\r
137         return DrvUtil_Video_WriteLFB(giPL110_BufferMode, &gPL110_DrvUtil_BufInfo, Offset, Length, Buffer);\r
138 }\r
139 \r
140 const char *csaPL110_IOCtls[] = {DRV_IOCTLNAMES, DRV_VIDEO_IOCTLNAMES, NULL};\r
141 \r
142 /**\r
143  * \brief Handle messages to the device\r
144  */\r
145 int PL110_IOCtl(tVFS_Node *Node, int ID, void *Data)\r
146 {\r
147          int    ret = -2;\r
148         ENTER("pNode iID pData", Node, ID, Data);\r
149         \r
150         switch(ID)\r
151         {\r
152         BASE_IOCTLS(DRV_TYPE_VIDEO, "PL110", VERSION, csaPL110_IOCtls);\r
153 \r
154         case VIDEO_IOCTL_SETBUFFORMAT:\r
155                 ret = giPL110_BufferMode;\r
156                 if(Data)        giPL110_BufferMode = *(int*)Data;\r
157                 break;\r
158         \r
159         case VIDEO_IOCTL_GETSETMODE:\r
160                 if(Data)\r
161                 {\r
162                          int    newMode;\r
163                         \r
164                         if( !CheckMem(Data, sizeof(int)) )\r
165                                 LEAVE_RET('i', -1);\r
166                         \r
167                         newMode = *(int*)Data;\r
168                         \r
169                         if(newMode < 0 || newMode >= ciPL110_ModeCount)\r
170                                 LEAVE_RET('i', -1);\r
171 \r
172                         if(newMode != giPL110_CurrentMode)\r
173                         {\r
174                                 giPL110_CurrentMode = newMode;\r
175                                 PL110_int_SetResolution( caPL110_Modes[newMode].W, caPL110_Modes[newMode].H );\r
176                         }\r
177                 }\r
178                 ret = giPL110_CurrentMode;\r
179                 break;\r
180         \r
181         case VIDEO_IOCTL_FINDMODE:\r
182                 {\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
188                         LEAVE_RET('i', 0);\r
189                 if( mode->flags != 0 )\r
190                         LEAVE_RET('i', 0);\r
191 \r
192                 ret = 0;\r
193 \r
194                 for( int i = 0; i < ciPL110_ModeCount; i ++ )\r
195                 {\r
196                          int    area;\r
197                         if(mode->width == caPL110_Modes[i].W && mode->height == caPL110_Modes[i].H) {\r
198                                 mode->id = i;\r
199                                 ret = 1;\r
200                                 break;\r
201                         }\r
202                         \r
203                         area = caPL110_Modes[i].W * caPL110_Modes[i].H;\r
204                         if(!reqArea) {\r
205                                 reqArea = mode->width * mode->height;\r
206                                 closest = i;\r
207                                 closestArea = area;\r
208                         }\r
209                         else if( ABS(area - reqArea) < ABS(closestArea - reqArea) ) {\r
210                                 closest = i;\r
211                                 closestArea = area;\r
212                         }\r
213                 }\r
214                 \r
215                 if( ret == 0 )\r
216                 {\r
217                         mode->id = closest;\r
218                         ret = 1;\r
219                 }\r
220                 mode->width = caPL110_Modes[mode->id].W;\r
221                 mode->height = caPL110_Modes[mode->id].H;\r
222                 break;\r
223                 }\r
224         \r
225         case VIDEO_IOCTL_MODEINFO:\r
226                 {\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
231                         LEAVE_RET('i', 0);\r
232                 \r
233 \r
234                 mode->bpp = 32;\r
235                 mode->flags = 0;\r
236                 mode->width = caPL110_Modes[mode->id].W;\r
237                 mode->height = caPL110_Modes[mode->id].H;\r
238 \r
239                 ret = 1;\r
240                 break;\r
241                 }\r
242         \r
243         case VIDEO_IOCTL_SETCURSOR:     break;\r
244         \r
245         default:\r
246                 LEAVE('i', -2);\r
247                 return -2;\r
248         }\r
249         \r
250         LEAVE('i', ret);\r
251         return ret;\r
252 }\r
253 \r
254 //\r
255 //\r
256 //\r
257 \r
258 /**\r
259  */\r
260 int PL110_int_SetResolution(int W, int H)\r
261 {\r
262         W = (W + 15)/16;\r
263         if(W > 1024)    W = 1024;\r
264         if(H > 768)     H = 768;\r
265 \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
270 \r
271         if( gpPL110_Framebuffer ) {\r
272                 MM_UnmapHWPages((tVAddr)gpPL110_Framebuffer, (giPL110_FramebufferSize+0xFFF)>>12);\r
273         }\r
274         giPL110_FramebufferSize = W*H*4;\r
275 \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
279 \r
280         gpPL110_IOMem->LCDIMSC = 0;\r
281         gpPL110_IOMem->LCDControl = (1 << 11)|(1 << 5)|(5<<1)|1;\r
282 \r
283         giPL110_Width = W;\r
284         giPL110_Height = H;\r
285 \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
292         \r
293         return 0;\r
294 }\r

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