[Intel-gfx] [RFC][PATCH 3/4] drm/i915: Enable PAL and SECAM format for SDVO-TV

ling.ma at intel.com ling.ma at intel.com
Fri Jul 3 17:29:00 CEST 2009


Currently SDVO TV only support NTSC-M format. In this patch
we introduce PAL and SECAM formats available and create seting-format
property at detection time. When user dynamically chose preferred
format by xrandr command, it will refine all modelines
provided by SDVO device, then instruct SDVO device to execute.

In comming version we will implment HDTV format.

Any comments are welcome.

Signed-off-by: Ma Ling <ling.ma at intel.com>
---
 drivers/gpu/drm/i915/intel_sdvo.c |  214 ++++++++++++++++++++++++++++--------
 1 files changed, 166 insertions(+), 48 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index 53a7204..20b9b57 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -37,6 +37,20 @@
 
 #undef SDVO_DEBUG
 #define I915_SDVO	"i915_sdvo"
+
+static char *tv_format_names[] = {
+	"NTSC_M"   , "NTSC_J"  , "NTSC_443",
+	"PAL_B"    , "PAL_D"   , "PAL_G"   ,
+	"PAL_H"    , "PAL_I"   , "PAL_M"   ,
+	"PAL_N"    , "PAL_NC"  , "PAL_60"  ,
+	"SECAM_B"  , "SECAM_D" , "SECAM_G" ,
+	"SECAM_K"  , "SECAM_K1", "SECAM_L" ,
+	"SECAM_60"
+};
+
+#define TV_FORMAT_NUM  (sizeof(tv_format_names) / sizeof(*tv_format_names))
+
+
 struct intel_sdvo_priv {
 	u8 slave_addr;
 
@@ -64,6 +78,15 @@ struct intel_sdvo_priv {
 	 */
 	bool is_tv;
 
+	/* This is for current tv format name */
+	char *tv_format_name;
+
+	/* This contains all current supported TV format */
+	char *tv_format_supported[TV_FORMAT_NUM];
+	int   format_supported_num;
+	struct drm_property *tv_format_property;
+	struct drm_property *tv_format_name_property[TV_FORMAT_NUM];
+
 	/**
 	 * This is set if we treat the device as HDMI, instead of DVI.
 	 */
@@ -90,14 +113,6 @@ struct intel_sdvo_priv {
 	 */
 	struct intel_sdvo_sdtv_resolution_reply sdtv_resolutions;
 
-	/**
-	 * Current selected TV format.
-	 *
-	 * This is stored in the same structure that's passed to the device, for
-	 * convenience.
-	 */
-	struct intel_sdvo_tv_format tv_format;
-
 	/*
 	 * supported encoding mode, used to determine whether HDMI is
 	 * supported
@@ -935,23 +950,28 @@ static void intel_sdvo_set_avi_infoframe(struct intel_output *output,
 
 static void intel_sdvo_set_tv_format(struct intel_output *output)
 {
+
+	struct intel_sdvo_tv_format format;
 	struct intel_sdvo_priv *sdvo_priv = output->dev_priv;
-	struct intel_sdvo_tv_format *format, unset;
-	u8 status;
+	uint32_t format_map, i;
+	uint8_t status;
 
-	format = &sdvo_priv->tv_format;
-	memset(&unset, 0, sizeof(unset));
-	if (memcmp(format, &unset, sizeof(*format))) {
-		DRM_DEBUG("%s: Choosing default TV format of NTSC-M\n",
-				SDVO_NAME(sdvo_priv));
-		format->ntsc_m = 1;
-		intel_sdvo_write_cmd(output, SDVO_CMD_SET_TV_FORMAT, format,
-				sizeof(*format));
-		status = intel_sdvo_read_response(output, NULL, 0);
-		if (status != SDVO_CMD_STATUS_SUCCESS)
-			DRM_DEBUG("%s: Failed to set TV format\n",
-					SDVO_NAME(sdvo_priv));
-	}
+	for (i = 0; i < TV_FORMAT_NUM; i++)
+		if (tv_format_names[i] == sdvo_priv->tv_format_name)
+			break;
+
+	format_map = 1 << i;
+	memset(&format, 0, sizeof(format));
+	memcpy(&format, &format_map, sizeof(format_map) > sizeof(format) ?
+			sizeof(format) : sizeof(format_map));
+
+	intel_sdvo_write_cmd(output, SDVO_CMD_SET_TV_FORMAT, &format_map,
+			     sizeof(format));
+
+	status = intel_sdvo_read_response(output, NULL, 0);
+	if (status != SDVO_CMD_STATUS_SUCCESS)
+		DRM_DEBUG("%s: Failed to set TV format\n",
+			  SDVO_NAME(sdvo_priv));
 }
 
 static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
@@ -1451,6 +1471,55 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector)
 	}
 }
 
+static void intel_sdvo_tv_create_property(struct drm_connector *connector)
+{
+	struct intel_output *intel_output = to_intel_output(connector);
+	struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+	struct intel_sdvo_tv_format format;
+	uint32_t format_map, i;
+	uint8_t status;
+
+	intel_sdvo_set_target_output(intel_output,
+				     sdvo_priv->controlled_output);
+
+	intel_sdvo_write_cmd(intel_output,
+			     SDVO_CMD_GET_SUPPORTED_TV_FORMATS, NULL, 0);
+	status = intel_sdvo_read_response(intel_output,
+					  &format, sizeof(format));
+	if (status != SDVO_CMD_STATUS_SUCCESS)
+		return;
+
+	memcpy(&format_map, &format, sizeof(format) > sizeof(format_map) ?
+	       sizeof(format_map) : sizeof(format));
+
+	if (format_map == 0)
+		return;
+
+	sdvo_priv->format_supported_num = 0;
+	for (i = 0 ; i < TV_FORMAT_NUM; i++)
+		if (format_map & (1 << i)) {
+			sdvo_priv->tv_format_supported
+			[sdvo_priv->format_supported_num++] =
+			tv_format_names[i];
+		}
+
+
+	sdvo_priv->tv_format_property =
+			drm_property_create(
+				connector->dev, DRM_MODE_PROP_ENUM,
+				"mode", sdvo_priv->format_supported_num);
+
+	for (i = 0; i < sdvo_priv->format_supported_num; i++)
+		drm_property_add_enum(
+				connector->dev->mode_config.tv_mode_property, i,
+				i, sdvo_priv->tv_format_supported[i]);
+
+	sdvo_priv->tv_format_name = sdvo_priv->tv_format_supported[0];
+	drm_connector_attach_property(
+			connector, sdvo_priv->tv_format_property, 0);
+
+}
+
 static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connector)
 {
 	u16 response;
@@ -1458,7 +1527,8 @@ static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connect
 	struct intel_output *intel_output = to_intel_output(connector);
 	struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
 
-	intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0);
+	intel_sdvo_write_cmd(intel_output,
+			     SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0);
 	status = intel_sdvo_read_response(intel_output, &response, 2);
 
 	DRM_DEBUG("SDVO response %d %d\n", response & 0xff, response >> 8);
@@ -1468,6 +1538,8 @@ static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connect
 
 	if (response & sdvo_priv->controlled_output) {
 		intel_sdvo_hdmi_sink_detect(connector);
+		if (sdvo_priv->is_tv)
+			intel_sdvo_tv_create_property(connector);
 		return connector_status_connected;
 	} else
 		return connector_status_disconnected;
@@ -1503,25 +1575,6 @@ static void intel_sdvo_get_ddc_modes(struct drm_connector *connector)
 #endif
 }
 
-/**
- * This function checks the current TV format, and chooses a default if
- * it hasn't been set.
- */
-static void
-intel_sdvo_check_tv_format(struct intel_output *output)
-{
-	struct intel_sdvo_priv *dev_priv = output->dev_priv;
-	struct intel_sdvo_tv_format format;
-	uint8_t status;
-
-	intel_sdvo_write_cmd(output, SDVO_CMD_GET_TV_FORMAT, NULL, 0);
-	status = intel_sdvo_read_response(output, &format, sizeof(format));
-	if (status != SDVO_CMD_STATUS_SUCCESS)
-		return;
-
-	memcpy(&dev_priv->tv_format, &format, sizeof(format));
-}
-
 /*
  * Set of SDVO TV modes.
  * Note!  This is in reply order (see loop in get_tv_modes).
@@ -1592,17 +1645,26 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector)
 	struct intel_output *output = to_intel_output(connector);
 	struct intel_sdvo_priv *sdvo_priv = output->dev_priv;
 	struct intel_sdvo_sdtv_resolution_request tv_res;
-	uint32_t reply = 0;
+	uint32_t reply = 0, format_map = 0;
+	int i;
 	uint8_t status;
-	int i = 0;
 
-	intel_sdvo_check_tv_format(output);
 
 	/* Read the list of supported input resolutions for the selected TV
 	 * format.
 	 */
-	memset(&tv_res, 0, sizeof(tv_res));
-	memcpy(&tv_res, &sdvo_priv->tv_format, sizeof(tv_res));
+	for (i = 0; i < TV_FORMAT_NUM; i++)
+		if (tv_format_names[i] ==  sdvo_priv->tv_format_name)
+			break;
+
+	format_map = (1 << i);
+	memcpy(&tv_res, &format_map,
+	       sizeof(struct intel_sdvo_sdtv_resolution_request) >
+	       sizeof(format_map) ? sizeof(format_map) :
+	       sizeof(struct intel_sdvo_sdtv_resolution_request));
+
+	intel_sdvo_set_target_output(output, sdvo_priv->controlled_output);
+
 	intel_sdvo_write_cmd(output, SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT,
 			     &tv_res, sizeof(tv_res));
 	status = intel_sdvo_read_response(output, &reply, 3);
@@ -1617,6 +1679,7 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector)
 			if (nmode)
 				drm_mode_probed_add(connector, nmode);
 		}
+
 }
 
 static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
@@ -1695,6 +1758,46 @@ static void intel_sdvo_destroy(struct drm_connector *connector)
 	kfree(intel_output);
 }
 
+static int
+intel_sdvo_set_property(struct drm_connector *connector,
+			struct drm_property *property,
+			uint64_t val)
+{
+	struct drm_device *dev = connector->dev;
+	struct intel_output *intel_output = to_intel_output(connector);
+	struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+	struct drm_encoder *encoder = &intel_output->enc;
+	struct drm_crtc *crtc = encoder->crtc;
+	int ret = 0;
+	bool changed = false;
+
+	ret = drm_connector_property_set_value(connector, property, val);
+	if (ret < 0)
+		goto out;
+
+	if (property == dev->mode_config.tv_mode_property) {
+		if (val >= TV_FORMAT_NUM) {
+			ret = -EINVAL;
+			goto out;
+		}
+		if (sdvo_priv->tv_format_name ==
+		    sdvo_priv->tv_format_supported[val])
+			goto out;
+
+		sdvo_priv->tv_format_name = sdvo_priv->tv_format_supported[val];
+		changed = true;
+	} else {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (changed && crtc)
+		drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x,
+				crtc->y, crtc->fb);
+out:
+	return ret;
+}
+
 static const struct drm_encoder_helper_funcs intel_sdvo_helper_funcs = {
 	.dpms = intel_sdvo_dpms,
 	.mode_fixup = intel_sdvo_mode_fixup,
@@ -1709,6 +1812,7 @@ static const struct drm_connector_funcs intel_sdvo_connector_funcs = {
 	.restore = intel_sdvo_restore,
 	.detect = intel_sdvo_detect,
 	.fill_modes = drm_helper_probe_single_connector_modes,
+	.set_property = intel_sdvo_set_property,
 	.destroy = intel_sdvo_destroy,
 };
 
@@ -1972,6 +2076,20 @@ static int intel_sdvo_outputs_init(struct drm_device *dev, int output_device,
 		connector_type = DRM_MODE_CONNECTOR_SVIDEO;
 		sdvo_priv->is_tv = true;
 		intel_output->needs_tv_clock = true;
+	} else if (maked_output_flags & SDVO_OUTPUT_CVBS0) {
+
+		sdvo_priv->controlled_output = SDVO_OUTPUT_CVBS0;
+		encoder_type = DRM_MODE_ENCODER_TVDAC;
+		connector_type = DRM_MODE_CONNECTOR_Composite;
+		sdvo_priv->is_tv = true;
+		intel_output->needs_tv_clock = true;
+	} else if (maked_output_flags & SDVO_OUTPUT_YPRPB0) {
+
+		sdvo_priv->controlled_output = SDVO_OUTPUT_YPRPB0;
+		encoder_type = DRM_MODE_ENCODER_TVDAC;
+		connector_type = DRM_MODE_CONNECTOR_Component;
+		sdvo_priv->is_tv = true;
+		intel_output->needs_tv_clock = true;
 	} else if (maked_output_flags & SDVO_OUTPUT_RGB0) {
 
 		sdvo_priv->controlled_output = SDVO_OUTPUT_RGB0;
-- 
1.5.4.4




More information about the Intel-gfx mailing list