Modules/USB - Debugging polling and async
[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      // Integrator\r
48 \r
49 const struct {\r
50         short W, H;\r
51 }       caPL110_Modes[] = {\r
52         {640,480},\r
53         {800,600},\r
54         {1024,768}      // MAX\r
55 };\r
56 const int       ciPL110_ModeCount = sizeof(caPL110_Modes)/sizeof(caPL110_Modes[0]);\r
57 \r
58 // === PROTOTYPES ===\r
59 // Driver\r
60  int    PL110_Install(char **Arguments);\r
61 void    PL110_Uninstall();\r
62 // Internal\r
63 // Filesystem\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
67 // -- Internals\r
68  int    PL110_int_SetResolution(int W, int H);\r
69 \r
70 // === GLOBALS ===\r
71 MODULE_DEFINE(0, VERSION, PL110, PL110_Install, NULL, NULL);\r
72 tDevFS_Driver   gPL110_DriverStruct = {\r
73         NULL, "PL110",\r
74         {\r
75         .Read = PL110_Read,\r
76         .Write = PL110_Write,\r
77         .IOCtl = PL110_IOCtl\r
78         }\r
79 };\r
80 // -- Options\r
81 tPAddr  gPL110_PhysBase = PL110_BASE;\r
82  int    gbPL110_IsVersatile = 1;\r
83 // -- KeyVal parse rules\r
84 const tKeyVal_ParseRules        gPL110_KeyValueParser = {\r
85         NULL,\r
86         {\r
87                 {"Base", "P", &gPL110_PhysBase},\r
88                 {"IsVersatile", "i", &gbPL110_IsVersatile},\r
89                 {NULL, NULL, NULL}\r
90         }\r
91 };\r
92 // -- Driver state\r
93  int    giPL110_CurrentMode = 0;\r
94  int    giPL110_BufferMode;\r
95  int    giPL110_Width = 640;\r
96  int    giPL110_Height = 480;\r
97 size_t  giPL110_FramebufferSize;\r
98 tPL110  *gpPL110_IOMem;\r
99 tPAddr  gPL110_FramebufferPhys;\r
100 void    *gpPL110_Framebuffer;\r
101 // -- Misc\r
102 tDrvUtil_Video_BufInfo  gPL110_DrvUtil_BufInfo;\r
103 tVideo_IOCtl_Pos        gPL110_CursorPos;\r
104 \r
105 // === CODE ===\r
106 /**\r
107  */\r
108 int PL110_Install(char **Arguments)\r
109 {\r
110 //      KeyVal_Parse(&gPL110_KeyValueParser, Arguments);\r
111         \r
112         gpPL110_IOMem = (void*)MM_MapHWPages(gPL110_PhysBase, 1);\r
113 \r
114         PL110_int_SetResolution(caPL110_Modes[0].W, caPL110_Modes[0].H);\r
115 \r
116         DevFS_AddDevice( &gPL110_DriverStruct );\r
117 \r
118         return 0;\r
119 }\r
120 \r
121 /**\r
122  * \brief Clean up resources for driver unloading\r
123  */\r
124 void PL110_Uninstall()\r
125 {\r
126 }\r
127 \r
128 /**\r
129  * \brief Read from the framebuffer\r
130  */\r
131 Uint64 PL110_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer)\r
132 {\r
133         return 0;\r
134 }\r
135 \r
136 /**\r
137  * \brief Write to the framebuffer\r
138  */\r
139 Uint64 PL110_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)\r
140 {\r
141         gPL110_DrvUtil_BufInfo.BufferFormat = giPL110_BufferMode;\r
142         return DrvUtil_Video_WriteLFB(&gPL110_DrvUtil_BufInfo, Offset, Length, Buffer);\r
143 }\r
144 \r
145 const char *csaPL110_IOCtls[] = {DRV_IOCTLNAMES, DRV_VIDEO_IOCTLNAMES, NULL};\r
146 \r
147 /**\r
148  * \brief Handle messages to the device\r
149  */\r
150 int PL110_IOCtl(tVFS_Node *Node, int ID, void *Data)\r
151 {\r
152          int    ret = -2;\r
153         ENTER("pNode iID pData", Node, ID, Data);\r
154         \r
155         switch(ID)\r
156         {\r
157         BASE_IOCTLS(DRV_TYPE_VIDEO, "PL110", VERSION, csaPL110_IOCtls);\r
158 \r
159         case VIDEO_IOCTL_SETBUFFORMAT:\r
160                 DrvUtil_Video_RemoveCursor( &gPL110_DrvUtil_BufInfo );\r
161                 ret = giPL110_BufferMode;\r
162                 if(Data)        giPL110_BufferMode = *(int*)Data;\r
163                 if(gPL110_DrvUtil_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)\r
164                         DrvUtil_Video_SetCursor( &gPL110_DrvUtil_BufInfo, &gDrvUtil_TextModeCursor );\r
165                 break;\r
166         \r
167         case VIDEO_IOCTL_GETSETMODE:\r
168                 if(Data)\r
169                 {\r
170                          int    newMode;\r
171                         \r
172                         if( !CheckMem(Data, sizeof(int)) )\r
173                                 LEAVE_RET('i', -1);\r
174                         \r
175                         newMode = *(int*)Data;\r
176                         \r
177                         if(newMode < 0 || newMode >= ciPL110_ModeCount)\r
178                                 LEAVE_RET('i', -1);\r
179 \r
180                         if(newMode != giPL110_CurrentMode)\r
181                         {\r
182                                 giPL110_CurrentMode = newMode;\r
183                                 PL110_int_SetResolution( caPL110_Modes[newMode].W, caPL110_Modes[newMode].H );\r
184                         }\r
185                 }\r
186                 ret = giPL110_CurrentMode;\r
187                 break;\r
188         \r
189         case VIDEO_IOCTL_FINDMODE:\r
190                 {\r
191                 tVideo_IOCtl_Mode *mode = Data;\r
192                  int    closest, closestArea, reqArea = 0;\r
193                 if(!Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Mode)))\r
194                         LEAVE_RET('i', -1);\r
195                 if( mode->bpp != 32 )\r
196                         LEAVE_RET('i', 0);\r
197                 if( mode->flags != 0 )\r
198                         LEAVE_RET('i', 0);\r
199 \r
200                 ret = 0;\r
201 \r
202                 for( int i = 0; i < ciPL110_ModeCount; i ++ )\r
203                 {\r
204                          int    area;\r
205                         if(mode->width == caPL110_Modes[i].W && mode->height == caPL110_Modes[i].H) {\r
206                                 mode->id = i;\r
207                                 ret = 1;\r
208                                 break;\r
209                         }\r
210                         \r
211                         area = caPL110_Modes[i].W * caPL110_Modes[i].H;\r
212                         if(!reqArea) {\r
213                                 reqArea = mode->width * mode->height;\r
214                                 closest = i;\r
215                                 closestArea = area;\r
216                         }\r
217                         else if( ABS(area - reqArea) < ABS(closestArea - reqArea) ) {\r
218                                 closest = i;\r
219                                 closestArea = area;\r
220                         }\r
221                 }\r
222                 \r
223                 if( ret == 0 )\r
224                 {\r
225                         mode->id = closest;\r
226                         ret = 1;\r
227                 }\r
228                 mode->width = caPL110_Modes[mode->id].W;\r
229                 mode->height = caPL110_Modes[mode->id].H;\r
230                 break;\r
231                 }\r
232         \r
233         case VIDEO_IOCTL_MODEINFO:\r
234                 {\r
235                 tVideo_IOCtl_Mode *mode = Data;\r
236                 if(!Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Mode)))\r
237                         LEAVE_RET('i', -1);\r
238                 if(mode->id < 0 || mode->id >= ciPL110_ModeCount)\r
239                         LEAVE_RET('i', 0);\r
240                 \r
241 \r
242                 mode->bpp = 32;\r
243                 mode->flags = 0;\r
244                 mode->width = caPL110_Modes[mode->id].W;\r
245                 mode->height = caPL110_Modes[mode->id].H;\r
246 \r
247                 ret = 1;\r
248                 break;\r
249                 }\r
250         \r
251         case VIDEO_IOCTL_SETCURSOR:\r
252                 if( !Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Pos)) )\r
253                         LEAVE_RET('i', -1);\r
254 \r
255                 DrvUtil_Video_RemoveCursor( &gPL110_DrvUtil_BufInfo );\r
256                 \r
257                 gPL110_CursorPos = *(tVideo_IOCtl_Pos*)Data;\r
258                 if(gPL110_DrvUtil_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)\r
259                         DrvUtil_Video_DrawCursor(\r
260                                 &gPL110_DrvUtil_BufInfo,\r
261                                 gPL110_CursorPos.x*giVT_CharWidth,\r
262                                 gPL110_CursorPos.y*giVT_CharHeight\r
263                                 );\r
264                 else\r
265                         DrvUtil_Video_DrawCursor(\r
266                                 &gPL110_DrvUtil_BufInfo,\r
267                                 gPL110_CursorPos.x,\r
268                                 gPL110_CursorPos.y\r
269                                 );\r
270                 break;\r
271         \r
272         default:\r
273                 LEAVE('i', -2);\r
274                 return -2;\r
275         }\r
276         \r
277         LEAVE('i', ret);\r
278         return ret;\r
279 }\r
280 \r
281 //\r
282 //\r
283 //\r
284 \r
285 /**\r
286  * \brief Set the LCD controller resolution\r
287  * \param W     Width (aligned to 16 pixels, cipped to 1024)\r
288  * \param H     Height (clipped to 768)\r
289  * \return Boolean failure\r
290  */\r
291 int PL110_int_SetResolution(int W, int H)\r
292 {\r
293         W = (W + 15) & ~0xF;\r
294         if(W <= 0 || H <= 0) {\r
295                 Log_Warning("PL110", "Attempted to set invalid resolution (%ix%i)", W, H);\r
296                 return 1;\r
297         }\r
298         if(W > 1024)    W = 1024;\r
299         if(H > 768)     H = 768;\r
300 \r
301         gpPL110_IOMem->LCDTiming0 = ((W/16)-1) << 2;\r
302         gpPL110_IOMem->LCDTiming1 = H-1;\r
303         gpPL110_IOMem->LCDTiming2 = (14 << 27);\r
304         gpPL110_IOMem->LCDTiming3 = 0;\r
305 \r
306         if( gpPL110_Framebuffer ) {\r
307                 MM_UnmapHWPages((tVAddr)gpPL110_Framebuffer, (giPL110_FramebufferSize+0xFFF)>>12);\r
308         }\r
309         giPL110_FramebufferSize = W*H*4;\r
310 \r
311         gpPL110_Framebuffer = (void*)MM_AllocDMA( (giPL110_FramebufferSize+0xFFF)>>12, 32, &gPL110_FramebufferPhys );\r
312         gpPL110_IOMem->LCDUPBase = gPL110_FramebufferPhys;\r
313         gpPL110_IOMem->LCDLPBase = 0;\r
314 \r
315         // Power on, BGR mode, ???, ???, enabled\r
316         Uint32  controlWord = (1 << 11)|(1 << 8)|(1 << 5)|(5 << 1)|1;\r
317         // According to qemu, the Versatile version has these two the wrong\r
318         // way around\r
319         if( gbPL110_IsVersatile )\r
320         {\r
321                 gpPL110_IOMem->LCDIMSC = controlWord;   // Actually LCDControl\r
322                 gpPL110_IOMem->LCDControl = 0;  // Actually LCDIMSC\r
323         }\r
324         else\r
325         {\r
326                 gpPL110_IOMem->LCDIMSC = 0;\r
327                 gpPL110_IOMem->LCDControl = controlWord;\r
328         }\r
329 \r
330         giPL110_Width = W;\r
331         giPL110_Height = H;\r
332 \r
333         // Update the DrvUtil buffer info\r
334         gPL110_DrvUtil_BufInfo.Framebuffer = gpPL110_Framebuffer;\r
335         gPL110_DrvUtil_BufInfo.Pitch = W * 4;\r
336         gPL110_DrvUtil_BufInfo.Width = W;\r
337         gPL110_DrvUtil_BufInfo.Height = H;\r
338         gPL110_DrvUtil_BufInfo.Depth = 32;\r
339         \r
340         return 0;\r
341 }\r

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