linux/drivers/gpu/drm/drm_edid_load.c
<<
>>
Prefs
   1/*
   2   drm_edid_load.c: use a built-in EDID data set or load it via the firmware
   3                    interface
   4
   5   Copyright (C) 2012 Carsten Emde <C.Emde@osadl.org>
   6
   7   This program is free software; you can redistribute it and/or
   8   modify it under the terms of the GNU General Public License
   9   as published by the Free Software Foundation; either version 2
  10   of the License, or (at your option) any later version.
  11
  12   This program is distributed in the hope that it will be useful,
  13   but WITHOUT ANY WARRANTY; without even the implied warranty of
  14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15   GNU General Public License for more details.
  16
  17   You should have received a copy of the GNU General Public License
  18   along with this program; if not, write to the Free Software
  19   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
  20*/
  21
  22#include <linux/module.h>
  23#include <linux/firmware.h>
  24#include <drm/drmP.h>
  25#include <drm/drm_crtc.h>
  26#include <drm/drm_crtc_helper.h>
  27#include <drm/drm_edid.h>
  28
  29static char edid_firmware[PATH_MAX];
  30module_param_string(edid_firmware, edid_firmware, sizeof(edid_firmware), 0644);
  31MODULE_PARM_DESC(edid_firmware, "Do not probe monitor, use specified EDID blob "
  32        "from built-in data or /lib/firmware instead. ");
  33
  34#define GENERIC_EDIDS 5
  35static char *generic_edid_name[GENERIC_EDIDS] = {
  36        "edid/1024x768.bin",
  37        "edid/1280x1024.bin",
  38        "edid/1600x1200.bin",
  39        "edid/1680x1050.bin",
  40        "edid/1920x1080.bin",
  41};
  42
  43static u8 generic_edid[GENERIC_EDIDS][128] = {
  44        {
  45        0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
  46        0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  47        0x05, 0x16, 0x01, 0x03, 0x6d, 0x23, 0x1a, 0x78,
  48        0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
  49        0x20, 0x50, 0x54, 0x00, 0x08, 0x00, 0x61, 0x40,
  50        0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
  51        0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x64, 0x19,
  52        0x00, 0x40, 0x41, 0x00, 0x26, 0x30, 0x08, 0x90,
  53        0x36, 0x00, 0x63, 0x0a, 0x11, 0x00, 0x00, 0x18,
  54        0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
  55        0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
  56        0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
  57        0x3d, 0x2f, 0x31, 0x07, 0x00, 0x0a, 0x20, 0x20,
  58        0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
  59        0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x58,
  60        0x47, 0x41, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x55,
  61        },
  62        {
  63        0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
  64        0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  65        0x05, 0x16, 0x01, 0x03, 0x6d, 0x2c, 0x23, 0x78,
  66        0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
  67        0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0x81, 0x80,
  68        0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
  69        0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x30, 0x2a,
  70        0x00, 0x98, 0x51, 0x00, 0x2a, 0x40, 0x30, 0x70,
  71        0x13, 0x00, 0xbc, 0x63, 0x11, 0x00, 0x00, 0x1e,
  72        0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
  73        0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
  74        0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
  75        0x3d, 0x3e, 0x40, 0x0b, 0x00, 0x0a, 0x20, 0x20,
  76        0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
  77        0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x53,
  78        0x58, 0x47, 0x41, 0x0a, 0x20, 0x20, 0x00, 0xa0,
  79        },
  80        {
  81        0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
  82        0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  83        0x05, 0x16, 0x01, 0x03, 0x6d, 0x37, 0x29, 0x78,
  84        0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
  85        0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xa9, 0x40,
  86        0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
  87        0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x48, 0x3f,
  88        0x40, 0x30, 0x62, 0xb0, 0x32, 0x40, 0x40, 0xc0,
  89        0x13, 0x00, 0x2b, 0xa0, 0x21, 0x00, 0x00, 0x1e,
  90        0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
  91        0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
  92        0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
  93        0x3d, 0x4a, 0x4c, 0x11, 0x00, 0x0a, 0x20, 0x20,
  94        0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
  95        0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x55,
  96        0x58, 0x47, 0x41, 0x0a, 0x20, 0x20, 0x00, 0x9d,
  97        },
  98        {
  99        0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
 100        0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 101        0x05, 0x16, 0x01, 0x03, 0x6d, 0x2b, 0x1b, 0x78,
 102        0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
 103        0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xb3, 0x00,
 104        0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
 105        0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x21, 0x39,
 106        0x90, 0x30, 0x62, 0x1a, 0x27, 0x40, 0x68, 0xb0,
 107        0x36, 0x00, 0xb5, 0x11, 0x11, 0x00, 0x00, 0x1e,
 108        0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
 109        0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
 110        0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
 111        0x3d, 0x40, 0x42, 0x0f, 0x00, 0x0a, 0x20, 0x20,
 112        0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
 113        0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x57,
 114        0x53, 0x58, 0x47, 0x41, 0x0a, 0x20, 0x00, 0x26,
 115        },
 116        {
 117        0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
 118        0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 119        0x05, 0x16, 0x01, 0x03, 0x6d, 0x32, 0x1c, 0x78,
 120        0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
 121        0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xd1, 0xc0,
 122        0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
 123        0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3a,
 124        0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
 125        0x45, 0x00, 0xf4, 0x19, 0x11, 0x00, 0x00, 0x1e,
 126        0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
 127        0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
 128        0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
 129        0x3d, 0x42, 0x44, 0x0f, 0x00, 0x0a, 0x20, 0x20,
 130        0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
 131        0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x46,
 132        0x48, 0x44, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x05,
 133        },
 134};
 135
 136static u8 *edid_load(struct drm_connector *connector, char *name,
 137                        char *connector_name)
 138{
 139        const struct firmware *fw;
 140        struct platform_device *pdev;
 141        u8 *fwdata = NULL, *edid, *new_edid;
 142        int fwsize, expected;
 143        int builtin = 0, err = 0;
 144        int i, valid_extensions = 0;
 145        bool print_bad_edid = !connector->bad_edid_counter || (drm_debug & DRM_UT_KMS);
 146
 147        pdev = platform_device_register_simple(connector_name, -1, NULL, 0);
 148        if (IS_ERR(pdev)) {
 149                DRM_ERROR("Failed to register EDID firmware platform device "
 150                    "for connector \"%s\"\n", connector_name);
 151                err = -EINVAL;
 152                goto out;
 153        }
 154
 155        err = request_firmware(&fw, name, &pdev->dev);
 156        platform_device_unregister(pdev);
 157
 158        if (err) {
 159                i = 0;
 160                while (i < GENERIC_EDIDS && strcmp(name, generic_edid_name[i]))
 161                        i++;
 162                if (i < GENERIC_EDIDS) {
 163                        err = 0;
 164                        builtin = 1;
 165                        fwdata = generic_edid[i];
 166                        fwsize = sizeof(generic_edid[i]);
 167                }
 168        }
 169
 170        if (err) {
 171                DRM_ERROR("Requesting EDID firmware \"%s\" failed (err=%d)\n",
 172                    name, err);
 173                goto out;
 174        }
 175
 176        if (fwdata == NULL) {
 177                fwdata = (u8 *) fw->data;
 178                fwsize = fw->size;
 179        }
 180
 181        expected = (fwdata[0x7e] + 1) * EDID_LENGTH;
 182        if (expected != fwsize) {
 183                DRM_ERROR("Size of EDID firmware \"%s\" is invalid "
 184                    "(expected %d, got %d)\n", name, expected, (int) fwsize);
 185                err = -EINVAL;
 186                goto relfw_out;
 187        }
 188
 189        edid = kmalloc(fwsize, GFP_KERNEL);
 190        if (edid == NULL) {
 191                err = -ENOMEM;
 192                goto relfw_out;
 193        }
 194        memcpy(edid, fwdata, fwsize);
 195
 196        if (!drm_edid_block_valid(edid, 0, print_bad_edid)) {
 197                connector->bad_edid_counter++;
 198                DRM_ERROR("Base block of EDID firmware \"%s\" is invalid ",
 199                    name);
 200                kfree(edid);
 201                err = -EINVAL;
 202                goto relfw_out;
 203        }
 204
 205        for (i = 1; i <= edid[0x7e]; i++) {
 206                if (i != valid_extensions + 1)
 207                        memcpy(edid + (valid_extensions + 1) * EDID_LENGTH,
 208                            edid + i * EDID_LENGTH, EDID_LENGTH);
 209                if (drm_edid_block_valid(edid + i * EDID_LENGTH, i, print_bad_edid))
 210                        valid_extensions++;
 211        }
 212
 213        if (valid_extensions != edid[0x7e]) {
 214                edid[EDID_LENGTH-1] += edid[0x7e] - valid_extensions;
 215                DRM_INFO("Found %d valid extensions instead of %d in EDID data "
 216                    "\"%s\" for connector \"%s\"\n", valid_extensions,
 217                    edid[0x7e], name, connector_name);
 218                edid[0x7e] = valid_extensions;
 219                new_edid = krealloc(edid, (valid_extensions + 1) * EDID_LENGTH,
 220                    GFP_KERNEL);
 221                if (new_edid == NULL) {
 222                        err = -ENOMEM;
 223                        kfree(edid);
 224                        goto relfw_out;
 225                }
 226                edid = new_edid;
 227        }
 228
 229        DRM_INFO("Got %s EDID base block and %d extension%s from "
 230            "\"%s\" for connector \"%s\"\n", builtin ? "built-in" :
 231            "external", valid_extensions, valid_extensions == 1 ? "" : "s",
 232            name, connector_name);
 233
 234relfw_out:
 235        release_firmware(fw);
 236
 237out:
 238        if (err)
 239                return ERR_PTR(err);
 240
 241        return edid;
 242}
 243
 244int drm_load_edid_firmware(struct drm_connector *connector)
 245{
 246        char *connector_name = drm_get_connector_name(connector);
 247        char *edidname = edid_firmware, *last, *colon;
 248        int ret;
 249        struct edid *edid;
 250
 251        if (*edidname == '\0')
 252                return 0;
 253
 254        colon = strchr(edidname, ':');
 255        if (colon != NULL) {
 256                if (strncmp(connector_name, edidname, colon - edidname))
 257                        return 0;
 258                edidname = colon + 1;
 259                if (*edidname == '\0')
 260                        return 0;
 261        }
 262
 263        last = edidname + strlen(edidname) - 1;
 264        if (*last == '\n')
 265                *last = '\0';
 266
 267        edid = (struct edid *) edid_load(connector, edidname, connector_name);
 268        if (IS_ERR_OR_NULL(edid))
 269                return 0;
 270
 271        drm_mode_connector_update_edid_property(connector, edid);
 272        ret = drm_add_edid_modes(connector, edid);
 273        kfree(edid);
 274
 275        return ret;
 276}
 277