|
@@ -38,6 +38,18 @@
|
|
|
|
|
|
#undef SDVO_DEBUG
|
|
#undef SDVO_DEBUG
|
|
#define I915_SDVO "i915_sdvo"
|
|
#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 {
|
|
struct intel_sdvo_priv {
|
|
u8 slave_addr;
|
|
u8 slave_addr;
|
|
|
|
|
|
@@ -71,6 +83,15 @@ struct intel_sdvo_priv {
|
|
*/
|
|
*/
|
|
bool is_tv;
|
|
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.
|
|
* This is set if we treat the device as HDMI, instead of DVI.
|
|
*/
|
|
*/
|
|
@@ -97,14 +118,6 @@ struct intel_sdvo_priv {
|
|
*/
|
|
*/
|
|
struct intel_sdvo_sdtv_resolution_reply sdtv_resolutions;
|
|
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 encoding mode, used to determine whether HDMI is
|
|
* supported
|
|
* supported
|
|
@@ -945,23 +958,28 @@ static void intel_sdvo_set_avi_infoframe(struct intel_output *output,
|
|
|
|
|
|
static void intel_sdvo_set_tv_format(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_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,
|
|
static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
|
|
@@ -1516,7 +1534,8 @@ static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connect
|
|
struct intel_output *intel_output = to_intel_output(connector);
|
|
struct intel_output *intel_output = to_intel_output(connector);
|
|
struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
|
|
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);
|
|
status = intel_sdvo_read_response(intel_output, &response, 2);
|
|
|
|
|
|
DRM_DEBUG("SDVO response %d %d\n", response & 0xff, response >> 8);
|
|
DRM_DEBUG("SDVO response %d %d\n", response & 0xff, response >> 8);
|
|
@@ -1567,25 +1586,6 @@ static void intel_sdvo_get_ddc_modes(struct drm_connector *connector)
|
|
#endif
|
|
#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.
|
|
* Set of SDVO TV modes.
|
|
* Note! This is in reply order (see loop in get_tv_modes).
|
|
* Note! This is in reply order (see loop in get_tv_modes).
|
|
@@ -1656,17 +1656,26 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector)
|
|
struct intel_output *output = to_intel_output(connector);
|
|
struct intel_output *output = to_intel_output(connector);
|
|
struct intel_sdvo_priv *sdvo_priv = output->dev_priv;
|
|
struct intel_sdvo_priv *sdvo_priv = output->dev_priv;
|
|
struct intel_sdvo_sdtv_resolution_request tv_res;
|
|
struct intel_sdvo_sdtv_resolution_request tv_res;
|
|
- uint32_t reply = 0;
|
|
|
|
|
|
+ uint32_t reply = 0, format_map = 0;
|
|
|
|
+ int i;
|
|
uint8_t status;
|
|
uint8_t status;
|
|
- int i = 0;
|
|
|
|
|
|
|
|
- intel_sdvo_check_tv_format(output);
|
|
|
|
|
|
|
|
/* Read the list of supported input resolutions for the selected TV
|
|
/* Read the list of supported input resolutions for the selected TV
|
|
* format.
|
|
* 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,
|
|
intel_sdvo_write_cmd(output, SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT,
|
|
&tv_res, sizeof(tv_res));
|
|
&tv_res, sizeof(tv_res));
|
|
status = intel_sdvo_read_response(output, &reply, 3);
|
|
status = intel_sdvo_read_response(output, &reply, 3);
|
|
@@ -1681,6 +1690,7 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector)
|
|
if (nmode)
|
|
if (nmode)
|
|
drm_mode_probed_add(connector, nmode);
|
|
drm_mode_probed_add(connector, nmode);
|
|
}
|
|
}
|
|
|
|
+
|
|
}
|
|
}
|
|
|
|
|
|
static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
|
|
static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
|
|
@@ -1753,12 +1763,55 @@ static void intel_sdvo_destroy(struct drm_connector *connector)
|
|
drm_mode_destroy(connector->dev,
|
|
drm_mode_destroy(connector->dev,
|
|
sdvo_priv->sdvo_lvds_fixed_mode);
|
|
sdvo_priv->sdvo_lvds_fixed_mode);
|
|
|
|
|
|
|
|
+ if (sdvo_priv->tv_format_property)
|
|
|
|
+ drm_property_destroy(connector->dev,
|
|
|
|
+ sdvo_priv->tv_format_property);
|
|
|
|
+
|
|
drm_sysfs_connector_remove(connector);
|
|
drm_sysfs_connector_remove(connector);
|
|
drm_connector_cleanup(connector);
|
|
drm_connector_cleanup(connector);
|
|
|
|
|
|
kfree(intel_output);
|
|
kfree(intel_output);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int
|
|
|
|
+intel_sdvo_set_property(struct drm_connector *connector,
|
|
|
|
+ struct drm_property *property,
|
|
|
|
+ uint64_t val)
|
|
|
|
+{
|
|
|
|
+ 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 == sdvo_priv->tv_format_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 = {
|
|
static const struct drm_encoder_helper_funcs intel_sdvo_helper_funcs = {
|
|
.dpms = intel_sdvo_dpms,
|
|
.dpms = intel_sdvo_dpms,
|
|
.mode_fixup = intel_sdvo_mode_fixup,
|
|
.mode_fixup = intel_sdvo_mode_fixup,
|
|
@@ -1773,6 +1826,7 @@ static const struct drm_connector_funcs intel_sdvo_connector_funcs = {
|
|
.restore = intel_sdvo_restore,
|
|
.restore = intel_sdvo_restore,
|
|
.detect = intel_sdvo_detect,
|
|
.detect = intel_sdvo_detect,
|
|
.fill_modes = drm_helper_probe_single_connector_modes,
|
|
.fill_modes = drm_helper_probe_single_connector_modes,
|
|
|
|
+ .set_property = intel_sdvo_set_property,
|
|
.destroy = intel_sdvo_destroy,
|
|
.destroy = intel_sdvo_destroy,
|
|
};
|
|
};
|
|
|
|
|
|
@@ -2029,6 +2083,55 @@ intel_sdvo_output_setup(struct intel_output *intel_output, uint16_t flags)
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+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(
|
|
|
|
+ sdvo_priv->tv_format_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);
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
bool intel_sdvo_init(struct drm_device *dev, int output_device)
|
|
bool intel_sdvo_init(struct drm_device *dev, int output_device)
|
|
{
|
|
{
|
|
struct drm_connector *connector;
|
|
struct drm_connector *connector;
|
|
@@ -2111,6 +2214,8 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
|
|
drm_encoder_helper_add(&intel_output->enc, &intel_sdvo_helper_funcs);
|
|
drm_encoder_helper_add(&intel_output->enc, &intel_sdvo_helper_funcs);
|
|
|
|
|
|
drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc);
|
|
drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc);
|
|
|
|
+ if (sdvo_priv->is_tv)
|
|
|
|
+ intel_sdvo_tv_create_property(connector);
|
|
drm_sysfs_connector_add(connector);
|
|
drm_sysfs_connector_add(connector);
|
|
|
|
|
|
intel_sdvo_select_ddc_bus(sdvo_priv);
|
|
intel_sdvo_select_ddc_bus(sdvo_priv);
|