[PATCH 2/2] drm/i915: use GMBUS for EDID fetching
Use the GMBUS interface rather than direct bit banging to grab the EDID over DDC. The hope is that this method will be more reliable than bit banging for fetching EDIDs from buggy monitors or through switches. Signed-off-by: Jesse Barnes --- drivers/gpu/drm/i915/i915_reg.h| 52 ++-- drivers/gpu/drm/i915/intel_crt.c |7 ++ drivers/gpu/drm/i915/intel_modes.c | 164 +++- 3 files changed, 216 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 42c6024..b89599c 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -507,12 +507,52 @@ # define GPIO_DATA_VAL_IN (1 << 12) # define GPIO_DATA_PULLUP_DISABLE (1 << 13) -#define GMBUS0 0x5100 -#define GMBUS1 0x5104 -#define GMBUS2 0x5108 -#define GMBUS3 0x510c -#define GMBUS4 0x5110 -#define GMBUS5 0x5120 +#define GMBUS0 0x5100 /* clock/port select */ +#define GMBUS_RATE_100KHZ(0<<8) +#define GMBUS_RATE_50KHZ (1<<8) +#define GMBUS_RATE_400KHZ(2<<8) /* reserved on Pineview */ +#define GMBUS_RATE_1MHZ (3<<8) /* reserved on Pineview */ +#define GMBUS_HOLD_EXT (1<<7) /* 300ns hold time, rsvd on Pineview */ +#define GMBUS_PORT_DISABLED 0 +#define GMBUS_PORT_SSC 1 +#define GMBUS_PORT_VGADDC2 +#define GMBUS_PORT_PANEL 3 +#define GMBUS_PORT_DPC 4 /* HDMIC */ +#define GMBUS_PORT_DPB 5 /* SDVO, HDMIB */ +#define GMBUS_PORT_DPD 6 /* HDMID */ + /* 7 reserved */ +#define GMBUS1 0x5104 /* command/status */ +#define GMBUS_SW_CLR_INT (1<<31) +#define GMBUS_SW_RDY (1<<30) +#define GMBUS_ENT(1<<29) /* enable timeout */ +#define GMBUS_CYCLE_NONE (0<<25) +#define GMBUS_CYCLE_NI_NS_WAIT (1<<25) +#define GMBUS_CYCLE_I_NS_WAIT(3<<25) +#define GMBUS_CYCLE_STOP (4<<25) +#define GMBUS_CYCLE_NI_STOP (5<<25) +#define GMBUS_CYCLE_I_STOP (7<<25) +#define GMBUS_BYTE_COUNT_SHIFT 16 +#define GMBUS_SLAVE_INDEX_SHIFT 8 +#define GMBUS_SLAVE_ADDR_SHIFT 1 +#define GMBUS_SLAVE_READ (1<<0) +#define GMBUS_SLAVE_WRITE(0<<0) +#define GMBUS2 0x5108 /* status */ +#define GMBUS_INUSE (1<<15) +#define GMBUS_HW_WAIT_PHASE (1<<14) +#define GMBUS_STALL_TIMEOUT (1<<13) +#define GMBUS_INT(1<<12) +#define GMBUS_HW_RDY (1<<11) +#define GMBUS_SATOER (1<<10) +#define GMBUS_ACTIVE (1<<9) +#define GMBUS3 0x510c /* data buffer bytes 3-0 */ +#define GMBUS4 0x5110 /* interrupt mask (Pineview+) */ +#define GMBUS_SLAVE_TIMEOUT_EN (1<<4) +#define GMBUS_NAK_EN (1<<3) +#define GMBUS_IDLE_EN(1<<2) +#define GMBUS_HW_WAIT_EN (1<<1) +#define GMBUS_HW_RDY_EN (1<<0) +#define GMBUS5 0x5120 /* byte index */ +#define GMBUS_2BYTE_INDEX_EN (1<<31) /* * Clock control & power management diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index ee0732b..60dc11b 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -453,6 +453,12 @@ static int intel_crt_get_modes(struct drm_connector *connector) struct i2c_adapter *ddc_bus; struct drm_device *dev = connector->dev; + /* Try GMBUS first */ + ret = intel_gmbus_get_modes(connector, 0); + if (ret) { + DRM_DEBUG_DRIVER("got EDID from GMBUS\n"); + goto end; + } ret = intel_ddc_get_modes(connector, intel_encoder->ddc_bus); if (ret || !IS_G4X(dev)) @@ -466,6 +472,7 @@ static int intel_crt_get_modes(struct drm_connector *connector) "DDC bus registration failed for CRTDDC_D.\n"); goto end; } + /* Try to get modes by GPIOD port */ ret = intel_ddc_get_modes(connector, ddc_bus); intel_i2c_destroy(ddc_bus); diff --git a/drivers/gpu/drm/i915/intel_modes.c b/drivers/gpu/drm/i915/intel_modes.c index 35d15f8..c9b946d 100644 --- a/drivers/gpu/drm/i915/intel_modes.c +++ b/drivers/gpu/drm/i915/intel_modes.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2007 Dave Airlie - * Copyright (c) 2007 Intel Corporation + * Copyright (c) 2007, 2010 Intel Corporation * Jesse Barnes * * Permission is hereby granted, free of charge, to any person obtaining a @@ -89,3 +89,165 @@ int intel_ddc_get_modes(struct drm_connector *connector, return ret; } + +static void intel_dump_gmbus(drm_i915_private_t *dev_priv) +{ + DRM_DEBUG_DRIVER("GMBUS0: 0x%08x\n", I915_READ(GMBUS0)); + DRM_DEBUG_DRIVER("GMBUS1: 0x%08x\n", I915_READ(GMBUS1)); + DRM_DEBUG_DRIVER("GMBUS2: 0x%08x\n", I915_READ(GMBUS2)); + DRM_DEBUG_DRIVER("GMBUS3: 0x%08
[PATCH 2/2] drm/i915: use GMBUS for EDID fetching
Use the GMBUS interface rather than direct bit banging to grab the EDID over DDC. The hope is that this method will be more reliable than bit banging for fetching EDIDs from buggy monitors or through switches. Signed-off-by: Jesse Barnes --- drivers/gpu/drm/i915/i915_reg.h| 52 ++-- drivers/gpu/drm/i915/intel_crt.c |7 ++ drivers/gpu/drm/i915/intel_modes.c | 164 +++- 3 files changed, 216 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 42c6024..b89599c 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -507,12 +507,52 @@ # define GPIO_DATA_VAL_IN (1 << 12) # define GPIO_DATA_PULLUP_DISABLE (1 << 13) -#define GMBUS0 0x5100 -#define GMBUS1 0x5104 -#define GMBUS2 0x5108 -#define GMBUS3 0x510c -#define GMBUS4 0x5110 -#define GMBUS5 0x5120 +#define GMBUS0 0x5100 /* clock/port select */ +#define GMBUS_RATE_100KHZ(0<<8) +#define GMBUS_RATE_50KHZ (1<<8) +#define GMBUS_RATE_400KHZ(2<<8) /* reserved on Pineview */ +#define GMBUS_RATE_1MHZ (3<<8) /* reserved on Pineview */ +#define GMBUS_HOLD_EXT (1<<7) /* 300ns hold time, rsvd on Pineview */ +#define GMBUS_PORT_DISABLED 0 +#define GMBUS_PORT_SSC 1 +#define GMBUS_PORT_VGADDC2 +#define GMBUS_PORT_PANEL 3 +#define GMBUS_PORT_DPC 4 /* HDMIC */ +#define GMBUS_PORT_DPB 5 /* SDVO, HDMIB */ +#define GMBUS_PORT_DPD 6 /* HDMID */ + /* 7 reserved */ +#define GMBUS1 0x5104 /* command/status */ +#define GMBUS_SW_CLR_INT (1<<31) +#define GMBUS_SW_RDY (1<<30) +#define GMBUS_ENT(1<<29) /* enable timeout */ +#define GMBUS_CYCLE_NONE (0<<25) +#define GMBUS_CYCLE_NI_NS_WAIT (1<<25) +#define GMBUS_CYCLE_I_NS_WAIT(3<<25) +#define GMBUS_CYCLE_STOP (4<<25) +#define GMBUS_CYCLE_NI_STOP (5<<25) +#define GMBUS_CYCLE_I_STOP (7<<25) +#define GMBUS_BYTE_COUNT_SHIFT 16 +#define GMBUS_SLAVE_INDEX_SHIFT 8 +#define GMBUS_SLAVE_ADDR_SHIFT 1 +#define GMBUS_SLAVE_READ (1<<0) +#define GMBUS_SLAVE_WRITE(0<<0) +#define GMBUS2 0x5108 /* status */ +#define GMBUS_INUSE (1<<15) +#define GMBUS_HW_WAIT_PHASE (1<<14) +#define GMBUS_STALL_TIMEOUT (1<<13) +#define GMBUS_INT(1<<12) +#define GMBUS_HW_RDY (1<<11) +#define GMBUS_SATOER (1<<10) +#define GMBUS_ACTIVE (1<<9) +#define GMBUS3 0x510c /* data buffer bytes 3-0 */ +#define GMBUS4 0x5110 /* interrupt mask (Pineview+) */ +#define GMBUS_SLAVE_TIMEOUT_EN (1<<4) +#define GMBUS_NAK_EN (1<<3) +#define GMBUS_IDLE_EN(1<<2) +#define GMBUS_HW_WAIT_EN (1<<1) +#define GMBUS_HW_RDY_EN (1<<0) +#define GMBUS5 0x5120 /* byte index */ +#define GMBUS_2BYTE_INDEX_EN (1<<31) /* * Clock control & power management diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index ee0732b..60dc11b 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -453,6 +453,12 @@ static int intel_crt_get_modes(struct drm_connector *connector) struct i2c_adapter *ddc_bus; struct drm_device *dev = connector->dev; + /* Try GMBUS first */ + ret = intel_gmbus_get_modes(connector, 0); + if (ret) { + DRM_DEBUG_DRIVER("got EDID from GMBUS\n"); + goto end; + } ret = intel_ddc_get_modes(connector, intel_encoder->ddc_bus); if (ret || !IS_G4X(dev)) @@ -466,6 +472,7 @@ static int intel_crt_get_modes(struct drm_connector *connector) "DDC bus registration failed for CRTDDC_D.\n"); goto end; } + /* Try to get modes by GPIOD port */ ret = intel_ddc_get_modes(connector, ddc_bus); intel_i2c_destroy(ddc_bus); diff --git a/drivers/gpu/drm/i915/intel_modes.c b/drivers/gpu/drm/i915/intel_modes.c index 35d15f8..c9b946d 100644 --- a/drivers/gpu/drm/i915/intel_modes.c +++ b/drivers/gpu/drm/i915/intel_modes.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2007 Dave Airlie - * Copyright (c) 2007 Intel Corporation + * Copyright (c) 2007, 2010 Intel Corporation * Jesse Barnes * * Permission is hereby granted, free of charge, to any person obtaining a @@ -89,3 +89,165 @@ int intel_ddc_get_modes(struct drm_connector *connector, return ret; } + +static void intel_dump_gmbus(drm_i915_private_t *dev_priv) +{ + DRM_DEBUG_DRIVER("GMBUS0: 0x%08x\n", I915_READ(GMBUS0)); + DRM_DEBUG_DRIVER("GMBUS1: 0x%08x\n", I915_READ(GMBUS1)); + DRM_DEBUG_DRIVER("GMBUS2: 0x%08x\n", I915_READ(GMBUS2)); + DRM_DEBUG_DRIVER("GMBUS3: 0x%08x\n",