fixed, limit MX Sticks to 800MHz or they overheat and crash
[vuplus_xbmc] / xbmc / windowing / egl / EGLNativeTypeAmlogic.cpp
1 /*
2  *      Copyright (C) 2011-2013 Team XBMC
3  *      http://xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "EGLNativeTypeAmlogic.h"
22 #include "guilib/gui3d.h"
23 #include "utils/AMLUtils.h"
24 #include "utils/StringUtils.h"
25
26 #include <stdlib.h>
27 #include <linux/fb.h>
28 #include <sys/ioctl.h>
29 #include <EGL/egl.h>
30
31 CEGLNativeTypeAmlogic::CEGLNativeTypeAmlogic()
32 {
33   const char *env_framebuffer = getenv("FRAMEBUFFER");
34
35   // default to framebuffer 0
36   m_framebuffer_name = "fb0";
37   if (env_framebuffer)
38   {
39     std::string framebuffer(env_framebuffer);
40     std::string::size_type start = framebuffer.find("fb");
41     m_framebuffer_name = framebuffer.substr(start);
42   }
43   m_nativeWindow = NULL;
44 }
45
46 CEGLNativeTypeAmlogic::~CEGLNativeTypeAmlogic()
47 {
48 }
49
50 bool CEGLNativeTypeAmlogic::CheckCompatibility()
51 {
52   char name[256] = {0};
53   std::string modalias = "/sys/class/graphics/" + m_framebuffer_name + "/device/modalias";
54
55   aml_get_sysfs_str(modalias.c_str(), name, 255);
56   CStdString strName = name;
57   strName.Trim();
58   if (strName == "platform:mesonfb")
59     return true;
60   return false;
61 }
62
63 void CEGLNativeTypeAmlogic::Initialize()
64 {
65   aml_permissions();
66   aml_cpufreq_min(true);
67   aml_cpufreq_max(true);
68   return;
69 }
70 void CEGLNativeTypeAmlogic::Destroy()
71 {
72   aml_cpufreq_min(false);
73   aml_cpufreq_max(false);
74   return;
75 }
76
77 bool CEGLNativeTypeAmlogic::CreateNativeDisplay()
78 {
79   m_nativeDisplay = EGL_DEFAULT_DISPLAY;
80   return true;
81 }
82
83 bool CEGLNativeTypeAmlogic::CreateNativeWindow()
84 {
85 #if defined(_FBDEV_WINDOW_H_)
86   fbdev_window *nativeWindow = new fbdev_window;
87   if (!nativeWindow)
88     return false;
89
90   nativeWindow->width = 1280;
91   nativeWindow->height = 720;
92   m_nativeWindow = nativeWindow;
93   return true;
94 #else
95   return false;
96 #endif
97 }
98
99 bool CEGLNativeTypeAmlogic::GetNativeDisplay(XBNativeDisplayType **nativeDisplay) const
100 {
101   if (!nativeDisplay)
102     return false;
103   *nativeDisplay = (XBNativeDisplayType*) &m_nativeDisplay;
104   return true;
105 }
106
107 bool CEGLNativeTypeAmlogic::GetNativeWindow(XBNativeWindowType **nativeWindow) const
108 {
109   if (!nativeWindow)
110     return false;
111   *nativeWindow = (XBNativeWindowType*) &m_nativeWindow;
112   return true;
113 }
114
115 bool CEGLNativeTypeAmlogic::DestroyNativeDisplay()
116 {
117   return true;
118 }
119
120 bool CEGLNativeTypeAmlogic::DestroyNativeWindow()
121 {
122 #if defined(_FBDEV_WINDOW_H_)
123   delete (fbdev_window*)m_nativeWindow, m_nativeWindow = NULL;
124 #endif
125   return true;
126 }
127
128 bool CEGLNativeTypeAmlogic::GetNativeResolution(RESOLUTION_INFO *res) const
129 {
130   char mode[256] = {0};
131   aml_get_sysfs_str("/sys/class/display/mode", mode, 255);
132   return ModeToResolution(mode, res);
133 }
134
135 bool CEGLNativeTypeAmlogic::SetNativeResolution(const RESOLUTION_INFO &res)
136 {
137   switch((int)(0.5 + res.fRefreshRate))
138   {
139     default:
140     case 60:
141       switch(res.iScreenWidth)
142       {
143         default:
144         case 1280:
145           SetDisplayResolution("720p");
146           break;
147         case 1920:
148           if (res.dwFlags & D3DPRESENTFLAG_INTERLACED)
149             SetDisplayResolution("1080i");
150           else
151             SetDisplayResolution("1080p");
152           break;
153       }
154       break;
155     case 50:
156       switch(res.iScreenWidth)
157       {
158         default:
159         case 1280:
160           SetDisplayResolution("720p50hz");
161           break;
162         case 1920:
163           if (res.dwFlags & D3DPRESENTFLAG_INTERLACED)
164             SetDisplayResolution("1080i50hz");
165           else
166             SetDisplayResolution("1080p50hz");
167           break;
168       }
169       break;
170     case 30:
171       SetDisplayResolution("1080p30hz");
172       break;
173     case 24:
174       SetDisplayResolution("1080p24hz");
175       break;
176   }
177
178   return true;
179 }
180
181 bool CEGLNativeTypeAmlogic::ProbeResolutions(std::vector<RESOLUTION_INFO> &resolutions)
182 {
183   char valstr[256] = {0};
184   aml_get_sysfs_str("/sys/class/amhdmitx/amhdmitx0/disp_cap", valstr, 255);
185   std::vector<CStdString> probe_str;
186   StringUtils::SplitString(valstr, "\n", probe_str);
187
188   resolutions.clear();
189   RESOLUTION_INFO res;
190   for (size_t i = 0; i < probe_str.size(); i++)
191   {
192     if(ModeToResolution(probe_str[i].c_str(), &res))
193       resolutions.push_back(res);
194   }
195   return resolutions.size() > 0;
196
197 }
198
199 bool CEGLNativeTypeAmlogic::GetPreferredResolution(RESOLUTION_INFO *res) const
200 {
201   // check display/mode, it gets defaulted at boot
202   if (!GetNativeResolution(res))
203   {
204     // punt to 720p if we get nothing
205     ModeToResolution("720p", res);
206   }
207
208   return true;
209 }
210
211 bool CEGLNativeTypeAmlogic::ShowWindow(bool show)
212 {
213   std::string blank_framebuffer = "/sys/class/graphics/" + m_framebuffer_name + "/blank";
214   aml_set_sysfs_int(blank_framebuffer.c_str(), show ? 0 : 1);
215   return true;
216 }
217
218 bool CEGLNativeTypeAmlogic::SetDisplayResolution(const char *resolution)
219 {
220   CStdString modestr = resolution;
221   // switch display resolution
222   aml_set_sysfs_str("/sys/class/display/mode", modestr.c_str());
223
224   // setup gui freescale depending on display resolution
225   DisableFreeScale();
226   if (StringUtils::StartsWith(modestr, "1080"))
227   {
228     EnableFreeScale();
229   }
230
231   return true;
232 }
233
234 bool CEGLNativeTypeAmlogic::ModeToResolution(const char *mode, RESOLUTION_INFO *res) const
235 {
236   if (!res)
237     return false;
238
239   res->iWidth = 0;
240   res->iHeight= 0;
241
242   if(!mode)
243     return false;
244
245   CStdString fromMode = mode;
246   fromMode.Trim();
247   // strips, for example, 720p* to 720p
248   // the * indicate the 'native' mode of the display
249   if (fromMode.Right(1) == "*")
250     fromMode = fromMode.Left(std::max(0, (int)fromMode.size() - 1));
251
252   if (fromMode.Equals("720p"))
253   {
254     res->iWidth = 1280;
255     res->iHeight= 720;
256     res->iScreenWidth = 1280;
257     res->iScreenHeight= 720;
258     res->fRefreshRate = 60;
259     res->dwFlags = D3DPRESENTFLAG_PROGRESSIVE;
260   }
261   else if (fromMode.Equals("720p50hz"))
262   {
263     res->iWidth = 1280;
264     res->iHeight= 720;
265     res->iScreenWidth = 1280;
266     res->iScreenHeight= 720;
267     res->fRefreshRate = 50;
268     res->dwFlags = D3DPRESENTFLAG_PROGRESSIVE;
269   }
270   else if (fromMode.Equals("1080p"))
271   {
272     res->iWidth = 1280;
273     res->iHeight= 720;
274     res->iScreenWidth = 1920;
275     res->iScreenHeight= 1080;
276     res->fRefreshRate = 60;
277     res->dwFlags = D3DPRESENTFLAG_PROGRESSIVE;
278   }
279   else if (fromMode.Equals("1080p24hz"))
280   {
281     res->iWidth = 1280;
282     res->iHeight= 720;
283     res->iScreenWidth = 1920;
284     res->iScreenHeight= 1080;
285     res->fRefreshRate = 24;
286     res->dwFlags = D3DPRESENTFLAG_PROGRESSIVE;
287   }
288   else if (fromMode.Equals("1080p30hz"))
289   {
290     res->iWidth = 1280;
291     res->iHeight= 720;
292     res->iScreenWidth = 1920;
293     res->iScreenHeight= 1080;
294     res->fRefreshRate = 30;
295     res->dwFlags = D3DPRESENTFLAG_PROGRESSIVE;
296   }
297   else if (fromMode.Equals("1080p50hz"))
298   {
299     res->iWidth = 1280;
300     res->iHeight= 720;
301     res->iScreenWidth = 1920;
302     res->iScreenHeight= 1080;
303     res->fRefreshRate = 50;
304     res->dwFlags = D3DPRESENTFLAG_PROGRESSIVE;
305   }
306   else if (fromMode.Equals("1080i"))
307   {
308     res->iWidth = 1280;
309     res->iHeight= 720;
310     res->iScreenWidth = 1920;
311     res->iScreenHeight= 1080;
312     res->fRefreshRate = 60;
313     res->dwFlags = D3DPRESENTFLAG_INTERLACED;
314   }
315   else if (fromMode.Equals("1080i50hz"))
316   {
317     res->iWidth = 1280;
318     res->iHeight= 720;
319     res->iScreenWidth = 1920;
320     res->iScreenHeight= 1080;
321     res->fRefreshRate = 50;
322     res->dwFlags = D3DPRESENTFLAG_INTERLACED;
323   }
324   else
325   {
326     return false;
327   }
328
329
330   res->iScreen       = 0;
331   res->bFullScreen   = true;
332   res->iSubtitles    = (int)(0.965 * res->iHeight);
333   res->fPixelRatio   = 1.0f;
334   res->strMode.Format("%dx%d @ %.2f%s - Full Screen", res->iScreenWidth, res->iScreenHeight, res->fRefreshRate,
335     res->dwFlags & D3DPRESENTFLAG_INTERLACED ? "i" : "");
336
337   return res->iWidth > 0 && res->iHeight> 0;
338 }
339
340 void CEGLNativeTypeAmlogic::EnableFreeScale()
341 {
342   // enable OSD free scale using frame buffer size of 720p
343   aml_set_sysfs_int("/sys/class/graphics/fb0/free_scale", 0);
344   aml_set_sysfs_int("/sys/class/graphics/fb1/free_scale", 0);
345   aml_set_sysfs_int("/sys/class/graphics/fb0/scale_width",  1280);
346   aml_set_sysfs_int("/sys/class/graphics/fb0/scale_height", 720);
347   aml_set_sysfs_int("/sys/class/graphics/fb1/scale_width",  1280);
348   aml_set_sysfs_int("/sys/class/graphics/fb1/scale_height", 720);
349
350   // enable video free scale (scaling to 1920x1080 with frame buffer size 1280x720)
351   aml_set_sysfs_int("/sys/class/ppmgr/ppscaler", 0);
352   aml_set_sysfs_int("/sys/class/video/disable_video", 1);
353   aml_set_sysfs_int("/sys/class/ppmgr/ppscaler", 1);
354   aml_set_sysfs_str("/sys/class/ppmgr/ppscaler_rect", "0 0 1919 1079 0");
355   aml_set_sysfs_str("/sys/class/ppmgr/disp", "1280 720");
356   //
357   aml_set_sysfs_int("/sys/class/graphics/fb0/scale_width",  1280);
358   aml_set_sysfs_int("/sys/class/graphics/fb0/scale_height", 720);
359   aml_set_sysfs_int("/sys/class/graphics/fb1/scale_width",  1280);
360   aml_set_sysfs_int("/sys/class/graphics/fb1/scale_height", 720);
361   //
362   aml_set_sysfs_int("/sys/class/video/disable_video", 2);
363   aml_set_sysfs_str("/sys/class/display/axis", "0 0 1279 719 0 0 0 0");
364   aml_set_sysfs_str("/sys/class/ppmgr/ppscaler_rect", "0 0 1279 719 1");
365   //
366   aml_set_sysfs_int("/sys/class/graphics/fb0/free_scale", 1);
367   aml_set_sysfs_int("/sys/class/graphics/fb1/free_scale", 1);
368   aml_set_sysfs_str("/sys/class/graphics/fb0/free_scale_axis", "0 0 1279 719");
369 }
370
371 void CEGLNativeTypeAmlogic::DisableFreeScale()
372 {
373   // turn off frame buffer freescale
374   aml_set_sysfs_int("/sys/class/graphics/fb0/free_scale", 0);
375   aml_set_sysfs_int("/sys/class/graphics/fb1/free_scale", 0);
376   aml_set_sysfs_str("/sys/class/graphics/fb0/free_scale_axis", "0 0 1279 719");
377
378   aml_set_sysfs_int("/sys/class/ppmgr/ppscaler", 0);
379   aml_set_sysfs_int("/sys/class/video/disable_video", 0);
380   // now default video display to off
381   aml_set_sysfs_int("/sys/class/video/disable_video", 1);
382
383   // revert display axis
384   int fd0;
385   std::string framebuffer = "/dev/" + m_framebuffer_name;
386
387   if ((fd0 = open(framebuffer.c_str(), O_RDWR)) >= 0)
388   {
389     struct fb_var_screeninfo vinfo;
390     if (ioctl(fd0, FBIOGET_VSCREENINFO, &vinfo) == 0)
391     {
392       char daxis_str[255] = {0};
393       sprintf(daxis_str, "%d %d %d %d 0 0 0 0", 0, 0, vinfo.xres-1, vinfo.yres-1);
394       aml_set_sysfs_str("/sys/class/display/axis", daxis_str);
395     }
396     close(fd0);
397   }
398 }