aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_edid.c
diff options
context:
space:
mode:
authorAdam Jackson <ajax@redhat.com>2010-03-29 17:43:18 -0400
committerDave Airlie <airlied@redhat.com>2010-04-05 20:40:16 -0400
commit61e57a8d72f2336faf39b5d940215cf085e01e6e (patch)
tree8c9c6713b4f1ff4c610771860c6cca411cb28cfc /drivers/gpu/drm/drm_edid.c
parent95beb690170e6ce918fe53c73a0fcc7cf64d704a (diff)
drm/edid: Fix secondary block fetch.
This makes fetching the second EDID block on HDMI monitors actually work. DDC can't transfer more than 128 bytes at a time. Also, rearrange the code so the pure DDC bits are separate from block parse. Signed-off-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/drm_edid.c')
-rw-r--r--drivers/gpu/drm/drm_edid.c330
1 files changed, 187 insertions, 143 deletions
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 7e608f4a0df9..5e60a6129641 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -2,6 +2,7 @@
2 * Copyright (c) 2006 Luc Verhaegen (quirks list) 2 * Copyright (c) 2006 Luc Verhaegen (quirks list)
3 * Copyright (c) 2007-2008 Intel Corporation 3 * Copyright (c) 2007-2008 Intel Corporation
4 * Jesse Barnes <jesse.barnes@intel.com> 4 * Jesse Barnes <jesse.barnes@intel.com>
5 * Copyright 2010 Red Hat, Inc.
5 * 6 *
6 * DDC probing routines (drm_ddc_read & drm_do_probe_ddc_edid) originally from 7 * DDC probing routines (drm_ddc_read & drm_do_probe_ddc_edid) originally from
7 * FB layer. 8 * FB layer.
@@ -106,36 +107,38 @@ static struct edid_quirk {
106 { "SAM", 638, EDID_QUIRK_PREFER_LARGE_60 }, 107 { "SAM", 638, EDID_QUIRK_PREFER_LARGE_60 },
107}; 108};
108 109
110/*** DDC fetch and block validation ***/
109 111
110/* Valid EDID header has these bytes */
111static const u8 edid_header[] = { 112static const u8 edid_header[] = {
112 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 113 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00
113}; 114};
114 115
115/** 116/*
116 * drm_edid_is_valid - sanity check EDID data 117 * Sanity check the EDID block (base or extension). Return 0 if the block
117 * @edid: EDID data 118 * doesn't check out, or 1 if it's valid.
118 *
119 * Sanity check the EDID block by looking at the header, the version number
120 * and the checksum. Return 0 if the EDID doesn't check out, or 1 if it's
121 * valid.
122 */ 119 */
123bool drm_edid_is_valid(struct edid *edid) 120static bool
121drm_edid_block_valid(u8 *raw_edid)
124{ 122{
125 int i, score = 0; 123 int i;
126 u8 csum = 0; 124 u8 csum = 0;
127 u8 *raw_edid = (u8 *)edid; 125 struct edid *edid = (struct edid *)raw_edid;
128 126
129 for (i = 0; i < sizeof(edid_header); i++) 127 if (raw_edid[0] == 0x00) {
130 if (raw_edid[i] == edid_header[i]) 128 int score = 0;
131 score++;
132 129
133 if (score == 8) ; 130 for (i = 0; i < sizeof(edid_header); i++)
134 else if (score >= 6) { 131 if (raw_edid[i] == edid_header[i])
135 DRM_DEBUG("Fixing EDID header, your hardware may be failing\n"); 132 score++;
136 memcpy(raw_edid, edid_header, sizeof(edid_header)); 133
137 } else 134 if (score == 8) ;
138 goto bad; 135 else if (score >= 6) {
136 DRM_DEBUG("Fixing EDID header, your hardware may be failing\n");
137 memcpy(raw_edid, edid_header, sizeof(edid_header));
138 } else {
139 goto bad;
140 }
141 }
139 142
140 for (i = 0; i < EDID_LENGTH; i++) 143 for (i = 0; i < EDID_LENGTH; i++)
141 csum += raw_edid[i]; 144 csum += raw_edid[i];
@@ -144,13 +147,21 @@ bool drm_edid_is_valid(struct edid *edid)
144 goto bad; 147 goto bad;
145 } 148 }
146 149
147 if (edid->version != 1) { 150 /* per-block-type checks */
148 DRM_ERROR("EDID has major version %d, instead of 1\n", edid->version); 151 switch (raw_edid[0]) {
149 goto bad; 152 case 0: /* base */
150 } 153 if (edid->version != 1) {
154 DRM_ERROR("EDID has major version %d, instead of 1\n", edid->version);
155 goto bad;
156 }
151 157
152 if (edid->revision > 4) 158 if (edid->revision > 4)
153 DRM_DEBUG("EDID minor > 4, assuming backward compatibility\n"); 159 DRM_DEBUG("EDID minor > 4, assuming backward compatibility\n");
160 break;
161
162 default:
163 break;
164 }
154 165
155 return 1; 166 return 1;
156 167
@@ -162,8 +173,158 @@ bad:
162 } 173 }
163 return 0; 174 return 0;
164} 175}
176
177/**
178 * drm_edid_is_valid - sanity check EDID data
179 * @edid: EDID data
180 *
181 * Sanity-check an entire EDID record (including extensions)
182 */
183bool drm_edid_is_valid(struct edid *edid)
184{
185 int i;
186 u8 *raw = (u8 *)edid;
187
188 if (!edid)
189 return false;
190
191 for (i = 0; i <= edid->extensions; i++)
192 if (!drm_edid_block_valid(raw + i * EDID_LENGTH))
193 return false;
194
195 return true;
196}
165EXPORT_SYMBOL(drm_edid_is_valid); 197EXPORT_SYMBOL(drm_edid_is_valid);
166 198
199#define DDC_ADDR 0x50
200#define DDC_SEGMENT_ADDR 0x30
201/**
202 * Get EDID information via I2C.
203 *
204 * \param adapter : i2c device adaptor
205 * \param buf : EDID data buffer to be filled
206 * \param len : EDID data buffer length
207 * \return 0 on success or -1 on failure.
208 *
209 * Try to fetch EDID information by calling i2c driver function.
210 */
211static int
212drm_do_probe_ddc_edid(struct i2c_adapter *adapter, unsigned char *buf,
213 int block, int len)
214{
215 unsigned char start = block * EDID_LENGTH;
216 struct i2c_msg msgs[] = {
217 {
218 .addr = DDC_ADDR,
219 .flags = 0,
220 .len = 1,
221 .buf = &start,
222 }, {
223 .addr = DDC_ADDR,
224 .flags = I2C_M_RD,
225 .len = len,
226 .buf = buf + start,
227 }
228 };
229
230 if (i2c_transfer(adapter, msgs, 2) == 2)
231 return 0;
232
233 return -1;
234}
235
236static u8 *
237drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
238{
239 int i, j = 0;
240 u8 *block, *new;
241
242 if ((block = kmalloc(EDID_LENGTH, GFP_KERNEL)) == NULL)
243 return NULL;
244
245 /* base block fetch */
246 for (i = 0; i < 4; i++) {
247 if (drm_do_probe_ddc_edid(adapter, block, 0, EDID_LENGTH))
248 goto out;
249 if (drm_edid_block_valid(block))
250 break;
251 }
252 if (i == 4)
253 goto carp;
254
255 /* if there's no extensions, we're done */
256 if (block[0x7e] == 0)
257 return block;
258
259 new = krealloc(block, (block[0x7e] + 1) * EDID_LENGTH, GFP_KERNEL);
260 if (!new)
261 goto out;
262 block = new;
263
264 for (j = 1; j <= block[0x7e]; j++) {
265 for (i = 0; i < 4; i++) {
266 if (drm_do_probe_ddc_edid(adapter, block, j,
267 EDID_LENGTH))
268 goto out;
269 if (drm_edid_block_valid(block + j * EDID_LENGTH))
270 break;
271 }
272 if (i == 4)
273 goto carp;
274 }
275
276 return block;
277
278carp:
279 dev_warn(&connector->dev->pdev->dev, "%s: EDID block %d invalid.\n",
280 drm_get_connector_name(connector), j);
281
282out:
283 kfree(block);
284 return NULL;
285}
286
287/**
288 * Probe DDC presence.
289 *
290 * \param adapter : i2c device adaptor
291 * \return 1 on success
292 */
293static bool
294drm_probe_ddc(struct i2c_adapter *adapter)
295{
296 unsigned char out;
297
298 return (drm_do_probe_ddc_edid(adapter, &out, 0, 1) == 0);
299}
300
301/**
302 * drm_get_edid - get EDID data, if available
303 * @connector: connector we're probing
304 * @adapter: i2c adapter to use for DDC
305 *
306 * Poke the given i2c channel to grab EDID data if possible. If found,
307 * attach it to the connector.
308 *
309 * Return edid data or NULL if we couldn't find any.
310 */
311struct edid *drm_get_edid(struct drm_connector *connector,
312 struct i2c_adapter *adapter)
313{
314 struct edid *edid = NULL;
315
316 if (drm_probe_ddc(adapter))
317 edid = (struct edid *)drm_do_get_edid(connector, adapter);
318
319 connector->display_info.raw_edid = (char *)edid;
320
321 return edid;
322
323}
324EXPORT_SYMBOL(drm_get_edid);
325
326/*** EDID parsing ***/
327
167/** 328/**
168 * edid_vendor - match a string against EDID's obfuscated vendor field 329 * edid_vendor - match a string against EDID's obfuscated vendor field
169 * @edid: EDID to match 330 * @edid: EDID to match
@@ -1141,123 +1302,6 @@ static int add_detailed_info_eedid(struct drm_connector *connector,
1141 return modes; 1302 return modes;
1142} 1303}
1143 1304
1144#define DDC_ADDR 0x50
1145/**
1146 * Get EDID information via I2C.
1147 *
1148 * \param adapter : i2c device adaptor
1149 * \param buf : EDID data buffer to be filled
1150 * \param len : EDID data buffer length
1151 * \return 0 on success or -1 on failure.
1152 *
1153 * Try to fetch EDID information by calling i2c driver function.
1154 */
1155int drm_do_probe_ddc_edid(struct i2c_adapter *adapter,
1156 unsigned char *buf, int len)
1157{
1158 unsigned char start = 0x0;
1159 struct i2c_msg msgs[] = {
1160 {
1161 .addr = DDC_ADDR,
1162 .flags = 0,
1163 .len = 1,
1164 .buf = &start,
1165 }, {
1166 .addr = DDC_ADDR,
1167 .flags = I2C_M_RD,
1168 .len = len,
1169 .buf = buf,
1170 }
1171 };
1172
1173 if (i2c_transfer(adapter, msgs, 2) == 2)
1174 return 0;
1175
1176 return -1;
1177}
1178EXPORT_SYMBOL(drm_do_probe_ddc_edid);
1179
1180static int drm_ddc_read_edid(struct drm_connector *connector,
1181 struct i2c_adapter *adapter,
1182 char *buf, int len)
1183{
1184 int i;
1185
1186 for (i = 0; i < 4; i++) {
1187 if (drm_do_probe_ddc_edid(adapter, buf, len))
1188 return -1;
1189 if (drm_edid_is_valid((struct edid *)buf))
1190 return 0;
1191 }
1192
1193 /* repeated checksum failures; warn, but carry on */
1194 dev_warn(&connector->dev->pdev->dev, "%s: EDID invalid.\n",
1195 drm_get_connector_name(connector));
1196 return -1;
1197}
1198
1199/**
1200 * drm_get_edid - get EDID data, if available
1201 * @connector: connector we're probing
1202 * @adapter: i2c adapter to use for DDC
1203 *
1204 * Poke the given connector's i2c channel to grab EDID data if possible.
1205 *
1206 * Return edid data or NULL if we couldn't find any.
1207 */
1208struct edid *drm_get_edid(struct drm_connector *connector,
1209 struct i2c_adapter *adapter)
1210{
1211 int ret;
1212 struct edid *edid;
1213
1214 edid = kmalloc(EDID_LENGTH * (DRM_MAX_EDID_EXT_NUM + 1),
1215 GFP_KERNEL);
1216 if (edid == NULL) {
1217 dev_warn(&connector->dev->pdev->dev,
1218 "Failed to allocate EDID\n");
1219 goto end;
1220 }
1221
1222 /* Read first EDID block */
1223 ret = drm_ddc_read_edid(connector, adapter,
1224 (unsigned char *)edid, EDID_LENGTH);
1225 if (ret != 0)
1226 goto clean_up;
1227
1228 /* There are EDID extensions to be read */
1229 if (edid->extensions != 0) {
1230 int edid_ext_num = edid->extensions;
1231
1232 if (edid_ext_num > DRM_MAX_EDID_EXT_NUM) {
1233 dev_warn(&connector->dev->pdev->dev,
1234 "The number of extension(%d) is "
1235 "over max (%d), actually read number (%d)\n",
1236 edid_ext_num, DRM_MAX_EDID_EXT_NUM,
1237 DRM_MAX_EDID_EXT_NUM);
1238 /* Reset EDID extension number to be read */
1239 edid_ext_num = DRM_MAX_EDID_EXT_NUM;
1240 }
1241 /* Read EDID including extensions too */
1242 ret = drm_ddc_read_edid(connector, adapter, (char *)edid,
1243 EDID_LENGTH * (edid_ext_num + 1));
1244 if (ret != 0)
1245 goto clean_up;
1246
1247 }
1248
1249 connector->display_info.raw_edid = (char *)edid;
1250 goto end;
1251
1252clean_up:
1253 kfree(edid);
1254 edid = NULL;
1255end:
1256 return edid;
1257
1258}
1259EXPORT_SYMBOL(drm_get_edid);
1260
1261#define HDMI_IDENTIFIER 0x000C03 1305#define HDMI_IDENTIFIER 0x000C03
1262#define VENDOR_BLOCK 0x03 1306#define VENDOR_BLOCK 0x03
1263/** 1307/**