Modules/Tegra2Disp - Initial commit, doesn't work but getting there
[tpg/acess2.git] / Modules / Display / Tegra2 / main.c
1 /**\r
2  * main.c\r
3  * - Driver core\r
4  */\r
5 #define DEBUG   0\r
6 #define VERSION ((0<<8)|10)\r
7 #include <acess.h>\r
8 #include <errno.h>\r
9 #include <modules.h>\r
10 #include <vfs.h>\r
11 #include <fs_devfs.h>\r
12 #include <drv_pci.h>\r
13 #include <api_drv_video.h>\r
14 #include <lib/keyvalue.h>\r
15 #include <options.h>    // ARM Arch\r
16 \r
17 #define ABS(a)  ((a)>0?(a):-(a))\r
18 \r
19 // === PROTOTYPES ===\r
20 // Driver\r
21  int    Tegra2Vid_Install(char **Arguments);\r
22 void    Tegra2Vid_Uninstall();\r
23 // Internal\r
24 // Filesystem\r
25 Uint64  Tegra2Vid_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer);\r
26 Uint64  Tegra2Vid_Write(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer);\r
27  int    Tegra2Vid_IOCtl(tVFS_Node *node, int id, void *data);\r
28 // -- Internals\r
29  int    Tegra2Vid_int_SetResolution(int W, int H);\r
30 \r
31 // === GLOBALS ===\r
32 MODULE_DEFINE(0, VERSION, PL110, Tegra2Vid_Install, NULL, NULL);\r
33 tDevFS_Driver   gTegra2Vid_DriverStruct = {\r
34         NULL, "PL110",\r
35         {\r
36         .Read = Tegra2Vid_Read,\r
37         .Write = Tegra2Vid_Write,\r
38         .IOCtl = Tegra2Vid_IOCtl\r
39         }\r
40 };\r
41 // -- Options\r
42 tPAddr  gTegra2Vid_PhysBase = Tegra2Vid_BASE;\r
43  int    gbTegra2Vid_IsVersatile = 1;\r
44 // -- KeyVal parse rules\r
45 const tKeyVal_ParseRules        gTegra2Vid_KeyValueParser = {\r
46         NULL,\r
47         {\r
48                 {"Base", "P", &gTegra2Vid_PhysBase},\r
49                 {"IsVersatile", "i", &gbTegra2Vid_IsVersatile},\r
50                 {NULL, NULL, NULL}\r
51         }\r
52 };\r
53 // -- Driver state\r
54  int    giTegra2Vid_CurrentMode = 0;\r
55  int    giTegra2Vid_BufferMode;\r
56  int    giTegra2Vid_Width = 640;\r
57  int    giTegra2Vid_Height = 480;\r
58 size_t  giTegra2Vid_FramebufferSize;\r
59 Uint8   *gpTegra2Vid_IOMem;\r
60 tPAddr  gTegra2Vid_FramebufferPhys;\r
61 void    *gpTegra2Vid_Framebuffer;\r
62 // -- Misc\r
63 tDrvUtil_Video_BufInfo  gTegra2Vid_DrvUtil_BufInfo;\r
64 tVideo_IOCtl_Pos        gTegra2Vid_CursorPos;\r
65 \r
66 // === CODE ===\r
67 /**\r
68  */\r
69 int Tegra2Vid_Install(char **Arguments)\r
70 {\r
71 //      KeyVal_Parse(&gTegra2Vid_KeyValueParser, Arguments);\r
72         \r
73         gpTegra2Vid_IOMem = (void*)MM_MapHWPages(gTegra2Vid_PhysBase, 1);\r
74 \r
75         Tegra2Vid_int_SetResolution(caTegra2Vid_Modes[0].W, caTegra2Vid_Modes[0].H);\r
76 \r
77         DevFS_AddDevice( &gTegra2Vid_DriverStruct );\r
78 \r
79         return 0;\r
80 }\r
81 \r
82 /**\r
83  * \brief Clean up resources for driver unloading\r
84  */\r
85 void Tegra2Vid_Uninstall()\r
86 {\r
87 }\r
88 \r
89 /**\r
90  * \brief Read from the framebuffer\r
91  */\r
92 Uint64 Tegra2Vid_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer)\r
93 {\r
94         return 0;\r
95 }\r
96 \r
97 /**\r
98  * \brief Write to the framebuffer\r
99  */\r
100 Uint64 Tegra2Vid_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)\r
101 {\r
102         gTegra2Vid_DrvUtil_BufInfo.BufferFormat = giTegra2Vid_BufferMode;\r
103         return DrvUtil_Video_WriteLFB(&gTegra2Vid_DrvUtil_BufInfo, Offset, Length, Buffer);\r
104 }\r
105 \r
106 const char *csaTegra2Vid_IOCtls[] = {DRV_IOCTLNAMES, DRV_VIDEO_IOCTLNAMES, NULL};\r
107 \r
108 /**\r
109  * \brief Handle messages to the device\r
110  */\r
111 int Tegra2Vid_IOCtl(tVFS_Node *Node, int ID, void *Data)\r
112 {\r
113          int    ret = -2;\r
114         ENTER("pNode iID pData", Node, ID, Data);\r
115         \r
116         switch(ID)\r
117         {\r
118         BASE_IOCTLS(DRV_TYPE_VIDEO, "PL110", VERSION, csaTegra2Vid_IOCtls);\r
119 \r
120         case VIDEO_IOCTL_SETBUFFORMAT:\r
121                 DrvUtil_Video_RemoveCursor( &gTegra2Vid_DrvUtil_BufInfo );\r
122                 ret = giTegra2Vid_BufferMode;\r
123                 if(Data)        giTegra2Vid_BufferMode = *(int*)Data;\r
124                 if(gTegra2Vid_DrvUtil_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)\r
125                         DrvUtil_Video_SetCursor( &gTegra2Vid_DrvUtil_BufInfo, &gDrvUtil_TextModeCursor );\r
126                 break;\r
127         \r
128         case VIDEO_IOCTL_GETSETMODE:\r
129                 if(Data)\r
130                 {\r
131                          int    newMode;\r
132                         \r
133                         if( !CheckMem(Data, sizeof(int)) )\r
134                                 LEAVE_RET('i', -1);\r
135                         \r
136                         newMode = *(int*)Data;\r
137                         \r
138                         if(newMode < 0 || newMode >= ciTegra2Vid_ModeCount)\r
139                                 LEAVE_RET('i', -1);\r
140 \r
141                         if(newMode != giTegra2Vid_CurrentMode)\r
142                         {\r
143                                 giTegra2Vid_CurrentMode = newMode;\r
144                                 Tegra2Vid_int_SetResolution( caTegra2Vid_Modes[newMode].W, caTegra2Vid_Modes[newMode].H );\r
145                         }\r
146                 }\r
147                 ret = giTegra2Vid_CurrentMode;\r
148                 break;\r
149         \r
150         case VIDEO_IOCTL_FINDMODE:\r
151                 {\r
152                 tVideo_IOCtl_Mode *mode = Data;\r
153                  int    closest, closestArea, reqArea = 0;\r
154                 if(!Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Mode)))\r
155                         LEAVE_RET('i', -1);\r
156                 if( mode->bpp != 32 )\r
157                         LEAVE_RET('i', 0);\r
158                 if( mode->flags != 0 )\r
159                         LEAVE_RET('i', 0);\r
160 \r
161                 ret = 0;\r
162 \r
163                 for( int i = 0; i < ciTegra2Vid_ModeCount; i ++ )\r
164                 {\r
165                          int    area;\r
166                         if(mode->width == caTegra2Vid_Modes[i].W && mode->height == caTegra2Vid_Modes[i].H) {\r
167                                 mode->id = i;\r
168                                 ret = 1;\r
169                                 break;\r
170                         }\r
171                         \r
172                         area = caTegra2Vid_Modes[i].W * caTegra2Vid_Modes[i].H;\r
173                         if(!reqArea) {\r
174                                 reqArea = mode->width * mode->height;\r
175                                 closest = i;\r
176                                 closestArea = area;\r
177                         }\r
178                         else if( ABS(area - reqArea) < ABS(closestArea - reqArea) ) {\r
179                                 closest = i;\r
180                                 closestArea = area;\r
181                         }\r
182                 }\r
183                 \r
184                 if( ret == 0 )\r
185                 {\r
186                         mode->id = closest;\r
187                         ret = 1;\r
188                 }\r
189                 mode->width = caTegra2Vid_Modes[mode->id].W;\r
190                 mode->height = caTegra2Vid_Modes[mode->id].H;\r
191                 break;\r
192                 }\r
193         \r
194         case VIDEO_IOCTL_MODEINFO:\r
195                 {\r
196                 tVideo_IOCtl_Mode *mode = Data;\r
197                 if(!Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Mode)))\r
198                         LEAVE_RET('i', -1);\r
199                 if(mode->id < 0 || mode->id >= ciTegra2Vid_ModeCount)\r
200                         LEAVE_RET('i', 0);\r
201                 \r
202 \r
203                 mode->bpp = 32;\r
204                 mode->flags = 0;\r
205                 mode->width = caTegra2Vid_Modes[mode->id].W;\r
206                 mode->height = caTegra2Vid_Modes[mode->id].H;\r
207 \r
208                 ret = 1;\r
209                 break;\r
210                 }\r
211         \r
212         case VIDEO_IOCTL_SETCURSOR:\r
213                 if( !Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Pos)) )\r
214                         LEAVE_RET('i', -1);\r
215 \r
216                 DrvUtil_Video_RemoveCursor( &gTegra2Vid_DrvUtil_BufInfo );\r
217                 \r
218                 gTegra2Vid_CursorPos = *(tVideo_IOCtl_Pos*)Data;\r
219                 if(gTegra2Vid_DrvUtil_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)\r
220                         DrvUtil_Video_DrawCursor(\r
221                                 &gTegra2Vid_DrvUtil_BufInfo,\r
222                                 gTegra2Vid_CursorPos.x*giVT_CharWidth,\r
223                                 gTegra2Vid_CursorPos.y*giVT_CharHeight\r
224                                 );\r
225                 else\r
226                         DrvUtil_Video_DrawCursor(\r
227                                 &gTegra2Vid_DrvUtil_BufInfo,\r
228                                 gTegra2Vid_CursorPos.x,\r
229                                 gTegra2Vid_CursorPos.y\r
230                                 );\r
231                 break;\r
232         \r
233         default:\r
234                 LEAVE('i', -2);\r
235                 return -2;\r
236         }\r
237         \r
238         LEAVE('i', ret);\r
239         return ret;\r
240 }\r
241 \r
242 //\r
243 //\r
244 //\r
245 \r
246 /**\r
247  * \brief Set the LCD controller resolution\r
248  * \param W     Width (aligned to 16 pixels, cipped to 1024)\r
249  * \param H     Height (clipped to 768)\r
250  * \return Boolean failure\r
251  */\r
252 int Tegra2Vid_int_SetResolution(int W, int H)\r
253 {\r
254         W = (W + 15) & ~0xF;\r
255         if(W <= 0 || H <= 0) {\r
256                 Log_Warning("PL110", "Attempted to set invalid resolution (%ix%i)", W, H);\r
257                 return 1;\r
258         }\r
259         if(W > 1024)    W = 1920;\r
260         if(H > 768)     H = 1080;\r
261 \r
262         gpTegra2Vid_IOMem->DCWinAPos = 0;\r
263         gpTegra2Vid_IOMem->DCWinASize = (H << 16) | W;\r
264 \r
265         if( gpTegra2Vid_Framebuffer ) {\r
266                 MM_UnmapHWPages((tVAddr)gpTegra2Vid_Framebuffer, (giTegra2Vid_FramebufferSize+0xFFF)>>12);\r
267         }\r
268         giTegra2Vid_FramebufferSize = W*H*4;\r
269 \r
270         gpTegra2Vid_Framebuffer = (void*)MM_AllocDMA( (giTegra2Vid_FramebufferSize+0xFFF)>>12, 32, &gTegra2Vid_FramebufferPhys );\r
271         gpTegra2Vid_IOMem->LCDUPBase = gTegra2Vid_FramebufferPhys;\r
272         gpTegra2Vid_IOMem->LCDLPBase = 0;\r
273 \r
274         // Power on, BGR mode, ???, ???, enabled\r
275         Uint32  controlWord = (1 << 11)|(1 << 8)|(1 << 5)|(5 << 1)|1;\r
276         // According to qemu, the Versatile version has these two the wrong\r
277         // way around\r
278         if( gbTegra2Vid_IsVersatile )\r
279         {\r
280                 gpTegra2Vid_IOMem->LCDIMSC = controlWord;       // Actually LCDControl\r
281                 gpTegra2Vid_IOMem->LCDControl = 0;      // Actually LCDIMSC\r
282         }\r
283         else\r
284         {\r
285                 gpTegra2Vid_IOMem->LCDIMSC = 0;\r
286                 gpTegra2Vid_IOMem->LCDControl = controlWord;\r
287         }\r
288 \r
289         giTegra2Vid_Width = W;\r
290         giTegra2Vid_Height = H;\r
291 \r
292         // Update the DrvUtil buffer info\r
293         gTegra2Vid_DrvUtil_BufInfo.Framebuffer = gpTegra2Vid_Framebuffer;\r
294         gTegra2Vid_DrvUtil_BufInfo.Pitch = W * 4;\r
295         gTegra2Vid_DrvUtil_BufInfo.Width = W;\r
296         gTegra2Vid_DrvUtil_BufInfo.Height = H;\r
297         gTegra2Vid_DrvUtil_BufInfo.Depth = 32;\r
298         \r
299         return 0;\r
300 }\r
301 \r
302 int Tegra2_int_SetMode(int Mode)\r
303 {\r
304         *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_FRONT_PORTCH_0) = (gaTegra2Modes[Mode].VFP << 16) | gaTegra2Modes[Mode].HFP; \r
305         *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_SYNC_WIDTH_0) = (gaTegra2Modes[Mode].HS << 16) | gaTegra2Modes[Mode].HS;\r
306         *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_BACK_PORTCH_0) = (gaTegra2Modes[Mode].VBP << 16) | gaTegra2Modes[Mode].HBP;\r
307         *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_DISP_ACTIVE_0) = (gaTegra2Modes[Mode].VA << 16) | gaTegra2Modes[Mode].HA;\r
308 \r
309         *(Uint32*)(gpTegra2Vid_IOMem + DC_WIN_A_POSITION_0) = 0;\r
310         *(Uint32*)(gpTegra2Vid_IOMem + DC_WIN_A_SIZE_0) = (gaTegra2Modes[Mode].VA << 16) | gaTegra2Modes[Mode].HA;\r
311         *(Uint8*)(gpTegra2Vid_IOMem + DC_WIN_A_COLOR_DEPTH_0) = 12;     // Could be 13 (BGR/RGB)\r
312         *(Uint32*)(gpTegra2Vid_IOMem + DC_WIN_A_PRESCALED_SIZE_0) = (gaTegra2Modes[Mode].VA << 16) | gaTegra2Modes[Mode].HA;\r
313 \r
314         return 0;\r
315 }\r

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