diff --git a/libweston/backend-drm/drm-internal.h b/libweston/backend-drm/drm-internal.h
index f9d21e3b..6471357f 100644
--- a/libweston/backend-drm/drm-internal.h
+++ b/libweston/backend-drm/drm-internal.h
@@ -186,6 +186,7 @@ enum wdrm_connector_property {
 	WDRM_CONNECTOR_CONTENT_PROTECTION,
 	WDRM_CONNECTOR_HDCP_CONTENT_TYPE,
 	WDRM_CONNECTOR_PANEL_ORIENTATION,
+	WDRM_CONNECTOR_HDR_OUTPUT_METADATA,
 	WDRM_CONNECTOR__COUNT
 };
 
diff --git a/libweston/backend-drm/drm.c b/libweston/backend-drm/drm.c
index 225d47e2..d7e91e35 100644
--- a/libweston/backend-drm/drm.c
+++ b/libweston/backend-drm/drm.c
@@ -2053,12 +2053,21 @@ drm_connector_fini(struct drm_connector *connector)
 static void
 drm_head_log_info(struct drm_head *head, const char *msg)
 {
+	char *eotf_list;
+
 	if (head->base.connected) {
 		weston_log("DRM: head '%s' %s, connector %d is connected, "
 			   "EDID make '%s', model '%s', serial '%s'\n",
 			   head->base.name, msg, head->connector.connector_id,
 			   head->base.make, head->base.model,
 			   head->base.serial_number ?: "");
+		eotf_list = weston_eotf_mask_to_str(head->base.supported_eotf_mask);
+		if (eotf_list) {
+			weston_log_continue(STAMP_SPACE
+					    "Supported EOTF modes: %s\n",
+					    eotf_list);
+		}
+		free(eotf_list);
 	} else {
 		weston_log("DRM: head '%s' %s, connector %d is disconnected.\n",
 			   head->base.name, msg, head->connector.connector_id);
diff --git a/libweston/backend-drm/kms.c b/libweston/backend-drm/kms.c
index 780d0070..7ec274a2 100644
--- a/libweston/backend-drm/kms.c
+++ b/libweston/backend-drm/kms.c
@@ -143,6 +143,9 @@ const struct drm_property_info connector_props[] = {
 		.enum_values = panel_orientation_enums,
 		.num_enum_values = WDRM_PANEL_ORIENTATION__COUNT,
 	},
+	[WDRM_CONNECTOR_HDR_OUTPUT_METADATA] = {
+		.name = "HDR_OUTPUT_METADATA",
+	},
 };
 
 const struct drm_property_info crtc_props[] = {
diff --git a/libweston/backend-drm/modes.c b/libweston/backend-drm/modes.c
index a071375b..1c9d1068 100644
--- a/libweston/backend-drm/modes.c
+++ b/libweston/backend-drm/modes.c
@@ -304,6 +304,8 @@ edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
  * \param[out] make The monitor make (PNP ID).
  * \param[out] model The monitor model (name).
  * \param[out] serial_number The monitor serial number.
+ * \param[out] eotf_mask The monitor supported EOTF modes, combination of
+ * enum weston_eotf_mode bits.
  *
  * Each of \c *make, \c *model and \c *serial_number are set only if the
  * information is found in the EDID. The pointers they are set to must not
@@ -315,7 +317,8 @@ find_and_parse_output_edid(struct drm_head *head,
 			   drmModeObjectPropertiesPtr props,
 			   const char **make,
 			   const char **model,
-			   const char **serial_number)
+			   const char **serial_number,
+			   uint32_t *eotf_mask)
 {
 	drmModePropertyBlobPtr edid_blob = NULL;
 	uint32_t blob_id;
@@ -344,6 +347,21 @@ find_and_parse_output_edid(struct drm_head *head,
 			*serial_number = head->edid.serial_number;
 	}
 	drmModeFreePropertyBlob(edid_blob);
+
+	/* TODO: parse this from EDID */
+	*eotf_mask = WESTON_EOTF_MODE_ALL_MASK;
+}
+
+static void
+prune_eotf_modes_by_kms_support(struct drm_head *head, uint32_t *eotf_mask)
+{
+	const struct drm_property_info *info;
+
+	/* Without the KMS property, cannot do anything but SDR. */
+
+	info = &head->connector.props[WDRM_CONNECTOR_HDR_OUTPUT_METADATA];
+	if (info->prop_id == 0)
+		*eotf_mask = WESTON_EOTF_MODE_SDR;
 }
 
 static uint32_t
@@ -515,9 +533,12 @@ update_head_from_connector(struct drm_head *head)
 	const char *make = "unknown";
 	const char *model = "unknown";
 	const char *serial_number = "unknown";
+	uint32_t eotf_mask = WESTON_EOTF_MODE_SDR;
 
-	find_and_parse_output_edid(head, props, &make, &model, &serial_number);
+	find_and_parse_output_edid(head, props, &make, &model, &serial_number, &eotf_mask);
 	weston_head_set_monitor_strings(&head->base, make, model, serial_number);
+	prune_eotf_modes_by_kms_support(head, &eotf_mask);
+	weston_head_set_supported_eotf_mask(&head->base, eotf_mask);
 	weston_head_set_non_desktop(&head->base,
 				    check_non_desktop(connector, props));
 	weston_head_set_subpixel(&head->base,
diff --git a/libweston/color.c b/libweston/color.c
index c2605fd7..27991901 100644
--- a/libweston/color.c
+++ b/libweston/color.c
@@ -314,3 +314,38 @@ weston_eotf_mode_to_str(enum weston_eotf_mode e)
 	}
 	return "???";
 }
+
+/** A list of EOTF modes as a string
+ *
+ * \param eotf_mask Bitwise-or'd enum weston_eotf_mode values.
+ * \return Comma separated names of the listed EOTF modes. Must be free()'d by
+ * the caller.
+ */
+WL_EXPORT char *
+weston_eotf_mask_to_str(uint32_t eotf_mask)
+{
+	FILE *fp;
+	char *str = NULL;
+	size_t size = 0;
+	unsigned i;
+	const char *sep = "";
+
+	fp = open_memstream(&str, &size);
+	if (!fp)
+		return NULL;
+
+	for (i = 0; eotf_mask; i++) {
+		uint32_t bitmask = 1u << i;
+
+		if (eotf_mask & bitmask) {
+			fprintf(fp, "%s%s", sep,
+				weston_eotf_mode_to_str(bitmask));
+			sep = ", ";
+		}
+
+		eotf_mask &= ~bitmask;
+	}
+	fclose(fp);
+
+	return str;
+}
diff --git a/libweston/color.h b/libweston/color.h
index 4db42e71..7c1335fa 100644
--- a/libweston/color.h
+++ b/libweston/color.h
@@ -382,4 +382,7 @@ weston_color_manager_create(struct weston_compositor *compositor);
 const char *
 weston_eotf_mode_to_str(enum weston_eotf_mode e);
 
+char *
+weston_eotf_mask_to_str(uint32_t eotf_mask);
+
 #endif /* WESTON_COLOR_H */