[Intel-gfx] [PATCH 13/17] drm/i915: Hook up display port
Keith Packard
keithp at keithp.com
Sun May 31 05:42:37 CEST 2009
---
drivers/gpu/drm/i915/intel_display.c | 91 +++++++++++++++++++-
drivers/gpu/drm/i915/intel_dp.c | 62 +++++++++-----
drivers/gpu/drm/i915/intel_dp.h | 16 ++--
drivers/gpu/drm/i915/intel_dp_i2c.c | 157 ++++++++++++++++++++++------------
drivers/gpu/drm/i915/intel_drv.h | 3 +
5 files changed, 242 insertions(+), 87 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 2b042ea..220d54d 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -136,8 +136,9 @@ struct intel_limit {
#define INTEL_LIMIT_G4X_HDMI_DAC 5
#define INTEL_LIMIT_G4X_SINGLE_CHANNEL_LVDS 6
#define INTEL_LIMIT_G4X_DUAL_CHANNEL_LVDS 7
-#define INTEL_LIMIT_IGD_SDVO_DAC 8
-#define INTEL_LIMIT_IGD_LVDS 9
+#define INTEL_LIMIT_G4X_DISPLAY_PORT 8
+#define INTEL_LIMIT_IGD_SDVO_DAC 9
+#define INTEL_LIMIT_IGD_LVDS 10
/*The parameter is for SDVO on G4x platform*/
#define G4X_DOT_SDVO_MIN 25000
@@ -217,6 +218,25 @@ struct intel_limit {
#define G4X_P2_DUAL_CHANNEL_LVDS_FAST 7
#define G4X_P2_DUAL_CHANNEL_LVDS_LIMIT 0
+/*The parameter is for DISPLAY PORT on G4x platform*/
+#define G4X_DOT_DISPLAY_PORT_MIN 161670
+#define G4X_DOT_DISPLAY_PORT_MAX 227000
+#define G4X_N_DISPLAY_PORT_MIN 1
+#define G4X_N_DISPLAY_PORT_MAX 2
+#define G4X_M_DISPLAY_PORT_MIN 97
+#define G4X_M_DISPLAY_PORT_MAX 108
+#define G4X_M1_DISPLAY_PORT_MIN 0x10
+#define G4X_M1_DISPLAY_PORT_MAX 0x12
+#define G4X_M2_DISPLAY_PORT_MIN 0x05
+#define G4X_M2_DISPLAY_PORT_MAX 0x06
+#define G4X_P_DISPLAY_PORT_MIN 10
+#define G4X_P_DISPLAY_PORT_MAX 20
+#define G4X_P1_DISPLAY_PORT_MIN 1
+#define G4X_P1_DISPLAY_PORT_MAX 2
+#define G4X_P2_DISPLAY_PORT_SLOW 10
+#define G4X_P2_DISPLAY_PORT_FAST 10
+#define G4X_P2_DISPLAY_PORT_LIMIT 0
+
static bool
intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
int target, int refclk, intel_clock_t *best_clock);
@@ -224,6 +244,10 @@ static bool
intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
int target, int refclk, intel_clock_t *best_clock);
+static bool
+intel_find_pll_g4x_dp(const intel_limit_t *, struct drm_crtc *crtc,
+ int target, int refclk, intel_clock_t *best_clock);
+
static const intel_limit_t intel_limits[] = {
{ /* INTEL_LIMIT_I8XX_DVO_DAC */
.dot = { .min = I8XX_DOT_MIN, .max = I8XX_DOT_MAX },
@@ -357,6 +381,28 @@ static const intel_limit_t intel_limits[] = {
},
.find_pll = intel_g4x_find_best_PLL,
},
+ { /* INTEL_LIMIT_G4X_DISPLAY_PORT */
+ .dot = { .min = G4X_DOT_DISPLAY_PORT_MIN,
+ .max = G4X_DOT_DISPLAY_PORT_MAX },
+ .vco = { .min = G4X_VCO_MIN,
+ .max = G4X_VCO_MAX},
+ .n = { .min = G4X_N_DISPLAY_PORT_MIN,
+ .max = G4X_N_DISPLAY_PORT_MAX },
+ .m = { .min = G4X_M_DISPLAY_PORT_MIN,
+ .max = G4X_M_DISPLAY_PORT_MAX },
+ .m1 = { .min = G4X_M1_DISPLAY_PORT_MIN,
+ .max = G4X_M1_DISPLAY_PORT_MAX },
+ .m2 = { .min = G4X_M2_DISPLAY_PORT_MIN,
+ .max = G4X_M2_DISPLAY_PORT_MAX },
+ .p = { .min = G4X_P_DISPLAY_PORT_MIN,
+ .max = G4X_P_DISPLAY_PORT_MAX },
+ .p1 = { .min = G4X_P1_DISPLAY_PORT_MIN,
+ .max = G4X_P1_DISPLAY_PORT_MAX},
+ .p2 = { .dot_limit = G4X_P2_DISPLAY_PORT_LIMIT,
+ .p2_slow = G4X_P2_DISPLAY_PORT_SLOW,
+ .p2_fast = G4X_P2_DISPLAY_PORT_FAST },
+ .find_pll = intel_find_pll_g4x_dp,
+ },
{ /* INTEL_LIMIT_IGD_SDVO */
.dot = { .min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX},
.vco = { .min = IGD_VCO_MIN, .max = IGD_VCO_MAX },
@@ -408,6 +454,8 @@ static const intel_limit_t *intel_g4x_limit(struct drm_crtc *crtc)
limit = &intel_limits[INTEL_LIMIT_G4X_HDMI_DAC];
} else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_SDVO)) {
limit = &intel_limits[INTEL_LIMIT_G4X_SDVO];
+ } else if (intel_pipe_has_type (crtc, INTEL_OUTPUT_DISPLAYPORT)) {
+ limit = &intel_limits[INTEL_LIMIT_G4X_DISPLAY_PORT];
} else /* The option is for other outputs */
limit = &intel_limits[INTEL_LIMIT_I9XX_SDVO_DAC];
@@ -635,6 +683,35 @@ intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
return found;
}
+/* DisplayPort has only two frequencies, 162MHz and 270MHz */
+static bool
+intel_find_pll_g4x_dp(const intel_limit_t *limit, struct drm_crtc *crtc,
+ int target, int refclk, intel_clock_t *best_clock)
+{
+ intel_clock_t clock;
+ if (target < 200000) {
+ clock.dot = 161670;
+ clock.p = 20;
+ clock.p1 = 2;
+ clock.p2 = 10;
+ clock.n = 0x01;
+ clock.m = 97;
+ clock.m1 = 0x10;
+ clock.m2 = 0x05;
+ } else {
+ clock.dot = 270000;
+ clock.p = 10;
+ clock.p1 = 1;
+ clock.p2 = 10;
+ clock.n = 0x02;
+ clock.m = 108;
+ clock.m1 = 0x12;
+ clock.m2 = 0x06;
+ }
+ memcpy(best_clock, &clock, sizeof(intel_clock_t));
+ return true;
+}
+
void
intel_wait_for_vblank(struct drm_device *dev)
{
@@ -1108,6 +1185,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
} else {
refclk = 48000;
}
+
/*
* Returns a set of divisors for the desired target clock with the given
@@ -1275,6 +1353,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
I915_WRITE(LVDS, lvds);
I915_READ(LVDS);
}
+ if (is_dp)
+ intel_dp_set_m_n(crtc, mode, adjusted_mode);
I915_WRITE(fp_reg, fp);
I915_WRITE(dpll_reg, dpll);
@@ -1920,7 +2000,7 @@ static void intel_setup_outputs(struct drm_device *dev)
intel_dp_init(dev, DP_C);
}
if (SUPPORTS_INTEGRATED_DP(dev) && (I915_READ(DP_D) & DP_DETECTED))
- intel_dp_init(dev, DP_C);
+ intel_dp_init(dev, DP_D);
} else
intel_dvo_init(dev);
@@ -1963,6 +2043,11 @@ static void intel_setup_outputs(struct drm_device *dev)
(1 << 1));
clone_mask = (1 << INTEL_OUTPUT_TVOUT);
break;
+ case INTEL_OUTPUT_DISPLAYPORT:
+ crtc_mask = ((1 << 0) |
+ (1 << 1));
+ clone_mask = (1 << INTEL_OUTPUT_DISPLAYPORT);
+ break;
}
encoder->possible_crtcs = crtc_mask;
encoder->possible_clones = intel_connector_clones(dev, clone_mask);
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 50a75a1..ed3c7de 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -169,6 +169,12 @@ intel_dp_aux_ch(struct intel_output *intel_output,
uint32_t ctl;
uint32_t status;
+// printk(KERN_ERR "dp_aux_ch 0x%08x send %d:",
+// output_reg, send_bytes);
+// for (i = 0; i < send_bytes; i++)
+// printk(" %02x", send[i]);
+// printk("\n");
+
/* Load the send data into the aux channel data registers */
for (i = 0; i < send_bytes; i += 4) {
uint32_t d = pack_aux(send + i, send_bytes - i);;
@@ -189,13 +195,15 @@ intel_dp_aux_ch(struct intel_output *intel_output,
DP_AUX_CH_CTL_TIME_OUT_ERROR |
DP_AUX_CH_CTL_RECEIVE_ERROR);
+// printk(KERN_ERR "out ch_ctl 0x%08x 0x%08x\n", ch_ctl, ctl);
/* Send the command and wait for it to complete */
I915_WRITE(ch_ctl, ctl);
+ (void) I915_READ(ch_ctl);
for (;;) {
+ udelay(100);
status = I915_READ(ch_ctl);
if ((status & DP_AUX_CH_CTL_SEND_BUSY) == 0)
break;
- udelay(100);
}
/* Clear done status and any errors */
@@ -203,15 +211,20 @@ intel_dp_aux_ch(struct intel_output *intel_output,
DP_AUX_CH_CTL_DONE |
DP_AUX_CH_CTL_TIME_OUT_ERROR |
DP_AUX_CH_CTL_RECEIVE_ERROR));
+ (void) I915_READ(ch_ctl);
- if ((status & DP_AUX_CH_CTL_DONE) == 0)
+ if ((status & DP_AUX_CH_CTL_DONE) == 0) {
+ printk(KERN_ERR "dp_aux_ch not done status 0x%08x\n", status);
return -1;
+ }
/* Check for timeout or receive error.
* Timeouts occur when the sink is not connected
*/
- if (status & (DP_AUX_CH_CTL_TIME_OUT_ERROR | DP_AUX_CH_CTL_RECEIVE_ERROR))
+ if (status & (DP_AUX_CH_CTL_TIME_OUT_ERROR | DP_AUX_CH_CTL_RECEIVE_ERROR)) {
+ printk(KERN_ERR "dp_aux_ch error status 0x%08x\n", status);
return -1;
+ }
/* Unload any bytes sent back from the other side */
recv_bytes = ((status & DP_AUX_CH_CTL_MESSAGE_SIZE_MASK) >>
@@ -219,11 +232,17 @@ intel_dp_aux_ch(struct intel_output *intel_output,
if (recv_bytes > recv_size)
recv_bytes = recv_size;
+
for (i = 0; i < recv_bytes; i += 4) {
uint32_t d = I915_READ(ch_data + i);
+// printk(KERN_ERR "bytes %d-%d: 0x%08x\n", i, i + 3, d);
unpack_aux(d, recv + i, recv_bytes - i);
}
+// printk(KERN_ERR " 0x%08x: %d:", status, recv_bytes);
+// for (i = 0; i < recv_bytes; i ++)
+// printk(" %02x", recv[i]);
+// printk("\n");
return recv_bytes;
}
@@ -238,6 +257,9 @@ intel_dp_aux_native_write(struct intel_output *intel_output,
int msg_bytes;
uint8_t ack;
+// printk(KERN_ERR "dp_aux_native_write address 0x%04x num %d\n",
+// address, send_bytes);
+
if (send_bytes > 16)
return -1;
msg[0] = AUX_NATIVE_WRITE << 4;
@@ -280,6 +302,8 @@ intel_dp_aux_native_read(struct intel_output *intel_output,
uint8_t ack;
int ret;
+// printk(KERN_ERR "dp_aux_native_read address 0x%04x num %d\n",
+// address, recv_bytes);
msg[0] = AUX_NATIVE_READ << 4;
msg[1] = address >> 8;
msg[2] = address & 0xff;
@@ -296,6 +320,7 @@ intel_dp_aux_native_read(struct intel_output *intel_output,
ack = reply[0];
if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK) {
memcpy(recv, reply + 1, ret - 1);
+// printk("dp_aux_native_read got %d\n", ret - 1);
return ret - 1;
}
else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER)
@@ -324,6 +349,7 @@ intel_dp_i2c_init(struct intel_output *intel_output, const char *name)
{
struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+ DRM_ERROR("i2c_init %s\n", name);
dp_priv->algo.running = false;
dp_priv->algo.address = 0;
dp_priv->algo.aux_ch = intel_dp_i2c_aux_ch;
@@ -358,6 +384,9 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
dp_priv->link_bw = bws[clock];
dp_priv->lane_count = lane_count;
adjusted_mode->clock = intel_dp_link_clock(dp_priv->link_bw);
+ printk(KERN_ERR "link bw %02x lane count %d clock %d\n",
+ dp_priv->link_bw, dp_priv->lane_count,
+ adjusted_mode->clock);
return true;
}
}
@@ -552,8 +581,9 @@ intel_dp_save(struct drm_connector *connector)
struct intel_dp_priv *dp_priv = intel_output->dev_priv;
dp_priv->save_DP = I915_READ(dp_priv->output_reg);
- intel_dp_aux_native_read(intel_output, 0x100,
- dp_priv->save_link_configuration, sizeof (dp_priv->save_link_configuration));
+ intel_dp_aux_native_read(intel_output, DP_LINK_BW_SET,
+ dp_priv->save_link_configuration,
+ sizeof (dp_priv->save_link_configuration));
}
static uint8_t
@@ -937,15 +967,6 @@ intel_dp_detect(struct drm_connector *connector)
dp_priv->has_audio = false;
- /* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written 0xd.
- * Failure to do so will result in spurious interrupts being
- * generated on the port when a cable is not attached.
- */
- if (IS_G4X(dev) && !IS_GM45(dev)) {
- temp = I915_READ(PEG_BAND_GAP_DATA);
- I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd);
- }
-
temp = I915_READ(PORT_HOTPLUG_EN);
I915_WRITE(PORT_HOTPLUG_EN,
@@ -977,7 +998,7 @@ intel_dp_detect(struct drm_connector *connector)
status = connector_status_disconnected;
if (intel_dp_aux_native_read(intel_output,
- 0, dp_priv->dpcd,
+ 0x000, dp_priv->dpcd,
sizeof (dp_priv->dpcd)) == sizeof (dp_priv->dpcd))
{
if (dp_priv->dpcd[0] != 0)
@@ -1064,11 +1085,6 @@ intel_dp_init(struct drm_device *dev, int output_reg)
connector->interlace_allowed = true;
connector->doublescan_allowed = 0;
- /* Set up the DDC bus. */
- intel_dp_i2c_init(intel_output,
- (output_reg == DP_B) ? "DPDDC-B" :
- (output_reg == DP_C) ? "DPDDC-C" : "DPDDC_D");
-
dp_priv->intel_output = intel_output;
dp_priv->output_reg = output_reg;
dp_priv->has_audio = false;
@@ -1082,6 +1098,12 @@ intel_dp_init(struct drm_device *dev, int output_reg)
&intel_output->enc);
drm_sysfs_connector_add(connector);
+ /* Set up the DDC bus. */
+ intel_dp_i2c_init(intel_output,
+ (output_reg == DP_B) ? "DPDDC-B" :
+ (output_reg == DP_C) ? "DPDDC-C" : "DPDDC-D");
+ intel_output->ddc_bus = &dp_priv->adapter;
+
/* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written
* 0xd. Failure to do so will result in spurious interrupts being
* generated on the port when a cable is not attached.
diff --git a/drivers/gpu/drm/i915/intel_dp.h b/drivers/gpu/drm/i915/intel_dp.h
index 89310b9..2b38054 100644
--- a/drivers/gpu/drm/i915/intel_dp.h
+++ b/drivers/gpu/drm/i915/intel_dp.h
@@ -32,15 +32,15 @@
#define AUX_I2C_STATUS 0x2
#define AUX_I2C_MOT 0x4
-#define AUX_NATIVE_REPLY_ACK 0x0
-#define AUX_NATIVE_REPLY_NACK 0x1
-#define AUX_NATIVE_REPLY_DEFER 0x2
-#define AUX_NATIVE_REPLY_MASK 0x3
-
-#define AUX_I2C_REPLY_ACK (0x0 << 2)
-#define AUX_I2C_REPLY_NACK (0x1 << 2)
-#define AUX_I2C_REPLY_DEFER (0x2 << 2)
-#define AUX_I2C_REPLY_MASK (0x3 << 2)
+#define AUX_NATIVE_REPLY_ACK (0x0 << 4)
+#define AUX_NATIVE_REPLY_NACK (0x1 << 4)
+#define AUX_NATIVE_REPLY_DEFER (0x2 << 4)
+#define AUX_NATIVE_REPLY_MASK (0x3 << 4)
+
+#define AUX_I2C_REPLY_ACK (0x0 << 6)
+#define AUX_I2C_REPLY_NACK (0x1 << 6)
+#define AUX_I2C_REPLY_DEFER (0x2 << 6)
+#define AUX_I2C_REPLY_MASK (0x3 << 6)
/* AUX CH addresses */
#define DP_LINK_BW_SET 0x100
diff --git a/drivers/gpu/drm/i915/intel_dp_i2c.c b/drivers/gpu/drm/i915/intel_dp_i2c.c
index 4e4611c..11148c7 100644
--- a/drivers/gpu/drm/i915/intel_dp_i2c.c
+++ b/drivers/gpu/drm/i915/intel_dp_i2c.c
@@ -32,16 +32,13 @@
/* Run a single AUX_CH I2C transaction, writing/reading data as necessary */
-enum dp_aux_i2c_mode {
- aux_i2c_start,
- aux_i2c_write,
- aux_i2c_read,
- aux_i2c_stop
-};
+#define MODE_I2C_START 1
+#define MODE_I2C_WRITE 2
+#define MODE_I2C_READ 4
+#define MODE_I2C_STOP 8
static int
-i2c_algo_dp_aux_transaction(struct i2c_adapter *adapter,
- enum dp_aux_i2c_mode mode,
+i2c_algo_dp_aux_transaction(struct i2c_adapter *adapter, int mode,
uint8_t write_byte, uint8_t *read_byte)
{
struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
@@ -53,55 +50,69 @@ i2c_algo_dp_aux_transaction(struct i2c_adapter *adapter,
int ret;
/* Set up the command byte */
- if (address & 1)
+ if (mode & MODE_I2C_READ)
msg[0] = AUX_I2C_READ << 4;
else
msg[0] = AUX_I2C_WRITE << 4;
- if (mode != aux_i2c_stop)
+ if (!(mode & MODE_I2C_STOP))
msg[0] |= AUX_I2C_MOT << 4;
- /* Note that the AUX_CH I2C stuff wants the read/write
- * bit stripped off
- */
- msg[1] = address >> 9;
- msg[2] = address >> 1;
+ msg[1] = address >> 8;
+ msg[2] = address;
switch (mode) {
- case aux_i2c_start:
- case aux_i2c_stop:
- default:
- msg_bytes = 3;
- reply_bytes = 1;
- break;
- case aux_i2c_write:
+ case MODE_I2C_WRITE:
+// printk(KERN_ERR "dp_aux_transaction address %04x write %02x\n",
+// address, write_byte);
msg[3] = 0;
msg[4] = write_byte;
msg_bytes = 5;
reply_bytes = 1;
break;
- case aux_i2c_read:
+ case MODE_I2C_READ:
+// printk(KERN_ERR "dp_aux_transaction address %04x read\n",
+// address);
msg[3] = 0;
msg_bytes = 4;
reply_bytes = 2;
break;
+ default:
+// printk(KERN_ERR "dp_aux_transaction address %04x other\n",
+// address);
+ msg_bytes = 3;
+ reply_bytes = 1;
+ break;
}
for (;;) {
ret = (*algo_data->aux_ch)(adapter,
msg, msg_bytes,
reply, reply_bytes);
- if (ret <= 0)
- return -1;
- if ((reply[0] & AUX_I2C_REPLY_MASK) == AUX_I2C_REPLY_ACK) {
- if (mode == aux_i2c_read)
+ if (ret < 0) {
+ printk(KERN_ERR "aux_ch failed %d\n", ret);
+ return ret;
+ }
+ switch (reply[0] & AUX_I2C_REPLY_MASK) {
+ case AUX_I2C_REPLY_ACK:
+ if (mode == MODE_I2C_READ) {
+// printk(KERN_ERR "aux_ch read %02x\n", reply[1]);
*read_byte = reply[1];
+ }
+// printk(KERN_ERR "aux_ch_transaction return %d\n",
+// reply_bytes - 1);
return reply_bytes - 1;
- }
- else if ((reply[0] & AUX_I2C_REPLY_MASK) == AUX_I2C_REPLY_DEFER)
+ case AUX_I2C_REPLY_NACK:
+ printk(KERN_ERR "aux_ch nack\n");
+ return -EREMOTEIO;
+ case AUX_I2C_REPLY_DEFER:
+ printk(KERN_ERR "aux_ch defer\n");
udelay(100);
- else
- return -1;
+ break;
+ default:
+ printk(KERN_ERR "aux_ch invalid reply 0x%02x\n", reply[0]);
+ return -EREMOTEIO;
+ }
}
}
@@ -115,14 +126,22 @@ i2c_algo_dp_aux_transaction(struct i2c_adapter *adapter,
* a write followed by a read (as needed for DDC)
*/
static int
-i2c_algo_dp_aux_address(struct i2c_adapter *adapter, u16 address)
+i2c_algo_dp_aux_address(struct i2c_adapter *adapter, u16 address, bool reading)
{
struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
+ int mode = MODE_I2C_START;
+ int ret;
+// printk(KERN_ERR "dp_aux_put_address %04x\n", address);
+ if (reading)
+ mode |= MODE_I2C_READ;
+ else
+ mode |= MODE_I2C_WRITE;
algo_data->address = address;
algo_data->running = true;
- return i2c_algo_dp_aux_transaction(adapter, aux_i2c_start,
- 0, NULL);
+ ret = i2c_algo_dp_aux_transaction(adapter, mode, 0, NULL);
+// msleep(10);
+ return ret;
}
/*
@@ -130,15 +149,21 @@ i2c_algo_dp_aux_address(struct i2c_adapter *adapter, u16 address)
* a bare address packet with the MOT bit turned off
*/
static void
-i2c_algo_dp_aux_stop(struct i2c_adapter *adapter)
+i2c_algo_dp_aux_stop(struct i2c_adapter *adapter, bool reading)
{
struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
+ int mode = MODE_I2C_STOP;
+ if (reading)
+ mode |= MODE_I2C_READ;
+ else
+ mode |= MODE_I2C_WRITE;
+// printk(KERN_ERR "dp_aux_stop\n");
if (algo_data->running) {
- (void) i2c_algo_dp_aux_transaction(adapter, aux_i2c_stop,
- 0, NULL);
+ (void) i2c_algo_dp_aux_transaction(adapter, mode, 0, NULL);
algo_data->running = false;
}
+// msleep(10);
}
/*
@@ -149,12 +174,15 @@ static int
i2c_algo_dp_aux_put_byte(struct i2c_adapter *adapter, u8 byte)
{
struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
+ int ret;
+// printk(KERN_ERR "dp_aux_put_byte %02x\n", byte);
if (!algo_data->running)
return -EIO;
- return i2c_algo_dp_aux_transaction(adapter, aux_i2c_write,
- byte, NULL);
+ ret = i2c_algo_dp_aux_transaction(adapter, MODE_I2C_WRITE, byte, NULL);
+// msleep(10);
+ return ret;
}
/*
@@ -165,12 +193,15 @@ static int
i2c_algo_dp_aux_get_byte(struct i2c_adapter *adapter, u8 *byte_ret)
{
struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
+ int ret;
if (!algo_data->running)
return -EIO;
- return i2c_algo_dp_aux_transaction(adapter, aux_i2c_read,
- 0, byte_ret);
+ ret = i2c_algo_dp_aux_transaction(adapter, MODE_I2C_READ, 0, byte_ret);
+// printk(KERN_ERR "dp_aux_get_byte (status %d) %02x\n", ret, *byte_ret);
+// msleep(10);
+ return ret;
}
static int
@@ -178,34 +209,38 @@ i2c_algo_dp_aux_xfer(struct i2c_adapter *adapter,
struct i2c_msg *msgs,
int num)
{
- int orig_num = num;
int ret = 0;
- while (num--) {
- u16 len = msgs->len;
- u8 *buf = msgs->buf;
- ret = i2c_algo_dp_aux_address(adapter, msgs->addr);
+ bool reading = false;
+ int m;
+ int b;
+
+ for (m = 0; m < num; m++) {
+ u16 len = msgs[m].len;
+ u8 *buf = msgs[m].buf;
+ reading = (msgs[m].flags & I2C_M_RD) != 0;
+ ret = i2c_algo_dp_aux_address(adapter, msgs[m].addr, reading);
if (ret < 0)
break;
- if (msgs->flags & I2C_M_RD) {
- while (len--) {
- ret = i2c_algo_dp_aux_get_byte(adapter, buf++);
+ if (reading) {
+ for (b = 0; b < len; b++) {
+ ret = i2c_algo_dp_aux_get_byte(adapter, &buf[b]);
if (ret < 0)
break;
}
} else {
- while (len--) {
- ret = i2c_algo_dp_aux_put_byte(adapter, *buf++);
+ for (b = 0; b < len; b++) {
+ ret = i2c_algo_dp_aux_put_byte(adapter, buf[b]);
if (ret < 0)
break;
}
}
if (ret < 0)
break;
- msgs++;
}
- if (ret == 0)
- ret = orig_num;
- i2c_algo_dp_aux_stop(adapter);
+ if (ret >= 0)
+ ret = num;
+ i2c_algo_dp_aux_stop(adapter, reading);
+ printk(KERN_ERR "dp_aux_xfer return %d\n", ret);
return ret;
}
@@ -223,11 +258,20 @@ static const struct i2c_algorithm i2c_dp_aux_algo = {
.functionality = i2c_algo_dp_aux_functionality,
};
+static void
+i2c_dp_aux_reset_bus(struct i2c_adapter *adapter)
+{
+ (void) i2c_algo_dp_aux_address(adapter, 0, false);
+ (void) i2c_algo_dp_aux_stop(adapter, false);
+
+}
+
static int
i2c_dp_aux_prepare_bus(struct i2c_adapter *adapter)
{
adapter->algo = &i2c_dp_aux_algo;
adapter->retries = 3;
+ i2c_dp_aux_reset_bus(adapter);
return 0;
}
@@ -239,6 +283,7 @@ i2c_dp_aux_add_bus(struct i2c_adapter *adapter)
error = i2c_dp_aux_prepare_bus(adapter);
if (error)
return error;
- return i2c_add_adapter(adapter);
+ error = i2c_add_adapter(adapter);
+ return error;
}
EXPORT_SYMBOL(i2c_dp_aux_add_bus);
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 9b0882c..004541c 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -118,6 +118,9 @@ extern void intel_dvo_init(struct drm_device *dev);
extern void intel_tv_init(struct drm_device *dev);
extern void intel_lvds_init(struct drm_device *dev);
extern void intel_dp_init(struct drm_device *dev, int dp_reg);
+void
+intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode);
extern void intel_crtc_load_lut(struct drm_crtc *crtc);
extern void intel_encoder_prepare (struct drm_encoder *encoder);
--
1.6.3.1
More information about the Intel-gfx
mailing list