d9405be051b80d140803f896748bb2469a0a5f78
[tpg/acess2.git] / Modules / Display / Tegra2Vid / 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 #include "tegra2.h"\r
17 \r
18 #define ABS(a)  ((a)>0?(a):-(a))\r
19 \r
20 // === PROTOTYPES ===\r
21 // Driver\r
22  int    Tegra2Vid_Install(char **Arguments);\r
23 void    Tegra2Vid_Uninstall();\r
24 // Internal\r
25 // Filesystem\r
26 Uint64  Tegra2Vid_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer);\r
27 Uint64  Tegra2Vid_Write(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer);\r
28  int    Tegra2Vid_IOCtl(tVFS_Node *node, int id, void *data);\r
29 // -- Internals\r
30  int    Tegra2Vid_int_SetMode(int Mode);\r
31 \r
32 // === GLOBALS ===\r
33 MODULE_DEFINE(0, VERSION, Tegra2Vid, Tegra2Vid_Install, NULL, NULL);\r
34 tDevFS_Driver   gTegra2Vid_DriverStruct = {\r
35         NULL, "Tegra2Vid",\r
36         {\r
37         .Read = Tegra2Vid_Read,\r
38         .Write = Tegra2Vid_Write,\r
39         .IOCtl = Tegra2Vid_IOCtl\r
40         }\r
41 };\r
42 // -- Options\r
43 tPAddr  gTegra2Vid_PhysBase = TEGRA2VID_BASE;\r
44  int    gbTegra2Vid_IsVersatile = 1;\r
45 // -- KeyVal parse rules\r
46 const tKeyVal_ParseRules        gTegra2Vid_KeyValueParser = {\r
47         NULL,\r
48         {\r
49                 {"Base", "P", &gTegra2Vid_PhysBase},\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 size_t  giTegra2Vid_FramebufferSize;\r
57 Uint32  *gpTegra2Vid_IOMem;\r
58 tPAddr  gTegra2Vid_FramebufferPhys;\r
59 void    *gpTegra2Vid_Framebuffer;\r
60 // -- Misc\r
61 tDrvUtil_Video_BufInfo  gTegra2Vid_DrvUtil_BufInfo;\r
62 tVideo_IOCtl_Pos        gTegra2Vid_CursorPos;\r
63 \r
64 // === CODE ===\r
65 /**\r
66  */\r
67 int Tegra2Vid_Install(char **Arguments)\r
68 {\r
69 //      KeyVal_Parse(&gTegra2Vid_KeyValueParser, Arguments);\r
70 \r
71         gpTegra2Vid_IOMem = (void*)MM_MapHWPages(gTegra2Vid_PhysBase, 256/4);\r
72         {\r
73                 Log_Debug("Tegra2Vid", "Display CMD Registers");\r
74                 for( int i = 0x000; i <= 0x01A; i ++ )\r
75                         Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);\r
76                 for( int i = 0x028; i <= 0x043; i ++ )\r
77                         Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);\r
78                 Log_Debug("Tegra2Vid", "Display COM Registers");\r
79                 for( int i = 0x300; i <= 0x329; i ++ )\r
80                         Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);\r
81                 Log_Debug("Tegra2Vid", "Display DISP Registers");\r
82                 for( int i = 0x400; i <= 0x446; i ++ )\r
83                         Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);\r
84                 for( int i = 0x480; i <= 0x484; i ++ )\r
85                         Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);\r
86                 for( int i = 0x4C0; i <= 0x4C1; i ++ )\r
87                         Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);\r
88 \r
89                 Log_Debug("Tegra2Vid", "WINC_A Registers");\r
90                 for( int i = 0x700; i <= 0x714; i ++ )\r
91                         Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);\r
92                 Log_Debug("Tegra2Vid", "WINBUF_A");\r
93                 for( int i = 0x800; i <= 0x80A; i ++ )\r
94                         Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);\r
95         }\r
96 //      return 1;\r
97         \r
98         giTegra2Vid_FramebufferSize =\r
99                 (gpTegra2Vid_IOMem[DC_WIN_A_SIZE_0]&0xFFFF)\r
100                 *(gpTegra2Vid_IOMem[DC_WIN_A_SIZE_0]>>16)*4;\r
101 \r
102         Log_Debug("Tegra2Vid", "giTegra2Vid_FramebufferSize = 0x%x", giTegra2Vid_FramebufferSize);\r
103         gpTegra2Vid_Framebuffer = MM_MapHWPages(\r
104                 gpTegra2Vid_IOMem[DC_WINBUF_A_START_ADDR_0],\r
105                 (giTegra2Vid_FramebufferSize+PAGE_SIZE-1)/PAGE_SIZE\r
106                 );\r
107         memset(gpTegra2Vid_Framebuffer, 0x1F, 0x1000);\r
108 \r
109 \r
110 //      Tegra2Vid_int_SetMode(4);\r
111 \r
112         DevFS_AddDevice( &gTegra2Vid_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 Tegra2Vid_Uninstall()\r
121 {\r
122 }\r
123 \r
124 /**\r
125  * \brief Read from the framebuffer\r
126  */\r
127 Uint64 Tegra2Vid_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 Tegra2Vid_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)\r
136 {\r
137         gTegra2Vid_DrvUtil_BufInfo.BufferFormat = giTegra2Vid_BufferMode;\r
138         return DrvUtil_Video_WriteLFB(&gTegra2Vid_DrvUtil_BufInfo, Offset, Length, Buffer);\r
139 }\r
140 \r
141 const char *csaTegra2Vid_IOCtls[] = {DRV_IOCTLNAMES, DRV_VIDEO_IOCTLNAMES, NULL};\r
142 \r
143 /**\r
144  * \brief Handle messages to the device\r
145  */\r
146 int Tegra2Vid_IOCtl(tVFS_Node *Node, int ID, void *Data)\r
147 {\r
148          int    ret = -2;\r
149         ENTER("pNode iID pData", Node, ID, Data);\r
150         \r
151         switch(ID)\r
152         {\r
153         BASE_IOCTLS(DRV_TYPE_VIDEO, "PL110", VERSION, csaTegra2Vid_IOCtls);\r
154 \r
155         case VIDEO_IOCTL_SETBUFFORMAT:\r
156                 DrvUtil_Video_RemoveCursor( &gTegra2Vid_DrvUtil_BufInfo );\r
157                 ret = giTegra2Vid_BufferMode;\r
158                 if(Data)        giTegra2Vid_BufferMode = *(int*)Data;\r
159                 if(gTegra2Vid_DrvUtil_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)\r
160                         DrvUtil_Video_SetCursor( &gTegra2Vid_DrvUtil_BufInfo, &gDrvUtil_TextModeCursor );\r
161                 break;\r
162         \r
163         case VIDEO_IOCTL_GETSETMODE:\r
164                 if(Data)\r
165                 {\r
166                          int    newMode;\r
167                         \r
168                         if( !CheckMem(Data, sizeof(int)) )\r
169                                 LEAVE_RET('i', -1);\r
170                         \r
171                         newMode = *(int*)Data;\r
172                         \r
173                         if(newMode < 0 || newMode >= ciTegra2Vid_ModeCount)\r
174                                 LEAVE_RET('i', -1);\r
175 \r
176                         if(newMode != giTegra2Vid_CurrentMode)\r
177                         {\r
178                                 giTegra2Vid_CurrentMode = newMode;\r
179                                 Tegra2Vid_int_SetMode( newMode );\r
180                         }\r
181                 }\r
182                 ret = giTegra2Vid_CurrentMode;\r
183                 break;\r
184         \r
185         case VIDEO_IOCTL_FINDMODE:\r
186                 {\r
187                 tVideo_IOCtl_Mode *mode = Data;\r
188                  int    closest, closestArea, reqArea = 0;\r
189                 if(!Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Mode)))\r
190                         LEAVE_RET('i', -1);\r
191                 if( mode->bpp != 32 )\r
192                         LEAVE_RET('i', 0);\r
193                 if( mode->flags != 0 )\r
194                         LEAVE_RET('i', 0);\r
195 \r
196                 ret = 0;\r
197 \r
198                 for( int i = 0; i < ciTegra2Vid_ModeCount; i ++ )\r
199                 {\r
200                          int    area;\r
201                         if(mode->width == caTegra2Vid_Modes[i].W && mode->height == caTegra2Vid_Modes[i].H) {\r
202                                 mode->id = i;\r
203                                 ret = 1;\r
204                                 break;\r
205                         }\r
206                         \r
207                         area = caTegra2Vid_Modes[i].W * caTegra2Vid_Modes[i].H;\r
208                         if(!reqArea) {\r
209                                 reqArea = mode->width * mode->height;\r
210                                 closest = i;\r
211                                 closestArea = area;\r
212                         }\r
213                         else if( ABS(area - reqArea) < ABS(closestArea - reqArea) ) {\r
214                                 closest = i;\r
215                                 closestArea = area;\r
216                         }\r
217                 }\r
218                 \r
219                 if( ret == 0 )\r
220                 {\r
221                         mode->id = closest;\r
222                         ret = 1;\r
223                 }\r
224                 mode->width = caTegra2Vid_Modes[mode->id].W;\r
225                 mode->height = caTegra2Vid_Modes[mode->id].H;\r
226                 break;\r
227                 }\r
228         \r
229         case VIDEO_IOCTL_MODEINFO:\r
230                 {\r
231                 tVideo_IOCtl_Mode *mode = Data;\r
232                 if(!Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Mode)))\r
233                         LEAVE_RET('i', -1);\r
234                 if(mode->id < 0 || mode->id >= ciTegra2Vid_ModeCount)\r
235                         LEAVE_RET('i', 0);\r
236                 \r
237 \r
238                 mode->bpp = 32;\r
239                 mode->flags = 0;\r
240                 mode->width = caTegra2Vid_Modes[mode->id].W;\r
241                 mode->height = caTegra2Vid_Modes[mode->id].H;\r
242 \r
243                 ret = 1;\r
244                 break;\r
245                 }\r
246         \r
247         case VIDEO_IOCTL_SETCURSOR:\r
248                 if( !Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Pos)) )\r
249                         LEAVE_RET('i', -1);\r
250 \r
251                 DrvUtil_Video_RemoveCursor( &gTegra2Vid_DrvUtil_BufInfo );\r
252                 \r
253                 gTegra2Vid_CursorPos = *(tVideo_IOCtl_Pos*)Data;\r
254                 if(gTegra2Vid_DrvUtil_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)\r
255                         DrvUtil_Video_DrawCursor(\r
256                                 &gTegra2Vid_DrvUtil_BufInfo,\r
257                                 gTegra2Vid_CursorPos.x*giVT_CharWidth,\r
258                                 gTegra2Vid_CursorPos.y*giVT_CharHeight\r
259                                 );\r
260                 else\r
261                         DrvUtil_Video_DrawCursor(\r
262                                 &gTegra2Vid_DrvUtil_BufInfo,\r
263                                 gTegra2Vid_CursorPos.x,\r
264                                 gTegra2Vid_CursorPos.y\r
265                                 );\r
266                 break;\r
267         \r
268         default:\r
269                 LEAVE('i', -2);\r
270                 return -2;\r
271         }\r
272         \r
273         LEAVE('i', ret);\r
274         return ret;\r
275 }\r
276 \r
277 //\r
278 //\r
279 //\r
280 \r
281 int Tegra2Vid_int_SetMode(int Mode)\r
282 {\r
283         const struct sTegra2_Disp_Mode  *mode = &caTegra2Vid_Modes[Mode];\r
284          int    w = mode->W, h = mode->H;       // Horizontal/Vertical Active\r
285         *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_FRONT_PORCH_0) = (mode->VFP << 16) | mode->HFP; \r
286         *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_SYNC_WIDTH_0)  = (mode->HS << 16)  | mode->HS;\r
287         *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_BACK_PORCH_0)  = (mode->VBP << 16) | mode->HBP;\r
288         *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_DISP_ACTIVE_0) = (mode->H << 16)   | mode->W;\r
289 \r
290         *(Uint32*)(gpTegra2Vid_IOMem + DC_WIN_A_POSITION_0) = 0;\r
291         *(Uint32*)(gpTegra2Vid_IOMem + DC_WIN_A_SIZE_0) = (mode->H << 16) | mode->W;\r
292         *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_DISP_COLOR_CONTROL_0) = 0x8;     // BASE888\r
293         *(Uint32*)(gpTegra2Vid_IOMem + DC_WIN_A_COLOR_DEPTH_0) = 12;    // Could be 13 (BGR/RGB)\r
294         *(Uint32*)(gpTegra2Vid_IOMem + DC_WIN_A_PRESCALED_SIZE_0) = (mode->H << 16) | mode->W;\r
295 \r
296         Log_Debug("Tegra2Vid", "Mode %i (%ix%i) selected", Mode, w, h);\r
297 \r
298         if( !gpTegra2Vid_Framebuffer || w*h*4 != giTegra2Vid_FramebufferSize )\r
299         {\r
300                 if( gpTegra2Vid_Framebuffer )\r
301                 {\r
302                         // TODO: Free framebuffer for reallocation\r
303                 }\r
304 \r
305                 giTegra2Vid_FramebufferSize = w*h*4;            \r
306 \r
307                 gpTegra2Vid_Framebuffer = (void*)MM_AllocDMA(\r
308                         (giTegra2Vid_FramebufferSize + PAGE_SIZE-1) / PAGE_SIZE,\r
309                         32,\r
310                         &gTegra2Vid_FramebufferPhys\r
311                         );\r
312                 // TODO: Catch allocation failures\r
313                 Log_Debug("Tegra2Vid", "0x%x byte framebuffer at %p (%P phys)",\r
314                                 giTegra2Vid_FramebufferSize,\r
315                                 gpTegra2Vid_Framebuffer,\r
316                                 gTegra2Vid_FramebufferPhys\r
317                                 );\r
318                 \r
319                 // Tell hardware\r
320                 *(Uint32*)(gpTegra2Vid_IOMem + DC_WINBUF_A_START_ADDR_0) = gTegra2Vid_FramebufferPhys;\r
321                 *(Uint32*)(gpTegra2Vid_IOMem + DC_WINBUF_A_ADDR_V_OFFSET_0) = 0;        // Y offset\r
322                 *(Uint32*)(gpTegra2Vid_IOMem + DC_WINBUF_A_ADDR_H_OFFSET_0) = 0;        // X offset\r
323         }\r
324 \r
325         return 0;\r
326 }\r

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