deae8f6bd42cc49d1788178cadaf49c24ad122ca
[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         Tegra2Vid_int_SetMode(4);\r
74 \r
75         DevFS_AddDevice( &gTegra2Vid_DriverStruct );\r
76 \r
77         return 0;\r
78 }\r
79 \r
80 /**\r
81  * \brief Clean up resources for driver unloading\r
82  */\r
83 void Tegra2Vid_Uninstall()\r
84 {\r
85 }\r
86 \r
87 /**\r
88  * \brief Read from the framebuffer\r
89  */\r
90 Uint64 Tegra2Vid_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer)\r
91 {\r
92         return 0;\r
93 }\r
94 \r
95 /**\r
96  * \brief Write to the framebuffer\r
97  */\r
98 Uint64 Tegra2Vid_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)\r
99 {\r
100         gTegra2Vid_DrvUtil_BufInfo.BufferFormat = giTegra2Vid_BufferMode;\r
101         return DrvUtil_Video_WriteLFB(&gTegra2Vid_DrvUtil_BufInfo, Offset, Length, Buffer);\r
102 }\r
103 \r
104 const char *csaTegra2Vid_IOCtls[] = {DRV_IOCTLNAMES, DRV_VIDEO_IOCTLNAMES, NULL};\r
105 \r
106 /**\r
107  * \brief Handle messages to the device\r
108  */\r
109 int Tegra2Vid_IOCtl(tVFS_Node *Node, int ID, void *Data)\r
110 {\r
111          int    ret = -2;\r
112         ENTER("pNode iID pData", Node, ID, Data);\r
113         \r
114         switch(ID)\r
115         {\r
116         BASE_IOCTLS(DRV_TYPE_VIDEO, "PL110", VERSION, csaTegra2Vid_IOCtls);\r
117 \r
118         case VIDEO_IOCTL_SETBUFFORMAT:\r
119                 DrvUtil_Video_RemoveCursor( &gTegra2Vid_DrvUtil_BufInfo );\r
120                 ret = giTegra2Vid_BufferMode;\r
121                 if(Data)        giTegra2Vid_BufferMode = *(int*)Data;\r
122                 if(gTegra2Vid_DrvUtil_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)\r
123                         DrvUtil_Video_SetCursor( &gTegra2Vid_DrvUtil_BufInfo, &gDrvUtil_TextModeCursor );\r
124                 break;\r
125         \r
126         case VIDEO_IOCTL_GETSETMODE:\r
127                 if(Data)\r
128                 {\r
129                          int    newMode;\r
130                         \r
131                         if( !CheckMem(Data, sizeof(int)) )\r
132                                 LEAVE_RET('i', -1);\r
133                         \r
134                         newMode = *(int*)Data;\r
135                         \r
136                         if(newMode < 0 || newMode >= ciTegra2Vid_ModeCount)\r
137                                 LEAVE_RET('i', -1);\r
138 \r
139                         if(newMode != giTegra2Vid_CurrentMode)\r
140                         {\r
141                                 giTegra2Vid_CurrentMode = newMode;\r
142                                 Tegra2Vid_int_SetMode( newMode );\r
143                         }\r
144                 }\r
145                 ret = giTegra2Vid_CurrentMode;\r
146                 break;\r
147         \r
148         case VIDEO_IOCTL_FINDMODE:\r
149                 {\r
150                 tVideo_IOCtl_Mode *mode = Data;\r
151                  int    closest, closestArea, reqArea = 0;\r
152                 if(!Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Mode)))\r
153                         LEAVE_RET('i', -1);\r
154                 if( mode->bpp != 32 )\r
155                         LEAVE_RET('i', 0);\r
156                 if( mode->flags != 0 )\r
157                         LEAVE_RET('i', 0);\r
158 \r
159                 ret = 0;\r
160 \r
161                 for( int i = 0; i < ciTegra2Vid_ModeCount; i ++ )\r
162                 {\r
163                          int    area;\r
164                         if(mode->width == caTegra2Vid_Modes[i].W && mode->height == caTegra2Vid_Modes[i].H) {\r
165                                 mode->id = i;\r
166                                 ret = 1;\r
167                                 break;\r
168                         }\r
169                         \r
170                         area = caTegra2Vid_Modes[i].W * caTegra2Vid_Modes[i].H;\r
171                         if(!reqArea) {\r
172                                 reqArea = mode->width * mode->height;\r
173                                 closest = i;\r
174                                 closestArea = area;\r
175                         }\r
176                         else if( ABS(area - reqArea) < ABS(closestArea - reqArea) ) {\r
177                                 closest = i;\r
178                                 closestArea = area;\r
179                         }\r
180                 }\r
181                 \r
182                 if( ret == 0 )\r
183                 {\r
184                         mode->id = closest;\r
185                         ret = 1;\r
186                 }\r
187                 mode->width = caTegra2Vid_Modes[mode->id].W;\r
188                 mode->height = caTegra2Vid_Modes[mode->id].H;\r
189                 break;\r
190                 }\r
191         \r
192         case VIDEO_IOCTL_MODEINFO:\r
193                 {\r
194                 tVideo_IOCtl_Mode *mode = Data;\r
195                 if(!Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Mode)))\r
196                         LEAVE_RET('i', -1);\r
197                 if(mode->id < 0 || mode->id >= ciTegra2Vid_ModeCount)\r
198                         LEAVE_RET('i', 0);\r
199                 \r
200 \r
201                 mode->bpp = 32;\r
202                 mode->flags = 0;\r
203                 mode->width = caTegra2Vid_Modes[mode->id].W;\r
204                 mode->height = caTegra2Vid_Modes[mode->id].H;\r
205 \r
206                 ret = 1;\r
207                 break;\r
208                 }\r
209         \r
210         case VIDEO_IOCTL_SETCURSOR:\r
211                 if( !Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Pos)) )\r
212                         LEAVE_RET('i', -1);\r
213 \r
214                 DrvUtil_Video_RemoveCursor( &gTegra2Vid_DrvUtil_BufInfo );\r
215                 \r
216                 gTegra2Vid_CursorPos = *(tVideo_IOCtl_Pos*)Data;\r
217                 if(gTegra2Vid_DrvUtil_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)\r
218                         DrvUtil_Video_DrawCursor(\r
219                                 &gTegra2Vid_DrvUtil_BufInfo,\r
220                                 gTegra2Vid_CursorPos.x*giVT_CharWidth,\r
221                                 gTegra2Vid_CursorPos.y*giVT_CharHeight\r
222                                 );\r
223                 else\r
224                         DrvUtil_Video_DrawCursor(\r
225                                 &gTegra2Vid_DrvUtil_BufInfo,\r
226                                 gTegra2Vid_CursorPos.x,\r
227                                 gTegra2Vid_CursorPos.y\r
228                                 );\r
229                 break;\r
230         \r
231         default:\r
232                 LEAVE('i', -2);\r
233                 return -2;\r
234         }\r
235         \r
236         LEAVE('i', ret);\r
237         return ret;\r
238 }\r
239 \r
240 //\r
241 //\r
242 //\r
243 \r
244 int Tegra2Vid_int_SetMode(int Mode)\r
245 {\r
246         const struct sTegra2_Disp_Mode  *mode = &caTegra2Vid_Modes[Mode];\r
247          int    w = mode->W, h = mode->H;       // Horizontal/Vertical Active\r
248         *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_FRONT_PORCH_0) = (mode->VFP << 16) | mode->HFP; \r
249         *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_SYNC_WIDTH_0)  = (mode->HS << 16)  | mode->HS;\r
250         *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_BACK_PORCH_0)  = (mode->VBP << 16) | mode->HBP;\r
251         *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_DISP_ACTIVE_0) = (mode->H << 16)   | mode->W;\r
252 \r
253         *(Uint32*)(gpTegra2Vid_IOMem + DC_WIN_A_POSITION_0) = 0;\r
254         *(Uint32*)(gpTegra2Vid_IOMem + DC_WIN_A_SIZE_0) = (mode->H << 16) | mode->W;\r
255         *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_DISP_COLOR_CONTROL_0) = 0x8;     // BASE888\r
256         *(Uint32*)(gpTegra2Vid_IOMem + DC_WIN_A_COLOR_DEPTH_0) = 12;    // Could be 13 (BGR/RGB)\r
257         *(Uint32*)(gpTegra2Vid_IOMem + DC_WIN_A_PRESCALED_SIZE_0) = (mode->H << 16) | mode->W;\r
258 \r
259         Log_Debug("Tegra2Vid", "Mode %i (%ix%i) selected", Mode, w, h);\r
260 \r
261         if( !gpTegra2Vid_Framebuffer || w*h*4 != giTegra2Vid_FramebufferSize )\r
262         {\r
263                 if( gpTegra2Vid_Framebuffer )\r
264                 {\r
265                         // TODO: Free framebuffer for reallocation\r
266                 }\r
267 \r
268                 giTegra2Vid_FramebufferSize = w*h*4;            \r
269 \r
270                 gpTegra2Vid_Framebuffer = (void*)MM_AllocDMA(\r
271                         (giTegra2Vid_FramebufferSize + PAGE_SIZE-1) / PAGE_SIZE,\r
272                         32,\r
273                         &gTegra2Vid_FramebufferPhys\r
274                         );\r
275                 // TODO: Catch allocation failures\r
276                 Log_Debug("Tegra2Vid", "0x%x byte framebuffer at %p (%P phys)",\r
277                                 giTegra2Vid_FramebufferSize,\r
278                                 gpTegra2Vid_Framebuffer,\r
279                                 gTegra2Vid_FramebufferPhys\r
280                                 );\r
281                 \r
282                 // Tell hardware\r
283                 *(Uint32*)(gpTegra2Vid_IOMem + DC_WINBUF_A_START_ADDR_0) = gTegra2Vid_FramebufferPhys;\r
284                 *(Uint32*)(gpTegra2Vid_IOMem + DC_WINBUF_A_ADDR_V_OFFSET_0) = 0;        // Y offset\r
285                 *(Uint32*)(gpTegra2Vid_IOMem + DC_WINBUF_A_ADDR_H_OFFSET_0) = 0;        // X offset\r
286         }\r
287 \r
288         return 0;\r
289 }\r

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