diff options
Diffstat (limited to 'drivers/gpu/drm/drm_edid.c')
-rw-r--r-- | drivers/gpu/drm/drm_edid.c | 231 |
1 files changed, 201 insertions, 30 deletions
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 3bf999134bcc..53bc7a628909 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/module.h> | 34 | #include <linux/module.h> |
35 | #include <drm/drmP.h> | 35 | #include <drm/drmP.h> |
36 | #include <drm/drm_edid.h> | 36 | #include <drm/drm_edid.h> |
37 | #include <drm/drm_displayid.h> | ||
37 | 38 | ||
38 | #define version_greater(edid, maj, min) \ | 39 | #define version_greater(edid, maj, min) \ |
39 | (((edid)->version > (maj)) || \ | 40 | (((edid)->version > (maj)) || \ |
@@ -1014,6 +1015,27 @@ module_param_named(edid_fixup, edid_fixup, int, 0400); | |||
1014 | MODULE_PARM_DESC(edid_fixup, | 1015 | MODULE_PARM_DESC(edid_fixup, |
1015 | "Minimum number of valid EDID header bytes (0-8, default 6)"); | 1016 | "Minimum number of valid EDID header bytes (0-8, default 6)"); |
1016 | 1017 | ||
1018 | static void drm_get_displayid(struct drm_connector *connector, | ||
1019 | struct edid *edid); | ||
1020 | |||
1021 | static int drm_edid_block_checksum(const u8 *raw_edid) | ||
1022 | { | ||
1023 | int i; | ||
1024 | u8 csum = 0; | ||
1025 | for (i = 0; i < EDID_LENGTH; i++) | ||
1026 | csum += raw_edid[i]; | ||
1027 | |||
1028 | return csum; | ||
1029 | } | ||
1030 | |||
1031 | static bool drm_edid_is_zero(const u8 *in_edid, int length) | ||
1032 | { | ||
1033 | if (memchr_inv(in_edid, 0, length)) | ||
1034 | return false; | ||
1035 | |||
1036 | return true; | ||
1037 | } | ||
1038 | |||
1017 | /** | 1039 | /** |
1018 | * drm_edid_block_valid - Sanity check the EDID block (base or extension) | 1040 | * drm_edid_block_valid - Sanity check the EDID block (base or extension) |
1019 | * @raw_edid: pointer to raw EDID block | 1041 | * @raw_edid: pointer to raw EDID block |
@@ -1027,8 +1049,7 @@ MODULE_PARM_DESC(edid_fixup, | |||
1027 | */ | 1049 | */ |
1028 | bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid) | 1050 | bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid) |
1029 | { | 1051 | { |
1030 | int i; | 1052 | u8 csum; |
1031 | u8 csum = 0; | ||
1032 | struct edid *edid = (struct edid *)raw_edid; | 1053 | struct edid *edid = (struct edid *)raw_edid; |
1033 | 1054 | ||
1034 | if (WARN_ON(!raw_edid)) | 1055 | if (WARN_ON(!raw_edid)) |
@@ -1048,8 +1069,7 @@ bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid) | |||
1048 | } | 1069 | } |
1049 | } | 1070 | } |
1050 | 1071 | ||
1051 | for (i = 0; i < EDID_LENGTH; i++) | 1072 | csum = drm_edid_block_checksum(raw_edid); |
1052 | csum += raw_edid[i]; | ||
1053 | if (csum) { | 1073 | if (csum) { |
1054 | if (print_bad_edid) { | 1074 | if (print_bad_edid) { |
1055 | DRM_ERROR("EDID checksum is invalid, remainder is %d\n", csum); | 1075 | DRM_ERROR("EDID checksum is invalid, remainder is %d\n", csum); |
@@ -1080,9 +1100,13 @@ bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid) | |||
1080 | 1100 | ||
1081 | bad: | 1101 | bad: |
1082 | if (print_bad_edid) { | 1102 | if (print_bad_edid) { |
1083 | printk(KERN_ERR "Raw EDID:\n"); | 1103 | if (drm_edid_is_zero(raw_edid, EDID_LENGTH)) { |
1084 | print_hex_dump(KERN_ERR, " \t", DUMP_PREFIX_NONE, 16, 1, | 1104 | printk(KERN_ERR "EDID block is all zeroes\n"); |
1105 | } else { | ||
1106 | printk(KERN_ERR "Raw EDID:\n"); | ||
1107 | print_hex_dump(KERN_ERR, " \t", DUMP_PREFIX_NONE, 16, 1, | ||
1085 | raw_edid, EDID_LENGTH, false); | 1108 | raw_edid, EDID_LENGTH, false); |
1109 | } | ||
1086 | } | 1110 | } |
1087 | return false; | 1111 | return false; |
1088 | } | 1112 | } |
@@ -1115,7 +1139,7 @@ EXPORT_SYMBOL(drm_edid_is_valid); | |||
1115 | #define DDC_SEGMENT_ADDR 0x30 | 1139 | #define DDC_SEGMENT_ADDR 0x30 |
1116 | /** | 1140 | /** |
1117 | * drm_do_probe_ddc_edid() - get EDID information via I2C | 1141 | * drm_do_probe_ddc_edid() - get EDID information via I2C |
1118 | * @adapter: I2C device adaptor | 1142 | * @data: I2C device adapter |
1119 | * @buf: EDID data buffer to be filled | 1143 | * @buf: EDID data buffer to be filled |
1120 | * @block: 128 byte EDID block to start fetching from | 1144 | * @block: 128 byte EDID block to start fetching from |
1121 | * @len: EDID data buffer length to fetch | 1145 | * @len: EDID data buffer length to fetch |
@@ -1125,9 +1149,9 @@ EXPORT_SYMBOL(drm_edid_is_valid); | |||
1125 | * Return: 0 on success or -1 on failure. | 1149 | * Return: 0 on success or -1 on failure. |
1126 | */ | 1150 | */ |
1127 | static int | 1151 | static int |
1128 | drm_do_probe_ddc_edid(struct i2c_adapter *adapter, unsigned char *buf, | 1152 | drm_do_probe_ddc_edid(void *data, u8 *buf, unsigned int block, size_t len) |
1129 | int block, int len) | ||
1130 | { | 1153 | { |
1154 | struct i2c_adapter *adapter = data; | ||
1131 | unsigned char start = block * EDID_LENGTH; | 1155 | unsigned char start = block * EDID_LENGTH; |
1132 | unsigned char segment = block >> 1; | 1156 | unsigned char segment = block >> 1; |
1133 | unsigned char xfers = segment ? 3 : 2; | 1157 | unsigned char xfers = segment ? 3 : 2; |
@@ -1176,16 +1200,26 @@ drm_do_probe_ddc_edid(struct i2c_adapter *adapter, unsigned char *buf, | |||
1176 | return ret == xfers ? 0 : -1; | 1200 | return ret == xfers ? 0 : -1; |
1177 | } | 1201 | } |
1178 | 1202 | ||
1179 | static bool drm_edid_is_zero(u8 *in_edid, int length) | 1203 | /** |
1180 | { | 1204 | * drm_do_get_edid - get EDID data using a custom EDID block read function |
1181 | if (memchr_inv(in_edid, 0, length)) | 1205 | * @connector: connector we're probing |
1182 | return false; | 1206 | * @get_edid_block: EDID block read function |
1183 | 1207 | * @data: private data passed to the block read function | |
1184 | return true; | 1208 | * |
1185 | } | 1209 | * When the I2C adapter connected to the DDC bus is hidden behind a device that |
1186 | 1210 | * exposes a different interface to read EDID blocks this function can be used | |
1187 | static u8 * | 1211 | * to get EDID data using a custom block read function. |
1188 | drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) | 1212 | * |
1213 | * As in the general case the DDC bus is accessible by the kernel at the I2C | ||
1214 | * level, drivers must make all reasonable efforts to expose it as an I2C | ||
1215 | * adapter and use drm_get_edid() instead of abusing this function. | ||
1216 | * | ||
1217 | * Return: Pointer to valid EDID or NULL if we couldn't find any. | ||
1218 | */ | ||
1219 | struct edid *drm_do_get_edid(struct drm_connector *connector, | ||
1220 | int (*get_edid_block)(void *data, u8 *buf, unsigned int block, | ||
1221 | size_t len), | ||
1222 | void *data) | ||
1189 | { | 1223 | { |
1190 | int i, j = 0, valid_extensions = 0; | 1224 | int i, j = 0, valid_extensions = 0; |
1191 | u8 *block, *new; | 1225 | u8 *block, *new; |
@@ -1196,7 +1230,7 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) | |||
1196 | 1230 | ||
1197 | /* base block fetch */ | 1231 | /* base block fetch */ |
1198 | for (i = 0; i < 4; i++) { | 1232 | for (i = 0; i < 4; i++) { |
1199 | if (drm_do_probe_ddc_edid(adapter, block, 0, EDID_LENGTH)) | 1233 | if (get_edid_block(data, block, 0, EDID_LENGTH)) |
1200 | goto out; | 1234 | goto out; |
1201 | if (drm_edid_block_valid(block, 0, print_bad_edid)) | 1235 | if (drm_edid_block_valid(block, 0, print_bad_edid)) |
1202 | break; | 1236 | break; |
@@ -1210,7 +1244,7 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) | |||
1210 | 1244 | ||
1211 | /* if there's no extensions, we're done */ | 1245 | /* if there's no extensions, we're done */ |
1212 | if (block[0x7e] == 0) | 1246 | if (block[0x7e] == 0) |
1213 | return block; | 1247 | return (struct edid *)block; |
1214 | 1248 | ||
1215 | new = krealloc(block, (block[0x7e] + 1) * EDID_LENGTH, GFP_KERNEL); | 1249 | new = krealloc(block, (block[0x7e] + 1) * EDID_LENGTH, GFP_KERNEL); |
1216 | if (!new) | 1250 | if (!new) |
@@ -1219,7 +1253,7 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) | |||
1219 | 1253 | ||
1220 | for (j = 1; j <= block[0x7e]; j++) { | 1254 | for (j = 1; j <= block[0x7e]; j++) { |
1221 | for (i = 0; i < 4; i++) { | 1255 | for (i = 0; i < 4; i++) { |
1222 | if (drm_do_probe_ddc_edid(adapter, | 1256 | if (get_edid_block(data, |
1223 | block + (valid_extensions + 1) * EDID_LENGTH, | 1257 | block + (valid_extensions + 1) * EDID_LENGTH, |
1224 | j, EDID_LENGTH)) | 1258 | j, EDID_LENGTH)) |
1225 | goto out; | 1259 | goto out; |
@@ -1247,7 +1281,7 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) | |||
1247 | block = new; | 1281 | block = new; |
1248 | } | 1282 | } |
1249 | 1283 | ||
1250 | return block; | 1284 | return (struct edid *)block; |
1251 | 1285 | ||
1252 | carp: | 1286 | carp: |
1253 | if (print_bad_edid) { | 1287 | if (print_bad_edid) { |
@@ -1260,6 +1294,7 @@ out: | |||
1260 | kfree(block); | 1294 | kfree(block); |
1261 | return NULL; | 1295 | return NULL; |
1262 | } | 1296 | } |
1297 | EXPORT_SYMBOL_GPL(drm_do_get_edid); | ||
1263 | 1298 | ||
1264 | /** | 1299 | /** |
1265 | * drm_probe_ddc() - probe DDC presence | 1300 | * drm_probe_ddc() - probe DDC presence |
@@ -1289,11 +1324,14 @@ EXPORT_SYMBOL(drm_probe_ddc); | |||
1289 | struct edid *drm_get_edid(struct drm_connector *connector, | 1324 | struct edid *drm_get_edid(struct drm_connector *connector, |
1290 | struct i2c_adapter *adapter) | 1325 | struct i2c_adapter *adapter) |
1291 | { | 1326 | { |
1292 | struct edid *edid = NULL; | 1327 | struct edid *edid; |
1293 | 1328 | ||
1294 | if (drm_probe_ddc(adapter)) | 1329 | if (!drm_probe_ddc(adapter)) |
1295 | edid = (struct edid *)drm_do_get_edid(connector, adapter); | 1330 | return NULL; |
1296 | 1331 | ||
1332 | edid = drm_do_get_edid(connector, drm_do_probe_ddc_edid, adapter); | ||
1333 | if (edid) | ||
1334 | drm_get_displayid(connector, edid); | ||
1297 | return edid; | 1335 | return edid; |
1298 | } | 1336 | } |
1299 | EXPORT_SYMBOL(drm_get_edid); | 1337 | EXPORT_SYMBOL(drm_get_edid); |
@@ -2389,7 +2427,7 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid, | |||
2389 | /* | 2427 | /* |
2390 | * Search EDID for CEA extension block. | 2428 | * Search EDID for CEA extension block. |
2391 | */ | 2429 | */ |
2392 | static u8 *drm_find_cea_extension(struct edid *edid) | 2430 | static u8 *drm_find_edid_extension(struct edid *edid, int ext_id) |
2393 | { | 2431 | { |
2394 | u8 *edid_ext = NULL; | 2432 | u8 *edid_ext = NULL; |
2395 | int i; | 2433 | int i; |
@@ -2401,7 +2439,7 @@ static u8 *drm_find_cea_extension(struct edid *edid) | |||
2401 | /* Find CEA extension */ | 2439 | /* Find CEA extension */ |
2402 | for (i = 0; i < edid->extensions; i++) { | 2440 | for (i = 0; i < edid->extensions; i++) { |
2403 | edid_ext = (u8 *)edid + EDID_LENGTH * (i + 1); | 2441 | edid_ext = (u8 *)edid + EDID_LENGTH * (i + 1); |
2404 | if (edid_ext[0] == CEA_EXT) | 2442 | if (edid_ext[0] == ext_id) |
2405 | break; | 2443 | break; |
2406 | } | 2444 | } |
2407 | 2445 | ||
@@ -2411,6 +2449,16 @@ static u8 *drm_find_cea_extension(struct edid *edid) | |||
2411 | return edid_ext; | 2449 | return edid_ext; |
2412 | } | 2450 | } |
2413 | 2451 | ||
2452 | static u8 *drm_find_cea_extension(struct edid *edid) | ||
2453 | { | ||
2454 | return drm_find_edid_extension(edid, CEA_EXT); | ||
2455 | } | ||
2456 | |||
2457 | static u8 *drm_find_displayid_extension(struct edid *edid) | ||
2458 | { | ||
2459 | return drm_find_edid_extension(edid, DISPLAYID_EXT); | ||
2460 | } | ||
2461 | |||
2414 | /* | 2462 | /* |
2415 | * Calculate the alternate clock for the CEA mode | 2463 | * Calculate the alternate clock for the CEA mode |
2416 | * (60Hz vs. 59.94Hz etc.) | 2464 | * (60Hz vs. 59.94Hz etc.) |
@@ -3128,9 +3176,12 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) | |||
3128 | } | 3176 | } |
3129 | } | 3177 | } |
3130 | eld[5] |= sad_count << 4; | 3178 | eld[5] |= sad_count << 4; |
3131 | eld[2] = (20 + mnl + sad_count * 3 + 3) / 4; | ||
3132 | 3179 | ||
3133 | DRM_DEBUG_KMS("ELD size %d, SAD count %d\n", (int)eld[2], sad_count); | 3180 | eld[DRM_ELD_BASELINE_ELD_LEN] = |
3181 | DIV_ROUND_UP(drm_eld_calc_baseline_block_size(eld), 4); | ||
3182 | |||
3183 | DRM_DEBUG_KMS("ELD size %d, SAD count %d\n", | ||
3184 | drm_eld_size(eld), sad_count); | ||
3134 | } | 3185 | } |
3135 | EXPORT_SYMBOL(drm_edid_to_eld); | 3186 | EXPORT_SYMBOL(drm_edid_to_eld); |
3136 | 3187 | ||
@@ -3868,3 +3919,123 @@ drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame, | |||
3868 | return 0; | 3919 | return 0; |
3869 | } | 3920 | } |
3870 | EXPORT_SYMBOL(drm_hdmi_vendor_infoframe_from_display_mode); | 3921 | EXPORT_SYMBOL(drm_hdmi_vendor_infoframe_from_display_mode); |
3922 | |||
3923 | static int drm_parse_display_id(struct drm_connector *connector, | ||
3924 | u8 *displayid, int length, | ||
3925 | bool is_edid_extension) | ||
3926 | { | ||
3927 | /* if this is an EDID extension the first byte will be 0x70 */ | ||
3928 | int idx = 0; | ||
3929 | struct displayid_hdr *base; | ||
3930 | struct displayid_block *block; | ||
3931 | u8 csum = 0; | ||
3932 | int i; | ||
3933 | |||
3934 | if (is_edid_extension) | ||
3935 | idx = 1; | ||
3936 | |||
3937 | base = (struct displayid_hdr *)&displayid[idx]; | ||
3938 | |||
3939 | DRM_DEBUG_KMS("base revision 0x%x, length %d, %d %d\n", | ||
3940 | base->rev, base->bytes, base->prod_id, base->ext_count); | ||
3941 | |||
3942 | if (base->bytes + 5 > length - idx) | ||
3943 | return -EINVAL; | ||
3944 | |||
3945 | for (i = idx; i <= base->bytes + 5; i++) { | ||
3946 | csum += displayid[i]; | ||
3947 | } | ||
3948 | if (csum) { | ||
3949 | DRM_ERROR("DisplayID checksum invalid, remainder is %d\n", csum); | ||
3950 | return -EINVAL; | ||
3951 | } | ||
3952 | |||
3953 | block = (struct displayid_block *)&displayid[idx + 4]; | ||
3954 | DRM_DEBUG_KMS("block id %d, rev %d, len %d\n", | ||
3955 | block->tag, block->rev, block->num_bytes); | ||
3956 | |||
3957 | switch (block->tag) { | ||
3958 | case DATA_BLOCK_TILED_DISPLAY: { | ||
3959 | struct displayid_tiled_block *tile = (struct displayid_tiled_block *)block; | ||
3960 | |||
3961 | u16 w, h; | ||
3962 | u8 tile_v_loc, tile_h_loc; | ||
3963 | u8 num_v_tile, num_h_tile; | ||
3964 | struct drm_tile_group *tg; | ||
3965 | |||
3966 | w = tile->tile_size[0] | tile->tile_size[1] << 8; | ||
3967 | h = tile->tile_size[2] | tile->tile_size[3] << 8; | ||
3968 | |||
3969 | num_v_tile = (tile->topo[0] & 0xf) | (tile->topo[2] & 0x30); | ||
3970 | num_h_tile = (tile->topo[0] >> 4) | ((tile->topo[2] >> 2) & 0x30); | ||
3971 | tile_v_loc = (tile->topo[1] & 0xf) | ((tile->topo[2] & 0x3) << 4); | ||
3972 | tile_h_loc = (tile->topo[1] >> 4) | (((tile->topo[2] >> 2) & 0x3) << 4); | ||
3973 | |||
3974 | connector->has_tile = true; | ||
3975 | if (tile->tile_cap & 0x80) | ||
3976 | connector->tile_is_single_monitor = true; | ||
3977 | |||
3978 | connector->num_h_tile = num_h_tile + 1; | ||
3979 | connector->num_v_tile = num_v_tile + 1; | ||
3980 | connector->tile_h_loc = tile_h_loc; | ||
3981 | connector->tile_v_loc = tile_v_loc; | ||
3982 | connector->tile_h_size = w + 1; | ||
3983 | connector->tile_v_size = h + 1; | ||
3984 | |||
3985 | DRM_DEBUG_KMS("tile cap 0x%x\n", tile->tile_cap); | ||
3986 | DRM_DEBUG_KMS("tile_size %d x %d\n", w + 1, h + 1); | ||
3987 | DRM_DEBUG_KMS("topo num tiles %dx%d, location %dx%d\n", | ||
3988 | num_h_tile + 1, num_v_tile + 1, tile_h_loc, tile_v_loc); | ||
3989 | DRM_DEBUG_KMS("vend %c%c%c\n", tile->topology_id[0], tile->topology_id[1], tile->topology_id[2]); | ||
3990 | |||
3991 | tg = drm_mode_get_tile_group(connector->dev, tile->topology_id); | ||
3992 | if (!tg) { | ||
3993 | tg = drm_mode_create_tile_group(connector->dev, tile->topology_id); | ||
3994 | } | ||
3995 | if (!tg) | ||
3996 | return -ENOMEM; | ||
3997 | |||
3998 | if (connector->tile_group != tg) { | ||
3999 | /* if we haven't got a pointer, | ||
4000 | take the reference, drop ref to old tile group */ | ||
4001 | if (connector->tile_group) { | ||
4002 | drm_mode_put_tile_group(connector->dev, connector->tile_group); | ||
4003 | } | ||
4004 | connector->tile_group = tg; | ||
4005 | } else | ||
4006 | /* if same tile group, then release the ref we just took. */ | ||
4007 | drm_mode_put_tile_group(connector->dev, tg); | ||
4008 | } | ||
4009 | break; | ||
4010 | default: | ||
4011 | printk("unknown displayid tag %d\n", block->tag); | ||
4012 | break; | ||
4013 | } | ||
4014 | return 0; | ||
4015 | } | ||
4016 | |||
4017 | static void drm_get_displayid(struct drm_connector *connector, | ||
4018 | struct edid *edid) | ||
4019 | { | ||
4020 | void *displayid = NULL; | ||
4021 | int ret; | ||
4022 | connector->has_tile = false; | ||
4023 | displayid = drm_find_displayid_extension(edid); | ||
4024 | if (!displayid) { | ||
4025 | /* drop reference to any tile group we had */ | ||
4026 | goto out_drop_ref; | ||
4027 | } | ||
4028 | |||
4029 | ret = drm_parse_display_id(connector, displayid, EDID_LENGTH, true); | ||
4030 | if (ret < 0) | ||
4031 | goto out_drop_ref; | ||
4032 | if (!connector->has_tile) | ||
4033 | goto out_drop_ref; | ||
4034 | return; | ||
4035 | out_drop_ref: | ||
4036 | if (connector->tile_group) { | ||
4037 | drm_mode_put_tile_group(connector->dev, connector->tile_group); | ||
4038 | connector->tile_group = NULL; | ||
4039 | } | ||
4040 | return; | ||
4041 | } | ||