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