From: Dave Airlie <airlied@xxxxxxxxxx> Just enough to get the tiling info from a Dell 4k monitor. Signed-off-by: Dave Airlie <airlied@xxxxxxxxxx> --- drivers/gpu/drm/Makefile | 2 +- drivers/gpu/drm/drm_displayid.c | 68 ++++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/drm_edid.c | 29 ++++++++++++++-- drivers/gpu/drm/i915/intel_modes.c | 3 ++ include/drm/drm_crtc.h | 5 +++ include/drm/drm_displayid.h | 55 ++++++++++++++++++++++++++++++ include/drm/drm_edid.h | 2 ++ 7 files changed, 161 insertions(+), 3 deletions(-) create mode 100644 drivers/gpu/drm/drm_displayid.c create mode 100644 include/drm/drm_displayid.h diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 4a55d59..50eebe1 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -14,7 +14,7 @@ drm-y := drm_auth.o drm_buffer.o drm_bufs.o drm_cache.o \ drm_info.o drm_debugfs.o drm_encoder_slave.o \ drm_trace_points.o drm_global.o drm_prime.o \ drm_rect.o drm_vma_manager.o drm_flip_work.o \ - drm_modeset_lock.o + drm_modeset_lock.o drm_displayid.o drm-$(CONFIG_COMPAT) += drm_ioc32.o drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o diff --git a/drivers/gpu/drm/drm_displayid.c b/drivers/gpu/drm/drm_displayid.c new file mode 100644 index 0000000..d434da1 --- /dev/null +++ b/drivers/gpu/drm/drm_displayid.c @@ -0,0 +1,68 @@ +/* decode display ID block */ + +/* just enough coding to get tiling blocks from new monitors */ + +#include "drmP.h" +#include "drm_edid.h" +#include "drm_displayid.h" + +int drm_parse_display_id(struct drm_connector *connector, + u8 *displayid, int length, bool is_edid_extension) +{ + /* if this is an EDID extension the first byte will be 0x70 */ + int idx = 0; + struct displayid_hdr *base; + struct displayid_block *block; + u8 csum = 0; + int i; + if (is_edid_extension) + idx = 1; + + base = (struct displayid_hdr *)&displayid[idx]; + + printk("base revision 0x%x, length %d, %d %d\n", + base->rev, base->bytes, base->prod_id, base->ext_count); + + if (base->bytes + 5 > length - idx) + return -EINVAL; + + for (i = idx; i <= base->bytes + 5; i++) { + csum += displayid[i]; + } + if (csum) { + DRM_ERROR("DisplayID checksum invalid, remainder is %d\n", csum); + return -EINVAL; + } + + block = (struct displayid_block *)&displayid[idx + 4]; + printk("block id %d, rev %d, len %d\n", + block->tag, block->rev, block->num_bytes); + + switch (block->tag) { + case DATA_BLOCK_TILED_DISPLAY: { + struct displayid_tiled_block *tile = (struct displayid_tiled_block *)block; + u16 w, h; + u8 tile_v_loc, tile_h_loc; + u8 num_v_tile, num_h_tile; + + w = tile->tile_size[0] | tile->tile_size[1] << 8; + h = tile->tile_size[2] | tile->tile_size[3] << 8; + + num_v_tile = (tile->topo[0] & 0xf) | (tile->topo[2] & 0x30); + num_h_tile = (tile->topo[0] >> 4) | ((tile->topo[2] >> 2) & 0x30); + tile_v_loc = (tile->topo[1] & 0xf) | ((tile->topo[2] & 0x3) << 4); + tile_h_loc = (tile->topo[1] >> 4) | (((tile->topo[2] >> 2) & 0x3) << 4); + + printk("tile cap %d\n", tile->tile_cap); + printk("tile_size %d x %d\n", w, h); + printk("topo num tiles %dx%d, location %dx%d\n", + num_h_tile, num_v_tile, tile_h_loc, tile_v_loc); + printk("vend %c%c%c\n", tile->topology_id[0], tile->topology_id[1], tile->topology_id[2]); + } + break; + default: + printk("unknown displayid tag %d\n", block->tag); + break; + } + return 0; +} diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 1dbf3bc..3d805aa 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -2386,7 +2386,7 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid, /* * Search EDID for CEA extension block. */ -static u8 *drm_find_cea_extension(struct edid *edid) +static u8 *drm_find_edid_extension(struct edid *edid, int ext_id) { u8 *edid_ext = NULL; int i; @@ -2398,7 +2398,7 @@ static u8 *drm_find_cea_extension(struct edid *edid) /* Find CEA extension */ for (i = 0; i < edid->extensions; i++) { edid_ext = (u8 *)edid + EDID_LENGTH * (i + 1); - if (edid_ext[0] == CEA_EXT) + if (edid_ext[0] == ext_id) break; } @@ -2408,6 +2408,16 @@ static u8 *drm_find_cea_extension(struct edid *edid) return edid_ext; } +static u8 *drm_find_cea_extension(struct edid *edid) +{ + return drm_find_edid_extension(edid, CEA_EXT); +} + +static u8 *drm_find_displayid_extension(struct edid *edid) +{ + return drm_find_edid_extension(edid, DISPLAYID_EXT); +} + /* * Calculate the alternate clock for the CEA mode * (60Hz vs. 59.94Hz etc.) @@ -3865,3 +3875,18 @@ drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame, return 0; } EXPORT_SYMBOL(drm_hdmi_vendor_infoframe_from_display_mode); + +void drm_get_displayid(struct drm_connector *connector, + struct i2c_adapter *adapter, struct edid *edid, + bool secondary) +{ + void *displayid = NULL; + displayid = drm_find_displayid_extension(edid); + if (!displayid) { + return; + } + + drm_parse_display_id(connector, displayid, EDID_LENGTH, true); + return; +} +EXPORT_SYMBOL(drm_get_displayid); diff --git a/drivers/gpu/drm/i915/intel_modes.c b/drivers/gpu/drm/i915/intel_modes.c index 0e860f3..35a327e 100644 --- a/drivers/gpu/drm/i915/intel_modes.c +++ b/drivers/gpu/drm/i915/intel_modes.c @@ -65,6 +65,9 @@ int intel_ddc_get_modes(struct drm_connector *connector, if (!edid) return 0; + if (edid) { + drm_get_displayid(connector, adapter, edid, true); + } ret = intel_connector_update_modes(connector, edid); kfree(edid); diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index f1105d0..1efc007 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -964,6 +964,9 @@ extern void drm_reinit_primary_mode_group(struct drm_device *dev); extern bool drm_probe_ddc(struct i2c_adapter *adapter); extern struct edid *drm_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter); +extern void drm_get_displayid(struct drm_connector *connector, + struct i2c_adapter *adapter, struct edid *edid, + bool secondary); extern struct edid *drm_edid_duplicate(const struct edid *edid); extern int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid); extern void drm_mode_config_init(struct drm_device *dev); @@ -1106,6 +1109,8 @@ extern void drm_set_preferred_mode(struct drm_connector *connector, extern int drm_edid_header_is_valid(const u8 *raw_edid); extern bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid); extern bool drm_edid_is_valid(struct edid *edid); +extern int drm_parse_display_id(struct drm_connector *connector, + u8 *displayid, int length, bool is_edid_extension); struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev, int hsize, int vsize, int fresh, bool rb); diff --git a/include/drm/drm_displayid.h b/include/drm/drm_displayid.h new file mode 100644 index 0000000..9374f0e --- /dev/null +++ b/include/drm/drm_displayid.h @@ -0,0 +1,55 @@ +#ifndef DRM_DISPLAYID_H +#define DRM_DISPLAYID_H + +#define DATA_BLOCK_PRODUCT_ID 0x00 +#define DATA_BLOCK_DISPLAY_PARAMETERS 0x01 +#define DATA_BLOCK_COLOR_CHARACTERISTICS 0x02 +#define DATA_BLOCK_TYPE_1_DETAILED_TIMING 0x03 +#define DATA_BLOCK_TYPE_2_DETAILED_TIMING 0x04 +#define DATA_BLOCK_TYPE_3_SHORT_TIMING 0x05 +#define DATA_BLOCK_TYPE_4_DMT_TIMING 0x06 +#define DATA_BLOCK_VESA_TIMING 0x07 +#define DATA_BLOCK_CEA_TIMING 0x08 +#define DATA_BLOCK_VIDEO_TIMING_RANGE 0x09 +#define DATA_BLOCK_PRODUCT_SERIAL_NUMBER 0x0a +#define DATA_BLOCK_GP_ASCII_STRING 0x0b +#define DATA_BLOCK_DISPLAY_DEVICE_DATA 0x0c +#define DATA_BLOCK_INTERFACE_POWER_SEQUENCING 0x0d +#define DATA_BLOCK_TRANSFER_CHARACTERISTICS 0x0e +#define DATA_BLOCK_DISPLAY_INTERFACE 0x0f +#define DATA_BLOCK_STEREO_DISPLAY_INTERFACE 0x10 +#define DATA_BLOCK_TILED_DISPLAY 0x12 + +#define DATA_BLOCK_VENDOR_SPECIFIC 0x7f + +#define PRODUCT_TYPE_EXTENSION 0 +#define PRODUCT_TYPE_TEST 1 +#define PRODUCT_TYPE_PANEL 2 +#define PRODUCT_TYPE_MONITOR 3 +#define PRODUCT_TYPE_TV 4 +#define PRODUCT_TYPE_REPEATER 5 +#define PRODUCT_TYPE_DIRECT_DRIVE 6 + +struct displayid_hdr { + u8 rev; + u8 bytes; + u8 prod_id; + u8 ext_count; +} __attribute__((packed)); + +struct displayid_block { + u8 tag; + u8 rev; + u8 num_bytes; +}; + +struct displayid_tiled_block { + struct displayid_block base; + u8 tile_cap; + u8 topo[3]; + u8 tile_size[4]; + u8 tile_pixel_bezel[5]; + u8 topology_id[8]; +} __attribute__((packed)); + +#endif diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index b96031d..3e87f5a 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -27,12 +27,14 @@ #define EDID_LENGTH 128 #define DDC_ADDR 0x50 +#define DDC_ADDR2 0x52 /* E-DDC 1.2 - where DisplayID can hide */ #define CEA_EXT 0x02 #define VTB_EXT 0x10 #define DI_EXT 0x40 #define LS_EXT 0x50 #define MI_EXT 0x60 +#define DISPLAYID_EXT 0x70 struct est_timings { u8 t1; -- 1.9.3 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/intel-gfx