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 const 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 const 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 int edid_size(const u8 *edid, int data_size)
 137{
 138        if (data_size < EDID_LENGTH)
 139                return 0;
 140
 141        return (edid[0x7e] + 1) * EDID_LENGTH;
 142}
 143
 144static u8 *edid_load(struct drm_connector *connector, const char *name,
 145                        const char *connector_name)
 146{
 147        const struct firmware *fw = NULL;
 148        const u8 *fwdata;
 149        u8 *edid;
 150        int fwsize, builtin;
 151        int i, valid_extensions = 0;
 152        bool print_bad_edid = !connector->bad_edid_counter || (drm_debug & DRM_UT_KMS);
 153
 154        builtin = 0;
 155        for (i = 0; i < GENERIC_EDIDS; i++) {
 156                if (strcmp(name, generic_edid_name[i]) == 0) {
 157                        fwdata = generic_edid[i];
 158                        fwsize = sizeof(generic_edid[i]);
 159                        builtin = 1;
 160                        break;
 161                }
 162        }
 163        if (!builtin) {
 164                struct platform_device *pdev;
 165                int err;
 166
 167                pdev = platform_device_register_simple(connector_name, -1, NULL, 0);
 168                if (IS_ERR(pdev)) {
 169                        DRM_ERROR("Failed to register EDID firmware platform device "
 170                                  "for connector \"%s\"\n", connector_name);
 171                        return ERR_CAST(pdev);
 172                }
 173
 174                err = request_firmware(&fw, name, &pdev->dev);
 175                platform_device_unregister(pdev);
 176                if (err) {
 177                        DRM_ERROR("Requesting EDID firmware \"%s\" failed (err=%d)\n",
 178                                  name, err);
 179                        return ERR_PTR(err);
 180                }
 181
 182                fwdata = fw->data;
 183                fwsize = fw->size;
 184        }
 185
 186        if (edid_size(fwdata, fwsize) != fwsize) {
 187                DRM_ERROR("Size of EDID firmware \"%s\" is invalid "
 188                          "(expected %d, got %d\n", name,
 189                          edid_size(fwdata, fwsize), (int)fwsize);
 190                edid = ERR_PTR(-EINVAL);
 191                goto out;
 192        }
 193
 194        edid = kmemdup(fwdata, fwsize, GFP_KERNEL);
 195        if (edid == NULL) {
 196                edid = ERR_PTR(-ENOMEM);
 197                goto out;
 198        }
 199
 200        if (!drm_edid_block_valid(edid, 0, print_bad_edid)) {
 201                connector->bad_edid_counter++;
 202                DRM_ERROR("Base block of EDID firmware \"%s\" is invalid ",
 203                    name);
 204                kfree(edid);
 205                edid = ERR_PTR(-EINVAL);
 206                goto out;
 207        }
 208
 209        for (i = 1; i <= edid[0x7e]; i++) {
 210                if (i != valid_extensions + 1)
 211                        memcpy(edid + (valid_extensions + 1) * EDID_LENGTH,
 212                            edid + i * EDID_LENGTH, EDID_LENGTH);
 213                if (drm_edid_block_valid(edid + i * EDID_LENGTH, i, print_bad_edid))
 214                        valid_extensions++;
 215        }
 216
 217        if (valid_extensions != edid[0x7e]) {
 218                u8 *new_edid;
 219
 220                edid[EDID_LENGTH-1] += edid[0x7e] - valid_extensions;
 221                DRM_INFO("Found %d valid extensions instead of %d in EDID data "
 222                    "\"%s\" for connector \"%s\"\n", valid_extensions,
 223                    edid[0x7e], name, connector_name);
 224                edid[0x7e] = valid_extensions;
 225
 226                new_edid = krealloc(edid, (valid_extensions + 1) * EDID_LENGTH,
 227                                    GFP_KERNEL);
 228                if (new_edid)
 229                        edid = new_edid;
 230        }
 231
 232        DRM_INFO("Got %s EDID base block and %d extension%s from "
 233            "\"%s\" for connector \"%s\"\n", builtin ? "built-in" :
 234            "external", valid_extensions, valid_extensions == 1 ? "" : "s",
 235            name, connector_name);
 236
 237out:
 238        if (fw)
 239                release_firmware(fw);
 240        return edid;
 241}
 242
 243int drm_load_edid_firmware(struct drm_connector *connector)
 244{
 245        const char *connector_name = drm_get_connector_name(connector);
 246        char *edidname = edid_firmware, *last, *colon;
 247        int ret;
 248        struct edid *edid;
 249
 250        if (*edidname == '\0')
 251                return 0;
 252
 253        colon = strchr(edidname, ':');
 254        if (colon != NULL) {
 255                if (strncmp(connector_name, edidname, colon - edidname))
 256                        return 0;
 257                edidname = colon + 1;
 258                if (*edidname == '\0')
 259                        return 0;
 260        }
 261
 262        last = edidname + strlen(edidname) - 1;
 263        if (*last == '\n')
 264                *last = '\0';
 265
 266        edid = (struct edid *) edid_load(connector, edidname, connector_name);
 267        if (IS_ERR_OR_NULL(edid))
 268                return 0;
 269
 270        drm_mode_connector_update_edid_property(connector, edid);
 271        ret = drm_add_edid_modes(connector, edid);
 272        kfree(edid);
 273
 274        return ret;
 275}
 276