uboot/drivers/video/videomodes.c
<<
>>
Prefs
   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 <edid.h>
  62#include <errno.h>
  63#include <linux/ctype.h>
  64
  65#include "videomodes.h"
  66
  67const struct ctfb_vesa_modes vesa_modes[VESA_MODES_COUNT] = {
  68        {0x301, RES_MODE_640x480, 8},
  69        {0x310, RES_MODE_640x480, 15},
  70        {0x311, RES_MODE_640x480, 16},
  71        {0x312, RES_MODE_640x480, 24},
  72        {0x303, RES_MODE_800x600, 8},
  73        {0x313, RES_MODE_800x600, 15},
  74        {0x314, RES_MODE_800x600, 16},
  75        {0x315, RES_MODE_800x600, 24},
  76        {0x305, RES_MODE_1024x768, 8},
  77        {0x316, RES_MODE_1024x768, 15},
  78        {0x317, RES_MODE_1024x768, 16},
  79        {0x318, RES_MODE_1024x768, 24},
  80        {0x161, RES_MODE_1152x864, 8},
  81        {0x162, RES_MODE_1152x864, 15},
  82        {0x163, RES_MODE_1152x864, 16},
  83        {0x307, RES_MODE_1280x1024, 8},
  84        {0x319, RES_MODE_1280x1024, 15},
  85        {0x31A, RES_MODE_1280x1024, 16},
  86        {0x31B, RES_MODE_1280x1024, 24},
  87};
  88const struct ctfb_res_modes res_mode_init[RES_MODES_COUNT] = {
  89        /*  x     y  hz  pixclk ps/kHz   le   ri  up  lo   hs vs  s  vmode */
  90#ifndef CONFIG_VIDEO_STD_TIMINGS
  91        { 640,  480, 60, 39721,  25180,  40,  24, 32, 11,  96, 2, 0, FB_VMODE_NONINTERLACED},
  92        { 800,  600, 60, 27778,  36000,  64,  24, 22,  1,  72, 2, 0, FB_VMODE_NONINTERLACED},
  93        {1024,  768, 60, 15384,  65000, 168,   8, 29,  3, 144, 4, 0, FB_VMODE_NONINTERLACED},
  94        { 960,  720, 80, 13100,  76335, 160,  40, 32,  8,  80, 4, 0, FB_VMODE_NONINTERLACED},
  95        {1152,  864, 60, 12004,  83300, 200,  64, 32, 16,  80, 4, 0, FB_VMODE_NONINTERLACED},
  96        {1280, 1024, 60,  9090, 110000, 200,  48, 26,  1, 184, 3, 0, FB_VMODE_NONINTERLACED},
  97#else
  98        { 640,  480, 60, 39683,  25200,  48,  16, 33, 10,  96, 2, 0, FB_VMODE_NONINTERLACED},
  99        { 800,  600, 60, 25000,  40000,  88,  40, 23,  1, 128, 4, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED},
 100        {1024,  768, 60, 15384,  65000, 160,  24, 29,  3, 136, 6, 0, FB_VMODE_NONINTERLACED},
 101        { 960,  720, 75, 13468,  74250, 176,  72, 27,  1, 112, 2, 0, FB_VMODE_NONINTERLACED},
 102        {1152,  864, 75,  9259, 108000, 256,  64, 32,  1, 128, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED},
 103        {1280, 1024, 60,  9259, 108000, 248,  48, 38,  1, 112, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED},
 104#endif
 105        {1280,  720, 60, 13468,  74250, 220, 110, 20,  5,  40, 5, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED},
 106        {1360,  768, 60, 11696,  85500, 256,  64, 17,  3, 112, 7, 0, FB_VMODE_NONINTERLACED},
 107        {1920, 1080, 60,  6734, 148500, 148,  88, 36,  4,  44, 5, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED},
 108        {1920, 1200, 60,  6494, 154000,  80,  48, 26,  3,  32, 6, FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED},
 109};
 110
 111/************************************************************************
 112 * Get Parameters for the video mode:
 113 */
 114/*********************************************************************
 115 * returns the length to the next seperator
 116 */
 117static int
 118video_get_param_len(const char *start, char sep)
 119{
 120        int i = 0;
 121        while ((*start != 0) && (*start != sep)) {
 122                start++;
 123                i++;
 124        }
 125        return i;
 126}
 127
 128static int
 129video_search_param (char *start, char *param)
 130{
 131        int len, totallen, i;
 132        char *p = start;
 133        len = strlen (param);
 134        totallen = len + strlen (start);
 135        for (i = 0; i < totallen; i++) {
 136                if (strncmp (p++, param, len) == 0)
 137                        return (i);
 138        }
 139        return -1;
 140}
 141
 142/***************************************************************
 143 * Get parameter via the environment as it is done for the
 144 * linux kernel i.e:
 145 * video=ctfb:x:800,xv:1280,y:600,yv:1024,depth:16,mode:0,pclk:25000,
 146 *       le:56,ri:48,up:26,lo:5,hs:152,vs:2,sync:0,vmode:0,accel:0
 147 *
 148 * penv is a pointer to the environment, containing the string, or the name of
 149 * another environment variable. It could even be the term "bootargs"
 150 */
 151
 152#define GET_OPTION(name,var)                            \
 153        if(strncmp(p,name,strlen(name))==0) {           \
 154                val_s=p+strlen(name);                   \
 155                var=simple_strtoul(val_s, NULL, 10);    \
 156        }
 157
 158int video_get_params (struct ctfb_res_modes *pPar, char *penv)
 159{
 160        char *p, *s, *val_s;
 161        int i = 0;
 162        int bpp;
 163        int mode;
 164
 165        /* first search for the environment containing the real param string */
 166        s = penv;
 167
 168        if ((p = getenv (s)) != NULL)
 169                s = p;
 170
 171        /*
 172         * in case of the bootargs line, we have to start
 173         * after "video=ctfb:"
 174         */
 175        i = video_search_param (s, "video=ctfb:");
 176        if (i >= 0) {
 177                s += i;
 178                s += strlen ("video=ctfb:");
 179        }
 180        /* search for mode as a default value */
 181        p = s;
 182        mode = 0;               /* default */
 183
 184        while ((i = video_get_param_len (p, ',')) != 0) {
 185                GET_OPTION ("mode:", mode)
 186                        p += i;
 187                if (*p != 0)
 188                        p++;    /* skip ',' */
 189        }
 190
 191        if (mode >= RES_MODES_COUNT)
 192                mode = 0;
 193
 194        *pPar = res_mode_init[mode];    /* copy default values */
 195        bpp = 24 - ((mode % 3) * 8);
 196        p = s;                  /* restart */
 197
 198        while ((i = video_get_param_len (p, ',')) != 0) {
 199                GET_OPTION ("x:", pPar->xres)
 200                        GET_OPTION ("y:", pPar->yres)
 201                        GET_OPTION ("refresh:", pPar->refresh)
 202                        GET_OPTION ("le:", pPar->left_margin)
 203                        GET_OPTION ("ri:", pPar->right_margin)
 204                        GET_OPTION ("up:", pPar->upper_margin)
 205                        GET_OPTION ("lo:", pPar->lower_margin)
 206                        GET_OPTION ("hs:", pPar->hsync_len)
 207                        GET_OPTION ("vs:", pPar->vsync_len)
 208                        GET_OPTION ("sync:", pPar->sync)
 209                        GET_OPTION ("vmode:", pPar->vmode)
 210                        GET_OPTION ("pclk:", pPar->pixclock)
 211                        GET_OPTION ("pclk_khz:", pPar->pixclock_khz)
 212                        GET_OPTION ("depth:", bpp)
 213                        p += i;
 214                if (*p != 0)
 215                        p++;    /* skip ',' */
 216        }
 217        return bpp;
 218}
 219
 220/*
 221 * Parse the 'video-mode' environment variable
 222 *
 223 * Example: "video-mode=fslfb:1280x1024-32@60,monitor=dvi".  See
 224 * doc/README.video for more information on how to set the variable.
 225 *
 226 * @xres: returned value of X-resolution
 227 * @yres: returned value of Y-resolution
 228 * @depth: returned value of color depth
 229 * @freq: returned value of monitor frequency
 230 * @options: pointer to any remaining options, or NULL
 231 *
 232 * Returns 1 if valid values were found, 0 otherwise
 233 */
 234int video_get_video_mode(unsigned int *xres, unsigned int *yres,
 235        unsigned int *depth, unsigned int *freq, const char **options)
 236{
 237        char *p = getenv("video-mode");
 238        if (!p)
 239                return 0;
 240
 241        /* Skip over the driver name, which we don't care about. */
 242        p = strchr(p, ':');
 243        if (!p)
 244                return 0;
 245
 246        /* Get the X-resolution*/
 247        while (*p && !isdigit(*p))
 248                p++;
 249        *xres = simple_strtoul(p, &p, 10);
 250        if (!*xres)
 251                return 0;
 252
 253        /* Get the Y-resolution */
 254        while (*p && !isdigit(*p))
 255                p++;
 256        *yres = simple_strtoul(p, &p, 10);
 257        if (!*yres)
 258                return 0;
 259
 260        /* Get the depth */
 261        while (*p && !isdigit(*p))
 262                p++;
 263        *depth = simple_strtoul(p, &p, 10);
 264        if (!*depth)
 265                return 0;
 266
 267        /* Get the frequency */
 268        while (*p && !isdigit(*p))
 269                p++;
 270        *freq = simple_strtoul(p, &p, 10);
 271        if (!*freq)
 272                return 0;
 273
 274        /* Find the extra options, if any */
 275        p = strchr(p, ',');
 276        *options = p ? p + 1 : NULL;
 277
 278        return 1;
 279}
 280
 281/*
 282 * Parse the 'video-mode' environment variable using video_get_video_mode()
 283 * and lookup the matching ctfb_res_modes in res_mode_init.
 284 *
 285 * @default_mode: RES_MODE_##x## define for the mode to store in mode_ret
 286 *   when 'video-mode' is not set or does not contain a valid mode
 287 * @default_depth: depth to set when 'video-mode' is not set
 288 * @mode_ret: pointer where the mode will be stored
 289 * @depth_ret: pointer where the depth will be stored
 290 * @options: pointer to any remaining options, or NULL
 291 */
 292void video_get_ctfb_res_modes(int default_mode, unsigned int default_depth,
 293                              const struct ctfb_res_modes **mode_ret,
 294                              unsigned int *depth_ret,
 295                              const char **options)
 296{
 297        unsigned int i, xres, yres, depth, refresh;
 298
 299        *mode_ret = &res_mode_init[default_mode];
 300        *depth_ret = default_depth;
 301        *options = NULL;
 302
 303        if (!video_get_video_mode(&xres, &yres, &depth, &refresh, options))
 304                return;
 305
 306        for (i = 0; i < RES_MODES_COUNT; i++) {
 307                if (res_mode_init[i].xres == xres &&
 308                    res_mode_init[i].yres == yres &&
 309                    res_mode_init[i].refresh == refresh) {
 310                        *mode_ret = &res_mode_init[i];
 311                        *depth_ret = depth;
 312                        return;
 313                }
 314        }
 315
 316        printf("video-mode %dx%d-%d@%d not available, falling back to %dx%d-%d@%d\n",
 317               xres, yres, depth, refresh, (*mode_ret)->xres,
 318               (*mode_ret)->yres, *depth_ret, (*mode_ret)->refresh);
 319}
 320
 321/*
 322 * Find the named string option within the ',' separated options string, and
 323 * store its value in dest.
 324 *
 325 * @options: ',' separated options string
 326 * @name: name of the option to look for
 327 * @dest: destination buffer to store the value of the option in
 328 * @dest_len: length of dest
 329 * @def: value to store in dest if the option is not present in options
 330 */
 331void video_get_option_string(const char *options, const char *name,
 332                             char *dest, int dest_len, const char *def)
 333{
 334        const char *p = options;
 335        const int name_len = strlen(name);
 336        int i, len;
 337
 338        while (p && (i = video_get_param_len(p, ',')) != 0) {
 339                if (strncmp(p, name, name_len) == 0 && p[name_len] == '=') {
 340                        len = i - (name_len + 1);
 341                        if (len >= dest_len)
 342                                len = dest_len - 1;
 343                        memcpy(dest, &p[name_len + 1], len);
 344                        dest[len] = 0;
 345                        return;
 346                }
 347                p += i;
 348                if (*p != 0)
 349                        p++;    /* skip ',' */
 350        }
 351        strcpy(dest, def);
 352}
 353
 354/*
 355 * Find the named integer option within the ',' separated options string, and
 356 * return its value.
 357 *
 358 * @options: ',' separated options string
 359 * @name: name of the option to look for
 360 * @def: value to return if the option is not present in options
 361 */
 362int video_get_option_int(const char *options, const char *name, int def)
 363{
 364        const char *p = options;
 365        const int name_len = strlen(name);
 366        int i;
 367
 368        while (p && (i = video_get_param_len(p, ',')) != 0) {
 369                if (strncmp(p, name, name_len) == 0 && p[name_len] == '=')
 370                        return simple_strtoul(&p[name_len + 1], NULL, 10);
 371
 372                p += i;
 373                if (*p != 0)
 374                        p++;    /* skip ',' */
 375        }
 376        return def;
 377}
 378
 379/**
 380 * Convert an EDID detailed timing to a struct ctfb_res_modes
 381 *
 382 * @param t             The EDID detailed timing to be converted
 383 * @param mode          Returns the converted timing
 384 *
 385 * @return 0 on success, or a negative errno on error
 386 */
 387int video_edid_dtd_to_ctfb_res_modes(struct edid_detailed_timing *t,
 388                                     struct ctfb_res_modes *mode)
 389{
 390        int margin, h_total, v_total;
 391
 392        /* Check all timings are non 0 */
 393        if (EDID_DETAILED_TIMING_PIXEL_CLOCK(*t) == 0 ||
 394            EDID_DETAILED_TIMING_HORIZONTAL_ACTIVE(*t) == 0 ||
 395            EDID_DETAILED_TIMING_HORIZONTAL_BLANKING(*t) == 0 ||
 396            EDID_DETAILED_TIMING_VERTICAL_ACTIVE(*t) == 0 ||
 397            EDID_DETAILED_TIMING_VERTICAL_BLANKING(*t) == 0 ||
 398            EDID_DETAILED_TIMING_HSYNC_OFFSET(*t) == 0 ||
 399            EDID_DETAILED_TIMING_HSYNC_PULSE_WIDTH(*t) == 0 ||
 400            EDID_DETAILED_TIMING_VSYNC_OFFSET(*t) == 0 ||
 401            EDID_DETAILED_TIMING_VSYNC_PULSE_WIDTH(*t) == 0 ||
 402            /* 3d formats are not supported*/
 403            EDID_DETAILED_TIMING_FLAG_STEREO(*t) != 0)
 404                return -EINVAL;
 405
 406        mode->xres = EDID_DETAILED_TIMING_HORIZONTAL_ACTIVE(*t);
 407        mode->yres = EDID_DETAILED_TIMING_VERTICAL_ACTIVE(*t);
 408
 409        h_total = mode->xres + EDID_DETAILED_TIMING_HORIZONTAL_BLANKING(*t);
 410        v_total = mode->yres + EDID_DETAILED_TIMING_VERTICAL_BLANKING(*t);
 411        mode->refresh = EDID_DETAILED_TIMING_PIXEL_CLOCK(*t) /
 412                        (h_total * v_total);
 413
 414        mode->pixclock_khz = EDID_DETAILED_TIMING_PIXEL_CLOCK(*t) / 1000;
 415        mode->pixclock = 1000000000L / mode->pixclock_khz;
 416
 417        mode->right_margin = EDID_DETAILED_TIMING_HSYNC_OFFSET(*t);
 418        mode->hsync_len = EDID_DETAILED_TIMING_HSYNC_PULSE_WIDTH(*t);
 419        margin = EDID_DETAILED_TIMING_HORIZONTAL_BLANKING(*t) -
 420                        (mode->right_margin + mode->hsync_len);
 421        if (margin <= 0)
 422                return -EINVAL;
 423
 424        mode->left_margin = margin;
 425
 426        mode->lower_margin = EDID_DETAILED_TIMING_VSYNC_OFFSET(*t);
 427        mode->vsync_len = EDID_DETAILED_TIMING_VSYNC_PULSE_WIDTH(*t);
 428        margin = EDID_DETAILED_TIMING_VERTICAL_BLANKING(*t) -
 429                        (mode->lower_margin + mode->vsync_len);
 430        if (margin <= 0)
 431                return -EINVAL;
 432
 433        mode->upper_margin = margin;
 434
 435        mode->sync = 0;
 436        if (EDID_DETAILED_TIMING_FLAG_HSYNC_POLARITY(*t))
 437                mode->sync |= FB_SYNC_HOR_HIGH_ACT;
 438        if (EDID_DETAILED_TIMING_FLAG_VSYNC_POLARITY(*t))
 439                mode->sync |= FB_SYNC_VERT_HIGH_ACT;
 440
 441        if (EDID_DETAILED_TIMING_FLAG_INTERLACED(*t))
 442                mode->vmode = FB_VMODE_INTERLACED;
 443        else
 444                mode->vmode = FB_VMODE_NONINTERLACED;
 445
 446        return 0;
 447}
 448