xref: /rk3399_rockchip-uboot/drivers/video/videomodes.c (revision e976b868f2f77eddf7f61d52dfe2a23075ae272d)
1 /*
2  * (C) Copyright 2004
3  * Pierre Aubert, Staubli Faverges , <p.aubert@staubli.com>
4  * Copyright 2011 Freescale Semiconductor, Inc.
5  *
6  * SPDX-License-Identifier:	GPL-2.0+
7  */
8 
9 /************************************************************************
10   Get Parameters for the video mode:
11   The default video mode can be defined in CONFIG_SYS_DEFAULT_VIDEO_MODE.
12   If undefined, default video mode is set to 0x301
13   Parameters can be set via the variable "videomode" in the environment.
14   2 diferent ways are possible:
15   "videomode=301"   - 301 is a hexadecimal number describing the VESA
16 		      mode. Following modes are implemented:
17 
18 		      Colors	640x480 800x600 1024x768 1152x864 1280x1024
19 		     --------+---------------------------------------------
20 		      8 bits |	0x301	0x303	 0x305	  0x161	    0x307
21 		     15 bits |	0x310	0x313	 0x316	  0x162	    0x319
22 		     16 bits |	0x311	0x314	 0x317	  0x163	    0x31A
23 		     24 bits |	0x312	0x315	 0x318	    ?	    0x31B
24 		     --------+---------------------------------------------
25   "videomode=bootargs"
26 		   - the parameters are parsed from the bootargs.
27 		      The format is "NAME:VALUE,NAME:VALUE" etc.
28 		      Ex.:
29 		      "bootargs=video=ctfb:x:800,y:600,depth:16,pclk:25000"
30 		      Parameters not included in the list will be taken from
31 		      the default mode, which is one of the following:
32 		      mode:0  640x480x24
33 		      mode:1  800x600x16
34 		      mode:2  1024x768x8
35 		      mode:3  960x720x24
36 		      mode:4  1152x864x16
37 		      mode:5  1280x1024x8
38 
39 		      if "mode" is not provided within the parameter list,
40 		      mode:0 is assumed.
41 		      Following parameters are supported:
42 		      x	      xres = visible resolution horizontal
43 		      y	      yres = visible resolution vertical
44 		      pclk    pixelclocks in pico sec
45 		      le      left_marging time from sync to picture in pixelclocks
46 		      ri      right_marging time from picture to sync in pixelclocks
47 		      up      upper_margin time from sync to picture
48 		      lo      lower_margin
49 		      hs      hsync_len length of horizontal sync
50 		      vs      vsync_len length of vertical sync
51 		      sync    see FB_SYNC_*
52 		      vmode   see FB_VMODE_*
53 		      depth   Color depth in bits per pixel
54 		      All other parameters in the variable bootargs are ignored.
55 		      It is also possible to set the parameters direct in the
56 		      variable "videomode", or in another variable i.e.
57 		      "myvideo" and setting the variable "videomode=myvideo"..
58 ****************************************************************************/
59 
60 #include <common.h>
61 #include <linux/ctype.h>
62 
63 #include "videomodes.h"
64 
65 const struct ctfb_vesa_modes vesa_modes[VESA_MODES_COUNT] = {
66 	{0x301, RES_MODE_640x480, 8},
67 	{0x310, RES_MODE_640x480, 15},
68 	{0x311, RES_MODE_640x480, 16},
69 	{0x312, RES_MODE_640x480, 24},
70 	{0x303, RES_MODE_800x600, 8},
71 	{0x313, RES_MODE_800x600, 15},
72 	{0x314, RES_MODE_800x600, 16},
73 	{0x315, RES_MODE_800x600, 24},
74 	{0x305, RES_MODE_1024x768, 8},
75 	{0x316, RES_MODE_1024x768, 15},
76 	{0x317, RES_MODE_1024x768, 16},
77 	{0x318, RES_MODE_1024x768, 24},
78 	{0x161, RES_MODE_1152x864, 8},
79 	{0x162, RES_MODE_1152x864, 15},
80 	{0x163, RES_MODE_1152x864, 16},
81 	{0x307, RES_MODE_1280x1024, 8},
82 	{0x319, RES_MODE_1280x1024, 15},
83 	{0x31A, RES_MODE_1280x1024, 16},
84 	{0x31B, RES_MODE_1280x1024, 24},
85 };
86 const struct ctfb_res_modes res_mode_init[RES_MODES_COUNT] = {
87 	/*  x     y  hz  pixclk ps/kHz   le   ri  up  lo   hs vs  s  vmode */
88 #ifndef CONFIG_VIDEO_STD_TIMINGS
89 	{ 640,  480, 60, 39721,  25180,  40,  24, 32, 11,  96, 2, 0, FB_VMODE_NONINTERLACED},
90 	{ 800,  600, 60, 27778,  36000,  64,  24, 22,  1,  72, 2, 0, FB_VMODE_NONINTERLACED},
91 	{1024,  768, 60, 15384,  65000, 168,   8, 29,  3, 144, 4, 0, FB_VMODE_NONINTERLACED},
92 	{ 960,  720, 80, 13100,  76335, 160,  40, 32,  8,  80, 4, 0, FB_VMODE_NONINTERLACED},
93 	{1152,  864, 60, 12004,  83300, 200,  64, 32, 16,  80, 4, 0, FB_VMODE_NONINTERLACED},
94 	{1280, 1024, 60,  9090, 110000, 200,  48, 26,  1, 184, 3, 0, FB_VMODE_NONINTERLACED},
95 #else
96 	{ 640,  480, 60, 39683,  25200,  48,  16, 33, 10,  96, 2, 0, FB_VMODE_NONINTERLACED},
97 	{ 800,  600, 60, 25000,  40000,  88,  40, 23,  1, 128, 4, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED},
98 	{1024,  768, 60, 15384,  65000, 160,  24, 29,  3, 136, 6, 0, FB_VMODE_NONINTERLACED},
99 	{ 960,  720, 75, 13468,  74250, 176,  72, 27,  1, 112, 2, 0, FB_VMODE_NONINTERLACED},
100 	{1152,  864, 75,  9259, 108000, 256,  64, 32,  1, 128, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED},
101 	{1280, 1024, 60,  9259, 108000, 248,  48, 38,  1, 112, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED},
102 #endif
103 	{1280,  720, 60, 13468,  74250, 220, 110, 20,  5,  40, 5, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED},
104 	{1360,  768, 60, 11696,  85500, 256,  64, 17,  3, 112, 7, 0, FB_VMODE_NONINTERLACED},
105 	{1920, 1080, 60,  6734, 148500, 148,  88, 36,  4,  44, 5, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED},
106 	{1920, 1200, 60,  6494, 154000,  80,  48, 26,  3,  32, 6, FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED},
107 };
108 
109 /************************************************************************
110  * Get Parameters for the video mode:
111  */
112 /*********************************************************************
113  * returns the length to the next seperator
114  */
115 static int
116 video_get_param_len (char *start, char sep)
117 {
118 	int i = 0;
119 	while ((*start != 0) && (*start != sep)) {
120 		start++;
121 		i++;
122 	}
123 	return i;
124 }
125 
126 static int
127 video_search_param (char *start, char *param)
128 {
129 	int len, totallen, i;
130 	char *p = start;
131 	len = strlen (param);
132 	totallen = len + strlen (start);
133 	for (i = 0; i < totallen; i++) {
134 		if (strncmp (p++, param, len) == 0)
135 			return (i);
136 	}
137 	return -1;
138 }
139 
140 /***************************************************************
141  * Get parameter via the environment as it is done for the
142  * linux kernel i.e:
143  * video=ctfb:x:800,xv:1280,y:600,yv:1024,depth:16,mode:0,pclk:25000,
144  *	 le:56,ri:48,up:26,lo:5,hs:152,vs:2,sync:0,vmode:0,accel:0
145  *
146  * penv is a pointer to the environment, containing the string, or the name of
147  * another environment variable. It could even be the term "bootargs"
148  */
149 
150 #define GET_OPTION(name,var)				\
151 	if(strncmp(p,name,strlen(name))==0) {		\
152 		val_s=p+strlen(name);			\
153 		var=simple_strtoul(val_s, NULL, 10);	\
154 	}
155 
156 int video_get_params (struct ctfb_res_modes *pPar, char *penv)
157 {
158 	char *p, *s, *val_s;
159 	int i = 0;
160 	int bpp;
161 	int mode;
162 
163 	/* first search for the environment containing the real param string */
164 	s = penv;
165 
166 	if ((p = getenv (s)) != NULL)
167 		s = p;
168 
169 	/*
170 	 * in case of the bootargs line, we have to start
171 	 * after "video=ctfb:"
172 	 */
173 	i = video_search_param (s, "video=ctfb:");
174 	if (i >= 0) {
175 		s += i;
176 		s += strlen ("video=ctfb:");
177 	}
178 	/* search for mode as a default value */
179 	p = s;
180 	mode = 0;		/* default */
181 
182 	while ((i = video_get_param_len (p, ',')) != 0) {
183 		GET_OPTION ("mode:", mode)
184 			p += i;
185 		if (*p != 0)
186 			p++;	/* skip ',' */
187 	}
188 
189 	if (mode >= RES_MODES_COUNT)
190 		mode = 0;
191 
192 	*pPar = res_mode_init[mode];	/* copy default values */
193 	bpp = 24 - ((mode % 3) * 8);
194 	p = s;			/* restart */
195 
196 	while ((i = video_get_param_len (p, ',')) != 0) {
197 		GET_OPTION ("x:", pPar->xres)
198 			GET_OPTION ("y:", pPar->yres)
199 			GET_OPTION ("refresh:", pPar->refresh)
200 			GET_OPTION ("le:", pPar->left_margin)
201 			GET_OPTION ("ri:", pPar->right_margin)
202 			GET_OPTION ("up:", pPar->upper_margin)
203 			GET_OPTION ("lo:", pPar->lower_margin)
204 			GET_OPTION ("hs:", pPar->hsync_len)
205 			GET_OPTION ("vs:", pPar->vsync_len)
206 			GET_OPTION ("sync:", pPar->sync)
207 			GET_OPTION ("vmode:", pPar->vmode)
208 			GET_OPTION ("pclk:", pPar->pixclock)
209 			GET_OPTION ("pclk_khz:", pPar->pixclock_khz)
210 			GET_OPTION ("depth:", bpp)
211 			p += i;
212 		if (*p != 0)
213 			p++;	/* skip ',' */
214 	}
215 	return bpp;
216 }
217 
218 /*
219  * Parse the 'video-mode' environment variable
220  *
221  * Example: "video-mode=fslfb:1280x1024-32@60,monitor=dvi".  See
222  * doc/README.video for more information on how to set the variable.
223  *
224  * @xres: returned value of X-resolution
225  * @yres: returned value of Y-resolution
226  * @depth: returned value of color depth
227  * @freq: returned value of monitor frequency
228  * @options: pointer to any remaining options, or NULL
229  *
230  * Returns 1 if valid values were found, 0 otherwise
231  */
232 int video_get_video_mode(unsigned int *xres, unsigned int *yres,
233 	unsigned int *depth, unsigned int *freq, const char **options)
234 {
235 	char *p = getenv("video-mode");
236 	if (!p)
237 		return 0;
238 
239 	/* Skip over the driver name, which we don't care about. */
240 	p = strchr(p, ':');
241 	if (!p)
242 		return 0;
243 
244 	/* Get the X-resolution*/
245 	while (*p && !isdigit(*p))
246 		p++;
247 	*xres = simple_strtoul(p, &p, 10);
248 	if (!*xres)
249 		return 0;
250 
251 	/* Get the Y-resolution */
252 	while (*p && !isdigit(*p))
253 		p++;
254 	*yres = simple_strtoul(p, &p, 10);
255 	if (!*yres)
256 		return 0;
257 
258 	/* Get the depth */
259 	while (*p && !isdigit(*p))
260 		p++;
261 	*depth = simple_strtoul(p, &p, 10);
262 	if (!*depth)
263 		return 0;
264 
265 	/* Get the frequency */
266 	while (*p && !isdigit(*p))
267 		p++;
268 	*freq = simple_strtoul(p, &p, 10);
269 	if (!*freq)
270 		return 0;
271 
272 	/* Find the extra options, if any */
273 	p = strchr(p, ',');
274 	*options = p ? p + 1 : NULL;
275 
276 	return 1;
277 }
278 
279 /*
280  * Parse the 'video-mode' environment variable using video_get_video_mode()
281  * and lookup the matching ctfb_res_modes in res_mode_init.
282  *
283  * @default_mode: RES_MODE_##x## define for the mode to store in mode_ret
284  *   when 'video-mode' is not set or does not contain a valid mode
285  * @default_depth: depth to set when 'video-mode' is not set
286  * @mode_ret: pointer where the mode will be stored
287  * @depth_ret: pointer where the depth will be stored
288  * @options: pointer to any remaining options, or NULL
289  */
290 void video_get_ctfb_res_modes(int default_mode, unsigned int default_depth,
291 			      const struct ctfb_res_modes **mode_ret,
292 			      unsigned int *depth_ret,
293 			      const char **options)
294 {
295 	unsigned int i, xres, yres, depth, refresh;
296 
297 	*mode_ret = &res_mode_init[default_mode];
298 	*depth_ret = default_depth;
299 	*options = NULL;
300 
301 	if (!video_get_video_mode(&xres, &yres, &depth, &refresh, options))
302 		return;
303 
304 	for (i = 0; i < RES_MODES_COUNT; i++) {
305 		if (res_mode_init[i].xres == xres &&
306 		    res_mode_init[i].yres == yres &&
307 		    res_mode_init[i].refresh == refresh) {
308 			*mode_ret = &res_mode_init[i];
309 			*depth_ret = depth;
310 			return;
311 		}
312 	}
313 
314 	printf("video-mode %dx%d-%d@%d not available, falling back to %dx%d-%d@%d\n",
315 	       xres, yres, depth, refresh, (*mode_ret)->xres,
316 	       (*mode_ret)->yres, *depth_ret, (*mode_ret)->refresh);
317 }
318