From: Keith P. <ke...@ke...> - 2009-06-01 13:20:30
|
--- 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 |