Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/connector: store tile information from displayid (v3)

This creates a tile group from DisplayID block, and
stores the pieces of parsed info from the DisplayID block
into the connector.

v2: add missing signoff, add new connector bits to docs.

v3: remove some debugging.

Signed-off-by: Dave Airlie <airlied@redhat.com>

+164 -3
+5
drivers/gpu/drm/drm_crtc.c
··· 908 908 struct drm_device *dev = connector->dev; 909 909 struct drm_display_mode *mode, *t; 910 910 911 + if (connector->tile_group) { 912 + drm_mode_put_tile_group(dev, connector->tile_group); 913 + connector->tile_group = NULL; 914 + } 915 + 911 916 list_for_each_entry_safe(mode, t, &connector->probed_modes, head) 912 917 drm_mode_remove(connector, mode); 913 918
+141 -3
drivers/gpu/drm/drm_edid.c
··· 34 34 #include <linux/module.h> 35 35 #include <drm/drmP.h> 36 36 #include <drm/drm_edid.h> 37 + #include <drm/drm_displayid.h> 37 38 38 39 #define version_greater(edid, maj, min) \ 39 40 (((edid)->version > (maj)) || \ ··· 1015 1014 MODULE_PARM_DESC(edid_fixup, 1016 1015 "Minimum number of valid EDID header bytes (0-8, default 6)"); 1017 1016 1017 + static void drm_get_displayid(struct drm_connector *connector, 1018 + struct edid *edid); 1018 1019 /** 1019 1020 * drm_edid_block_valid - Sanity check the EDID block (base or extension) 1020 1021 * @raw_edid: pointer to raw EDID block ··· 1311 1308 struct edid *drm_get_edid(struct drm_connector *connector, 1312 1309 struct i2c_adapter *adapter) 1313 1310 { 1311 + struct edid *edid; 1312 + 1314 1313 if (!drm_probe_ddc(adapter)) 1315 1314 return NULL; 1316 1315 1317 - return drm_do_get_edid(connector, drm_do_probe_ddc_edid, adapter); 1316 + edid = drm_do_get_edid(connector, drm_do_probe_ddc_edid, adapter); 1317 + if (edid) 1318 + drm_get_displayid(connector, edid); 1319 + return edid; 1318 1320 } 1319 1321 EXPORT_SYMBOL(drm_get_edid); 1320 1322 ··· 2414 2406 /* 2415 2407 * Search EDID for CEA extension block. 2416 2408 */ 2417 - static u8 *drm_find_cea_extension(struct edid *edid) 2409 + static u8 *drm_find_edid_extension(struct edid *edid, int ext_id) 2418 2410 { 2419 2411 u8 *edid_ext = NULL; 2420 2412 int i; ··· 2426 2418 /* Find CEA extension */ 2427 2419 for (i = 0; i < edid->extensions; i++) { 2428 2420 edid_ext = (u8 *)edid + EDID_LENGTH * (i + 1); 2429 - if (edid_ext[0] == CEA_EXT) 2421 + if (edid_ext[0] == ext_id) 2430 2422 break; 2431 2423 } 2432 2424 ··· 2434 2426 return NULL; 2435 2427 2436 2428 return edid_ext; 2429 + } 2430 + 2431 + static u8 *drm_find_cea_extension(struct edid *edid) 2432 + { 2433 + return drm_find_edid_extension(edid, CEA_EXT); 2434 + } 2435 + 2436 + static u8 *drm_find_displayid_extension(struct edid *edid) 2437 + { 2438 + return drm_find_edid_extension(edid, DISPLAYID_EXT); 2437 2439 } 2438 2440 2439 2441 /* ··· 3906 3888 return 0; 3907 3889 } 3908 3890 EXPORT_SYMBOL(drm_hdmi_vendor_infoframe_from_display_mode); 3891 + 3892 + static int drm_parse_display_id(struct drm_connector *connector, 3893 + u8 *displayid, int length, 3894 + bool is_edid_extension) 3895 + { 3896 + /* if this is an EDID extension the first byte will be 0x70 */ 3897 + int idx = 0; 3898 + struct displayid_hdr *base; 3899 + struct displayid_block *block; 3900 + u8 csum = 0; 3901 + int i; 3902 + 3903 + if (is_edid_extension) 3904 + idx = 1; 3905 + 3906 + base = (struct displayid_hdr *)&displayid[idx]; 3907 + 3908 + DRM_DEBUG_KMS("base revision 0x%x, length %d, %d %d\n", 3909 + base->rev, base->bytes, base->prod_id, base->ext_count); 3910 + 3911 + if (base->bytes + 5 > length - idx) 3912 + return -EINVAL; 3913 + 3914 + for (i = idx; i <= base->bytes + 5; i++) { 3915 + csum += displayid[i]; 3916 + } 3917 + if (csum) { 3918 + DRM_ERROR("DisplayID checksum invalid, remainder is %d\n", csum); 3919 + return -EINVAL; 3920 + } 3921 + 3922 + block = (struct displayid_block *)&displayid[idx + 4]; 3923 + DRM_DEBUG_KMS("block id %d, rev %d, len %d\n", 3924 + block->tag, block->rev, block->num_bytes); 3925 + 3926 + switch (block->tag) { 3927 + case DATA_BLOCK_TILED_DISPLAY: { 3928 + struct displayid_tiled_block *tile = (struct displayid_tiled_block *)block; 3929 + 3930 + u16 w, h; 3931 + u8 tile_v_loc, tile_h_loc; 3932 + u8 num_v_tile, num_h_tile; 3933 + struct drm_tile_group *tg; 3934 + 3935 + w = tile->tile_size[0] | tile->tile_size[1] << 8; 3936 + h = tile->tile_size[2] | tile->tile_size[3] << 8; 3937 + 3938 + num_v_tile = (tile->topo[0] & 0xf) | (tile->topo[2] & 0x30); 3939 + num_h_tile = (tile->topo[0] >> 4) | ((tile->topo[2] >> 2) & 0x30); 3940 + tile_v_loc = (tile->topo[1] & 0xf) | ((tile->topo[2] & 0x3) << 4); 3941 + tile_h_loc = (tile->topo[1] >> 4) | (((tile->topo[2] >> 2) & 0x3) << 4); 3942 + 3943 + connector->has_tile = true; 3944 + if (tile->tile_cap & 0x80) 3945 + connector->tile_is_single_monitor = true; 3946 + 3947 + connector->num_h_tile = num_h_tile + 1; 3948 + connector->num_v_tile = num_v_tile + 1; 3949 + connector->tile_h_loc = tile_h_loc; 3950 + connector->tile_v_loc = tile_v_loc; 3951 + connector->tile_h_size = w + 1; 3952 + connector->tile_v_size = h + 1; 3953 + 3954 + DRM_DEBUG_KMS("tile cap 0x%x\n", tile->tile_cap); 3955 + DRM_DEBUG_KMS("tile_size %d x %d\n", w + 1, h + 1); 3956 + DRM_DEBUG_KMS("topo num tiles %dx%d, location %dx%d\n", 3957 + num_h_tile + 1, num_v_tile + 1, tile_h_loc, tile_v_loc); 3958 + DRM_DEBUG_KMS("vend %c%c%c\n", tile->topology_id[0], tile->topology_id[1], tile->topology_id[2]); 3959 + 3960 + tg = drm_mode_get_tile_group(connector->dev, tile->topology_id); 3961 + if (!tg) { 3962 + tg = drm_mode_create_tile_group(connector->dev, tile->topology_id); 3963 + } 3964 + if (!tg) 3965 + return -ENOMEM; 3966 + 3967 + if (connector->tile_group != tg) { 3968 + /* if we haven't got a pointer, 3969 + take the reference, drop ref to old tile group */ 3970 + if (connector->tile_group) { 3971 + drm_mode_put_tile_group(connector->dev, connector->tile_group); 3972 + } 3973 + connector->tile_group = tg; 3974 + } else 3975 + /* if same tile group, then release the ref we just took. */ 3976 + drm_mode_put_tile_group(connector->dev, tg); 3977 + } 3978 + break; 3979 + default: 3980 + printk("unknown displayid tag %d\n", block->tag); 3981 + break; 3982 + } 3983 + return 0; 3984 + } 3985 + 3986 + static void drm_get_displayid(struct drm_connector *connector, 3987 + struct edid *edid) 3988 + { 3989 + void *displayid = NULL; 3990 + int ret; 3991 + connector->has_tile = false; 3992 + displayid = drm_find_displayid_extension(edid); 3993 + if (!displayid) { 3994 + /* drop reference to any tile group we had */ 3995 + goto out_drop_ref; 3996 + } 3997 + 3998 + ret = drm_parse_display_id(connector, displayid, EDID_LENGTH, true); 3999 + if (ret < 0) 4000 + goto out_drop_ref; 4001 + if (!connector->has_tile) 4002 + goto out_drop_ref; 4003 + return; 4004 + out_drop_ref: 4005 + if (connector->tile_group) { 4006 + drm_mode_put_tile_group(connector->dev, connector->tile_group); 4007 + connector->tile_group = NULL; 4008 + } 4009 + return; 4010 + }
+18
include/drm/drm_crtc.h
··· 607 607 * @bad_edid_counter: track sinks that give us an EDID with invalid checksum 608 608 * @debugfs_entry: debugfs directory for this connector 609 609 * @state: current atomic state for this connector 610 + * @has_tile: is this connector connected to a tiled monitor 611 + * @tile_group: tile group for the connected monitor 612 + * @tile_is_single_monitor: whether the tile is one monitor housing 613 + * @num_h_tile: number of horizontal tiles in the tile group 614 + * @num_v_tile: number of vertical tiles in the tile group 615 + * @tile_h_loc: horizontal location of this tile 616 + * @tile_v_loc: vertical location of this tile 617 + * @tile_h_size: horizontal size of this tile. 618 + * @tile_v_size: vertical size of this tile. 610 619 * 611 620 * Each connector may be connected to one or more CRTCs, or may be clonable by 612 621 * another connector if they can share a CRTC. Each connector also has a specific ··· 678 669 struct dentry *debugfs_entry; 679 670 680 671 struct drm_connector_state *state; 672 + 673 + /* DisplayID bits */ 674 + bool has_tile; 675 + struct drm_tile_group *tile_group; 676 + bool tile_is_single_monitor; 677 + 678 + uint8_t num_h_tile, num_v_tile; 679 + uint8_t tile_h_loc, tile_v_loc; 680 + uint16_t tile_h_size, tile_v_size; 681 681 }; 682 682 683 683 /**