[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