28,12 → 28,12 |
#include <linux/i2c.h> |
#include <linux/slab.h> |
//#include <linux/delay.h> |
#include "drmP.h" |
#include "drm.h" |
#include "drm_crtc.h" |
#include "drm_edid.h" |
#include <linux/export.h> |
#include <drm/drmP.h> |
#include <drm/drm_crtc.h> |
#include <drm/drm_edid.h> |
#include "intel_drv.h" |
#include "i915_drm.h" |
#include <drm/i915_drm.h> |
#include "i915_drv.h" |
#include "intel_sdvo_regs.h" |
|
49,7 → 49,7 |
#define SDVO_TMDS_MASK (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1) |
#define SDVO_RGB_MASK (SDVO_OUTPUT_RGB0 | SDVO_OUTPUT_RGB1) |
#define SDVO_LVDS_MASK (SDVO_OUTPUT_LVDS0 | SDVO_OUTPUT_LVDS1) |
#define SDVO_TV_MASK (SDVO_OUTPUT_CVBS0 | SDVO_OUTPUT_SVID0) |
#define SDVO_TV_MASK (SDVO_OUTPUT_CVBS0 | SDVO_OUTPUT_SVID0 | SDVO_OUTPUT_YPRPB0) |
|
#define SDVO_OUTPUT_MASK (SDVO_TMDS_MASK | SDVO_RGB_MASK | SDVO_LVDS_MASK |\ |
SDVO_TV_MASK) |
82,7 → 82,7 |
struct i2c_adapter ddc; |
|
/* Register for the SDVO device: SDVOB or SDVOC */ |
int sdvo_reg; |
uint32_t sdvo_reg; |
|
/* Active outputs controlled by this SDVO output */ |
uint16_t controlled_output; |
105,7 → 105,7 |
/* |
* Hotplug activation bits for this device |
*/ |
uint8_t hotplug_active[2]; |
uint16_t hotplug_active; |
|
/** |
* This is used to select the color range of RBG outputs in HDMI mode. |
122,6 → 122,9 |
*/ |
bool is_tv; |
|
/* On different gens SDVOB is at different places. */ |
bool is_sdvob; |
|
/* This is for current tv format name */ |
int tv_format_index; |
|
146,8 → 149,10 |
/* DDC bus used by this SDVO encoder */ |
uint8_t ddc_bus; |
|
/* Input timings for adjusted_mode */ |
struct intel_sdvo_dtd input_dtd; |
/* |
* the sdvo flag gets lost in round trip: dtd->adjusted_mode->dtd |
*/ |
uint8_t dtd_sdvo_flags; |
}; |
|
struct intel_sdvo_connector { |
156,7 → 161,7 |
/* Mark the type of connector */ |
uint16_t output_flag; |
|
int force_audio; |
enum hdmi_force_audio force_audio; |
|
/* This contains all current supported TV format */ |
u8 tv_format_supported[TV_FORMAT_NUM]; |
411,8 → 416,7 |
SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HBUF_DATA), |
}; |
|
#define IS_SDVOB(reg) (reg == SDVOB || reg == PCH_SDVOB) |
#define SDVO_NAME(svdo) (IS_SDVOB((svdo)->sdvo_reg) ? "SDVOB" : "SDVOC") |
#define SDVO_NAME(svdo) ((svdo)->is_sdvob ? "SDVOB" : "SDVOC") |
|
static void intel_sdvo_debug_write(struct intel_sdvo *intel_sdvo, u8 cmd, |
const void *args, int args_len) |
449,10 → 453,21 |
static bool intel_sdvo_write_cmd(struct intel_sdvo *intel_sdvo, u8 cmd, |
const void *args, int args_len) |
{ |
u8 buf[args_len*2 + 2], status; |
struct i2c_msg msgs[args_len + 3]; |
int i, ret; |
u8 *buf, status; |
struct i2c_msg *msgs; |
int i, ret = true; |
|
/* Would be simpler to allocate both in one go ? */ |
buf = (u8 *)kzalloc(args_len * 2 + 2, GFP_KERNEL); |
if (!buf) |
return false; |
|
msgs = kcalloc(args_len + 3, sizeof(*msgs), GFP_KERNEL); |
if (!msgs) { |
kfree(buf); |
return false; |
} |
|
intel_sdvo_debug_write(intel_sdvo, cmd, args, args_len); |
|
for (i = 0; i < args_len; i++) { |
485,15 → 500,19 |
ret = i2c_transfer(intel_sdvo->i2c, msgs, i+3); |
if (ret < 0) { |
DRM_DEBUG_KMS("I2c transfer returned %d\n", ret); |
return false; |
ret = false; |
goto out; |
} |
if (ret != i+3) { |
/* failure in I2C transfer */ |
DRM_DEBUG_KMS("I2c transfer returned %d/%d\n", ret, i+3); |
return false; |
ret = false; |
} |
|
return true; |
out: |
kfree(msgs); |
kfree(buf); |
return ret; |
} |
|
static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo, |
622,6 → 641,14 |
&outputs, sizeof(outputs)); |
} |
|
static bool intel_sdvo_get_active_outputs(struct intel_sdvo *intel_sdvo, |
u16 *outputs) |
{ |
return intel_sdvo_get_value(intel_sdvo, |
SDVO_CMD_GET_ACTIVE_OUTPUTS, |
outputs, sizeof(*outputs)); |
} |
|
static bool intel_sdvo_set_encoder_power_state(struct intel_sdvo *intel_sdvo, |
int mode) |
{ |
739,21 → 766,26 |
uint16_t width, height; |
uint16_t h_blank_len, h_sync_len, v_blank_len, v_sync_len; |
uint16_t h_sync_offset, v_sync_offset; |
int mode_clock; |
|
width = mode->crtc_hdisplay; |
height = mode->crtc_vdisplay; |
width = mode->hdisplay; |
height = mode->vdisplay; |
|
/* do some mode translations */ |
h_blank_len = mode->crtc_hblank_end - mode->crtc_hblank_start; |
h_sync_len = mode->crtc_hsync_end - mode->crtc_hsync_start; |
h_blank_len = mode->htotal - mode->hdisplay; |
h_sync_len = mode->hsync_end - mode->hsync_start; |
|
v_blank_len = mode->crtc_vblank_end - mode->crtc_vblank_start; |
v_sync_len = mode->crtc_vsync_end - mode->crtc_vsync_start; |
v_blank_len = mode->vtotal - mode->vdisplay; |
v_sync_len = mode->vsync_end - mode->vsync_start; |
|
h_sync_offset = mode->crtc_hsync_start - mode->crtc_hblank_start; |
v_sync_offset = mode->crtc_vsync_start - mode->crtc_vblank_start; |
h_sync_offset = mode->hsync_start - mode->hdisplay; |
v_sync_offset = mode->vsync_start - mode->vdisplay; |
|
dtd->part1.clock = mode->clock / 10; |
mode_clock = mode->clock; |
mode_clock /= intel_mode_get_pixel_multiplier(mode) ?: 1; |
mode_clock /= 10; |
dtd->part1.clock = mode_clock; |
|
dtd->part1.h_active = width & 0xff; |
dtd->part1.h_blank = h_blank_len & 0xff; |
dtd->part1.h_high = (((width >> 8) & 0xf) << 4) | |
772,10 → 804,12 |
((v_sync_len & 0x30) >> 4); |
|
dtd->part2.dtd_flags = 0x18; |
if (mode->flags & DRM_MODE_FLAG_INTERLACE) |
dtd->part2.dtd_flags |= DTD_FLAG_INTERLACE; |
if (mode->flags & DRM_MODE_FLAG_PHSYNC) |
dtd->part2.dtd_flags |= 0x2; |
dtd->part2.dtd_flags |= DTD_FLAG_HSYNC_POSITIVE; |
if (mode->flags & DRM_MODE_FLAG_PVSYNC) |
dtd->part2.dtd_flags |= 0x4; |
dtd->part2.dtd_flags |= DTD_FLAG_VSYNC_POSITIVE; |
|
dtd->part2.sdvo_flags = 0; |
dtd->part2.v_sync_off_high = v_sync_offset & 0xc0; |
809,9 → 843,11 |
mode->clock = dtd->part1.clock * 10; |
|
mode->flags &= ~(DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC); |
if (dtd->part2.dtd_flags & 0x2) |
if (dtd->part2.dtd_flags & DTD_FLAG_INTERLACE) |
mode->flags |= DRM_MODE_FLAG_INTERLACE; |
if (dtd->part2.dtd_flags & DTD_FLAG_HSYNC_POSITIVE) |
mode->flags |= DRM_MODE_FLAG_PHSYNC; |
if (dtd->part2.dtd_flags & 0x4) |
if (dtd->part2.dtd_flags & DTD_FLAG_VSYNC_POSITIVE) |
mode->flags |= DRM_MODE_FLAG_PVSYNC; |
} |
|
867,31 → 903,38 |
} |
#endif |
|
static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo) |
static bool intel_sdvo_write_infoframe(struct intel_sdvo *intel_sdvo, |
unsigned if_index, uint8_t tx_rate, |
uint8_t *data, unsigned length) |
{ |
struct dip_infoframe avi_if = { |
.type = DIP_TYPE_AVI, |
.ver = DIP_VERSION_AVI, |
.len = DIP_LEN_AVI, |
}; |
uint8_t tx_rate = SDVO_HBUF_TX_VSYNC; |
uint8_t set_buf_index[2] = { 1, 0 }; |
uint64_t *data = (uint64_t *)&avi_if; |
unsigned i; |
uint8_t set_buf_index[2] = { if_index, 0 }; |
uint8_t hbuf_size, tmp[8]; |
int i; |
|
intel_dip_infoframe_csum(&avi_if); |
|
if (!intel_sdvo_set_value(intel_sdvo, |
SDVO_CMD_SET_HBUF_INDEX, |
set_buf_index, 2)) |
return false; |
|
for (i = 0; i < sizeof(avi_if); i += 8) { |
if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_HBUF_INFO, |
&hbuf_size, 1)) |
return false; |
|
/* Buffer size is 0 based, hooray! */ |
hbuf_size++; |
|
DRM_DEBUG_KMS("writing sdvo hbuf: %i, hbuf_size %i, hbuf_size: %i\n", |
if_index, length, hbuf_size); |
|
for (i = 0; i < hbuf_size; i += 8) { |
memset(tmp, 0, 8); |
if (i < length) |
memcpy(tmp, data + i, min_t(unsigned, 8, length - i)); |
|
if (!intel_sdvo_set_value(intel_sdvo, |
SDVO_CMD_SET_HBUF_DATA, |
data, 8)) |
tmp, 8)) |
return false; |
data++; |
} |
|
return intel_sdvo_set_value(intel_sdvo, |
899,6 → 942,28 |
&tx_rate, 1); |
} |
|
static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo) |
{ |
struct dip_infoframe avi_if = { |
.type = DIP_TYPE_AVI, |
.ver = DIP_VERSION_AVI, |
.len = DIP_LEN_AVI, |
}; |
uint8_t sdvo_data[4 + sizeof(avi_if.body.avi)]; |
|
intel_dip_infoframe_csum(&avi_if); |
|
/* sdvo spec says that the ecc is handled by the hw, and it looks like |
* we must not send the ecc field, either. */ |
memcpy(sdvo_data, &avi_if, 3); |
sdvo_data[3] = avi_if.checksum; |
memcpy(&sdvo_data[4], &avi_if.body, sizeof(avi_if.body.avi)); |
|
return intel_sdvo_write_infoframe(intel_sdvo, SDVO_HBUF_INDEX_AVI_IF, |
SDVO_HBUF_TX_VSYNC, |
sdvo_data, sizeof(sdvo_data)); |
} |
|
static bool intel_sdvo_set_tv_format(struct intel_sdvo *intel_sdvo) |
{ |
struct intel_sdvo_tv_format format; |
916,7 → 981,7 |
|
static bool |
intel_sdvo_set_output_timings_from_mode(struct intel_sdvo *intel_sdvo, |
struct drm_display_mode *mode) |
const struct drm_display_mode *mode) |
{ |
struct intel_sdvo_dtd output_dtd; |
|
931,11 → 996,15 |
return true; |
} |
|
/* Asks the sdvo controller for the preferred input mode given the output mode. |
* Unfortunately we have to set up the full output mode to do that. */ |
static bool |
intel_sdvo_set_input_timings_for_mode(struct intel_sdvo *intel_sdvo, |
struct drm_display_mode *mode, |
intel_sdvo_get_preferred_input_mode(struct intel_sdvo *intel_sdvo, |
const struct drm_display_mode *mode, |
struct drm_display_mode *adjusted_mode) |
{ |
struct intel_sdvo_dtd input_dtd; |
|
/* Reset the input timing to the screen. Assume always input 0. */ |
if (!intel_sdvo_set_target_input(intel_sdvo)) |
return false; |
947,17 → 1016,17 |
return false; |
|
if (!intel_sdvo_get_preferred_input_timing(intel_sdvo, |
&intel_sdvo->input_dtd)) |
&input_dtd)) |
return false; |
|
intel_sdvo_get_mode_from_dtd(adjusted_mode, &intel_sdvo->input_dtd); |
intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd); |
intel_sdvo->dtd_sdvo_flags = input_dtd.part2.sdvo_flags; |
|
drm_mode_set_crtcinfo(adjusted_mode, 0); |
return true; |
} |
|
static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, |
struct drm_display_mode *mode, |
const struct drm_display_mode *mode, |
struct drm_display_mode *adjusted_mode) |
{ |
struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder); |
972,7 → 1041,7 |
if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo, mode)) |
return false; |
|
(void) intel_sdvo_set_input_timings_for_mode(intel_sdvo, |
(void) intel_sdvo_get_preferred_input_mode(intel_sdvo, |
mode, |
adjusted_mode); |
} else if (intel_sdvo->is_lvds) { |
980,7 → 1049,7 |
intel_sdvo->sdvo_lvds_fixed_mode)) |
return false; |
|
(void) intel_sdvo_set_input_timings_for_mode(intel_sdvo, |
(void) intel_sdvo_get_preferred_input_mode(intel_sdvo, |
mode, |
adjusted_mode); |
} |
1005,7 → 1074,7 |
struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder); |
u32 sdvox; |
struct intel_sdvo_in_out_map in_out; |
struct intel_sdvo_dtd input_dtd; |
struct intel_sdvo_dtd input_dtd, output_dtd; |
int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode); |
int rate; |
|
1030,21 → 1099,16 |
intel_sdvo->attached_output)) |
return; |
|
/* We have tried to get input timing in mode_fixup, and filled into |
* adjusted_mode. |
*/ |
if (intel_sdvo->is_tv || intel_sdvo->is_lvds) { |
input_dtd = intel_sdvo->input_dtd; |
} else { |
/* Set the output timing to the screen */ |
if (!intel_sdvo_set_target_output(intel_sdvo, |
intel_sdvo->attached_output)) |
return; |
/* lvds has a special fixed output timing. */ |
if (intel_sdvo->is_lvds) |
intel_sdvo_get_dtd_from_mode(&output_dtd, |
intel_sdvo->sdvo_lvds_fixed_mode); |
else |
intel_sdvo_get_dtd_from_mode(&output_dtd, mode); |
if (!intel_sdvo_set_output_timing(intel_sdvo, &output_dtd)) |
DRM_INFO("Setting output timings on %s failed\n", |
SDVO_NAME(intel_sdvo)); |
|
intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode); |
(void) intel_sdvo_set_output_timing(intel_sdvo, &input_dtd); |
} |
|
/* Set the input timing to the screen. Assume always input 0. */ |
if (!intel_sdvo_set_target_input(intel_sdvo)) |
return; |
1061,7 → 1125,15 |
!intel_sdvo_set_tv_format(intel_sdvo)) |
return; |
|
(void) intel_sdvo_set_input_timing(intel_sdvo, &input_dtd); |
/* We have tried to get input timing in mode_fixup, and filled into |
* adjusted_mode. |
*/ |
intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode); |
if (intel_sdvo->is_tv || intel_sdvo->is_lvds) |
input_dtd.part2.sdvo_flags = intel_sdvo->dtd_sdvo_flags; |
if (!intel_sdvo_set_input_timing(intel_sdvo, &input_dtd)) |
DRM_INFO("Setting input timings on %s failed\n", |
SDVO_NAME(intel_sdvo)); |
|
switch (pixel_multiplier) { |
default: |
1116,26 → 1188,66 |
intel_sdvo_write_sdvox(intel_sdvo, sdvox); |
} |
|
static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode) |
static bool intel_sdvo_connector_get_hw_state(struct intel_connector *connector) |
{ |
struct drm_device *dev = encoder->dev; |
struct intel_sdvo_connector *intel_sdvo_connector = |
to_intel_sdvo_connector(&connector->base); |
struct intel_sdvo *intel_sdvo = intel_attached_sdvo(&connector->base); |
u16 active_outputs; |
|
intel_sdvo_get_active_outputs(intel_sdvo, &active_outputs); |
|
if (active_outputs & intel_sdvo_connector->output_flag) |
return true; |
else |
return false; |
} |
|
static bool intel_sdvo_get_hw_state(struct intel_encoder *encoder, |
enum pipe *pipe) |
{ |
struct drm_device *dev = encoder->base.dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder); |
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); |
struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base); |
u32 tmp; |
|
tmp = I915_READ(intel_sdvo->sdvo_reg); |
|
if (!(tmp & SDVO_ENABLE)) |
return false; |
|
if (HAS_PCH_CPT(dev)) |
*pipe = PORT_TO_PIPE_CPT(tmp); |
else |
*pipe = PORT_TO_PIPE(tmp); |
|
return true; |
} |
|
static void intel_disable_sdvo(struct intel_encoder *encoder) |
{ |
struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; |
struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base); |
u32 temp; |
|
if (mode != DRM_MODE_DPMS_ON) { |
intel_sdvo_set_active_outputs(intel_sdvo, 0); |
if (0) |
intel_sdvo_set_encoder_power_state(intel_sdvo, mode); |
intel_sdvo_set_encoder_power_state(intel_sdvo, |
DRM_MODE_DPMS_OFF); |
|
if (mode == DRM_MODE_DPMS_OFF) { |
temp = I915_READ(intel_sdvo->sdvo_reg); |
if ((temp & SDVO_ENABLE) != 0) { |
intel_sdvo_write_sdvox(intel_sdvo, temp & ~SDVO_ENABLE); |
} |
} |
} else { |
|
static void intel_enable_sdvo(struct intel_encoder *encoder) |
{ |
struct drm_device *dev = encoder->base.dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base); |
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); |
u32 temp; |
bool input1, input2; |
int i; |
u8 status; |
1157,12 → 1269,53 |
} |
|
if (0) |
intel_sdvo_set_encoder_power_state(intel_sdvo, mode); |
intel_sdvo_set_encoder_power_state(intel_sdvo, |
DRM_MODE_DPMS_ON); |
intel_sdvo_set_active_outputs(intel_sdvo, intel_sdvo->attached_output); |
} |
|
static void intel_sdvo_dpms(struct drm_connector *connector, int mode) |
{ |
struct drm_crtc *crtc; |
struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector); |
|
/* dvo supports only 2 dpms states. */ |
if (mode != DRM_MODE_DPMS_ON) |
mode = DRM_MODE_DPMS_OFF; |
|
if (mode == connector->dpms) |
return; |
|
connector->dpms = mode; |
|
/* Only need to change hw state when actually enabled */ |
crtc = intel_sdvo->base.base.crtc; |
if (!crtc) { |
intel_sdvo->base.connectors_active = false; |
return; |
} |
|
if (mode != DRM_MODE_DPMS_ON) { |
intel_sdvo_set_active_outputs(intel_sdvo, 0); |
if (0) |
intel_sdvo_set_encoder_power_state(intel_sdvo, mode); |
|
intel_sdvo->base.connectors_active = false; |
|
intel_crtc_update_dpms(crtc); |
} else { |
intel_sdvo->base.connectors_active = true; |
|
intel_crtc_update_dpms(crtc); |
|
if (0) |
intel_sdvo_set_encoder_power_state(intel_sdvo, mode); |
intel_sdvo_set_active_outputs(intel_sdvo, intel_sdvo->attached_output); |
} |
|
intel_modeset_check_state(connector->dev); |
} |
|
static int intel_sdvo_mode_valid(struct drm_connector *connector, |
struct drm_display_mode *mode) |
{ |
1225,12 → 1378,21 |
return true; |
} |
|
static int intel_sdvo_supports_hotplug(struct intel_sdvo *intel_sdvo) |
static uint16_t intel_sdvo_get_hotplug_support(struct intel_sdvo *intel_sdvo) |
{ |
u8 response[2]; |
struct drm_device *dev = intel_sdvo->base.base.dev; |
uint16_t hotplug; |
|
return intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_HOT_PLUG_SUPPORT, |
&response, 2) && response[0]; |
/* HW Erratum: SDVO Hotplug is broken on all i945G chips, there's noise |
* on the line. */ |
if (IS_I945G(dev) || IS_I945GM(dev)) |
return 0; |
|
if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_HOT_PLUG_SUPPORT, |
&hotplug, sizeof(hotplug))) |
return 0; |
|
return hotplug; |
} |
|
static void intel_sdvo_enable_hotplug(struct intel_encoder *encoder) |
1237,7 → 1399,8 |
{ |
struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base); |
|
intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &intel_sdvo->hotplug_active, 2); |
intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ACTIVE_HOT_PLUG, |
&intel_sdvo->hotplug_active, 2); |
} |
|
static bool |
1261,10 → 1424,11 |
struct drm_i915_private *dev_priv = connector->dev->dev_private; |
|
return drm_get_edid(connector, |
&dev_priv->gmbus[dev_priv->crt_ddc_pin].adapter); |
intel_gmbus_get_adapter(dev_priv, |
dev_priv->crt_ddc_pin)); |
} |
|
enum drm_connector_status |
static enum drm_connector_status |
intel_sdvo_tmds_sink_detect(struct drm_connector *connector) |
{ |
struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector); |
1312,14 → 1476,13 |
} |
} else |
status = connector_status_disconnected; |
connector->display_info.raw_edid = NULL; |
kfree(edid); |
} |
|
if (status == connector_status_connected) { |
struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); |
if (intel_sdvo_connector->force_audio) |
intel_sdvo->has_hdmi_audio = intel_sdvo_connector->force_audio > 0; |
if (intel_sdvo_connector->force_audio != HDMI_AUDIO_AUTO) |
intel_sdvo->has_hdmi_audio = (intel_sdvo_connector->force_audio == HDMI_AUDIO_ON); |
} |
|
return status; |
1350,9 → 1513,8 |
return connector_status_unknown; |
|
/* add 30ms delay when the output type might be TV */ |
if (intel_sdvo->caps.output_flags & |
(SDVO_OUTPUT_SVID0 | SDVO_OUTPUT_CVBS0)) |
mdelay(30); |
if (intel_sdvo->caps.output_flags & SDVO_TV_MASK) |
msleep(30); |
|
if (!intel_sdvo_read_response(intel_sdvo, &response, 2)) |
return connector_status_unknown; |
1387,7 → 1549,6 |
else |
ret = connector_status_disconnected; |
|
connector->display_info.raw_edid = NULL; |
kfree(edid); |
} else |
ret = connector_status_connected; |
1433,7 → 1594,6 |
drm_add_edid_modes(connector, edid); |
} |
|
connector->display_info.raw_edid = NULL; |
kfree(edid); |
} |
} |
1571,9 → 1731,6 |
intel_sdvo->sdvo_lvds_fixed_mode = |
drm_mode_duplicate(connector->dev, newmode); |
|
drm_mode_set_crtcinfo(intel_sdvo->sdvo_lvds_fixed_mode, |
0); |
|
intel_sdvo->is_lvds = true; |
break; |
} |
1651,9 → 1808,22 |
kfree(connector); |
} |
|
static bool intel_sdvo_detect_hdmi_audio(struct drm_connector *connector) |
{ |
struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector); |
struct edid *edid; |
bool has_audio = false; |
|
if (!intel_sdvo->is_hdmi) |
return false; |
|
edid = intel_sdvo_get_edid(connector); |
if (edid != NULL && edid->input & DRM_EDID_INPUT_DIGITAL) |
has_audio = drm_detect_monitor_audio(edid); |
kfree(edid); |
|
return has_audio; |
} |
|
static int |
intel_sdvo_set_property(struct drm_connector *connector, |
1681,10 → 1851,10 |
|
intel_sdvo_connector->force_audio = i; |
|
if (i == 0) |
if (i == HDMI_AUDIO_AUTO) |
has_audio = intel_sdvo_detect_hdmi_audio(connector); |
else |
has_audio = i > 0; |
has_audio = (i == HDMI_AUDIO_ON); |
|
if (has_audio == intel_sdvo->has_hdmi_audio) |
return 0; |
1797,8 → 1967,8 |
done: |
if (intel_sdvo->base.base.crtc) { |
struct drm_crtc *crtc = intel_sdvo->base.base.crtc; |
drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x, |
crtc->y, crtc->fb); |
intel_set_mode(crtc, &crtc->mode, |
crtc->x, crtc->y, crtc->fb); |
} |
|
return 0; |
1806,15 → 1976,13 |
} |
|
static const struct drm_encoder_helper_funcs intel_sdvo_helper_funcs = { |
.dpms = intel_sdvo_dpms, |
.mode_fixup = intel_sdvo_mode_fixup, |
.prepare = intel_encoder_prepare, |
.mode_set = intel_sdvo_mode_set, |
.commit = intel_encoder_commit, |
.disable = intel_encoder_noop, |
}; |
|
static const struct drm_connector_funcs intel_sdvo_connector_funcs = { |
.dpms = drm_helper_connector_dpms, |
.dpms = intel_sdvo_dpms, |
.detect = intel_sdvo_detect, |
.fill_modes = drm_helper_probe_single_connector_modes, |
.set_property = intel_sdvo_set_property, |
1892,7 → 2060,7 |
{ |
struct sdvo_device_mapping *mapping; |
|
if (IS_SDVOB(reg)) |
if (sdvo->is_sdvob) |
mapping = &(dev_priv->sdvo_mappings[0]); |
else |
mapping = &(dev_priv->sdvo_mappings[1]); |
1910,7 → 2078,7 |
struct sdvo_device_mapping *mapping; |
u8 pin; |
|
if (IS_SDVOB(reg)) |
if (sdvo->is_sdvob) |
mapping = &dev_priv->sdvo_mappings[0]; |
else |
mapping = &dev_priv->sdvo_mappings[1]; |
1919,12 → 2087,12 |
if (mapping->initialized) |
pin = mapping->i2c_pin; |
|
if (pin < GMBUS_NUM_PORTS) { |
sdvo->i2c = &dev_priv->gmbus[pin].adapter; |
if (intel_gmbus_is_port_valid(pin)) { |
sdvo->i2c = intel_gmbus_get_adapter(dev_priv, pin); |
intel_gmbus_set_speed(sdvo->i2c, GMBUS_RATE_1MHZ); |
intel_gmbus_force_bit(sdvo->i2c, true); |
} else { |
sdvo->i2c = &dev_priv->gmbus[GMBUS_PORT_DPB].adapter; |
sdvo->i2c = intel_gmbus_get_adapter(dev_priv, GMBUS_PORT_DPB); |
} |
} |
|
1935,12 → 2103,12 |
} |
|
static u8 |
intel_sdvo_get_slave_addr(struct drm_device *dev, int sdvo_reg) |
intel_sdvo_get_slave_addr(struct drm_device *dev, struct intel_sdvo *sdvo) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct sdvo_device_mapping *my_mapping, *other_mapping; |
|
if (IS_SDVOB(sdvo_reg)) { |
if (sdvo->is_sdvob) { |
my_mapping = &dev_priv->sdvo_mappings[0]; |
other_mapping = &dev_priv->sdvo_mappings[1]; |
} else { |
1965,7 → 2133,7 |
/* No SDVO device info is found for another DVO port, |
* so use mapping assumption we had before BIOS parsing. |
*/ |
if (IS_SDVOB(sdvo_reg)) |
if (sdvo->is_sdvob) |
return 0x70; |
else |
return 0x72; |
1983,9 → 2151,10 |
drm_connector_helper_add(&connector->base.base, |
&intel_sdvo_connector_helper_funcs); |
|
connector->base.base.interlace_allowed = 0; |
connector->base.base.interlace_allowed = 1; |
connector->base.base.doublescan_allowed = 0; |
connector->base.base.display_info.subpixel_order = SubPixelHorizontalRGB; |
connector->base.get_hw_state = intel_sdvo_connector_get_hw_state; |
|
intel_connector_attach_encoder(&connector->base, &encoder->base); |
drm_sysfs_connector_add(&connector->base.base); |
2024,17 → 2193,18 |
|
intel_connector = &intel_sdvo_connector->base; |
connector = &intel_connector->base; |
if (intel_sdvo_supports_hotplug(intel_sdvo) & (1 << device)) { |
if (intel_sdvo_get_hotplug_support(intel_sdvo) & |
intel_sdvo_connector->output_flag) { |
connector->polled = DRM_CONNECTOR_POLL_HPD; |
intel_sdvo->hotplug_active[0] |= 1 << device; |
intel_sdvo->hotplug_active |= intel_sdvo_connector->output_flag; |
/* Some SDVO devices have one-shot hotplug interrupts. |
* Ensure that they get re-enabled when an interrupt happens. |
*/ |
intel_encoder->hot_plug = intel_sdvo_enable_hotplug; |
intel_sdvo_enable_hotplug(intel_encoder); |
} else { |
connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; |
} |
else |
connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; |
encoder->encoder_type = DRM_MODE_ENCODER_TMDS; |
connector->connector_type = DRM_MODE_CONNECTOR_DVID; |
|
2042,8 → 2212,7 |
connector->connector_type = DRM_MODE_CONNECTOR_HDMIA; |
intel_sdvo->is_hdmi = true; |
} |
intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) | |
(1 << INTEL_ANALOG_CLONE_BIT)); |
intel_sdvo->base.cloneable = true; |
|
intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo); |
if (intel_sdvo->is_hdmi) |
2074,7 → 2243,7 |
|
intel_sdvo->is_tv = true; |
intel_sdvo->base.needs_tv_clock = true; |
intel_sdvo->base.clone_mask = 1 << INTEL_SDVO_TV_CLONE_BIT; |
intel_sdvo->base.cloneable = false; |
|
intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo); |
|
2117,8 → 2286,7 |
intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB1; |
} |
|
intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) | |
(1 << INTEL_ANALOG_CLONE_BIT)); |
intel_sdvo->base.cloneable = true; |
|
intel_sdvo_connector_init(intel_sdvo_connector, |
intel_sdvo); |
2150,8 → 2318,8 |
intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS1; |
} |
|
intel_sdvo->base.clone_mask = ((1 << INTEL_ANALOG_CLONE_BIT) | |
(1 << INTEL_SDVO_LVDS_CLONE_BIT)); |
/* SDVO LVDS is not cloneable because the input mode gets adjusted by the encoder */ |
intel_sdvo->base.cloneable = false; |
|
intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo); |
if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector)) |
2190,6 → 2358,10 |
if (!intel_sdvo_tv_init(intel_sdvo, SDVO_OUTPUT_CVBS0)) |
return false; |
|
if (flags & SDVO_OUTPUT_YPRPB0) |
if (!intel_sdvo_tv_init(intel_sdvo, SDVO_OUTPUT_YPRPB0)) |
return false; |
|
if (flags & SDVO_OUTPUT_RGB0) |
if (!intel_sdvo_analog_init(intel_sdvo, 0)) |
return false; |
2275,10 → 2447,8 |
intel_sdvo_connector->max_##name = data_value[0]; \ |
intel_sdvo_connector->cur_##name = response; \ |
intel_sdvo_connector->name = \ |
drm_property_create(dev, DRM_MODE_PROP_RANGE, #name, 2); \ |
drm_property_create_range(dev, 0, #name, 0, data_value[0]); \ |
if (!intel_sdvo_connector->name) return false; \ |
intel_sdvo_connector->name->values[0] = 0; \ |
intel_sdvo_connector->name->values[1] = data_value[0]; \ |
drm_connector_attach_property(connector, \ |
intel_sdvo_connector->name, \ |
intel_sdvo_connector->cur_##name); \ |
2312,25 → 2482,19 |
intel_sdvo_connector->left_margin = data_value[0] - response; |
intel_sdvo_connector->right_margin = intel_sdvo_connector->left_margin; |
intel_sdvo_connector->left = |
drm_property_create(dev, DRM_MODE_PROP_RANGE, |
"left_margin", 2); |
drm_property_create_range(dev, 0, "left_margin", 0, data_value[0]); |
if (!intel_sdvo_connector->left) |
return false; |
|
intel_sdvo_connector->left->values[0] = 0; |
intel_sdvo_connector->left->values[1] = data_value[0]; |
drm_connector_attach_property(connector, |
intel_sdvo_connector->left, |
intel_sdvo_connector->left_margin); |
|
intel_sdvo_connector->right = |
drm_property_create(dev, DRM_MODE_PROP_RANGE, |
"right_margin", 2); |
drm_property_create_range(dev, 0, "right_margin", 0, data_value[0]); |
if (!intel_sdvo_connector->right) |
return false; |
|
intel_sdvo_connector->right->values[0] = 0; |
intel_sdvo_connector->right->values[1] = data_value[0]; |
drm_connector_attach_property(connector, |
intel_sdvo_connector->right, |
intel_sdvo_connector->right_margin); |
2354,25 → 2518,21 |
intel_sdvo_connector->top_margin = data_value[0] - response; |
intel_sdvo_connector->bottom_margin = intel_sdvo_connector->top_margin; |
intel_sdvo_connector->top = |
drm_property_create(dev, DRM_MODE_PROP_RANGE, |
"top_margin", 2); |
drm_property_create_range(dev, 0, |
"top_margin", 0, data_value[0]); |
if (!intel_sdvo_connector->top) |
return false; |
|
intel_sdvo_connector->top->values[0] = 0; |
intel_sdvo_connector->top->values[1] = data_value[0]; |
drm_connector_attach_property(connector, |
intel_sdvo_connector->top, |
intel_sdvo_connector->top_margin); |
|
intel_sdvo_connector->bottom = |
drm_property_create(dev, DRM_MODE_PROP_RANGE, |
"bottom_margin", 2); |
drm_property_create_range(dev, 0, |
"bottom_margin", 0, data_value[0]); |
if (!intel_sdvo_connector->bottom) |
return false; |
|
intel_sdvo_connector->bottom->values[0] = 0; |
intel_sdvo_connector->bottom->values[1] = data_value[0]; |
drm_connector_attach_property(connector, |
intel_sdvo_connector->bottom, |
intel_sdvo_connector->bottom_margin); |
2401,12 → 2561,10 |
intel_sdvo_connector->max_dot_crawl = 1; |
intel_sdvo_connector->cur_dot_crawl = response & 0x1; |
intel_sdvo_connector->dot_crawl = |
drm_property_create(dev, DRM_MODE_PROP_RANGE, "dot_crawl", 2); |
drm_property_create_range(dev, 0, "dot_crawl", 0, 1); |
if (!intel_sdvo_connector->dot_crawl) |
return false; |
|
intel_sdvo_connector->dot_crawl->values[0] = 0; |
intel_sdvo_connector->dot_crawl->values[1] = 1; |
drm_connector_attach_property(connector, |
intel_sdvo_connector->dot_crawl, |
intel_sdvo_connector->cur_dot_crawl); |
2485,7 → 2643,7 |
intel_sdvo_init_ddc_proxy(struct intel_sdvo *sdvo, |
struct drm_device *dev) |
{ |
// sdvo->ddc.owner = THIS_MODULE; |
sdvo->ddc.owner = THIS_MODULE; |
sdvo->ddc.class = I2C_CLASS_DDC; |
snprintf(sdvo->ddc.name, I2C_NAME_SIZE, "SDVO DDC proxy"); |
sdvo->ddc.dev.parent = &dev->pdev->dev; |
2495,11 → 2653,12 |
return 1; //i2c_add_adapter(&sdvo->ddc) == 0; |
} |
|
bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) |
bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct intel_encoder *intel_encoder; |
struct intel_sdvo *intel_sdvo; |
u32 hotplug_mask; |
int i; |
|
intel_sdvo = kzalloc(sizeof(struct intel_sdvo), GFP_KERNEL); |
2507,7 → 2666,8 |
return false; |
|
intel_sdvo->sdvo_reg = sdvo_reg; |
intel_sdvo->slave_addr = intel_sdvo_get_slave_addr(dev, sdvo_reg) >> 1; |
intel_sdvo->is_sdvob = is_sdvob; |
intel_sdvo->slave_addr = intel_sdvo_get_slave_addr(dev, intel_sdvo) >> 1; |
intel_sdvo_select_i2c_bus(dev_priv, intel_sdvo, sdvo_reg); |
if (!intel_sdvo_init_ddc_proxy(intel_sdvo, dev)) { |
kfree(intel_sdvo); |
2524,38 → 2684,47 |
u8 byte; |
|
if (!intel_sdvo_read_byte(intel_sdvo, i, &byte)) { |
DRM_DEBUG_KMS("No SDVO device found on SDVO%c\n", |
IS_SDVOB(sdvo_reg) ? 'B' : 'C'); |
DRM_DEBUG_KMS("No SDVO device found on %s\n", |
SDVO_NAME(intel_sdvo)); |
goto err; |
} |
} |
|
if (IS_SDVOB(sdvo_reg)) |
dev_priv->hotplug_supported_mask |= SDVOB_HOTPLUG_INT_STATUS; |
else |
dev_priv->hotplug_supported_mask |= SDVOC_HOTPLUG_INT_STATUS; |
hotplug_mask = 0; |
if (IS_G4X(dev)) { |
hotplug_mask = intel_sdvo->is_sdvob ? |
SDVOB_HOTPLUG_INT_STATUS_G4X : SDVOC_HOTPLUG_INT_STATUS_G4X; |
} else if (IS_GEN4(dev)) { |
hotplug_mask = intel_sdvo->is_sdvob ? |
SDVOB_HOTPLUG_INT_STATUS_I965 : SDVOC_HOTPLUG_INT_STATUS_I965; |
} else { |
hotplug_mask = intel_sdvo->is_sdvob ? |
SDVOB_HOTPLUG_INT_STATUS_I915 : SDVOC_HOTPLUG_INT_STATUS_I915; |
} |
|
drm_encoder_helper_add(&intel_encoder->base, &intel_sdvo_helper_funcs); |
|
intel_encoder->disable = intel_disable_sdvo; |
intel_encoder->enable = intel_enable_sdvo; |
intel_encoder->get_hw_state = intel_sdvo_get_hw_state; |
|
/* In default case sdvo lvds is false */ |
if (!intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps)) |
goto err; |
|
/* Set up hotplug command - note paranoia about contents of reply. |
* We assume that the hardware is in a sane state, and only touch |
* the bits we think we understand. |
*/ |
intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_ACTIVE_HOT_PLUG, |
&intel_sdvo->hotplug_active, 2); |
intel_sdvo->hotplug_active[0] &= ~0x3; |
|
if (intel_sdvo_output_setup(intel_sdvo, |
intel_sdvo->caps.output_flags) != true) { |
DRM_DEBUG_KMS("SDVO output failed to setup on SDVO%c\n", |
IS_SDVOB(sdvo_reg) ? 'B' : 'C'); |
DRM_DEBUG_KMS("SDVO output failed to setup on %s\n", |
SDVO_NAME(intel_sdvo)); |
goto err; |
} |
|
/* Only enable the hotplug irq if we need it, to work around noisy |
* hotplug lines. |
*/ |
if (intel_sdvo->hotplug_active) |
dev_priv->hotplug_supported_mask |= hotplug_mask; |
|
intel_sdvo_select_ddc_bus(dev_priv, intel_sdvo, sdvo_reg); |
|
/* Set the input timing to the screen. Assume always input 0. */ |