blob: 40c3315aa9ef89ed54887169f6a5b7a3eb076e29 [file] [log] [blame]
wdenkeeb1b772004-03-23 22:53:55 +00001/*
2 * (C) Copyright 2004
3 * Pierre Aubert, Staubli Faverges , <p.aubert@staubli.com>
Timur Tabia5dbdc82011-03-21 16:38:49 -05004 * Copyright 2011 Freescale Semiconductor, Inc.
wdenkeeb1b772004-03-23 22:53:55 +00005 *
Wolfgang Denk3765b3e2013-10-07 13:07:26 +02006 * SPDX-License-Identifier: GPL-2.0+
wdenkeeb1b772004-03-23 22:53:55 +00007 */
8
9/************************************************************************
10 Get Parameters for the video mode:
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020011 The default video mode can be defined in CONFIG_SYS_DEFAULT_VIDEO_MODE.
wdenkeeb1b772004-03-23 22:53:55 +000012 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>
Timur Tabia5dbdc82011-03-21 16:38:49 -050061#include <linux/ctype.h>
62
wdenkeeb1b772004-03-23 22:53:55 +000063#include "videomodes.h"
64
65const 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};
86const struct ctfb_res_modes res_mode_init[RES_MODES_COUNT] = {
Hans de Goede0c91d2572014-12-19 10:38:49 +010087 /* x y hz pixclk ps/kHz le ri up lo hs vs s vmode */
Hans de Goede92a88c32014-12-19 11:11:52 +010088#ifndef CONFIG_VIDEO_STD_TIMINGS
Hans de Goede0c91d2572014-12-19 10:38:49 +010089 { 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},
Hans de Goede92a88c32014-12-19 11:11:52 +010095#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
Hans de Goede59bb6102014-12-19 11:45:19 +0100103 {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},
wdenkeeb1b772004-03-23 22:53:55 +0000107};
108
109/************************************************************************
110 * Get Parameters for the video mode:
111 */
112/*********************************************************************
113 * returns the length to the next seperator
114 */
115static int
Hans de Goedeeb3c0cf2014-12-19 14:27:46 +0100116video_get_param_len(const char *start, char sep)
wdenkeeb1b772004-03-23 22:53:55 +0000117{
118 int i = 0;
119 while ((*start != 0) && (*start != sep)) {
120 start++;
121 i++;
122 }
123 return i;
124}
125
126static int
127video_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
156int video_get_params (struct ctfb_res_modes *pPar, char *penv)
157{
158 char *p, *s, *val_s;
Wolfgang Denk40ac78a2011-11-04 15:55:14 +0000159 int i = 0;
wdenkeeb1b772004-03-23 22:53:55 +0000160 int bpp;
161 int mode;
Wolfgang Denk40ac78a2011-11-04 15:55:14 +0000162
wdenkeeb1b772004-03-23 22:53:55 +0000163 /* first search for the environment containing the real param string */
164 s = penv;
Wolfgang Denk40ac78a2011-11-04 15:55:14 +0000165
166 if ((p = getenv (s)) != NULL)
wdenkeeb1b772004-03-23 22:53:55 +0000167 s = p;
Wolfgang Denk40ac78a2011-11-04 15:55:14 +0000168
169 /*
170 * in case of the bootargs line, we have to start
wdenkeeb1b772004-03-23 22:53:55 +0000171 * 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;
wdenkeeb1b772004-03-23 22:53:55 +0000180 mode = 0; /* default */
Wolfgang Denk40ac78a2011-11-04 15:55:14 +0000181
wdenkeeb1b772004-03-23 22:53:55 +0000182 while ((i = video_get_param_len (p, ',')) != 0) {
183 GET_OPTION ("mode:", mode)
184 p += i;
185 if (*p != 0)
186 p++; /* skip ',' */
187 }
Wolfgang Denk40ac78a2011-11-04 15:55:14 +0000188
wdenkeeb1b772004-03-23 22:53:55 +0000189 if (mode >= RES_MODES_COUNT)
190 mode = 0;
Wolfgang Denk40ac78a2011-11-04 15:55:14 +0000191
wdenkeeb1b772004-03-23 22:53:55 +0000192 *pPar = res_mode_init[mode]; /* copy default values */
193 bpp = 24 - ((mode % 3) * 8);
194 p = s; /* restart */
Wolfgang Denk40ac78a2011-11-04 15:55:14 +0000195
wdenkeeb1b772004-03-23 22:53:55 +0000196 while ((i = video_get_param_len (p, ',')) != 0) {
197 GET_OPTION ("x:", pPar->xres)
198 GET_OPTION ("y:", pPar->yres)
Hans de Goede0c91d2572014-12-19 10:38:49 +0100199 GET_OPTION ("refresh:", pPar->refresh)
wdenkeeb1b772004-03-23 22:53:55 +0000200 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)
Hans de Goede0c91d2572014-12-19 10:38:49 +0100209 GET_OPTION ("pclk_khz:", pPar->pixclock_khz)
wdenkeeb1b772004-03-23 22:53:55 +0000210 GET_OPTION ("depth:", bpp)
211 p += i;
212 if (*p != 0)
213 p++; /* skip ',' */
214 }
215 return bpp;
216}
Timur Tabia5dbdc82011-03-21 16:38:49 -0500217
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 */
232int 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}
Hans de Goedee976b862014-12-19 13:22:47 +0100278
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 */
290void 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}
Hans de Goedeeb3c0cf2014-12-19 14:27:46 +0100318
319/*
320 * Find the named string option within the ',' separated options string, and
321 * store its value in dest.
322 *
323 * @options: ',' separated options string
324 * @name: name of the option to look for
325 * @dest: destination buffer to store the value of the option in
326 * @dest_len: length of dest
327 * @def: value to store in dest if the option is not present in options
328 */
329void video_get_option_string(const char *options, const char *name,
330 char *dest, int dest_len, const char *def)
331{
332 const char *p = options;
333 const int name_len = strlen(name);
334 int i, len;
335
336 while (p && (i = video_get_param_len(p, ',')) != 0) {
337 if (strncmp(p, name, name_len) == 0 && p[name_len] == '=') {
338 len = i - (name_len + 1);
339 if (len >= dest_len)
340 len = dest_len - 1;
341 memcpy(dest, &p[name_len + 1], len);
342 dest[len] = 0;
343 return;
344 }
345 p += i;
346 if (*p != 0)
347 p++; /* skip ',' */
348 }
349 strcpy(dest, def);
350}
351
352/*
353 * Find the named integer option within the ',' separated options string, and
354 * return its value.
355 *
356 * @options: ',' separated options string
357 * @name: name of the option to look for
358 * @def: value to return if the option is not present in options
359 */
360int video_get_option_int(const char *options, const char *name, int def)
361{
362 const char *p = options;
363 const int name_len = strlen(name);
364 int i;
365
366 while (p && (i = video_get_param_len(p, ',')) != 0) {
367 if (strncmp(p, name, name_len) == 0 && p[name_len] == '=')
368 return simple_strtoul(&p[name_len + 1], NULL, 10);
369
370 p += i;
371 if (*p != 0)
372 p++; /* skip ',' */
373 }
374 return def;
375}