Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0454beab authored by Michel Dänzer's avatar Michel Dänzer Committed by Dave Airlie
Browse files

drm: EDID endianness fixes.



Mostly replacing bitfields with explicit masks and shifts.

Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
parent 00fa28ae
Loading
Loading
Loading
Loading
+52 −48
Original line number Diff line number Diff line
@@ -252,16 +252,18 @@ struct drm_display_mode *drm_mode_std(struct drm_device *dev,
{
	struct drm_display_mode *mode;
	int hsize = t->hsize * 8 + 248, vsize;
	unsigned aspect_ratio = (t->vfreq_aspect & EDID_TIMING_ASPECT_MASK)
		>> EDID_TIMING_ASPECT_SHIFT;

	mode = drm_mode_create(dev);
	if (!mode)
		return NULL;

	if (t->aspect_ratio == 0)
	if (aspect_ratio == 0)
		vsize = (hsize * 10) / 16;
	else if (t->aspect_ratio == 1)
	else if (aspect_ratio == 1)
		vsize = (hsize * 3) / 4;
	else if (t->aspect_ratio == 2)
	else if (aspect_ratio == 2)
		vsize = (hsize * 4) / 5;
	else
		vsize = (hsize * 9) / 16;
@@ -288,17 +290,24 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev,
{
	struct drm_display_mode *mode;
	struct detailed_pixel_timing *pt = &timing->data.pixel_data;
	unsigned hactive = (pt->hactive_hblank_hi & 0xf0) << 4 | pt->hactive_lo;
	unsigned vactive = (pt->vactive_vblank_hi & 0xf0) << 4 | pt->vactive_lo;
	unsigned hblank = (pt->hactive_hblank_hi & 0xf) << 8 | pt->hblank_lo;
	unsigned vblank = (pt->vactive_vblank_hi & 0xf) << 8 | pt->vblank_lo;
	unsigned hsync_offset = (pt->hsync_vsync_offset_pulse_width_hi & 0x3) << 8 | pt->hsync_offset_lo;
	unsigned hsync_pulse_width = (pt->hsync_vsync_offset_pulse_width_hi & 0xc) << 6 | pt->hsync_pulse_width_lo;
	unsigned vsync_offset = (pt->hsync_vsync_offset_pulse_width_hi & 0x30) | (pt->vsync_offset_pulse_width_lo & 0xf);
	unsigned vsync_pulse_width = (pt->hsync_vsync_offset_pulse_width_hi & 0xc0) >> 2 | pt->vsync_offset_pulse_width_lo >> 4;

	/* ignore tiny modes */
	if (((pt->hactive_hi << 8) | pt->hactive_lo) < 64 ||
	    ((pt->vactive_hi << 8) | pt->hactive_lo) < 64)
	if (hactive < 64 || vactive < 64)
		return NULL;

	if (pt->stereo) {
	if (pt->misc & DRM_EDID_PT_STEREO) {
		printk(KERN_WARNING "stereo mode not supported\n");
		return NULL;
	}
	if (!pt->separate_sync) {
	if (!(pt->misc & DRM_EDID_PT_SEPARATE_SYNC)) {
		printk(KERN_WARNING "integrated sync not supported\n");
		return NULL;
	}
@@ -310,41 +319,36 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev,
	mode->type = DRM_MODE_TYPE_DRIVER;

	if (quirks & EDID_QUIRK_135_CLOCK_TOO_HIGH)
		timing->pixel_clock = 1088;

	mode->clock = timing->pixel_clock * 10;

	mode->hdisplay = (pt->hactive_hi << 8) | pt->hactive_lo;
	mode->hsync_start = mode->hdisplay + ((pt->hsync_offset_hi << 8) |
					      pt->hsync_offset_lo);
	mode->hsync_end = mode->hsync_start +
		((pt->hsync_pulse_width_hi << 8) |
		 pt->hsync_pulse_width_lo);
	mode->htotal = mode->hdisplay + ((pt->hblank_hi << 8) | pt->hblank_lo);

	mode->vdisplay = (pt->vactive_hi << 8) | pt->vactive_lo;
	mode->vsync_start = mode->vdisplay + ((pt->vsync_offset_hi << 4) |
					      pt->vsync_offset_lo);
	mode->vsync_end = mode->vsync_start +
		((pt->vsync_pulse_width_hi << 4) |
		 pt->vsync_pulse_width_lo);
	mode->vtotal = mode->vdisplay + ((pt->vblank_hi << 8) | pt->vblank_lo);
		timing->pixel_clock = cpu_to_le16(1088);

	mode->clock = le16_to_cpu(timing->pixel_clock) * 10;

	mode->hdisplay = hactive;
	mode->hsync_start = mode->hdisplay + hsync_offset;
	mode->hsync_end = mode->hsync_start + hsync_pulse_width;
	mode->htotal = mode->hdisplay + hblank;

	mode->vdisplay = vactive;
	mode->vsync_start = mode->vdisplay + vsync_offset;
	mode->vsync_end = mode->vsync_start + vsync_pulse_width;
	mode->vtotal = mode->vdisplay + vblank;

	drm_mode_set_name(mode);

	if (pt->interlaced)
	if (pt->misc & DRM_EDID_PT_INTERLACED)
		mode->flags |= DRM_MODE_FLAG_INTERLACE;

	if (quirks & EDID_QUIRK_DETAILED_SYNC_PP) {
		pt->hsync_positive = 1;
		pt->vsync_positive = 1;
		pt->misc |= DRM_EDID_PT_HSYNC_POSITIVE | DRM_EDID_PT_VSYNC_POSITIVE;
	}

	mode->flags |= pt->hsync_positive ? DRM_MODE_FLAG_PHSYNC : DRM_MODE_FLAG_NHSYNC;
	mode->flags |= pt->vsync_positive ? DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC;
	mode->flags |= (pt->misc & DRM_EDID_PT_HSYNC_POSITIVE) ?
		DRM_MODE_FLAG_PHSYNC : DRM_MODE_FLAG_NHSYNC;
	mode->flags |= (pt->misc & DRM_EDID_PT_VSYNC_POSITIVE) ?
		DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC;

	mode->width_mm = pt->width_mm_lo | (pt->width_mm_hi << 8);
	mode->height_mm = pt->height_mm_lo | (pt->height_mm_hi << 8);
	mode->width_mm = pt->width_mm_lo | (pt->width_height_mm_hi & 0xf) << 8;
	mode->height_mm = pt->height_mm_lo | (pt->width_height_mm_hi & 0xf0) << 4;

	if (quirks & EDID_QUIRK_DETAILED_IN_CM) {
		mode->width_mm *= 10;
@@ -465,7 +469,7 @@ static int add_standard_modes(struct drm_connector *connector, struct edid *edid
		struct drm_display_mode *newmode;

		/* If std timings bytes are 1, 1 it's empty */
		if (t->hsize == 1 && (t->aspect_ratio | t->vfreq) == 1)
		if (t->hsize == 1 && t->vfreq_aspect == 1)
			continue;

		newmode = drm_mode_std(dev, &edid->standard_timings[i]);
@@ -509,7 +513,7 @@ static int add_detailed_info(struct drm_connector *connector,
				continue;

			/* First detailed mode is preferred */
			if (i == 0 && edid->preferred_timing)
			if (i == 0 && (edid->features & DRM_EDID_FEATURE_PREFERRED_TIMING))
				newmode->type |= DRM_MODE_TYPE_PREFERRED;
			drm_mode_probed_add(connector, newmode);

@@ -767,22 +771,22 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
	if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75))
		edid_fixup_preferred(connector, quirks);

	connector->display_info.serration_vsync = edid->serration_vsync;
	connector->display_info.sync_on_green = edid->sync_on_green;
	connector->display_info.composite_sync = edid->composite_sync;
	connector->display_info.separate_syncs = edid->separate_syncs;
	connector->display_info.blank_to_black = edid->blank_to_black;
	connector->display_info.video_level = edid->video_level;
	connector->display_info.digital = edid->digital;
	connector->display_info.serration_vsync = (edid->input & DRM_EDID_INPUT_SERRATION_VSYNC) ? 1 : 0;
	connector->display_info.sync_on_green = (edid->input & DRM_EDID_INPUT_SYNC_ON_GREEN) ? 1 : 0;
	connector->display_info.composite_sync = (edid->input & DRM_EDID_INPUT_COMPOSITE_SYNC) ? 1 : 0;
	connector->display_info.separate_syncs = (edid->input & DRM_EDID_INPUT_SEPARATE_SYNCS) ? 1 : 0;
	connector->display_info.blank_to_black = (edid->input & DRM_EDID_INPUT_BLANK_TO_BLACK) ? 1 : 0;
	connector->display_info.video_level = (edid->input & DRM_EDID_INPUT_VIDEO_LEVEL) >> 5;
	connector->display_info.digital = (edid->input & DRM_EDID_INPUT_DIGITAL) ? 1 : 0;
	connector->display_info.width_mm = edid->width_cm * 10;
	connector->display_info.height_mm = edid->height_cm * 10;
	connector->display_info.gamma = edid->gamma;
	connector->display_info.gtf_supported = edid->default_gtf;
	connector->display_info.standard_color = edid->standard_color;
	connector->display_info.display_type = edid->display_type;
	connector->display_info.active_off_supported = edid->pm_active_off;
	connector->display_info.suspend_supported = edid->pm_suspend;
	connector->display_info.standby_supported = edid->pm_standby;
	connector->display_info.gtf_supported = (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF) ? 1 : 0;
	connector->display_info.standard_color = (edid->features & DRM_EDID_FEATURE_STANDARD_COLOR) ? 1 : 0;
	connector->display_info.display_type = (edid->features & DRM_EDID_FEATURE_DISPLAY_TYPE) >> 3;
	connector->display_info.active_off_supported = (edid->features & DRM_EDID_FEATURE_PM_ACTIVE_OFF) ? 1 : 0;
	connector->display_info.suspend_supported = (edid->features & DRM_EDID_FEATURE_PM_SUSPEND) ? 1 : 0;
	connector->display_info.standby_supported = (edid->features & DRM_EDID_FEATURE_PM_STANDBY) ? 1 : 0;
	connector->display_info.gamma = edid->gamma;

	return num_modes;
+1 −1
Original line number Diff line number Diff line
@@ -351,7 +351,7 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector)
	radeon_i2c_do_lock(radeon_connector, 0);
	if (edid) {
		/* update digital bits here */
		if (edid->digital)
		if (edid->input & DRM_EDID_INPUT_DIGITAL)
			radeon_connector->use_digital = 1;
		else
			radeon_connector->use_digital = 0;
+43 −49
Original line number Diff line number Diff line
@@ -28,53 +28,49 @@
#define EDID_LENGTH 128
#define DDC_ADDR 0x50

#ifdef BIG_ENDIAN
#error "EDID structure is little endian, need big endian versions"
#else

struct est_timings {
	u8 t1;
	u8 t2;
	u8 mfg_rsvd;
} __attribute__((packed));

/* 00=16:10, 01=4:3, 10=5:4, 11=16:9 */
#define EDID_TIMING_ASPECT_SHIFT 0
#define EDID_TIMING_ASPECT_MASK  (0x3 << EDID_TIMING_ASPECT_SHIFT)

/* need to add 60 */
#define EDID_TIMING_VFREQ_SHIFT  2
#define EDID_TIMING_VFREQ_MASK   (0x3f << EDID_TIMING_VFREQ_SHIFT)

struct std_timing {
	u8 hsize; /* need to multiply by 8 then add 248 */
	u8 vfreq:6; /* need to add 60 */
	u8 aspect_ratio:2; /* 00=16:10, 01=4:3, 10=5:4, 11=16:9 */
	u8 vfreq_aspect;
} __attribute__((packed));

#define DRM_EDID_PT_HSYNC_POSITIVE (1 << 6)
#define DRM_EDID_PT_VSYNC_POSITIVE (1 << 5)
#define DRM_EDID_PT_SEPARATE_SYNC  (3 << 3)
#define DRM_EDID_PT_STEREO         (1 << 2)
#define DRM_EDID_PT_INTERLACED     (1 << 1)

/* If detailed data is pixel timing */
struct detailed_pixel_timing {
	u8 hactive_lo;
	u8 hblank_lo;
	u8 hblank_hi:4;
	u8 hactive_hi:4;
	u8 hactive_hblank_hi;
	u8 vactive_lo;
	u8 vblank_lo;
	u8 vblank_hi:4;
	u8 vactive_hi:4;
	u8 vactive_vblank_hi;
	u8 hsync_offset_lo;
	u8 hsync_pulse_width_lo;
	u8 vsync_pulse_width_lo:4;
	u8 vsync_offset_lo:4;
	u8 vsync_pulse_width_hi:2;
	u8 vsync_offset_hi:2;
	u8 hsync_pulse_width_hi:2;
	u8 hsync_offset_hi:2;
	u8 vsync_offset_pulse_width_lo;
	u8 hsync_vsync_offset_pulse_width_hi;
	u8 width_mm_lo;
	u8 height_mm_lo;
	u8 height_mm_hi:4;
	u8 width_mm_hi:4;
	u8 width_height_mm_hi;
	u8 hborder;
	u8 vborder;
	u8 unknown0:1;
	u8 hsync_positive:1;
	u8 vsync_positive:1;
	u8 separate_sync:2;
	u8 stereo:1;
	u8 unknown6:1;
	u8 interlaced:1;
	u8 misc;
} __attribute__((packed));

/* If it's not pixel timing, it'll be one of the below */
@@ -88,18 +84,16 @@ struct detailed_data_monitor_range {
	u8 min_hfreq_khz;
	u8 max_hfreq_khz;
	u8 pixel_clock_mhz; /* need to multiply by 10 */
	u16 sec_gtf_toggle; /* A000=use above, 20=use below */ /* FIXME: byte order */
	__le16 sec_gtf_toggle; /* A000=use above, 20=use below */
	u8 hfreq_start_khz; /* need to multiply by 2 */
	u8 c; /* need to divide by 2 */
	u16 m; /* FIXME: byte order */
	__le16 m;
	u8 k;
	u8 j; /* need to divide by 2 */
} __attribute__((packed));

struct detailed_data_wpindex {
	u8 white_y_lo:2;
	u8 white_x_lo:2;
	u8 pad:4;
	u8 white_xy_lo; /* Upper 2 bits each */
	u8 white_x_hi;
	u8 white_y_hi;
	u8 gamma; /* need to divide by 100 then add 1 */
@@ -134,13 +128,29 @@ struct detailed_non_pixel {
#define EDID_DETAIL_MONITOR_SERIAL 0xff

struct detailed_timing {
	u16 pixel_clock; /* need to multiply by 10 KHz */ /* FIXME: byte order */
	__le16 pixel_clock; /* need to multiply by 10 KHz */
	union {
		struct detailed_pixel_timing pixel_data;
		struct detailed_non_pixel other_data;
	} data;
} __attribute__((packed));

#define DRM_EDID_INPUT_SERRATION_VSYNC (1 << 7)
#define DRM_EDID_INPUT_SYNC_ON_GREEN   (1 << 5)
#define DRM_EDID_INPUT_COMPOSITE_SYNC  (1 << 4)
#define DRM_EDID_INPUT_SEPARATE_SYNCS  (1 << 3)
#define DRM_EDID_INPUT_BLANK_TO_BLACK  (1 << 2)
#define DRM_EDID_INPUT_VIDEO_LEVEL     (3 << 1)
#define DRM_EDID_INPUT_DIGITAL         (1 << 0) /* bits above must be zero if set */

#define DRM_EDID_FEATURE_DEFAULT_GTF      (1 << 7)
#define DRM_EDID_FEATURE_PREFERRED_TIMING (1 << 6)
#define DRM_EDID_FEATURE_STANDARD_COLOR   (1 << 5)
#define DRM_EDID_FEATURE_DISPLAY_TYPE     (3 << 3) /* 00=mono, 01=rgb, 10=non-rgb, 11=unknown */
#define DRM_EDID_FEATURE_PM_ACTIVE_OFF    (1 << 2)
#define DRM_EDID_FEATURE_PM_SUSPEND       (1 << 1)
#define DRM_EDID_FEATURE_PM_STANDBY       (1 << 0)

struct edid {
	u8 header[8];
	/* Vendor & product info */
@@ -153,25 +163,11 @@ struct edid {
	u8 version;
	u8 revision;
	/* Display info: */
	/*   input definition */
	u8 serration_vsync:1;
	u8 sync_on_green:1;
	u8 composite_sync:1;
	u8 separate_syncs:1;
	u8 blank_to_black:1;
	u8 video_level:2;
	u8 digital:1; /* bits below must be zero if set */
	u8 input;
	u8 width_cm;
	u8 height_cm;
	u8 gamma;
	/*   feature support */
	u8 default_gtf:1;
	u8 preferred_timing:1;
	u8 standard_color:1;
	u8 display_type:2; /* 00=mono, 01=rgb, 10=non-rgb, 11=unknown */
	u8 pm_active_off:1;
	u8 pm_suspend:1;
	u8 pm_standby:1;
	u8 features;
	/* Color characteristics */
	u8 red_green_lo;
	u8 black_white_lo;
@@ -195,8 +191,6 @@ struct edid {
	u8 checksum;
} __attribute__((packed));

#endif /* little endian structs */

#define EDID_PRODUCT_ID(e) ((e)->prod_code[0] | ((e)->prod_code[1] << 8))

#endif /* __DRM_EDID_H__ */