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

Commit 9ffdd894 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "drivers/video: Add new aspect ratios for HDMI 2.0"

parents 9898f867 073d867c
Loading
Loading
Loading
Loading
+171 −0
Original line number Diff line number Diff line
@@ -3076,6 +3076,21 @@ static bool cea_db_is_hdmi_vsdb(const u8 *db)
	return hdmi_id == HDMI_IEEE_OUI;
}

static bool cea_db_is_hdmi_hf_vsdb(const u8 *db)
{
	int hdmi_id;

	if (cea_db_tag(db) != VENDOR_BLOCK)
		return false;

	if (cea_db_payload_len(db) < 7)
		return false;

	hdmi_id = db[1] | (db[2] << 8) | (db[3] << 16);

	return hdmi_id == HDMI_IEEE_OUI_HF;
}

#define for_each_cea_db(cea, i, start, end) \
	for ((i) = (start); (i) < (end) && (i) + cea_db_payload_len(&(cea)[(i)]) < (end); (i) += cea_db_payload_len(&(cea)[(i)]) + 1)

@@ -3198,6 +3213,37 @@ parse_hdmi_vsdb(struct drm_connector *connector, const u8 *db)
		    connector->audio_latency[1]);
}

static void
parse_hdmi_hf_vsdb(struct drm_connector *connector, const u8 *db)
{
	u8 len = cea_db_payload_len(db);

	if (len < 7)
		return;

	if (db[4] != 1)
		return; /* invalid version */

	connector->max_tmds_char = db[5] * 5;
	connector->scdc_present = db[6] & (1 << 7);
	connector->rr_capable = db[6] & (1 << 6);
	connector->flags_3d = db[6] & 0x7;
	connector->supports_scramble = connector->scdc_present &&
			(db[6] & (1 << 3));

	DRM_DEBUG_KMS("HDMI v2: max TMDS char %d, "
			"scdc %s, "
			"rr %s, "
			"3D flags 0x%x, "
			"scramble %s\n",
			connector->max_tmds_char,
			connector->scdc_present ? "available" : "not available",
			connector->rr_capable ? "capable" : "not capable",
			connector->flags_3d,
			connector->supports_scramble ?
				"supported" : "not supported");
}

static void
monitor_name(struct detailed_timing *t, void *data)
{
@@ -3277,6 +3323,9 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid)
				/* HDMI Vendor-Specific Data Block */
				if (cea_db_is_hdmi_vsdb(db))
					parse_hdmi_vsdb(connector, db);
				/* HDMI Forum Vendor-Specific Data Block */
				else if (cea_db_is_hdmi_hf_vsdb(db))
					parse_hdmi_hf_vsdb(connector, db);
				break;
			default:
				break;
@@ -3799,6 +3848,124 @@ static int validate_displayid(u8 *displayid, int length, int idx)
	return 0;
}

static struct drm_display_mode *
drm_mode_displayid_detailed(struct drm_device *dev,
struct displayid_detailed_timings_1 *timings)
{
	struct drm_display_mode *mode;
	unsigned pixel_clock = (timings->pixel_clock[0] |
				(timings->pixel_clock[1] << 8) |
				(timings->pixel_clock[2] << 16));
	unsigned hactive = (timings->hactive[0] | timings->hactive[1] << 8) + 1;
	unsigned hblank =
		(timings->hblank[0] |
		timings->hblank[1] << 8) + 1;
	unsigned hsync = (timings->hsync[0] |
			(timings->hsync[1] & 0x7f) << 8) + 1;
	unsigned hsync_width = (timings->hsw[0] | timings->hsw[1] << 8) + 1;
	unsigned vactive = (timings->vactive[0] | timings->vactive[1] << 8) + 1;
	unsigned vblank =
		(timings->vblank[0] |
		 timings->vblank[1] << 8) + 1;
	unsigned vsync =
		(timings->vsync[0] |
		 (timings->vsync[1] & 0x7f) << 8) + 1;
	unsigned vsync_width = (timings->vsw[0] | timings->vsw[1] << 8) + 1;
	bool hsync_positive = (timings->hsync[1] >> 7) & 0x1;
	bool vsync_positive = (timings->vsync[1] >> 7) & 0x1;

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

	mode->clock = pixel_clock * 10;
	mode->hdisplay = hactive;
	mode->hsync_start = mode->hdisplay + hsync;
	mode->hsync_end = mode->hsync_start + hsync_width;
	mode->htotal = mode->hdisplay + hblank;

	mode->vdisplay = vactive;
	mode->vsync_start = mode->vdisplay + vsync;
	mode->vsync_end = mode->vsync_start + vsync_width;
	mode->vtotal = mode->vdisplay + vblank;

	mode->flags = 0;
	mode->flags |= hsync_positive ?
				DRM_MODE_FLAG_PHSYNC : DRM_MODE_FLAG_NHSYNC;
	mode->flags |= vsync_positive ?
				DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC;
	mode->type = DRM_MODE_TYPE_DRIVER;

	if (timings->flags & 0x80)
		mode->type |= DRM_MODE_TYPE_PREFERRED;
	mode->vrefresh = drm_mode_vrefresh(mode);
	drm_mode_set_name(mode);

	return mode;
}

static int add_displayid_detailed_1_modes(struct drm_connector *connector,
			struct displayid_block *block)
{
	struct displayid_detailed_timing_block *det =
		(struct displayid_detailed_timing_block *)block;
	int i;
	int num_timings;
	struct drm_display_mode *newmode;
	int num_modes = 0;
	/* blocks must be multiple of 20 bytes length */
	if (block->num_bytes % 20)
		return 0;

	num_timings = block->num_bytes / 20;
	for (i = 0; i < num_timings; i++) {
		struct displayid_detailed_timings_1 *timings = &det->timings[i];

		newmode = drm_mode_displayid_detailed(connector->dev, timings);
		if (!newmode)
			continue;

		drm_mode_probed_add(connector, newmode);
		num_modes++;
	}
	return num_modes;
}

static int add_displayid_detailed_modes(struct drm_connector *connector,
					struct edid *edid)
{
	u8 *displayid;
	int ret;
	int idx = 1;
	int length = EDID_LENGTH;
	struct displayid_block *block;
	int num_modes = 0;

	displayid = drm_find_displayid_extension(edid);
	if (!displayid)
		return 0;

	ret = validate_displayid(displayid, length, idx);
	if (ret)
		return 0;

	idx += sizeof(struct displayid_hdr);
	while (block = (struct displayid_block *)&displayid[idx],
	       idx + sizeof(struct displayid_block) <= length &&
	       idx + sizeof(struct displayid_block) +
		   block->num_bytes <= length &&
	       block->num_bytes > 0) {
		idx += block->num_bytes + sizeof(struct displayid_block);
		switch (block->tag) {
		case DATA_BLOCK_TYPE_1_DETAILED_TIMING:
			num_modes += add_displayid_detailed_1_modes(connector,
						block);
			break;
		}
	}
	return num_modes;
}

/**
 * drm_add_edid_modes - add modes from EDID data, if available
 * @connector: connector we're probing
@@ -3844,6 +4011,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
	num_modes += add_established_modes(connector, edid);
	num_modes += add_cea_modes(connector, edid);
	num_modes += add_alternate_cea_modes(connector, edid);
	num_modes += add_displayid_detailed_modes(connector, edid);
	if (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF)
		num_modes += add_inferred_modes(connector, edid);

@@ -4144,6 +4312,9 @@ static int drm_parse_display_id(struct drm_connector *connector,
			if (ret)
				return ret;
			break;
		case DATA_BLOCK_TYPE_1_DETAILED_TIMING:
			/* handled in mode gathering code. */
			break;
		default:
			DRM_DEBUG_KMS("found DisplayID tag 0x%x, unhandled\n",
						  block->tag);
+4 −0
Original line number Diff line number Diff line
@@ -533,6 +533,10 @@ hdmi_picture_aspect_get_name(enum hdmi_picture_aspect picture_aspect)
		return "4:3";
	case HDMI_PICTURE_ASPECT_16_9:
		return "16:9";
	case HDMI_PICTURE_ASPECT_64_27:
		return "64:27";
	case HDMI_PICTURE_ASPECT_256_135:
		return "256:135";
	case HDMI_PICTURE_ASPECT_RESERVED:
		return "Reserved";
	}
+12 −0
Original line number Diff line number Diff line
@@ -644,6 +644,11 @@ struct drm_encoder {
 * @audio_latency: audio latency info from ELD, if found
 * @null_edid_counter: track sinks that give us all zeros for the EDID
 * @bad_edid_counter: track sinks that give us an EDID with invalid checksum
 * @max_tmds_char: indicates the maximum TMDS Character Rate supported
 * @scdc_present: when set the sink supports SCDC functionality
 * @rr_capable: when set the sink is capable of initiating an SCDC read request
 * @supports_scramble: when set the sink supports less than 340Mcsc scrambling
 * @flags_3d: 3D view(s) supported by the sink, see drm_edid.h (DRM_EDID_3D_*)
 * @edid_corrupt: indicates whether the last read EDID was corrupt
 * @debugfs_entry: debugfs directory for this connector
 * @state: current atomic state for this connector
@@ -717,6 +722,13 @@ struct drm_connector {
	int null_edid_counter; /* needed to workaround some HW bugs where we get all 0s */
	unsigned bad_edid_counter;

	/* EDID bits HDMI 2.0 */
	int max_tmds_char;	/* in Mcsc */
	bool scdc_present;
	bool rr_capable;
	bool supports_scramble;
	int flags_3d;

	/* Flag for raw EDID header corruption - used in Displayport
	 * compliance testing - * Displayport Link CTS Core 1.2 rev1.1 4.2.2.6
	 */
+17 −0
Original line number Diff line number Diff line
@@ -73,4 +73,21 @@ struct displayid_tiled_block {
	u8 topology_id[8];
} __packed;

struct displayid_detailed_timings_1 {
	u8 pixel_clock[3];
	u8 flags;
	u8 hactive[2];
	u8 hblank[2];
	u8 hsync[2];
	u8 hsw[2];
	u8 vactive[2];
	u8 vblank[2];
	u8 vsync[2];
	u8 vsw[2];
} __packed;

struct displayid_detailed_timing_block {
	struct displayid_block base;
	struct displayid_detailed_timings_1 timings[0];
};
#endif
+5 −0
Original line number Diff line number Diff line
@@ -266,6 +266,11 @@ struct detailed_timing {

#define DRM_ELD_CEA_SAD(mnl, sad)	(20 + (mnl) + 3 * (sad))

/* HDMI 2.0 */
#define DRM_EDID_3D_INDEPENDENT_VIEW	(1 << 2)
#define DRM_EDID_3D_DUAL_VIEW		(1 << 1)
#define DRM_EDID_3D_OSD_DISPARITY	(1 << 0)

struct edid {
	u8 header[8];
	/* Vendor & product info */
Loading