Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 156526
b: refs/heads/master
c: 5eb08b6
h: refs/heads/master
v: v3
  • Loading branch information
Zhenyu Wang authored and Eric Anholt committed Jul 29, 2009
1 parent da930bd commit a67ed18
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 22 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: eebc863e469cd91d96c4e3636450596ae29f0502
refs/heads/master: 5eb08b69f510fadaba77eb9a1bda0f7299c4ebcc
25 changes: 25 additions & 0 deletions trunk/drivers/gpu/drm/i915/i915_reg.h
Original file line number Diff line number Diff line change
Expand Up @@ -1444,6 +1444,7 @@
#define DP_CLOCK_OUTPUT_ENABLE (1 << 13)

#define DP_SCRAMBLING_DISABLE (1 << 12)
#define DP_SCRAMBLING_DISABLE_IGDNG (1 << 7)

/** limit RGB values to avoid confusing TVs */
#define DP_COLOR_RANGE_16_235 (1 << 8)
Expand Down Expand Up @@ -2210,4 +2211,28 @@
#define PCH_PP_OFF_DELAYS 0xc720c
#define PCH_PP_DIVISOR 0xc7210

#define PCH_DP_B 0xe4100
#define PCH_DPB_AUX_CH_CTL 0xe4110
#define PCH_DPB_AUX_CH_DATA1 0xe4114
#define PCH_DPB_AUX_CH_DATA2 0xe4118
#define PCH_DPB_AUX_CH_DATA3 0xe411c
#define PCH_DPB_AUX_CH_DATA4 0xe4120
#define PCH_DPB_AUX_CH_DATA5 0xe4124

#define PCH_DP_C 0xe4200
#define PCH_DPC_AUX_CH_CTL 0xe4210
#define PCH_DPC_AUX_CH_DATA1 0xe4214
#define PCH_DPC_AUX_CH_DATA2 0xe4218
#define PCH_DPC_AUX_CH_DATA3 0xe421c
#define PCH_DPC_AUX_CH_DATA4 0xe4220
#define PCH_DPC_AUX_CH_DATA5 0xe4224

#define PCH_DP_D 0xe4300
#define PCH_DPD_AUX_CH_CTL 0xe4310
#define PCH_DPD_AUX_CH_DATA1 0xe4314
#define PCH_DPD_AUX_CH_DATA2 0xe4318
#define PCH_DPD_AUX_CH_DATA3 0xe431c
#define PCH_DPD_AUX_CH_DATA4 0xe4320
#define PCH_DPD_AUX_CH_DATA5 0xe4324

#endif /* _I915_REG_H_ */
51 changes: 49 additions & 2 deletions trunk/drivers/gpu/drm/i915/intel_display.c
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,9 @@ intel_igdng_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
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 bool
intel_find_pll_igdng_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_i8xx_dvo = {
.dot = { .min = I8XX_DOT_MIN, .max = I8XX_DOT_MAX },
Expand Down Expand Up @@ -751,6 +754,30 @@ intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
return found;
}

static bool
intel_find_pll_igdng_dp(const intel_limit_t *limit, struct drm_crtc *crtc,
int target, int refclk, intel_clock_t *best_clock)
{
struct drm_device *dev = crtc->dev;
intel_clock_t clock;
if (target < 200000) {
clock.n = 1;
clock.p1 = 2;
clock.p2 = 10;
clock.m1 = 12;
clock.m2 = 9;
} else {
clock.n = 2;
clock.p1 = 1;
clock.p2 = 10;
clock.m1 = 14;
clock.m2 = 8;
}
intel_clock(dev, refclk, &clock);
memcpy(best_clock, &clock, sizeof(intel_clock_t));
return true;
}

static bool
intel_igdng_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
int target, int refclk, intel_clock_t *best_clock)
Expand All @@ -763,6 +790,10 @@ intel_igdng_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
int err_most = 47;
found = false;

if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT))
return intel_find_pll_igdng_dp(limit, crtc, target,
refclk, best_clock);

if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
if ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) ==
LVDS_CLKB_POWER_UP)
Expand Down Expand Up @@ -2136,6 +2167,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
int lvds_reg = LVDS;
u32 temp;
int sdvo_pixel_multiply;
int target_clock;

drm_vblank_pre_modeset(dev, pipe);

Expand Down Expand Up @@ -2218,11 +2250,18 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
}

/* FDI link */
if (IS_IGDNG(dev))
if (IS_IGDNG(dev)) {
/* DP over FDI requires target mode clock
instead of link clock */
if (is_dp)
target_clock = mode->clock;
else
target_clock = adjusted_mode->clock;
igdng_compute_m_n(3, 4, /* lane num 4 */
adjusted_mode->clock,
target_clock,
270000, /* lane clock */
&m_n);
}

if (IS_IGD(dev))
fp = (1 << clock.n) << 16 | clock.m1 << 8 | clock.m2;
Expand Down Expand Up @@ -3050,6 +3089,8 @@ static void intel_setup_outputs(struct drm_device *dev)
found = 0;
if (!found)
intel_hdmi_init(dev, HDMIB);
if (!found && (I915_READ(PCH_DP_B) & DP_DETECTED))
intel_dp_init(dev, PCH_DP_B);
}

if (I915_READ(HDMIC) & PORT_DETECTED)
Expand All @@ -3058,6 +3099,12 @@ static void intel_setup_outputs(struct drm_device *dev)
if (I915_READ(HDMID) & PORT_DETECTED)
intel_hdmi_init(dev, HDMID);

if (I915_READ(PCH_DP_C) & DP_DETECTED)
intel_dp_init(dev, PCH_DP_C);

if (I915_READ(PCH_DP_D) & DP_DETECTED)
intel_dp_init(dev, PCH_DP_D);

} else if (IS_I9XX(dev)) {
int found;
u32 reg;
Expand Down
102 changes: 83 additions & 19 deletions trunk/drivers/gpu/drm/i915/intel_dp.c
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,12 @@ intel_dp_aux_ch(struct intel_output *intel_output,
* and would like to run at 2MHz. So, take the
* hrawclk value and divide by 2 and use that
*/
aux_clock_divider = intel_hrawclk(dev) / 2;
/* IGDNG: input clock fixed at 125Mhz, so aux_bit_clk always 62 */
if (IS_IGDNG(dev))
aux_clock_divider = 62;
else
aux_clock_divider = intel_hrawclk(dev) / 2;

/* Must try at least 3 times according to DP spec */
for (try = 0; try < 5; try++) {
/* Load the send data into the aux channel data registers */
Expand Down Expand Up @@ -493,22 +498,40 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
intel_dp_compute_m_n(3, lane_count,
mode->clock, adjusted_mode->clock, &m_n);

if (intel_crtc->pipe == 0) {
I915_WRITE(PIPEA_GMCH_DATA_M,
((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) |
m_n.gmch_m);
I915_WRITE(PIPEA_GMCH_DATA_N,
m_n.gmch_n);
I915_WRITE(PIPEA_DP_LINK_M, m_n.link_m);
I915_WRITE(PIPEA_DP_LINK_N, m_n.link_n);
if (IS_IGDNG(dev)) {
if (intel_crtc->pipe == 0) {
I915_WRITE(TRANSA_DATA_M1,
((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) |
m_n.gmch_m);
I915_WRITE(TRANSA_DATA_N1, m_n.gmch_n);
I915_WRITE(TRANSA_DP_LINK_M1, m_n.link_m);
I915_WRITE(TRANSA_DP_LINK_N1, m_n.link_n);
} else {
I915_WRITE(TRANSB_DATA_M1,
((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) |
m_n.gmch_m);
I915_WRITE(TRANSB_DATA_N1, m_n.gmch_n);
I915_WRITE(TRANSB_DP_LINK_M1, m_n.link_m);
I915_WRITE(TRANSB_DP_LINK_N1, m_n.link_n);
}
} else {
I915_WRITE(PIPEB_GMCH_DATA_M,
((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) |
m_n.gmch_m);
I915_WRITE(PIPEB_GMCH_DATA_N,
m_n.gmch_n);
I915_WRITE(PIPEB_DP_LINK_M, m_n.link_m);
I915_WRITE(PIPEB_DP_LINK_N, m_n.link_n);
if (intel_crtc->pipe == 0) {
I915_WRITE(PIPEA_GMCH_DATA_M,
((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) |
m_n.gmch_m);
I915_WRITE(PIPEA_GMCH_DATA_N,
m_n.gmch_n);
I915_WRITE(PIPEA_DP_LINK_M, m_n.link_m);
I915_WRITE(PIPEA_DP_LINK_N, m_n.link_n);
} else {
I915_WRITE(PIPEB_GMCH_DATA_M,
((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) |
m_n.gmch_m);
I915_WRITE(PIPEB_GMCH_DATA_N,
m_n.gmch_n);
I915_WRITE(PIPEB_DP_LINK_M, m_n.link_m);
I915_WRITE(PIPEB_DP_LINK_N, m_n.link_n);
}
}
}

Expand Down Expand Up @@ -935,6 +958,12 @@ intel_dp_link_down(struct intel_output *intel_output, uint32_t DP)
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_dp_priv *dp_priv = intel_output->dev_priv;

DP &= ~DP_LINK_TRAIN_MASK;
I915_WRITE(dp_priv->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE);
POSTING_READ(dp_priv->output_reg);

udelay(17000);

I915_WRITE(dp_priv->output_reg, DP & ~DP_PORT_EN);
POSTING_READ(dp_priv->output_reg);
}
Expand Down Expand Up @@ -978,6 +1007,24 @@ intel_dp_check_link_status(struct intel_output *intel_output)
intel_dp_link_train(intel_output, dp_priv->DP, dp_priv->link_configuration);
}

static enum drm_connector_status
igdng_dp_detect(struct drm_connector *connector)
{
struct intel_output *intel_output = to_intel_output(connector);
struct intel_dp_priv *dp_priv = intel_output->dev_priv;
enum drm_connector_status status;

status = connector_status_disconnected;
if (intel_dp_aux_native_read(intel_output,
0x000, dp_priv->dpcd,
sizeof (dp_priv->dpcd)) == sizeof (dp_priv->dpcd))
{
if (dp_priv->dpcd[0] != 0)
status = connector_status_connected;
}
return status;
}

/**
* Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect DP connection.
*
Expand All @@ -996,6 +1043,9 @@ intel_dp_detect(struct drm_connector *connector)

dp_priv->has_audio = false;

if (IS_IGDNG(dev))
return igdng_dp_detect(connector);

temp = I915_READ(PORT_HOTPLUG_EN);

I915_WRITE(PORT_HOTPLUG_EN,
Expand Down Expand Up @@ -1106,6 +1156,7 @@ intel_dp_init(struct drm_device *dev, int output_reg)
struct drm_connector *connector;
struct intel_output *intel_output;
struct intel_dp_priv *dp_priv;
const char *name = NULL;

intel_output = kcalloc(sizeof(struct intel_output) +
sizeof(struct intel_dp_priv), 1, GFP_KERNEL);
Expand Down Expand Up @@ -1139,9 +1190,22 @@ intel_dp_init(struct drm_device *dev, int output_reg)
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");
switch (output_reg) {
case DP_B:
case PCH_DP_B:
name = "DPDDC-B";
break;
case DP_C:
case PCH_DP_C:
name = "DPDDC-C";
break;
case DP_D:
case PCH_DP_D:
name = "DPDDC-D";
break;
}

intel_dp_i2c_init(intel_output, name);
intel_output->ddc_bus = &dp_priv->adapter;
intel_output->hot_plug = intel_dp_hot_plug;

Expand Down

0 comments on commit a67ed18

Please sign in to comment.