uboot/common/edid.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2012 The Chromium OS Authors.
   3 *
   4 * (C) Copyright 2010
   5 * Petr Stetiar <ynezz@true.cz>
   6 *
   7 * SPDX-License-Identifier:     GPL-2.0+
   8 *
   9 * Contains stolen code from ddcprobe project which is:
  10 * Copyright (C) Nalin Dahyabhai <bigfun@pobox.com>
  11 */
  12
  13#include <common.h>
  14#include <edid.h>
  15#include <linux/ctype.h>
  16#include <linux/string.h>
  17
  18int edid_check_info(struct edid1_info *edid_info)
  19{
  20        if ((edid_info == NULL) || (edid_info->version == 0))
  21                return -1;
  22
  23        if (memcmp(edid_info->header, "\x0\xff\xff\xff\xff\xff\xff\x0", 8))
  24                return -1;
  25
  26        if (edid_info->version == 0xff && edid_info->revision == 0xff)
  27                return -1;
  28
  29        return 0;
  30}
  31
  32int edid_get_ranges(struct edid1_info *edid, unsigned int *hmin,
  33                    unsigned int *hmax, unsigned int *vmin,
  34                    unsigned int *vmax)
  35{
  36        int i;
  37        struct edid_monitor_descriptor *monitor;
  38
  39        *hmin = *hmax = *vmin = *vmax = 0;
  40        if (edid_check_info(edid))
  41                return -1;
  42
  43        for (i = 0; i < ARRAY_SIZE(edid->monitor_details.descriptor); i++) {
  44                monitor = &edid->monitor_details.descriptor[i];
  45                if (monitor->type == EDID_MONITOR_DESCRIPTOR_RANGE) {
  46                        *hmin = monitor->data.range_data.horizontal_min;
  47                        *hmax = monitor->data.range_data.horizontal_max;
  48                        *vmin = monitor->data.range_data.vertical_min;
  49                        *vmax = monitor->data.range_data.vertical_max;
  50                        return 0;
  51                }
  52        }
  53        return -1;
  54}
  55
  56/**
  57 * Snip the tailing whitespace/return of a string.
  58 *
  59 * @param string        The string to be snipped
  60 * @return the snipped string
  61 */
  62static char *snip(char *string)
  63{
  64        char *s;
  65
  66        /*
  67         * This is always a 13 character buffer
  68         * and it's not always terminated.
  69         */
  70        string[12] = '\0';
  71        s = &string[strlen(string) - 1];
  72
  73        while (s >= string && (isspace(*s) || *s == '\n' || *s == '\r' ||
  74                        *s == '\0'))
  75                *(s--) = '\0';
  76
  77        return string;
  78}
  79
  80/**
  81 * Print an EDID monitor descriptor block
  82 *
  83 * @param monitor       The EDID monitor descriptor block
  84 * @have_timing         Modifies to 1 if the desciptor contains timing info
  85 */
  86static void edid_print_dtd(struct edid_monitor_descriptor *monitor,
  87                           unsigned int *have_timing)
  88{
  89        unsigned char *bytes = (unsigned char *)monitor;
  90        struct edid_detailed_timing *timing =
  91                        (struct edid_detailed_timing *)monitor;
  92
  93        if (bytes[0] == 0 && bytes[1] == 0) {
  94                if (monitor->type == EDID_MONITOR_DESCRIPTOR_SERIAL)
  95                        printf("Monitor serial number: %s\n",
  96                               snip(monitor->data.string));
  97                else if (monitor->type == EDID_MONITOR_DESCRIPTOR_ASCII)
  98                        printf("Monitor ID: %s\n",
  99                               snip(monitor->data.string));
 100                else if (monitor->type == EDID_MONITOR_DESCRIPTOR_NAME)
 101                        printf("Monitor name: %s\n",
 102                               snip(monitor->data.string));
 103                else if (monitor->type == EDID_MONITOR_DESCRIPTOR_RANGE)
 104                        printf("Monitor range limits, horizontal sync: "
 105                               "%d-%d kHz, vertical refresh: "
 106                               "%d-%d Hz, max pixel clock: "
 107                               "%d MHz\n",
 108                               monitor->data.range_data.horizontal_min,
 109                               monitor->data.range_data.horizontal_max,
 110                               monitor->data.range_data.vertical_min,
 111                               monitor->data.range_data.vertical_max,
 112                               monitor->data.range_data.pixel_clock_max * 10);
 113        } else {
 114                uint32_t pixclock, h_active, h_blanking, v_active, v_blanking;
 115                uint32_t h_total, v_total, vfreq;
 116
 117                pixclock = EDID_DETAILED_TIMING_PIXEL_CLOCK(*timing);
 118                h_active = EDID_DETAILED_TIMING_HORIZONTAL_ACTIVE(*timing);
 119                h_blanking = EDID_DETAILED_TIMING_HORIZONTAL_BLANKING(*timing);
 120                v_active = EDID_DETAILED_TIMING_VERTICAL_ACTIVE(*timing);
 121                v_blanking = EDID_DETAILED_TIMING_VERTICAL_BLANKING(*timing);
 122
 123                h_total = h_active + h_blanking;
 124                v_total = v_active + v_blanking;
 125                if (v_total * h_total)
 126                        vfreq = pixclock / (v_total * h_total);
 127                else
 128                        vfreq = 1; /* Error case */
 129                printf("\t%dx%d\%c\t%d Hz (detailed)\n", h_active,
 130                       v_active, h_active > 1000 ? ' ' : '\t', vfreq);
 131                *have_timing = 1;
 132        }
 133}
 134
 135/**
 136 * Get the manufacturer name from an EDID info.
 137 *
 138 * @param edid_info     The EDID info to be printed
 139 * @param name          Returns the string of the manufacturer name
 140 */
 141static void edid_get_manufacturer_name(struct edid1_info *edid, char *name)
 142{
 143        name[0] = EDID1_INFO_MANUFACTURER_NAME_CHAR1(*edid) + 'A' - 1;
 144        name[1] = EDID1_INFO_MANUFACTURER_NAME_CHAR2(*edid) + 'A' - 1;
 145        name[2] = EDID1_INFO_MANUFACTURER_NAME_CHAR3(*edid) + 'A' - 1;
 146        name[3] = '\0';
 147}
 148
 149void edid_print_info(struct edid1_info *edid_info)
 150{
 151        int i;
 152        char manufacturer[4];
 153        unsigned int have_timing = 0;
 154        uint32_t serial_number;
 155
 156        if (edid_check_info(edid_info)) {
 157                printf("Not a valid EDID\n");
 158                return;
 159        }
 160
 161        printf("EDID version: %d.%d\n",
 162               edid_info->version, edid_info->revision);
 163
 164        printf("Product ID code: %04x\n", EDID1_INFO_PRODUCT_CODE(*edid_info));
 165
 166        edid_get_manufacturer_name(edid_info, manufacturer);
 167        printf("Manufacturer: %s\n", manufacturer);
 168
 169        serial_number = EDID1_INFO_SERIAL_NUMBER(*edid_info);
 170        if (serial_number != 0xffffffff) {
 171                if (strcmp(manufacturer, "MAG") == 0)
 172                        serial_number -= 0x7000000;
 173                if (strcmp(manufacturer, "OQI") == 0)
 174                        serial_number -= 456150000;
 175                if (strcmp(manufacturer, "VSC") == 0)
 176                        serial_number -= 640000000;
 177        }
 178        printf("Serial number: %08x\n", serial_number);
 179        printf("Manufactured in week: %d year: %d\n",
 180               edid_info->week, edid_info->year + 1990);
 181
 182        printf("Video input definition: %svoltage level %d%s%s%s%s%s\n",
 183               EDID1_INFO_VIDEO_INPUT_DIGITAL(*edid_info) ?
 184               "digital signal, " : "analog signal, ",
 185               EDID1_INFO_VIDEO_INPUT_VOLTAGE_LEVEL(*edid_info),
 186               EDID1_INFO_VIDEO_INPUT_BLANK_TO_BLACK(*edid_info) ?
 187               ", blank to black" : "",
 188               EDID1_INFO_VIDEO_INPUT_SEPARATE_SYNC(*edid_info) ?
 189               ", separate sync" : "",
 190               EDID1_INFO_VIDEO_INPUT_COMPOSITE_SYNC(*edid_info) ?
 191               ", composite sync" : "",
 192               EDID1_INFO_VIDEO_INPUT_SYNC_ON_GREEN(*edid_info) ?
 193               ", sync on green" : "",
 194               EDID1_INFO_VIDEO_INPUT_SERRATION_V(*edid_info) ?
 195               ", serration v" : "");
 196
 197        printf("Monitor is %s\n",
 198               EDID1_INFO_FEATURE_RGB(*edid_info) ? "RGB" : "non-RGB");
 199
 200        printf("Maximum visible display size: %d cm x %d cm\n",
 201               edid_info->max_size_horizontal,
 202               edid_info->max_size_vertical);
 203
 204        printf("Power management features: %s%s, %s%s, %s%s\n",
 205               EDID1_INFO_FEATURE_ACTIVE_OFF(*edid_info) ?
 206               "" : "no ", "active off",
 207               EDID1_INFO_FEATURE_SUSPEND(*edid_info) ? "" : "no ", "suspend",
 208               EDID1_INFO_FEATURE_STANDBY(*edid_info) ? "" : "no ", "standby");
 209
 210        printf("Estabilished timings:\n");
 211        if (EDID1_INFO_ESTABLISHED_TIMING_720X400_70(*edid_info))
 212                printf("\t720x400\t\t70 Hz (VGA 640x400, IBM)\n");
 213        if (EDID1_INFO_ESTABLISHED_TIMING_720X400_88(*edid_info))
 214                printf("\t720x400\t\t88 Hz (XGA2)\n");
 215        if (EDID1_INFO_ESTABLISHED_TIMING_640X480_60(*edid_info))
 216                printf("\t640x480\t\t60 Hz (VGA)\n");
 217        if (EDID1_INFO_ESTABLISHED_TIMING_640X480_67(*edid_info))
 218                printf("\t640x480\t\t67 Hz (Mac II, Apple)\n");
 219        if (EDID1_INFO_ESTABLISHED_TIMING_640X480_72(*edid_info))
 220                printf("\t640x480\t\t72 Hz (VESA)\n");
 221        if (EDID1_INFO_ESTABLISHED_TIMING_640X480_75(*edid_info))
 222                printf("\t640x480\t\t75 Hz (VESA)\n");
 223        if (EDID1_INFO_ESTABLISHED_TIMING_800X600_56(*edid_info))
 224                printf("\t800x600\t\t56 Hz (VESA)\n");
 225        if (EDID1_INFO_ESTABLISHED_TIMING_800X600_60(*edid_info))
 226                printf("\t800x600\t\t60 Hz (VESA)\n");
 227        if (EDID1_INFO_ESTABLISHED_TIMING_800X600_72(*edid_info))
 228                printf("\t800x600\t\t72 Hz (VESA)\n");
 229        if (EDID1_INFO_ESTABLISHED_TIMING_800X600_75(*edid_info))
 230                printf("\t800x600\t\t75 Hz (VESA)\n");
 231        if (EDID1_INFO_ESTABLISHED_TIMING_832X624_75(*edid_info))
 232                printf("\t832x624\t\t75 Hz (Mac II)\n");
 233        if (EDID1_INFO_ESTABLISHED_TIMING_1024X768_87I(*edid_info))
 234                printf("\t1024x768\t87 Hz Interlaced (8514A)\n");
 235        if (EDID1_INFO_ESTABLISHED_TIMING_1024X768_60(*edid_info))
 236                printf("\t1024x768\t60 Hz (VESA)\n");
 237        if (EDID1_INFO_ESTABLISHED_TIMING_1024X768_70(*edid_info))
 238                printf("\t1024x768\t70 Hz (VESA)\n");
 239        if (EDID1_INFO_ESTABLISHED_TIMING_1024X768_75(*edid_info))
 240                printf("\t1024x768\t75 Hz (VESA)\n");
 241        if (EDID1_INFO_ESTABLISHED_TIMING_1280X1024_75(*edid_info))
 242                printf("\t1280x1024\t75 (VESA)\n");
 243        if (EDID1_INFO_ESTABLISHED_TIMING_1152X870_75(*edid_info))
 244                printf("\t1152x870\t75 (Mac II)\n");
 245
 246        /* Standard timings. */
 247        printf("Standard timings:\n");
 248        for (i = 0; i < ARRAY_SIZE(edid_info->standard_timings); i++) {
 249                unsigned int aspect = 10000;
 250                unsigned int x, y;
 251                unsigned char xres, vfreq;
 252
 253                xres = EDID1_INFO_STANDARD_TIMING_XRESOLUTION(*edid_info, i);
 254                vfreq = EDID1_INFO_STANDARD_TIMING_VFREQ(*edid_info, i);
 255                if ((xres != vfreq) ||
 256                    ((xres != 0) && (xres != 1)) ||
 257                    ((vfreq != 0) && (vfreq != 1))) {
 258                        switch (EDID1_INFO_STANDARD_TIMING_ASPECT(*edid_info,
 259                                        i)) {
 260                        case ASPECT_625:
 261                                aspect = 6250;
 262                                break;
 263                        case ASPECT_75:
 264                                aspect = 7500;
 265                                break;
 266                        case ASPECT_8:
 267                                aspect = 8000;
 268                                break;
 269                        case ASPECT_5625:
 270                                aspect = 5625;
 271                                break;
 272                        }
 273                        x = (xres + 31) * 8;
 274                        y = x * aspect / 10000;
 275                        printf("\t%dx%d%c\t%d Hz\n", x, y,
 276                               x > 1000 ? ' ' : '\t', (vfreq & 0x3f) + 60);
 277                        have_timing = 1;
 278                }
 279        }
 280
 281        /* Detailed timing information. */
 282        for (i = 0; i < ARRAY_SIZE(edid_info->monitor_details.descriptor);
 283                        i++) {
 284                edid_print_dtd(&edid_info->monitor_details.descriptor[i],
 285                               &have_timing);
 286        }
 287
 288        if (!have_timing)
 289                printf("\tNone\n");
 290}
 291