aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/drm_edid.c108
-rw-r--r--include/drm/drm_displayid.h17
2 files changed, 125 insertions, 0 deletions
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index fac4efc7dfe2..7df26d4b7ad8 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -3924,6 +3924,110 @@ static int validate_displayid(u8 *displayid, int length, int idx)
3924 return 0; 3924 return 0;
3925} 3925}
3926 3926
3927static struct drm_display_mode *drm_mode_displayid_detailed(struct drm_device *dev,
3928 struct displayid_detailed_timings_1 *timings)
3929{
3930 struct drm_display_mode *mode;
3931 unsigned pixel_clock = (timings->pixel_clock[0] |
3932 (timings->pixel_clock[1] << 8) |
3933 (timings->pixel_clock[2] << 16));
3934 unsigned hactive = (timings->hactive[0] | timings->hactive[1] << 8) + 1;
3935 unsigned hblank = (timings->hblank[0] | timings->hblank[1] << 8) + 1;
3936 unsigned hsync = (timings->hsync[0] | (timings->hsync[1] & 0x7f) << 8) + 1;
3937 unsigned hsync_width = (timings->hsw[0] | timings->hsw[1] << 8) + 1;
3938 unsigned vactive = (timings->vactive[0] | timings->vactive[1] << 8) + 1;
3939 unsigned vblank = (timings->vblank[0] | timings->vblank[1] << 8) + 1;
3940 unsigned vsync = (timings->vsync[0] | (timings->vsync[1] & 0x7f) << 8) + 1;
3941 unsigned vsync_width = (timings->vsw[0] | timings->vsw[1] << 8) + 1;
3942 bool hsync_positive = (timings->hsync[1] >> 7) & 0x1;
3943 bool vsync_positive = (timings->vsync[1] >> 7) & 0x1;
3944 mode = drm_mode_create(dev);
3945 if (!mode)
3946 return NULL;
3947
3948 mode->clock = pixel_clock * 10;
3949 mode->hdisplay = hactive;
3950 mode->hsync_start = mode->hdisplay + hsync;
3951 mode->hsync_end = mode->hsync_start + hsync_width;
3952 mode->htotal = mode->hdisplay + hblank;
3953
3954 mode->vdisplay = vactive;
3955 mode->vsync_start = mode->vdisplay + vsync;
3956 mode->vsync_end = mode->vsync_start + vsync_width;
3957 mode->vtotal = mode->vdisplay + vblank;
3958
3959 mode->flags = 0;
3960 mode->flags |= hsync_positive ? DRM_MODE_FLAG_PHSYNC : DRM_MODE_FLAG_NHSYNC;
3961 mode->flags |= vsync_positive ? DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC;
3962 mode->type = DRM_MODE_TYPE_DRIVER;
3963
3964 if (timings->flags & 0x80)
3965 mode->type |= DRM_MODE_TYPE_PREFERRED;
3966 mode->vrefresh = drm_mode_vrefresh(mode);
3967 drm_mode_set_name(mode);
3968
3969 return mode;
3970}
3971
3972static int add_displayid_detailed_1_modes(struct drm_connector *connector,
3973 struct displayid_block *block)
3974{
3975 struct displayid_detailed_timing_block *det = (struct displayid_detailed_timing_block *)block;
3976 int i;
3977 int num_timings;
3978 struct drm_display_mode *newmode;
3979 int num_modes = 0;
3980 /* blocks must be multiple of 20 bytes length */
3981 if (block->num_bytes % 20)
3982 return 0;
3983
3984 num_timings = block->num_bytes / 20;
3985 for (i = 0; i < num_timings; i++) {
3986 struct displayid_detailed_timings_1 *timings = &det->timings[i];
3987
3988 newmode = drm_mode_displayid_detailed(connector->dev, timings);
3989 if (!newmode)
3990 continue;
3991
3992 drm_mode_probed_add(connector, newmode);
3993 num_modes++;
3994 }
3995 return num_modes;
3996}
3997
3998static int add_displayid_detailed_modes(struct drm_connector *connector,
3999 struct edid *edid)
4000{
4001 u8 *displayid;
4002 int ret;
4003 int idx = 1;
4004 int length = EDID_LENGTH;
4005 struct displayid_block *block;
4006 int num_modes = 0;
4007
4008 displayid = drm_find_displayid_extension(edid);
4009 if (!displayid)
4010 return 0;
4011
4012 ret = validate_displayid(displayid, length, idx);
4013 if (ret)
4014 return 0;
4015
4016 idx += sizeof(struct displayid_hdr);
4017 while (block = (struct displayid_block *)&displayid[idx],
4018 idx + sizeof(struct displayid_block) <= length &&
4019 idx + sizeof(struct displayid_block) + block->num_bytes <= length &&
4020 block->num_bytes > 0) {
4021 idx += block->num_bytes + sizeof(struct displayid_block);
4022 switch (block->tag) {
4023 case DATA_BLOCK_TYPE_1_DETAILED_TIMING:
4024 num_modes += add_displayid_detailed_1_modes(connector, block);
4025 break;
4026 }
4027 }
4028 return num_modes;
4029}
4030
3927/** 4031/**
3928 * drm_add_edid_modes - add modes from EDID data, if available 4032 * drm_add_edid_modes - add modes from EDID data, if available
3929 * @connector: connector we're probing 4033 * @connector: connector we're probing
@@ -3969,6 +4073,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
3969 num_modes += add_established_modes(connector, edid); 4073 num_modes += add_established_modes(connector, edid);
3970 num_modes += add_cea_modes(connector, edid); 4074 num_modes += add_cea_modes(connector, edid);
3971 num_modes += add_alternate_cea_modes(connector, edid); 4075 num_modes += add_alternate_cea_modes(connector, edid);
4076 num_modes += add_displayid_detailed_modes(connector, edid);
3972 if (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF) 4077 if (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF)
3973 num_modes += add_inferred_modes(connector, edid); 4078 num_modes += add_inferred_modes(connector, edid);
3974 4079
@@ -4260,6 +4365,9 @@ static int drm_parse_display_id(struct drm_connector *connector,
4260 if (ret) 4365 if (ret)
4261 return ret; 4366 return ret;
4262 break; 4367 break;
4368 case DATA_BLOCK_TYPE_1_DETAILED_TIMING:
4369 /* handled in mode gathering code. */
4370 break;
4263 default: 4371 default:
4264 DRM_DEBUG_KMS("found DisplayID tag 0x%x, unhandled\n", block->tag); 4372 DRM_DEBUG_KMS("found DisplayID tag 0x%x, unhandled\n", block->tag);
4265 break; 4373 break;
diff --git a/include/drm/drm_displayid.h b/include/drm/drm_displayid.h
index 623b4e98e748..c0d4df6a606f 100644
--- a/include/drm/drm_displayid.h
+++ b/include/drm/drm_displayid.h
@@ -73,4 +73,21 @@ struct displayid_tiled_block {
73 u8 topology_id[8]; 73 u8 topology_id[8];
74} __packed; 74} __packed;
75 75
76struct displayid_detailed_timings_1 {
77 u8 pixel_clock[3];
78 u8 flags;
79 u8 hactive[2];
80 u8 hblank[2];
81 u8 hsync[2];
82 u8 hsw[2];
83 u8 vactive[2];
84 u8 vblank[2];
85 u8 vsync[2];
86 u8 vsw[2];
87} __packed;
88
89struct displayid_detailed_timing_block {
90 struct displayid_block base;
91 struct displayid_detailed_timings_1 timings[0];
92};
76#endif 93#endif