xref: /openbmc/u-boot/drivers/video/videomodes.c (revision 0b304a24)
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 pixclk   le	ri  up	lo   hs vs  s  vmode */
88 	{640, 480, 39721, 40, 24, 32, 11, 96, 2, 0, FB_VMODE_NONINTERLACED},
89 	{800, 600, 27778, 64, 24, 22, 1, 72, 2, 0, FB_VMODE_NONINTERLACED},
90 	{1024, 768, 15384, 168, 8, 29, 3, 144, 4, 0, FB_VMODE_NONINTERLACED},
91 	{960, 720, 13100, 160, 40, 32, 8, 80, 4, 0, FB_VMODE_NONINTERLACED},
92 	{1152, 864, 12004, 200, 64, 32, 16, 80, 4, 0, FB_VMODE_NONINTERLACED},
93 	{1280, 1024, 9090, 200, 48, 26, 1, 184, 3, 0, FB_VMODE_NONINTERLACED},
94 };
95 
96 /************************************************************************
97  * Get Parameters for the video mode:
98  */
99 /*********************************************************************
100  * returns the length to the next seperator
101  */
102 static int
103 video_get_param_len (char *start, char sep)
104 {
105 	int i = 0;
106 	while ((*start != 0) && (*start != sep)) {
107 		start++;
108 		i++;
109 	}
110 	return i;
111 }
112 
113 static int
114 video_search_param (char *start, char *param)
115 {
116 	int len, totallen, i;
117 	char *p = start;
118 	len = strlen (param);
119 	totallen = len + strlen (start);
120 	for (i = 0; i < totallen; i++) {
121 		if (strncmp (p++, param, len) == 0)
122 			return (i);
123 	}
124 	return -1;
125 }
126 
127 /***************************************************************
128  * Get parameter via the environment as it is done for the
129  * linux kernel i.e:
130  * video=ctfb:x:800,xv:1280,y:600,yv:1024,depth:16,mode:0,pclk:25000,
131  *	 le:56,ri:48,up:26,lo:5,hs:152,vs:2,sync:0,vmode:0,accel:0
132  *
133  * penv is a pointer to the environment, containing the string, or the name of
134  * another environment variable. It could even be the term "bootargs"
135  */
136 
137 #define GET_OPTION(name,var)				\
138 	if(strncmp(p,name,strlen(name))==0) {		\
139 		val_s=p+strlen(name);			\
140 		var=simple_strtoul(val_s, NULL, 10);	\
141 	}
142 
143 int video_get_params (struct ctfb_res_modes *pPar, char *penv)
144 {
145 	char *p, *s, *val_s;
146 	int i = 0;
147 	int bpp;
148 	int mode;
149 
150 	/* first search for the environment containing the real param string */
151 	s = penv;
152 
153 	if ((p = getenv (s)) != NULL)
154 		s = p;
155 
156 	/*
157 	 * in case of the bootargs line, we have to start
158 	 * after "video=ctfb:"
159 	 */
160 	i = video_search_param (s, "video=ctfb:");
161 	if (i >= 0) {
162 		s += i;
163 		s += strlen ("video=ctfb:");
164 	}
165 	/* search for mode as a default value */
166 	p = s;
167 	mode = 0;		/* default */
168 
169 	while ((i = video_get_param_len (p, ',')) != 0) {
170 		GET_OPTION ("mode:", mode)
171 			p += i;
172 		if (*p != 0)
173 			p++;	/* skip ',' */
174 	}
175 
176 	if (mode >= RES_MODES_COUNT)
177 		mode = 0;
178 
179 	*pPar = res_mode_init[mode];	/* copy default values */
180 	bpp = 24 - ((mode % 3) * 8);
181 	p = s;			/* restart */
182 
183 	while ((i = video_get_param_len (p, ',')) != 0) {
184 		GET_OPTION ("x:", pPar->xres)
185 			GET_OPTION ("y:", pPar->yres)
186 			GET_OPTION ("le:", pPar->left_margin)
187 			GET_OPTION ("ri:", pPar->right_margin)
188 			GET_OPTION ("up:", pPar->upper_margin)
189 			GET_OPTION ("lo:", pPar->lower_margin)
190 			GET_OPTION ("hs:", pPar->hsync_len)
191 			GET_OPTION ("vs:", pPar->vsync_len)
192 			GET_OPTION ("sync:", pPar->sync)
193 			GET_OPTION ("vmode:", pPar->vmode)
194 			GET_OPTION ("pclk:", pPar->pixclock)
195 			GET_OPTION ("depth:", bpp)
196 			p += i;
197 		if (*p != 0)
198 			p++;	/* skip ',' */
199 	}
200 	return bpp;
201 }
202 
203 /*
204  * Parse the 'video-mode' environment variable
205  *
206  * Example: "video-mode=fslfb:1280x1024-32@60,monitor=dvi".  See
207  * doc/README.video for more information on how to set the variable.
208  *
209  * @xres: returned value of X-resolution
210  * @yres: returned value of Y-resolution
211  * @depth: returned value of color depth
212  * @freq: returned value of monitor frequency
213  * @options: pointer to any remaining options, or NULL
214  *
215  * Returns 1 if valid values were found, 0 otherwise
216  */
217 int video_get_video_mode(unsigned int *xres, unsigned int *yres,
218 	unsigned int *depth, unsigned int *freq, const char **options)
219 {
220 	char *p = getenv("video-mode");
221 	if (!p)
222 		return 0;
223 
224 	/* Skip over the driver name, which we don't care about. */
225 	p = strchr(p, ':');
226 	if (!p)
227 		return 0;
228 
229 	/* Get the X-resolution*/
230 	while (*p && !isdigit(*p))
231 		p++;
232 	*xres = simple_strtoul(p, &p, 10);
233 	if (!*xres)
234 		return 0;
235 
236 	/* Get the Y-resolution */
237 	while (*p && !isdigit(*p))
238 		p++;
239 	*yres = simple_strtoul(p, &p, 10);
240 	if (!*yres)
241 		return 0;
242 
243 	/* Get the depth */
244 	while (*p && !isdigit(*p))
245 		p++;
246 	*depth = simple_strtoul(p, &p, 10);
247 	if (!*depth)
248 		return 0;
249 
250 	/* Get the frequency */
251 	while (*p && !isdigit(*p))
252 		p++;
253 	*freq = simple_strtoul(p, &p, 10);
254 	if (!*freq)
255 		return 0;
256 
257 	/* Find the extra options, if any */
258 	p = strchr(p, ',');
259 	*options = p ? p + 1 : NULL;
260 
261 	return 1;
262 }
263