Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 3030 → Rev 3031

/drivers/video/drm/i915/intel_sdvo.c
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. */