drm/i915: Convert intel_sdvo connector properties to atomic.

SDVO was the last connector that's still using the legacy paths
for properties, and this is with a reason!

This connector implements a lot of properties dynamically,
and some of them shared with the digital connector state,
so sdvo_connector_state subclasses intel_digital_connector_state.

set_property had a lot of validation, but this is handled in the
drm core, so most of the validation can die off. The properties
are written right before enabling the connector, since there is no
good way to update the properties without crtc.

Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/20170501133804.8116-13-maarten.lankhorst@linux.intel.com
This commit is contained in:
Maarten Lankhorst 2017-05-01 15:38:04 +02:00
parent b32962f87a
commit 630d30a4ee
4 changed files with 285 additions and 326 deletions

View File

@ -35,46 +35,6 @@
#include <drm/drm_plane_helper.h> #include <drm/drm_plane_helper.h>
#include "intel_drv.h" #include "intel_drv.h"
/**
* intel_connector_atomic_get_property - fetch legacy connector property value
* @connector: connector to fetch property for
* @state: state containing the property value
* @property: property to look up
* @val: pointer to write property value into
*
* The DRM core does not store shadow copies of properties for
* atomic-capable drivers. This entrypoint is used to fetch
* the current value of a driver-specific connector property.
*
* This is a intermediary solution until all connectors are
* converted to support full atomic properties.
*/
int intel_connector_atomic_get_property(struct drm_connector *connector,
const struct drm_connector_state *state,
struct drm_property *property,
uint64_t *val)
{
int i;
/*
* TODO: We only have atomic modeset for planes at the moment, so the
* crtc/connector code isn't quite ready yet. Until it's ready,
* continue to look up all property values in the DRM's shadow copy
* in obj->properties->values[].
*
* When the crtc/connector state work matures, this function should
* be updated to read the values out of the state structure instead.
*/
for (i = 0; i < connector->base.properties->count; i++) {
if (connector->base.properties->properties[i] == property) {
*val = connector->base.properties->values[i];
return 0;
}
}
return -EINVAL;
}
/** /**
* intel_digital_connector_atomic_get_property - hook for connector->atomic_get_property. * intel_digital_connector_atomic_get_property - hook for connector->atomic_get_property.
* @connector: Connector to get the property for. * @connector: Connector to get the property for.

View File

@ -13262,43 +13262,6 @@ static int intel_atomic_commit(struct drm_device *dev,
return 0; return 0;
} }
void intel_crtc_restore_mode(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
struct drm_atomic_state *state;
struct drm_crtc_state *crtc_state;
int ret;
state = drm_atomic_state_alloc(dev);
if (!state) {
DRM_DEBUG_KMS("[CRTC:%d:%s] crtc restore failed, out of memory",
crtc->base.id, crtc->name);
return;
}
state->acquire_ctx = crtc->dev->mode_config.acquire_ctx;
retry:
crtc_state = drm_atomic_get_crtc_state(state, crtc);
ret = PTR_ERR_OR_ZERO(crtc_state);
if (!ret) {
if (!crtc_state->active)
goto out;
crtc_state->mode_changed = true;
ret = drm_atomic_commit(state);
}
if (ret == -EDEADLK) {
drm_atomic_state_clear(state);
drm_modeset_backoff(state->acquire_ctx);
goto retry;
}
out:
drm_atomic_state_put(state);
}
static const struct drm_crtc_funcs intel_crtc_funcs = { static const struct drm_crtc_funcs intel_crtc_funcs = {
.gamma_set = drm_atomic_helper_legacy_gamma_set, .gamma_set = drm_atomic_helper_legacy_gamma_set,
.set_config = drm_atomic_helper_set_config, .set_config = drm_atomic_helper_set_config,

View File

@ -1349,7 +1349,6 @@ unsigned int intel_rotation_info_size(const struct intel_rotation_info *rot_info
bool intel_has_pending_fb_unpin(struct drm_i915_private *dev_priv); bool intel_has_pending_fb_unpin(struct drm_i915_private *dev_priv);
void intel_mark_busy(struct drm_i915_private *dev_priv); void intel_mark_busy(struct drm_i915_private *dev_priv);
void intel_mark_idle(struct drm_i915_private *dev_priv); void intel_mark_idle(struct drm_i915_private *dev_priv);
void intel_crtc_restore_mode(struct drm_crtc *crtc);
int intel_display_suspend(struct drm_device *dev); int intel_display_suspend(struct drm_device *dev);
void intel_pps_unlock_regs_wa(struct drm_i915_private *dev_priv); void intel_pps_unlock_regs_wa(struct drm_i915_private *dev_priv);
void intel_encoder_destroy(struct drm_encoder *encoder); void intel_encoder_destroy(struct drm_encoder *encoder);
@ -1911,11 +1910,6 @@ void intel_pipe_update_end(struct intel_crtc *crtc, struct intel_flip_work *work
void intel_tv_init(struct drm_i915_private *dev_priv); void intel_tv_init(struct drm_i915_private *dev_priv);
/* intel_atomic.c */ /* intel_atomic.c */
int intel_connector_atomic_get_property(struct drm_connector *connector,
const struct drm_connector_state *state,
struct drm_property *property,
uint64_t *val);
int intel_digital_connector_atomic_get_property(struct drm_connector *connector, int intel_digital_connector_atomic_get_property(struct drm_connector *connector,
const struct drm_connector_state *state, const struct drm_connector_state *state,
struct drm_property *property, struct drm_property *property,

View File

@ -99,13 +99,6 @@ struct intel_sdvo {
*/ */
uint16_t hotplug_active; uint16_t hotplug_active;
/**
* This is used to select the color range of RBG outputs in HDMI mode.
* It is only valid when using TMDS encoding and 8 bit per color mode.
*/
uint32_t color_range;
bool color_range_auto;
/** /**
* This is set if we're going to treat the device as TV-out. * This is set if we're going to treat the device as TV-out.
* *
@ -117,9 +110,6 @@ struct intel_sdvo {
enum port port; enum port port;
/* This is for current tv format name */
int tv_format_index;
/** /**
* 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.
*/ */
@ -154,8 +144,6 @@ struct intel_sdvo_connector {
/* Mark the type of connector */ /* Mark the type of connector */
uint16_t output_flag; uint16_t output_flag;
enum hdmi_force_audio force_audio;
/* This contains all current supported TV format */ /* This contains all current supported TV format */
u8 tv_format_supported[TV_FORMAT_NUM]; u8 tv_format_supported[TV_FORMAT_NUM];
int format_supported_num; int format_supported_num;
@ -182,24 +170,19 @@ struct intel_sdvo_connector {
/* add the property for the SDVO-TV/LVDS */ /* add the property for the SDVO-TV/LVDS */
struct drm_property *brightness; struct drm_property *brightness;
/* Add variable to record current setting for the above property */
u32 left_margin, right_margin, top_margin, bottom_margin;
/* this is to get the range of margin.*/ /* this is to get the range of margin.*/
u32 max_hscan, max_vscan; u32 max_hscan, max_vscan;
u32 max_hpos, cur_hpos; };
u32 max_vpos, cur_vpos;
u32 cur_brightness, max_brightness; struct intel_sdvo_connector_state {
u32 cur_contrast, max_contrast; /* base.base: tv.saturation/contrast/hue/brightness */
u32 cur_saturation, max_saturation; struct intel_digital_connector_state base;
u32 cur_hue, max_hue;
u32 cur_sharpness, max_sharpness; struct {
u32 cur_flicker_filter, max_flicker_filter; unsigned overscan_h, overscan_v, hpos, vpos, sharpness;
u32 cur_flicker_filter_adaptive, max_flicker_filter_adaptive; unsigned flicker_filter, flicker_filter_2d, flicker_filter_adaptive;
u32 cur_flicker_filter_2d, max_flicker_filter_2d; unsigned chroma_filter, luma_filter, dot_crawl;
u32 cur_tv_chroma_filter, max_tv_chroma_filter; } tv;
u32 cur_tv_luma_filter, max_tv_luma_filter;
u32 cur_dot_crawl, max_dot_crawl;
}; };
static struct intel_sdvo *to_sdvo(struct intel_encoder *encoder) static struct intel_sdvo *to_sdvo(struct intel_encoder *encoder)
@ -212,9 +195,16 @@ static struct intel_sdvo *intel_attached_sdvo(struct drm_connector *connector)
return to_sdvo(intel_attached_encoder(connector)); return to_sdvo(intel_attached_encoder(connector));
} }
static struct intel_sdvo_connector *to_intel_sdvo_connector(struct drm_connector *connector) static struct intel_sdvo_connector *
to_intel_sdvo_connector(struct drm_connector *connector)
{ {
return container_of(to_intel_connector(connector), struct intel_sdvo_connector, base); return container_of(connector, struct intel_sdvo_connector, base.base);
}
static struct intel_sdvo_connector_state *
to_intel_sdvo_connector_state(struct drm_connector_state *conn_state)
{
return container_of(conn_state, struct intel_sdvo_connector_state, base.base);
} }
static bool static bool
@ -1030,12 +1020,13 @@ static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo,
sdvo_data, sizeof(sdvo_data)); sdvo_data, sizeof(sdvo_data));
} }
static bool intel_sdvo_set_tv_format(struct intel_sdvo *intel_sdvo) static bool intel_sdvo_set_tv_format(struct intel_sdvo *intel_sdvo,
struct drm_connector_state *conn_state)
{ {
struct intel_sdvo_tv_format format; struct intel_sdvo_tv_format format;
uint32_t format_map; uint32_t format_map;
format_map = 1 << intel_sdvo->tv_format_index; format_map = 1 << conn_state->tv.mode;
memset(&format, 0, sizeof(format)); memset(&format, 0, sizeof(format));
memcpy(&format, &format_map, min(sizeof(format), sizeof(format_map))); memcpy(&format, &format_map, min(sizeof(format), sizeof(format_map)));
@ -1122,8 +1113,8 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder,
struct drm_connector_state *conn_state) struct drm_connector_state *conn_state)
{ {
struct intel_sdvo *intel_sdvo = to_sdvo(encoder); struct intel_sdvo *intel_sdvo = to_sdvo(encoder);
struct intel_sdvo_connector *intel_sdvo_connector = struct intel_sdvo_connector_state *intel_sdvo_state =
to_intel_sdvo_connector(conn_state->connector); to_intel_sdvo_connector_state(conn_state);
struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
struct drm_display_mode *mode = &pipe_config->base.mode; struct drm_display_mode *mode = &pipe_config->base.mode;
@ -1162,14 +1153,14 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder,
pipe_config->pixel_multiplier = pipe_config->pixel_multiplier =
intel_sdvo_get_pixel_multiplier(adjusted_mode); intel_sdvo_get_pixel_multiplier(adjusted_mode);
if (intel_sdvo_connector->force_audio != HDMI_AUDIO_OFF_DVI) if (intel_sdvo_state->base.force_audio != HDMI_AUDIO_OFF_DVI)
pipe_config->has_hdmi_sink = intel_sdvo->has_hdmi_monitor; pipe_config->has_hdmi_sink = intel_sdvo->has_hdmi_monitor;
if (intel_sdvo_connector->force_audio == HDMI_AUDIO_ON || if (intel_sdvo_state->base.force_audio == HDMI_AUDIO_ON ||
(intel_sdvo_connector->force_audio == HDMI_AUDIO_AUTO && intel_sdvo->has_hdmi_audio)) (intel_sdvo_state->base.force_audio == HDMI_AUDIO_AUTO && intel_sdvo->has_hdmi_audio))
pipe_config->has_audio = true; pipe_config->has_audio = true;
if (intel_sdvo->color_range_auto) { if (intel_sdvo_state->base.broadcast_rgb == INTEL_BROADCAST_RGB_AUTO) {
/* See CEA-861-E - 5.1 Default Encoding Parameters */ /* See CEA-861-E - 5.1 Default Encoding Parameters */
/* FIXME: This bit is only valid when using TMDS encoding and 8 /* FIXME: This bit is only valid when using TMDS encoding and 8
* bit per color mode. */ * bit per color mode. */
@ -1178,7 +1169,7 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder,
pipe_config->limited_color_range = true; pipe_config->limited_color_range = true;
} else { } else {
if (pipe_config->has_hdmi_sink && if (pipe_config->has_hdmi_sink &&
intel_sdvo->color_range == HDMI_COLOR_RANGE_16_235) intel_sdvo_state->base.broadcast_rgb == INTEL_BROADCAST_RGB_LIMITED)
pipe_config->limited_color_range = true; pipe_config->limited_color_range = true;
} }
@ -1193,6 +1184,68 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder,
return true; return true;
} }
#define UPDATE_PROPERTY(input, NAME) \
do { \
val = input; \
intel_sdvo_set_value(intel_sdvo, SDVO_CMD_SET_##NAME, &val, sizeof(val)); \
} while (0)
static void intel_sdvo_update_props(struct intel_sdvo *intel_sdvo,
struct intel_sdvo_connector_state *sdvo_state)
{
struct drm_connector_state *conn_state = &sdvo_state->base.base;
struct intel_sdvo_connector *intel_sdvo_conn =
to_intel_sdvo_connector(conn_state->connector);
uint16_t val;
if (intel_sdvo_conn->left)
UPDATE_PROPERTY(sdvo_state->tv.overscan_h, OVERSCAN_H);
if (intel_sdvo_conn->top)
UPDATE_PROPERTY(sdvo_state->tv.overscan_v, OVERSCAN_V);
if (intel_sdvo_conn->hpos)
UPDATE_PROPERTY(sdvo_state->tv.hpos, HPOS);
if (intel_sdvo_conn->vpos)
UPDATE_PROPERTY(sdvo_state->tv.vpos, VPOS);
if (intel_sdvo_conn->saturation)
UPDATE_PROPERTY(conn_state->tv.saturation, SATURATION);
if (intel_sdvo_conn->contrast)
UPDATE_PROPERTY(conn_state->tv.contrast, CONTRAST);
if (intel_sdvo_conn->hue)
UPDATE_PROPERTY(conn_state->tv.hue, HUE);
if (intel_sdvo_conn->brightness)
UPDATE_PROPERTY(conn_state->tv.brightness, BRIGHTNESS);
if (intel_sdvo_conn->sharpness)
UPDATE_PROPERTY(sdvo_state->tv.sharpness, SHARPNESS);
if (intel_sdvo_conn->flicker_filter)
UPDATE_PROPERTY(sdvo_state->tv.flicker_filter, FLICKER_FILTER);
if (intel_sdvo_conn->flicker_filter_2d)
UPDATE_PROPERTY(sdvo_state->tv.flicker_filter_2d, FLICKER_FILTER_2D);
if (intel_sdvo_conn->flicker_filter_adaptive)
UPDATE_PROPERTY(sdvo_state->tv.flicker_filter_adaptive, FLICKER_FILTER_ADAPTIVE);
if (intel_sdvo_conn->tv_chroma_filter)
UPDATE_PROPERTY(sdvo_state->tv.chroma_filter, TV_CHROMA_FILTER);
if (intel_sdvo_conn->tv_luma_filter)
UPDATE_PROPERTY(sdvo_state->tv.luma_filter, TV_LUMA_FILTER);
if (intel_sdvo_conn->dot_crawl)
UPDATE_PROPERTY(sdvo_state->tv.dot_crawl, DOT_CRAWL);
#undef UPDATE_PROPERTY
}
static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder, static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder,
struct intel_crtc_state *crtc_state, struct intel_crtc_state *crtc_state,
struct drm_connector_state *conn_state) struct drm_connector_state *conn_state)
@ -1200,6 +1253,7 @@ static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder,
struct drm_i915_private *dev_priv = to_i915(intel_encoder->base.dev); struct drm_i915_private *dev_priv = to_i915(intel_encoder->base.dev);
struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc); struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
const struct drm_display_mode *adjusted_mode = &crtc_state->base.adjusted_mode; const struct drm_display_mode *adjusted_mode = &crtc_state->base.adjusted_mode;
struct intel_sdvo_connector_state *sdvo_state = to_intel_sdvo_connector_state(conn_state);
struct drm_display_mode *mode = &crtc_state->base.mode; struct drm_display_mode *mode = &crtc_state->base.mode;
struct intel_sdvo *intel_sdvo = to_sdvo(intel_encoder); struct intel_sdvo *intel_sdvo = to_sdvo(intel_encoder);
u32 sdvox; u32 sdvox;
@ -1207,6 +1261,8 @@ static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder,
struct intel_sdvo_dtd input_dtd, output_dtd; struct intel_sdvo_dtd input_dtd, output_dtd;
int rate; int rate;
intel_sdvo_update_props(intel_sdvo, sdvo_state);
/* First, set the input mapping for the first input to our controlled /* First, set the input mapping for the first input to our controlled
* output. This is only correct if we're a single-input device, in * output. This is only correct if we're a single-input device, in
* which case the first input is the output from the appropriate SDVO * which case the first input is the output from the appropriate SDVO
@ -1248,7 +1304,7 @@ static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder,
intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_DVI); intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_DVI);
if (intel_sdvo->is_tv && if (intel_sdvo->is_tv &&
!intel_sdvo_set_tv_format(intel_sdvo)) !intel_sdvo_set_tv_format(intel_sdvo, conn_state))
return; return;
intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode); intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode);
@ -1880,6 +1936,7 @@ static const struct drm_display_mode sdvo_tv_modes[] = {
static void intel_sdvo_get_tv_modes(struct drm_connector *connector) static void intel_sdvo_get_tv_modes(struct drm_connector *connector)
{ {
struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector); struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
const struct drm_connector_state *conn_state = connector->state;
struct intel_sdvo_sdtv_resolution_request tv_res; struct intel_sdvo_sdtv_resolution_request tv_res;
uint32_t reply = 0, format_map = 0; uint32_t reply = 0, format_map = 0;
int i; int i;
@ -1890,7 +1947,7 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector)
/* Read the list of supported input resolutions for the selected TV /* Read the list of supported input resolutions for the selected TV
* format. * format.
*/ */
format_map = 1 << intel_sdvo->tv_format_index; format_map = 1 << conn_state->tv.mode;
memcpy(&tv_res, &format_map, memcpy(&tv_res, &format_map,
min(sizeof(format_map), sizeof(struct intel_sdvo_sdtv_resolution_request))); min(sizeof(format_map), sizeof(struct intel_sdvo_sdtv_resolution_request)));
@ -1980,175 +2037,120 @@ static void intel_sdvo_destroy(struct drm_connector *connector)
} }
static int static int
intel_sdvo_set_property(struct drm_connector *connector, intel_sdvo_connector_atomic_get_property(struct drm_connector *connector,
struct drm_property *property, const struct drm_connector_state *state,
uint64_t val) struct drm_property *property,
uint64_t *val)
{ {
struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
struct drm_i915_private *dev_priv = to_i915(connector->dev); const struct intel_sdvo_connector_state *sdvo_state = to_intel_sdvo_connector_state((void *)state);
uint16_t temp_value;
uint8_t cmd;
int ret;
ret = drm_object_property_set_value(&connector->base, property, val);
if (ret)
return ret;
if (property == dev_priv->force_audio_property) {
int i = val;
bool has_audio, old_audio;
if (intel_sdvo_connector->force_audio == HDMI_AUDIO_AUTO)
old_audio = intel_sdvo->has_hdmi_audio;
else
old_audio = intel_sdvo_connector->force_audio == HDMI_AUDIO_ON;
if (i == HDMI_AUDIO_AUTO)
has_audio = intel_sdvo->has_hdmi_audio;
else
has_audio = (i == HDMI_AUDIO_ON);
intel_sdvo_connector->force_audio = i;
if (has_audio == old_audio)
return 0;
goto done;
}
if (property == dev_priv->broadcast_rgb_property) {
bool old_auto = intel_sdvo->color_range_auto;
uint32_t old_range = intel_sdvo->color_range;
switch (val) {
case INTEL_BROADCAST_RGB_AUTO:
intel_sdvo->color_range_auto = true;
break;
case INTEL_BROADCAST_RGB_FULL:
intel_sdvo->color_range_auto = false;
intel_sdvo->color_range = 0;
break;
case INTEL_BROADCAST_RGB_LIMITED:
intel_sdvo->color_range_auto = false;
/* FIXME: this bit is only valid when using TMDS
* encoding and 8 bit per color mode. */
intel_sdvo->color_range = HDMI_COLOR_RANGE_16_235;
break;
default:
return -EINVAL;
}
if (old_auto == intel_sdvo->color_range_auto &&
old_range == intel_sdvo->color_range)
return 0;
goto done;
}
if (property == connector->dev->mode_config.aspect_ratio_property) {
connector->state->picture_aspect_ratio = val;
goto done;
}
#define CHECK_PROPERTY(name, NAME) \
if (intel_sdvo_connector->name == property) { \
if (intel_sdvo_connector->cur_##name == temp_value) return 0; \
if (intel_sdvo_connector->max_##name < temp_value) return -EINVAL; \
cmd = SDVO_CMD_SET_##NAME; \
intel_sdvo_connector->cur_##name = temp_value; \
goto set_value; \
}
if (property == intel_sdvo_connector->tv_format) { if (property == intel_sdvo_connector->tv_format) {
if (val >= TV_FORMAT_NUM) int i;
return -EINVAL;
if (intel_sdvo->tv_format_index == for (i = 0; i < intel_sdvo_connector->format_supported_num; i++)
intel_sdvo_connector->tv_format_supported[val]) if (state->tv.mode == intel_sdvo_connector->tv_format_supported[i]) {
return 0; *val = i;
intel_sdvo->tv_format_index = intel_sdvo_connector->tv_format_supported[val];
goto done;
} else if (IS_TV_OR_LVDS(intel_sdvo_connector)) {
temp_value = val;
if (intel_sdvo_connector->left == property) {
drm_object_property_set_value(&connector->base,
intel_sdvo_connector->right, val);
if (intel_sdvo_connector->left_margin == temp_value)
return 0; return 0;
}
intel_sdvo_connector->left_margin = temp_value; WARN_ON(1);
intel_sdvo_connector->right_margin = temp_value; *val = 0;
temp_value = intel_sdvo_connector->max_hscan - } else if (property == intel_sdvo_connector->top ||
intel_sdvo_connector->left_margin; property == intel_sdvo_connector->bottom)
cmd = SDVO_CMD_SET_OVERSCAN_H; *val = intel_sdvo_connector->max_vscan - sdvo_state->tv.overscan_v;
goto set_value; else if (property == intel_sdvo_connector->left ||
} else if (intel_sdvo_connector->right == property) { property == intel_sdvo_connector->right)
drm_object_property_set_value(&connector->base, *val = intel_sdvo_connector->max_hscan - sdvo_state->tv.overscan_h;
intel_sdvo_connector->left, val); else if (property == intel_sdvo_connector->hpos)
if (intel_sdvo_connector->right_margin == temp_value) *val = sdvo_state->tv.hpos;
return 0; else if (property == intel_sdvo_connector->vpos)
*val = sdvo_state->tv.vpos;
intel_sdvo_connector->left_margin = temp_value; else if (property == intel_sdvo_connector->saturation)
intel_sdvo_connector->right_margin = temp_value; *val = state->tv.saturation;
temp_value = intel_sdvo_connector->max_hscan - else if (property == intel_sdvo_connector->contrast)
intel_sdvo_connector->left_margin; *val = state->tv.contrast;
cmd = SDVO_CMD_SET_OVERSCAN_H; else if (property == intel_sdvo_connector->hue)
goto set_value; *val = state->tv.hue;
} else if (intel_sdvo_connector->top == property) { else if (property == intel_sdvo_connector->brightness)
drm_object_property_set_value(&connector->base, *val = state->tv.brightness;
intel_sdvo_connector->bottom, val); else if (property == intel_sdvo_connector->sharpness)
if (intel_sdvo_connector->top_margin == temp_value) *val = sdvo_state->tv.sharpness;
return 0; else if (property == intel_sdvo_connector->flicker_filter)
*val = sdvo_state->tv.flicker_filter;
intel_sdvo_connector->top_margin = temp_value; else if (property == intel_sdvo_connector->flicker_filter_2d)
intel_sdvo_connector->bottom_margin = temp_value; *val = sdvo_state->tv.flicker_filter_2d;
temp_value = intel_sdvo_connector->max_vscan - else if (property == intel_sdvo_connector->flicker_filter_adaptive)
intel_sdvo_connector->top_margin; *val = sdvo_state->tv.flicker_filter_adaptive;
cmd = SDVO_CMD_SET_OVERSCAN_V; else if (property == intel_sdvo_connector->tv_chroma_filter)
goto set_value; *val = sdvo_state->tv.chroma_filter;
} else if (intel_sdvo_connector->bottom == property) { else if (property == intel_sdvo_connector->tv_luma_filter)
drm_object_property_set_value(&connector->base, *val = sdvo_state->tv.luma_filter;
intel_sdvo_connector->top, val); else if (property == intel_sdvo_connector->dot_crawl)
if (intel_sdvo_connector->bottom_margin == temp_value) *val = sdvo_state->tv.dot_crawl;
return 0; else
return intel_digital_connector_atomic_get_property(connector, state, property, val);
intel_sdvo_connector->top_margin = temp_value;
intel_sdvo_connector->bottom_margin = temp_value; return 0;
temp_value = intel_sdvo_connector->max_vscan - }
intel_sdvo_connector->top_margin;
cmd = SDVO_CMD_SET_OVERSCAN_V; static int
goto set_value; intel_sdvo_connector_atomic_set_property(struct drm_connector *connector,
} struct drm_connector_state *state,
CHECK_PROPERTY(hpos, HPOS) struct drm_property *property,
CHECK_PROPERTY(vpos, VPOS) uint64_t val)
CHECK_PROPERTY(saturation, SATURATION) {
CHECK_PROPERTY(contrast, CONTRAST) struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
CHECK_PROPERTY(hue, HUE) struct intel_sdvo_connector_state *sdvo_state = to_intel_sdvo_connector_state(state);
CHECK_PROPERTY(brightness, BRIGHTNESS)
CHECK_PROPERTY(sharpness, SHARPNESS) if (property == intel_sdvo_connector->tv_format) {
CHECK_PROPERTY(flicker_filter, FLICKER_FILTER) state->tv.mode = intel_sdvo_connector->tv_format_supported[val];
CHECK_PROPERTY(flicker_filter_2d, FLICKER_FILTER_2D)
CHECK_PROPERTY(flicker_filter_adaptive, FLICKER_FILTER_ADAPTIVE) if (state->crtc) {
CHECK_PROPERTY(tv_chroma_filter, TV_CHROMA_FILTER) struct drm_crtc_state *crtc_state =
CHECK_PROPERTY(tv_luma_filter, TV_LUMA_FILTER) drm_atomic_get_new_crtc_state(state->state, state->crtc);
CHECK_PROPERTY(dot_crawl, DOT_CRAWL)
} crtc_state->connectors_changed = true;
}
return -EINVAL; /* unknown property */ } else if (property == intel_sdvo_connector->top ||
property == intel_sdvo_connector->bottom)
set_value: /* Cannot set these independent from each other */
if (!intel_sdvo_set_value(intel_sdvo, cmd, &temp_value, 2)) sdvo_state->tv.overscan_v = intel_sdvo_connector->max_vscan - val;
return -EIO; else if (property == intel_sdvo_connector->left ||
property == intel_sdvo_connector->right)
/* Cannot set these independent from each other */
done: sdvo_state->tv.overscan_h = intel_sdvo_connector->max_hscan - val;
if (intel_sdvo->base.base.crtc) else if (property == intel_sdvo_connector->hpos)
intel_crtc_restore_mode(intel_sdvo->base.base.crtc); sdvo_state->tv.hpos = val;
else if (property == intel_sdvo_connector->vpos)
sdvo_state->tv.vpos = val;
else if (property == intel_sdvo_connector->saturation)
state->tv.saturation = val;
else if (property == intel_sdvo_connector->contrast)
state->tv.contrast = val;
else if (property == intel_sdvo_connector->hue)
state->tv.hue = val;
else if (property == intel_sdvo_connector->brightness)
state->tv.brightness = val;
else if (property == intel_sdvo_connector->sharpness)
sdvo_state->tv.sharpness = val;
else if (property == intel_sdvo_connector->flicker_filter)
sdvo_state->tv.flicker_filter = val;
else if (property == intel_sdvo_connector->flicker_filter_2d)
sdvo_state->tv.flicker_filter_2d = val;
else if (property == intel_sdvo_connector->flicker_filter_adaptive)
sdvo_state->tv.flicker_filter_adaptive = val;
else if (property == intel_sdvo_connector->tv_chroma_filter)
sdvo_state->tv.chroma_filter = val;
else if (property == intel_sdvo_connector->tv_luma_filter)
sdvo_state->tv.luma_filter = val;
else if (property == intel_sdvo_connector->dot_crawl)
sdvo_state->tv.dot_crawl = val;
else
return intel_digital_connector_atomic_set_property(connector, state, property, val);
return 0; return 0;
#undef CHECK_PROPERTY
} }
static int static int
@ -2176,22 +2178,61 @@ intel_sdvo_connector_unregister(struct drm_connector *connector)
intel_connector_unregister(connector); intel_connector_unregister(connector);
} }
static struct drm_connector_state *
intel_sdvo_connector_duplicate_state(struct drm_connector *connector)
{
struct intel_sdvo_connector_state *state;
state = kmemdup(connector->state, sizeof(*state), GFP_KERNEL);
if (!state)
return NULL;
__drm_atomic_helper_connector_duplicate_state(connector, &state->base.base);
return &state->base.base;
}
static const struct drm_connector_funcs intel_sdvo_connector_funcs = { static const struct drm_connector_funcs intel_sdvo_connector_funcs = {
.dpms = drm_atomic_helper_connector_dpms, .dpms = drm_atomic_helper_connector_dpms,
.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, .set_property = drm_atomic_helper_connector_set_property,
.atomic_get_property = intel_connector_atomic_get_property, .atomic_get_property = intel_sdvo_connector_atomic_get_property,
.atomic_set_property = intel_sdvo_connector_atomic_set_property,
.late_register = intel_sdvo_connector_register, .late_register = intel_sdvo_connector_register,
.early_unregister = intel_sdvo_connector_unregister, .early_unregister = intel_sdvo_connector_unregister,
.destroy = intel_sdvo_destroy, .destroy = intel_sdvo_destroy,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state, .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, .atomic_duplicate_state = intel_sdvo_connector_duplicate_state,
}; };
static int intel_sdvo_atomic_check(struct drm_connector *conn,
struct drm_connector_state *new_conn_state)
{
struct drm_atomic_state *state = new_conn_state->state;
struct drm_connector_state *old_conn_state =
drm_atomic_get_old_connector_state(state, conn);
struct intel_sdvo_connector_state *old_state =
to_intel_sdvo_connector_state(old_conn_state);
struct intel_sdvo_connector_state *new_state =
to_intel_sdvo_connector_state(new_conn_state);
if (new_conn_state->crtc &&
(memcmp(&old_state->tv, &new_state->tv, sizeof(old_state->tv)) ||
memcmp(&old_conn_state->tv, &new_conn_state->tv, sizeof(old_conn_state->tv)))) {
struct drm_crtc_state *crtc_state =
drm_atomic_get_new_crtc_state(new_conn_state->state,
new_conn_state->crtc);
crtc_state->connectors_changed = true;
}
return intel_digital_connector_atomic_check(conn, new_conn_state);
}
static const struct drm_connector_helper_funcs intel_sdvo_connector_helper_funcs = { static const struct drm_connector_helper_funcs intel_sdvo_connector_helper_funcs = {
.get_modes = intel_sdvo_get_modes, .get_modes = intel_sdvo_get_modes,
.mode_valid = intel_sdvo_mode_valid, .mode_valid = intel_sdvo_mode_valid,
.atomic_check = intel_sdvo_atomic_check,
}; };
static void intel_sdvo_enc_destroy(struct drm_encoder *encoder) static void intel_sdvo_enc_destroy(struct drm_encoder *encoder)
@ -2383,7 +2424,6 @@ intel_sdvo_add_hdmi_properties(struct intel_sdvo *intel_sdvo,
intel_attach_force_audio_property(&connector->base.base); intel_attach_force_audio_property(&connector->base.base);
if (INTEL_GEN(dev_priv) >= 4 && IS_MOBILE(dev_priv)) { if (INTEL_GEN(dev_priv) >= 4 && IS_MOBILE(dev_priv)) {
intel_attach_broadcast_rgb_property(&connector->base.base); intel_attach_broadcast_rgb_property(&connector->base.base);
intel_sdvo->color_range_auto = true;
} }
intel_attach_aspect_ratio_property(&connector->base.base); intel_attach_aspect_ratio_property(&connector->base.base);
connector->base.base.state->picture_aspect_ratio = HDMI_PICTURE_ASPECT_NONE; connector->base.base.state->picture_aspect_ratio = HDMI_PICTURE_ASPECT_NONE;
@ -2392,16 +2432,21 @@ intel_sdvo_add_hdmi_properties(struct intel_sdvo *intel_sdvo,
static struct intel_sdvo_connector *intel_sdvo_connector_alloc(void) static struct intel_sdvo_connector *intel_sdvo_connector_alloc(void)
{ {
struct intel_sdvo_connector *sdvo_connector; struct intel_sdvo_connector *sdvo_connector;
struct intel_sdvo_connector_state *conn_state;
sdvo_connector = kzalloc(sizeof(*sdvo_connector), GFP_KERNEL); sdvo_connector = kzalloc(sizeof(*sdvo_connector), GFP_KERNEL);
if (!sdvo_connector) if (!sdvo_connector)
return NULL; return NULL;
if (intel_connector_init(&sdvo_connector->base) < 0) { conn_state = kzalloc(sizeof(*conn_state), GFP_KERNEL);
if (!conn_state) {
kfree(sdvo_connector); kfree(sdvo_connector);
return NULL; return NULL;
} }
__drm_atomic_helper_connector_reset(&sdvo_connector->base.base,
&conn_state->base.base);
return sdvo_connector; return sdvo_connector;
} }
@ -2693,31 +2738,30 @@ static bool intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo,
intel_sdvo_connector->tv_format, i, intel_sdvo_connector->tv_format, i,
i, tv_format_names[intel_sdvo_connector->tv_format_supported[i]]); i, tv_format_names[intel_sdvo_connector->tv_format_supported[i]]);
intel_sdvo->tv_format_index = intel_sdvo_connector->tv_format_supported[0]; intel_sdvo_connector->base.base.state->tv.mode = intel_sdvo_connector->tv_format_supported[0];
drm_object_attach_property(&intel_sdvo_connector->base.base.base, drm_object_attach_property(&intel_sdvo_connector->base.base.base, 0, 0);
intel_sdvo_connector->tv_format, 0);
return true; return true;
} }
#define ENHANCEMENT(name, NAME) do { \ #define _ENHANCEMENT(state_assignment, name, NAME) do { \
if (enhancements.name) { \ if (enhancements.name) { \
if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_MAX_##NAME, &data_value, 4) || \ if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_MAX_##NAME, &data_value, 4) || \
!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_##NAME, &response, 2)) \ !intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_##NAME, &response, 2)) \
return false; \ return false; \
intel_sdvo_connector->max_##name = data_value[0]; \
intel_sdvo_connector->cur_##name = response; \
intel_sdvo_connector->name = \ intel_sdvo_connector->name = \
drm_property_create_range(dev, 0, #name, 0, data_value[0]); \ drm_property_create_range(dev, 0, #name, 0, data_value[0]); \
if (!intel_sdvo_connector->name) return false; \ if (!intel_sdvo_connector->name) return false; \
state_assignment = response; \
drm_object_attach_property(&connector->base, \ drm_object_attach_property(&connector->base, \
intel_sdvo_connector->name, \ intel_sdvo_connector->name, 0); \
intel_sdvo_connector->cur_##name); \
DRM_DEBUG_KMS(#name ": max %d, default %d, current %d\n", \ DRM_DEBUG_KMS(#name ": max %d, default %d, current %d\n", \
data_value[0], data_value[1], response); \ data_value[0], data_value[1], response); \
} \ } \
} while (0) } while (0)
#define ENHANCEMENT(state, name, NAME) _ENHANCEMENT((state)->name, name, NAME)
static bool static bool
intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo, intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo,
struct intel_sdvo_connector *intel_sdvo_connector, struct intel_sdvo_connector *intel_sdvo_connector,
@ -2725,6 +2769,9 @@ intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo,
{ {
struct drm_device *dev = intel_sdvo->base.base.dev; struct drm_device *dev = intel_sdvo->base.base.dev;
struct drm_connector *connector = &intel_sdvo_connector->base.base; struct drm_connector *connector = &intel_sdvo_connector->base.base;
struct drm_connector_state *conn_state = connector->state;
struct intel_sdvo_connector_state *sdvo_state =
to_intel_sdvo_connector_state(conn_state);
uint16_t response, data_value[2]; uint16_t response, data_value[2];
/* when horizontal overscan is supported, Add the left/right property */ /* when horizontal overscan is supported, Add the left/right property */
@ -2739,17 +2786,16 @@ intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo,
&response, 2)) &response, 2))
return false; return false;
sdvo_state->tv.overscan_h = response;
intel_sdvo_connector->max_hscan = data_value[0]; intel_sdvo_connector->max_hscan = data_value[0];
intel_sdvo_connector->left_margin = data_value[0] - response;
intel_sdvo_connector->right_margin = intel_sdvo_connector->left_margin;
intel_sdvo_connector->left = intel_sdvo_connector->left =
drm_property_create_range(dev, 0, "left_margin", 0, data_value[0]); drm_property_create_range(dev, 0, "left_margin", 0, data_value[0]);
if (!intel_sdvo_connector->left) if (!intel_sdvo_connector->left)
return false; return false;
drm_object_attach_property(&connector->base, drm_object_attach_property(&connector->base,
intel_sdvo_connector->left, intel_sdvo_connector->left, 0);
intel_sdvo_connector->left_margin);
intel_sdvo_connector->right = intel_sdvo_connector->right =
drm_property_create_range(dev, 0, "right_margin", 0, data_value[0]); drm_property_create_range(dev, 0, "right_margin", 0, data_value[0]);
@ -2757,8 +2803,7 @@ intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo,
return false; return false;
drm_object_attach_property(&connector->base, drm_object_attach_property(&connector->base,
intel_sdvo_connector->right, intel_sdvo_connector->right, 0);
intel_sdvo_connector->right_margin);
DRM_DEBUG_KMS("h_overscan: max %d, " DRM_DEBUG_KMS("h_overscan: max %d, "
"default %d, current %d\n", "default %d, current %d\n",
data_value[0], data_value[1], response); data_value[0], data_value[1], response);
@ -2775,9 +2820,9 @@ intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo,
&response, 2)) &response, 2))
return false; return false;
sdvo_state->tv.overscan_v = response;
intel_sdvo_connector->max_vscan = data_value[0]; intel_sdvo_connector->max_vscan = data_value[0];
intel_sdvo_connector->top_margin = data_value[0] - response;
intel_sdvo_connector->bottom_margin = intel_sdvo_connector->top_margin;
intel_sdvo_connector->top = intel_sdvo_connector->top =
drm_property_create_range(dev, 0, drm_property_create_range(dev, 0,
"top_margin", 0, data_value[0]); "top_margin", 0, data_value[0]);
@ -2785,8 +2830,7 @@ intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo,
return false; return false;
drm_object_attach_property(&connector->base, drm_object_attach_property(&connector->base,
intel_sdvo_connector->top, intel_sdvo_connector->top, 0);
intel_sdvo_connector->top_margin);
intel_sdvo_connector->bottom = intel_sdvo_connector->bottom =
drm_property_create_range(dev, 0, drm_property_create_range(dev, 0,
@ -2795,40 +2839,37 @@ intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo,
return false; return false;
drm_object_attach_property(&connector->base, drm_object_attach_property(&connector->base,
intel_sdvo_connector->bottom, intel_sdvo_connector->bottom, 0);
intel_sdvo_connector->bottom_margin);
DRM_DEBUG_KMS("v_overscan: max %d, " DRM_DEBUG_KMS("v_overscan: max %d, "
"default %d, current %d\n", "default %d, current %d\n",
data_value[0], data_value[1], response); data_value[0], data_value[1], response);
} }
ENHANCEMENT(hpos, HPOS); ENHANCEMENT(&sdvo_state->tv, hpos, HPOS);
ENHANCEMENT(vpos, VPOS); ENHANCEMENT(&sdvo_state->tv, vpos, VPOS);
ENHANCEMENT(saturation, SATURATION); ENHANCEMENT(&conn_state->tv, saturation, SATURATION);
ENHANCEMENT(contrast, CONTRAST); ENHANCEMENT(&conn_state->tv, contrast, CONTRAST);
ENHANCEMENT(hue, HUE); ENHANCEMENT(&conn_state->tv, hue, HUE);
ENHANCEMENT(sharpness, SHARPNESS); ENHANCEMENT(&conn_state->tv, brightness, BRIGHTNESS);
ENHANCEMENT(brightness, BRIGHTNESS); ENHANCEMENT(&sdvo_state->tv, sharpness, SHARPNESS);
ENHANCEMENT(flicker_filter, FLICKER_FILTER); ENHANCEMENT(&sdvo_state->tv, flicker_filter, FLICKER_FILTER);
ENHANCEMENT(flicker_filter_adaptive, FLICKER_FILTER_ADAPTIVE); ENHANCEMENT(&sdvo_state->tv, flicker_filter_adaptive, FLICKER_FILTER_ADAPTIVE);
ENHANCEMENT(flicker_filter_2d, FLICKER_FILTER_2D); ENHANCEMENT(&sdvo_state->tv, flicker_filter_2d, FLICKER_FILTER_2D);
ENHANCEMENT(tv_chroma_filter, TV_CHROMA_FILTER); _ENHANCEMENT(sdvo_state->tv.chroma_filter, tv_chroma_filter, TV_CHROMA_FILTER);
ENHANCEMENT(tv_luma_filter, TV_LUMA_FILTER); _ENHANCEMENT(sdvo_state->tv.luma_filter, tv_luma_filter, TV_LUMA_FILTER);
if (enhancements.dot_crawl) { if (enhancements.dot_crawl) {
if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_DOT_CRAWL, &response, 2)) if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_DOT_CRAWL, &response, 2))
return false; return false;
intel_sdvo_connector->max_dot_crawl = 1; sdvo_state->tv.dot_crawl = response & 0x1;
intel_sdvo_connector->cur_dot_crawl = response & 0x1;
intel_sdvo_connector->dot_crawl = intel_sdvo_connector->dot_crawl =
drm_property_create_range(dev, 0, "dot_crawl", 0, 1); drm_property_create_range(dev, 0, "dot_crawl", 0, 1);
if (!intel_sdvo_connector->dot_crawl) if (!intel_sdvo_connector->dot_crawl)
return false; return false;
drm_object_attach_property(&connector->base, drm_object_attach_property(&connector->base,
intel_sdvo_connector->dot_crawl, intel_sdvo_connector->dot_crawl, 0);
intel_sdvo_connector->cur_dot_crawl);
DRM_DEBUG_KMS("dot crawl: current %d\n", response); DRM_DEBUG_KMS("dot crawl: current %d\n", response);
} }
@ -2844,11 +2885,12 @@ intel_sdvo_create_enhance_property_lvds(struct intel_sdvo *intel_sdvo,
struct drm_connector *connector = &intel_sdvo_connector->base.base; struct drm_connector *connector = &intel_sdvo_connector->base.base;
uint16_t response, data_value[2]; uint16_t response, data_value[2];
ENHANCEMENT(brightness, BRIGHTNESS); ENHANCEMENT(&connector->state->tv, brightness, BRIGHTNESS);
return true; return true;
} }
#undef ENHANCEMENT #undef ENHANCEMENT
#undef _ENHANCEMENT
static bool intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo, static bool intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo,
struct intel_sdvo_connector *intel_sdvo_connector) struct intel_sdvo_connector *intel_sdvo_connector)