Commit f899fc64 authored by Chris Wilson's avatar Chris Wilson

drm/i915: use GMBUS to manage i2c links

Use the GMBUS interface rather than direct bit banging to grab the EDID
over DDC (and for other forms of auxiliary communication with external
display controllers). The hope is that this method will be much faster
and more reliable than bit banging for fetching EDIDs from buggy monitors
or through switches, though we still preserve the bit banging as a
fallback in case GMBUS fails.

Based on an original patch by Jesse Barnes.

Cc: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
parent 373a3cf7
......@@ -30,7 +30,6 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
#include "drmP.h"
#include "drm_edid.h"
#include "drm_edid_modes.h"
......
......@@ -168,7 +168,6 @@ static void ch7017_dpms(struct intel_dvo_device *dvo, int mode);
static bool ch7017_read(struct intel_dvo_device *dvo, int addr, uint8_t *val)
{
struct i2c_adapter *adapter = dvo->i2c_bus;
struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
u8 out_buf[2];
u8 in_buf[2];
......@@ -190,7 +189,7 @@ static bool ch7017_read(struct intel_dvo_device *dvo, int addr, uint8_t *val)
out_buf[0] = addr;
out_buf[1] = 0;
if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) {
if (i2c_transfer(adapter, msgs, 2) == 2) {
*val= in_buf[0];
return true;
};
......@@ -201,7 +200,6 @@ static bool ch7017_read(struct intel_dvo_device *dvo, int addr, uint8_t *val)
static bool ch7017_write(struct intel_dvo_device *dvo, int addr, uint8_t val)
{
struct i2c_adapter *adapter = dvo->i2c_bus;
struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
uint8_t out_buf[2];
struct i2c_msg msg = {
.addr = dvo->slave_addr,
......@@ -213,7 +211,7 @@ static bool ch7017_write(struct intel_dvo_device *dvo, int addr, uint8_t val)
out_buf[0] = addr;
out_buf[1] = val;
if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1)
if (i2c_transfer(adapter, &msg, 1) == 1)
return true;
return false;
......@@ -223,7 +221,6 @@ static bool ch7017_write(struct intel_dvo_device *dvo, int addr, uint8_t val)
static bool ch7017_init(struct intel_dvo_device *dvo,
struct i2c_adapter *adapter)
{
struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
struct ch7017_priv *priv;
uint8_t val;
......@@ -242,7 +239,7 @@ static bool ch7017_init(struct intel_dvo_device *dvo,
val != CH7019_DEVICE_ID_VALUE) {
DRM_DEBUG_KMS("ch701x not detected, got %d: from %s "
"Slave %d.\n",
val, i2cbus->adapter.name,dvo->slave_addr);
val, adapter->name,dvo->slave_addr);
goto fail;
}
......
......@@ -113,7 +113,6 @@ static bool ch7xxx_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
{
struct ch7xxx_priv *ch7xxx= dvo->dev_priv;
struct i2c_adapter *adapter = dvo->i2c_bus;
struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
u8 out_buf[2];
u8 in_buf[2];
......@@ -135,14 +134,14 @@ static bool ch7xxx_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
out_buf[0] = addr;
out_buf[1] = 0;
if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) {
if (i2c_transfer(adapter, msgs, 2) == 2) {
*ch = in_buf[0];
return true;
};
if (!ch7xxx->quiet) {
DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n",
addr, i2cbus->adapter.name, dvo->slave_addr);
addr, adapter->name, dvo->slave_addr);
}
return false;
}
......@@ -152,7 +151,6 @@ static bool ch7xxx_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
{
struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
struct i2c_adapter *adapter = dvo->i2c_bus;
struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
uint8_t out_buf[2];
struct i2c_msg msg = {
.addr = dvo->slave_addr,
......@@ -164,12 +162,12 @@ static bool ch7xxx_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
out_buf[0] = addr;
out_buf[1] = ch;
if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1)
if (i2c_transfer(adapter, &msg, 1) == 1)
return true;
if (!ch7xxx->quiet) {
DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
addr, i2cbus->adapter.name, dvo->slave_addr);
addr, adapter->name, dvo->slave_addr);
}
return false;
......
......@@ -167,7 +167,6 @@ static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data)
{
struct ivch_priv *priv = dvo->dev_priv;
struct i2c_adapter *adapter = dvo->i2c_bus;
struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
u8 out_buf[1];
u8 in_buf[2];
......@@ -193,7 +192,7 @@ static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data)
out_buf[0] = addr;
if (i2c_transfer(&i2cbus->adapter, msgs, 3) == 3) {
if (i2c_transfer(adapter, msgs, 3) == 3) {
*data = (in_buf[1] << 8) | in_buf[0];
return true;
};
......@@ -201,7 +200,7 @@ static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data)
if (!priv->quiet) {
DRM_DEBUG_KMS("Unable to read register 0x%02x from "
"%s:%02x.\n",
addr, i2cbus->adapter.name, dvo->slave_addr);
addr, adapter->name, dvo->slave_addr);
}
return false;
}
......@@ -211,7 +210,6 @@ static bool ivch_write(struct intel_dvo_device *dvo, int addr, uint16_t data)
{
struct ivch_priv *priv = dvo->dev_priv;
struct i2c_adapter *adapter = dvo->i2c_bus;
struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
u8 out_buf[3];
struct i2c_msg msg = {
.addr = dvo->slave_addr,
......@@ -224,12 +222,12 @@ static bool ivch_write(struct intel_dvo_device *dvo, int addr, uint16_t data)
out_buf[1] = data & 0xff;
out_buf[2] = data >> 8;
if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1)
if (i2c_transfer(adapter, &msg, 1) == 1)
return true;
if (!priv->quiet) {
DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
addr, i2cbus->adapter.name, dvo->slave_addr);
addr, adapter->name, dvo->slave_addr);
}
return false;
......
......@@ -69,7 +69,6 @@ static bool sil164_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
{
struct sil164_priv *sil = dvo->dev_priv;
struct i2c_adapter *adapter = dvo->i2c_bus;
struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
u8 out_buf[2];
u8 in_buf[2];
......@@ -91,14 +90,14 @@ static bool sil164_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
out_buf[0] = addr;
out_buf[1] = 0;
if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) {
if (i2c_transfer(adapter, msgs, 2) == 2) {
*ch = in_buf[0];
return true;
};
if (!sil->quiet) {
DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n",
addr, i2cbus->adapter.name, dvo->slave_addr);
addr, adapter->name, dvo->slave_addr);
}
return false;
}
......@@ -107,7 +106,6 @@ static bool sil164_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
{
struct sil164_priv *sil= dvo->dev_priv;
struct i2c_adapter *adapter = dvo->i2c_bus;
struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
uint8_t out_buf[2];
struct i2c_msg msg = {
.addr = dvo->slave_addr,
......@@ -119,12 +117,12 @@ static bool sil164_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
out_buf[0] = addr;
out_buf[1] = ch;
if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1)
if (i2c_transfer(adapter, &msg, 1) == 1)
return true;
if (!sil->quiet) {
DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
addr, i2cbus->adapter.name, dvo->slave_addr);
addr, adapter->name, dvo->slave_addr);
}
return false;
......
......@@ -94,7 +94,6 @@ static bool tfp410_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
{
struct tfp410_priv *tfp = dvo->dev_priv;
struct i2c_adapter *adapter = dvo->i2c_bus;
struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
u8 out_buf[2];
u8 in_buf[2];
......@@ -116,14 +115,14 @@ static bool tfp410_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
out_buf[0] = addr;
out_buf[1] = 0;
if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) {
if (i2c_transfer(adapter, msgs, 2) == 2) {
*ch = in_buf[0];
return true;
};
if (!tfp->quiet) {
DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n",
addr, i2cbus->adapter.name, dvo->slave_addr);
addr, adapter->name, dvo->slave_addr);
}
return false;
}
......@@ -132,7 +131,6 @@ static bool tfp410_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
{
struct tfp410_priv *tfp = dvo->dev_priv;
struct i2c_adapter *adapter = dvo->i2c_bus;
struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
uint8_t out_buf[2];
struct i2c_msg msg = {
.addr = dvo->slave_addr,
......@@ -144,12 +142,12 @@ static bool tfp410_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
out_buf[0] = addr;
out_buf[1] = ch;
if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1)
if (i2c_transfer(adapter, &msg, 1) == 1)
return true;
if (!tfp->quiet) {
DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
addr, i2cbus->adapter.name, dvo->slave_addr);
addr, adapter->name, dvo->slave_addr);
}
return false;
......
......@@ -2001,6 +2001,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
/* Try to make sure MCHBAR is enabled before poking at it */
intel_setup_mchbar(dev);
intel_setup_gmbus(dev);
intel_opregion_setup(dev);
i915_gem_load(dev);
......@@ -2155,6 +2156,7 @@ int i915_driver_unload(struct drm_device *dev)
intel_cleanup_overlay(dev);
}
intel_teardown_gmbus(dev);
intel_teardown_mchbar(dev);
destroy_workqueue(dev_priv->wq);
......
......@@ -34,6 +34,7 @@
#include "intel_bios.h"
#include "intel_ringbuffer.h"
#include <linux/io-mapping.h>
#include <linux/i2c.h>
#include <drm/intel-gtt.h>
/* General customization:
......@@ -246,6 +247,12 @@ typedef struct drm_i915_private {
void __iomem *regs;
struct intel_gmbus {
struct i2c_adapter adapter;
struct i2c_adapter *force_bitbanging;
int pin;
} *gmbus;
struct pci_dev *bridge_dev;
struct intel_ring_buffer render_ring;
struct intel_ring_buffer bsd_ring;
......@@ -339,7 +346,7 @@ typedef struct drm_i915_private {
struct notifier_block lid_notifier;
int crt_ddc_bus; /* 0 = unknown, else GPIO to use for CRT DDC */
int crt_ddc_pin;
struct drm_i915_fence_reg fence_regs[16]; /* assume 965 */
int fence_reg_start; /* 4 if userland hasn't ioctl'd us yet */
int num_fence_regs; /* 8 on pre-965, 16 otherwise */
......@@ -1070,6 +1077,11 @@ extern int i915_restore_state(struct drm_device *dev);
extern int i915_save_state(struct drm_device *dev);
extern int i915_restore_state(struct drm_device *dev);
/* intel_i2c.c */
extern int intel_setup_gmbus(struct drm_device *dev);
extern void intel_teardown_gmbus(struct drm_device *dev);
extern void intel_i2c_reset(struct drm_device *dev);
/* intel_opregion.c */
extern int intel_opregion_setup(struct drm_device *dev);
#ifdef CONFIG_ACPI
......
......@@ -583,12 +583,51 @@
# 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_VGADDC 2
#define GMBUS_PORT_PANEL 3
#define GMBUS_PORT_DPC 4 /* HDMIC */
#define GMBUS_PORT_DPB 5 /* SDVO, HDMIB */
/* 6 reserved */
#define GMBUS_PORT_DPD 7 /* HDMID */
#define GMBUS_NUM_PORTS 8
#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_WAIT (1<<25)
#define GMBUS_CYCLE_INDEX (2<<25)
#define GMBUS_CYCLE_STOP (4<<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
......
......@@ -860,9 +860,7 @@ int i915_restore_state(struct drm_device *dev)
for (i = 0; i < 3; i++)
I915_WRITE(SWF30 + (i << 2), dev_priv->saveSWF2[i]);
/* I2C state */
intel_i2c_reset_gmbus(dev);
intel_i2c_reset(dev);
return 0;
}
......@@ -291,14 +291,6 @@ parse_general_definitions(struct drm_i915_private *dev_priv,
struct bdb_header *bdb)
{
struct bdb_general_definitions *general;
const int crt_bus_map_table[] = {
GPIOB,
GPIOA,
GPIOC,
GPIOD,
GPIOE,
GPIOF,
};
general = find_section(bdb, BDB_GENERAL_DEFINITIONS);
if (general) {
......@@ -306,10 +298,8 @@ parse_general_definitions(struct drm_i915_private *dev_priv,
if (block_size >= sizeof(*general)) {
int bus_pin = general->crt_ddc_gmbus_pin;
DRM_DEBUG_KMS("crt_ddc_bus_pin: %d\n", bus_pin);
if ((bus_pin >= 1) && (bus_pin <= 6)) {
dev_priv->crt_ddc_bus =
crt_bus_map_table[bus_pin-1];
}
if (bus_pin >= 1 && bus_pin <= 6)
dev_priv->crt_ddc_pin = bus_pin - 1;
} else {
DRM_DEBUG_KMS("BDB_GD too small (%d). Invalid.\n",
block_size);
......@@ -533,6 +523,8 @@ intel_init_bios(struct drm_device *dev)
struct bdb_header *bdb = NULL;
u8 __iomem *bios = NULL;
dev_priv->crt_ddc_pin = GMBUS_PORT_VGADDC;
/* XXX Should this validation be moved to intel_opregion.c? */
if (dev_priv->opregion.vbt) {
struct vbt_header *vbt = dev_priv->opregion.vbt;
......
......@@ -264,12 +264,13 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector)
static bool intel_crt_detect_ddc(struct drm_encoder *encoder)
{
struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
struct drm_i915_private *dev_priv = encoder->dev->dev_private;
/* CRT should always be at 0, but check anyway */
if (intel_encoder->type != INTEL_OUTPUT_ANALOG)
return false;
return intel_ddc_probe(intel_encoder);
return intel_ddc_probe(intel_encoder, dev_priv->crt_ddc_pin);
}
static enum drm_connector_status
......@@ -445,29 +446,18 @@ static void intel_crt_destroy(struct drm_connector *connector)
static int intel_crt_get_modes(struct drm_connector *connector)
{
struct intel_encoder *encoder = intel_attached_encoder(connector);
struct i2c_adapter *ddc_bus;
struct drm_device *dev = connector->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
int ret;
ret = intel_ddc_get_modes(connector, encoder->ddc_bus);
ret = intel_ddc_get_modes(connector,
&dev_priv->gmbus[dev_priv->crt_ddc_pin].adapter);
if (ret || !IS_G4X(dev))
goto end;
return ret;
/* Try to probe digital port for output in DVI-I -> VGA mode. */
ddc_bus = intel_i2c_create(encoder, GPIOD, "CRTDDC_D");
if (!ddc_bus) {
dev_printk(KERN_ERR, &connector->dev->pdev->dev,
"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);
end:
return ret;
return intel_ddc_get_modes(connector,
&dev_priv->gmbus[GMBUS_PORT_DPB].adapter);
}
static int intel_crt_set_property(struct drm_connector *connector,
......@@ -513,7 +503,6 @@ void intel_crt_init(struct drm_device *dev)
struct intel_encoder *intel_encoder;
struct intel_connector *intel_connector;
struct drm_i915_private *dev_priv = dev->dev_private;
u32 i2c_reg;
intel_encoder = kzalloc(sizeof(struct intel_encoder), GFP_KERNEL);
if (!intel_encoder)
......@@ -534,27 +523,6 @@ void intel_crt_init(struct drm_device *dev)
intel_connector_attach_encoder(intel_connector, intel_encoder);
/* Set up the DDC bus. */
if (HAS_PCH_SPLIT(dev))
i2c_reg = PCH_GPIOA;
else {
i2c_reg = GPIOA;
/* Use VBT information for CRT DDC if available */
if (dev_priv->crt_ddc_bus != 0)
i2c_reg = dev_priv->crt_ddc_bus;
}
intel_encoder->ddc_bus = intel_i2c_create(intel_encoder,
i2c_reg, "CRTDDC_A");
if (!intel_encoder->ddc_bus) {
dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration "
"failed.\n");
drm_connector_cleanup(&intel_connector->base);
kfree(intel_connector);
drm_encoder_cleanup(&intel_encoder->base);
kfree(intel_encoder);
return;
}
intel_encoder->type = INTEL_OUTPUT_ANALOG;
intel_encoder->clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
(1 << INTEL_ANALOG_CLONE_BIT) |
......
......@@ -2530,12 +2530,6 @@ void intel_encoder_destroy(struct drm_encoder *encoder)
{
struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
if (intel_encoder->ddc_bus)
intel_i2c_destroy(intel_encoder->ddc_bus);
if (intel_encoder->i2c_bus)
intel_i2c_destroy(intel_encoder->i2c_bus);
drm_encoder_cleanup(encoder);
kfree(intel_encoder);
}
......
......@@ -1490,7 +1490,7 @@ static int intel_dp_get_modes(struct drm_connector *connector)
/* We should parse the EDID data and find out if it has an audio sink
*/
ret = intel_ddc_get_modes(connector, intel_dp->base.ddc_bus);
ret = intel_ddc_get_modes(connector, &intel_dp->adapter);
if (ret) {
if ((IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) &&
!dev_priv->panel_fixed_mode) {
......@@ -1705,7 +1705,6 @@ intel_dp_init(struct drm_device *dev, int output_reg)
intel_dp_i2c_init(intel_dp, intel_connector, name);
intel_encoder->ddc_bus = &intel_dp->adapter;
intel_encoder->hot_plug = intel_dp_hot_plug;
if (output_reg == DP_A || IS_PCH_eDP(intel_dp)) {
......
......@@ -26,8 +26,6 @@
#define __INTEL_DRV_H__
#include <linux/i2c.h>
#include <linux/i2c-id.h>
#include <linux/i2c-algo-bit.h>
#include "i915_drv.h"
#include "drm_crtc.h"
#include "drm_crtc_helper.h"
......@@ -127,13 +125,6 @@ intel_mode_get_pixel_multiplier(const struct drm_display_mode *mode)
return (mode->private_flags & INTEL_MODE_PIXEL_MULTIPLIER_MASK) >> INTEL_MODE_PIXEL_MULTIPLIER_SHIFT;
}
struct intel_i2c_chan {
struct intel_encoder *encoder;
u32 reg; /* GPIO reg */
struct i2c_adapter adapter;
struct i2c_algo_bit_data algo;
};
struct intel_framebuffer {
struct drm_framebuffer base;
struct drm_gem_object *obj;
......@@ -149,8 +140,6 @@ struct intel_fbdev {
struct intel_encoder {
struct drm_encoder base;
int type;
struct i2c_adapter *i2c_bus;
struct i2c_adapter *ddc_bus;
bool load_detect_temp;
bool needs_tv_clock;
void (*hot_plug)(struct intel_encoder *);
......@@ -206,14 +195,8 @@ struct intel_unpin_work {
bool enable_stall_check;
};
struct i2c_adapter *intel_i2c_create(struct intel_encoder *encoder,
const u32 reg,
const char *name);
void intel_i2c_destroy(struct i2c_adapter *adapter);
int intel_ddc_get_modes(struct drm_connector *c, struct i2c_adapter *adapter);
extern bool intel_ddc_probe(struct intel_encoder *intel_encoder);
void intel_i2c_quirk_set(struct drm_device *dev, bool enable);
void intel_i2c_reset_gmbus(struct drm_device *dev);
extern bool intel_ddc_probe(struct intel_encoder *intel_encoder, int ddc_bus);
extern void intel_crt_init(struct drm_device *dev);
extern void intel_hdmi_init(struct drm_device *dev, int sdvox_reg);
......
......@@ -72,7 +72,7 @@ static const struct intel_dvo_device intel_dvo_devices[] = {
.name = "ch7017",
.dvo_reg = DVOC,
.slave_addr = 0x75,
.gpio = GPIOE,
.gpio = GMBUS_PORT_DPD,
.dev_ops = &ch7017_ops,
}
};
......@@ -81,6 +81,7 @@ struct intel_dvo {
struct intel_encoder base;
struct intel_dvo_device dev;
int ddc_bus;
struct drm_display_mode *panel_fixed_mode;
bool panel_wants_dither;
......@@ -235,13 +236,15 @@ static enum drm_connector_status intel_dvo_detect(struct drm_connector *connecto
static int intel_dvo_get_modes(struct drm_connector *connector)
{
struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
struct drm_i915_private *dev_priv = connector->dev->dev_private;
/* We should probably have an i2c driver get_modes function for those
* devices which will have a fixed set of modes determined by the chip
* (TV-out, for example), but for now with just TMDS and LVDS,
* that's not the case.
*/
intel_ddc_get_modes(connector, intel_dvo->base.ddc_bus);
intel_ddc_get_modes(connector,
&dev_priv->gmbus[intel_dvo->ddc_bus].adapter);
if (!list_empty(&connector->probed_modes))
return 1;
......@@ -341,10 +344,10 @@ intel_dvo_get_current_mode(struct drm_connector *connector)
void intel_dvo_init(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_encoder *intel_encoder;
struct intel_dvo *intel_dvo;
struct intel_connector *intel_connector;
struct i2c_adapter *i2cbus = NULL;
int ret = 0;
int i;
int encoder_type = DRM_MODE_ENCODER_NONE;
......@@ -364,15 +367,13 @@ void intel_dvo_init(struct drm_device *dev)
&intel_dvo_enc_funcs, encoder_type);
/* Set up the DDC bus */
intel_encoder->ddc_bus = intel_i2c_create(intel_encoder,
GPIOD, "DVODDC_D");
if (!intel_encoder->ddc_bus)
goto free_intel;
intel_dvo->ddc_bus = GMBUS_PORT_DPB;
/* Now, try to find a controller */
for (i = 0; i < ARRAY_SIZE(intel_dvo_devices); i++) {
struct drm_connector *connector = &intel_connector->base;
const struct intel_dvo_device *dvo = &intel_dvo_devices[i];
struct i2c_adapter *i2c;
int gpio;
/* Allow the I2C driver info to specify the GPIO to be used in
......@@ -382,23 +383,18 @@ void intel_dvo_init(struct drm_device *dev)
if (dvo->gpio != 0)
gpio = dvo->gpio;
else if (dvo->type == INTEL_DVO_CHIP_LVDS)
gpio = GPIOB;
gpio = GMBUS_PORT_PANEL;
else
gpio = GPIOE;
gpio = GMBUS_PORT_DPD;
/* Set up the I2C bus necessary for the chip we're probing.
* It appears that everything is on GPIOE except for panels
* on i830 laptops, which are on GPIOB (DVOA).
*/
if (i2cbus != NULL)
intel_i2c_destroy(i2cbus);
i2cbus = intel_i2c_create(intel_encoder, gpio,
gpio == GPIOB ? "DVOI2C_B" : "DVOI2C_E");
if (i2cbus == NULL)
continue;
i2c = &dev_priv->gmbus[gpio].adapter;
intel_dvo->dev = *dvo;
ret = dvo->dev_ops->init(&intel_dvo->dev, i2cbus);
ret = dvo->dev_ops->init(&intel_dvo->dev, i2c);
if (!ret)
continue;
......@@ -451,11 +447,6 @@ void intel_dvo_init(struct drm_device *dev)
return;
}
intel_i2c_destroy(intel_encoder->ddc_bus);
/* Didn't find a chip, so tear down. */
if (i2cbus != NULL)
intel_i2c_destroy(i2cbus);
free_intel:
drm_encoder_cleanup(&intel_encoder->base);
kfree(intel_dvo);
kfree(intel_connector);
......
......@@ -40,6 +40,7 @@
struct intel_hdmi {
struct intel_encoder base;
u32 sdvox_reg;
int ddc_bus;
bool has_hdmi_sink;
};
......@@ -148,11 +149,13 @@ static enum drm_connector_status
intel_hdmi_detect(struct drm_connector *connector)
{
struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
struct edid *edid = NULL;
struct drm_i915_private *dev_priv = connector->dev->dev_private;
struct edid *edid;
enum drm_connector_status status = connector_status_disconnected;
intel_hdmi->has_hdmi_sink = false;
edid = drm_get_edid(connector, intel_hdmi->base.ddc_bus);
edid = drm_get_edid(connector,
&dev_priv->gmbus[intel_hdmi->ddc_bus].adapter);
if (edid) {
if (edid->input & DRM_EDID_INPUT_DIGITAL) {
......@@ -169,12 +172,14 @@ intel_hdmi_detect(struct drm_connector *connector)
static int intel_hdmi_get_modes(struct drm_connector *connector)
{
struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
struct drm_i915_private *dev_priv = connector->dev->dev_private;
/* We should parse the EDID data and find out if it's an HDMI sink so
* we can send audio to it.
*/
return intel_ddc_get_modes(connector, intel_hdmi->base.ddc_bus);
return intel_ddc_get_modes(connector,
&dev_priv->gmbus[intel_hdmi->ddc_bus].adapter);
}
static void intel_hdmi_destroy(struct drm_connector *connector)
......@@ -246,32 +251,25 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
/* Set up the DDC bus. */
if (sdvox_reg == SDVOB) {
intel_encoder->clone_mask = (1 << INTEL_HDMIB_CLONE_BIT);
intel_encoder->ddc_bus = intel_i2c_create(intel_encoder,
GPIOE, "HDMIB");
intel_hdmi->ddc_bus = GMBUS_PORT_DPB;
dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS;
} else if (sdvox_reg == SDVOC) {
intel_encoder->clone_mask = (1 << INTEL_HDMIC_CLONE_BIT);
intel_encoder->ddc_bus = intel_i2c_create(intel_encoder,
GPIOD, "HDMIC");
intel_hdmi->ddc_bus = GMBUS_PORT_DPC;
dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS;
} else if (sdvox_reg == HDMIB) {
intel_encoder->clone_mask = (1 << INTEL_HDMID_CLONE_BIT);
intel_encoder->ddc_bus = intel_i2c_create(intel_encoder,
PCH_GPIOE, "HDMIB");
intel_hdmi->ddc_bus = GMBUS_PORT_DPB;
dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS;
} else if (sdvox_reg == HDMIC) {
intel_encoder->clone_mask = (1 << INTEL_HDMIE_CLONE_BIT);
intel_encoder->ddc_bus = intel_i2c_create(intel_encoder,
PCH_GPIOD, "HDMIC");
intel_hdmi->ddc_bus = GMBUS_PORT_DPC;
dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS;
} else if (sdvox_reg == HDMID) {
intel_encoder->clone_mask = (1 << INTEL_HDMIF_CLONE_BIT);
intel_encoder->ddc_bus = intel_i2c_create(intel_encoder,
PCH_GPIOF, "HDMID");
intel_hdmi->ddc_bus = GMBUS_PORT_DPD;
dev_priv->hotplug_supported_mask |= HDMID_HOTPLUG_INT_STATUS;
}
if (!intel_encoder->ddc_bus)
goto err_connector;
intel_hdmi->sdvox_reg = sdvox_reg;
......@@ -288,14 +286,4 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
u32 temp = I915_READ(PEG_BAND_GAP_DATA);
I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd);
}
return;
err_connector:
drm_encoder_cleanup(&intel_encoder->base);
drm_connector_cleanup(connector);
kfree(intel_hdmi);
kfree(intel_connector);
return;
}
This diff is collapsed.
......@@ -474,11 +474,12 @@ static int intel_lvds_get_modes(struct drm_connector *connector)
{
struct intel_lvds *intel_lvds = intel_attached_lvds(connector);
struct drm_device *dev = connector->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_display_mode *mode;
if (intel_lvds->edid_good) {
int ret = intel_ddc_get_modes(connector,
intel_lvds->base.ddc_bus);
&dev_priv->gmbus[GMBUS_PORT_PANEL].adapter);
if (ret)
return ret;
}
......@@ -898,21 +899,12 @@ void intel_lvds_init(struct drm_device *dev)
* if closed, act like it's not there for now
*/
/* Set up the DDC bus. */
intel_encoder->ddc_bus = intel_i2c_create(intel_encoder,
gpio, "LVDSDDC_C");
if (!intel_encoder->ddc_bus) {
dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration "
"failed.\n");
goto failed;
}
/*
* Attempt to get the fixed panel mode from DDC. Assume that the
* preferred mode is the right one.
*/
intel_lvds->edid_good = true;
if (!intel_ddc_get_modes(connector, intel_encoder->ddc_bus))
if (!intel_ddc_get_modes(connector, &dev_priv->gmbus[GMBUS_PORT_PANEL].adapter))
intel_lvds->edid_good = false;
if (!intel_lvds->edid_good) {
......@@ -999,8 +991,6 @@ void intel_lvds_init(struct drm_device *dev)
failed:
DRM_DEBUG_KMS("No LVDS modes found, disabling.\n");
if (intel_encoder->ddc_bus)
intel_i2c_destroy(intel_encoder->ddc_bus);
drm_connector_cleanup(connector);
drm_encoder_cleanup(encoder);
kfree(intel_lvds);
......
/*
* Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
* Copyright (c) 2007 Intel Corporation
* Copyright (c) 2007, 2010 Intel Corporation
* Jesse Barnes <jesse.barnes@intel.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
......@@ -34,11 +34,11 @@
* intel_ddc_probe
*
*/
bool intel_ddc_probe(struct intel_encoder *intel_encoder)
bool intel_ddc_probe(struct intel_encoder *intel_encoder, int ddc_bus)
{
struct drm_i915_private *dev_priv = intel_encoder->base.dev->dev_private;
u8 out_buf[] = { 0x0, 0x0};
u8 buf[2];
int ret;
struct i2c_msg msgs[] = {
{
.addr = 0x50,
......@@ -54,13 +54,7 @@ bool intel_ddc_probe(struct intel_encoder *intel_encoder)
}
};
intel_i2c_quirk_set(intel_encoder->base.dev, true);
ret = i2c_transfer(intel_encoder->ddc_bus, msgs, 2);
intel_i2c_quirk_set(intel_encoder->base.dev, false);
if (ret == 2)
return true;
return false;
return i2c_transfer(&dev_priv->gmbus[ddc_bus].adapter, msgs, 2) == 2;
}
/**
......@@ -76,9 +70,7 @@ int intel_ddc_get_modes(struct drm_connector *connector,
struct edid *edid;
int ret = 0;
intel_i2c_quirk_set(connector->dev, true);
edid = drm_get_edid(connector, adapter);
intel_i2c_quirk_set(connector->dev, false);
if (edid) {
drm_mode_connector_update_edid_property(connector, edid);
ret = drm_add_edid_modes(connector, edid);
......
......@@ -65,6 +65,7 @@ static const char *tv_format_names[] = {
struct intel_sdvo {
struct intel_encoder base;
struct i2c_adapter *i2c;
u8 slave_addr;
/* Register for the SDVO device: SDVOB or SDVOC */
......@@ -264,7 +265,7 @@ static bool intel_sdvo_read_byte(struct intel_sdvo *intel_sdvo, u8 addr, u8 *ch)
};
int ret;
if ((ret = i2c_transfer(intel_sdvo->base.i2c_bus, msgs, 2)) == 2)
if ((ret = i2c_transfer(intel_sdvo->i2c, msgs, 2)) == 2)
{
*ch = buf[0];
return true;
......@@ -286,7 +287,7 @@ static bool intel_sdvo_write_byte(struct intel_sdvo *intel_sdvo, int addr, u8 ch
}
};
return i2c_transfer(intel_sdvo->base.i2c_bus, msgs, 1) == 1;
return i2c_transfer(intel_sdvo->i2c, msgs, 1) == 1;
}
#define SDVO_CMD_NAME_ENTRY(cmd) {cmd, #cmd}
......@@ -566,7 +567,7 @@ static int intel_sdvo_set_control_bus_switch(struct intel_sdvo *intel_sdvo,
ret_value[0] = 0;
ret_value[1] = 0;
ret = i2c_transfer(intel_sdvo->base.i2c_bus, msgs, 3);
ret = i2c_transfer(intel_sdvo->i2c, msgs, 3);
if (ret < 0)
return ret;
if (ret != 3) {
......@@ -1375,6 +1376,19 @@ intel_sdvo_multifunc_encoder(struct intel_sdvo *intel_sdvo)
return (caps > 1);
}
static struct edid *
intel_sdvo_get_edid(struct drm_connector *connector, int ddc)
{
struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
int ret;
ret = intel_sdvo_set_control_bus_switch(intel_sdvo, ddc);
if (ret)
return NULL;
return drm_get_edid(connector, intel_sdvo->i2c);
}
static struct drm_connector *
intel_find_analog_connector(struct drm_device *dev)
{
......@@ -1418,28 +1432,12 @@ intel_analog_is_connected(struct drm_device *dev)
static struct edid *
intel_sdvo_get_analog_edid(struct drm_connector *connector)
{
struct intel_encoder *encoder = intel_attached_encoder(connector);
struct drm_device *dev = connector->dev;
struct i2c_adapter *ddc;
struct edid *edid;
u32 ddc_reg;
if (!intel_analog_is_connected(dev))
return NULL;
if (HAS_PCH_SPLIT(dev))
ddc_reg = PCH_GPIOA;
else
ddc_reg = GPIOA;
struct drm_i915_private *dev_priv = connector->dev->dev_private;
ddc = intel_i2c_create(encoder, ddc_reg, "SDVO/VGA DDC BUS");
if (ddc == NULL)
if (!intel_analog_is_connected(connector->dev))
return NULL;
edid = drm_get_edid(connector, ddc);
intel_i2c_destroy(ddc);
return edid;
return drm_get_edid(connector, &dev_priv->gmbus[dev_priv->crt_ddc_pin].adapter);
}
enum drm_connector_status
......@@ -1449,28 +1447,26 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector)
enum drm_connector_status status;
struct edid *edid;
edid = drm_get_edid(connector, intel_sdvo->base.ddc_bus);
edid = intel_sdvo_get_edid(connector, intel_sdvo->ddc_bus);
if (edid == NULL && intel_sdvo_multifunc_encoder(intel_sdvo)) {
u8 saved_ddc = intel_sdvo->ddc_bus, ddc;
u8 ddc;
/*
* Don't use the 1 as the argument of DDC bus switch to get
* the EDID. It is used for SDVO SPD ROM.
*/
for (ddc = intel_sdvo->ddc_bus >> 1; ddc > 1; ddc >>= 1) {
intel_sdvo->ddc_bus = ddc;
edid = drm_get_edid(connector, intel_sdvo->base.ddc_bus);
if (edid)
edid = intel_sdvo_get_edid(connector, ddc);
if (edid) {
/*
* If we found the EDID on the other bus,
* assume that is the correct DDC bus.
*/
intel_sdvo->ddc_bus = ddc;
break;
}
}
/*
* If we found the EDID on the other bus, maybe that is the
* correct DDC bus.
*/
if (edid == NULL)
intel_sdvo->ddc_bus = saved_ddc;
}
/*
......@@ -1546,12 +1542,9 @@ static void intel_sdvo_get_ddc_modes(struct drm_connector *connector)
{
struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
struct edid *edid;
int num_modes;
/* set the bus switch and get the modes */
num_modes = intel_ddc_get_modes(connector, intel_sdvo->base.ddc_bus);
if (num_modes)
return;
edid = intel_sdvo_get_edid(connector, intel_sdvo->ddc_bus);
/*
* Mac mini hack. On this device, the DVI-I connector shares one DDC
......@@ -1559,7 +1552,9 @@ static void intel_sdvo_get_ddc_modes(struct drm_connector *connector)
* DDC fails, check to see if the analog output is disconnected, in
* which case we'll look there for the digital DDC data.
*/
edid = intel_sdvo_get_analog_edid(connector);
if (edid == NULL)
edid = intel_sdvo_get_analog_edid(connector);
if (edid != NULL) {
drm_mode_connector_update_edid_property(connector, edid);
drm_add_edid_modes(connector, edid);
......@@ -1678,7 +1673,7 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
* Assume that the preferred modes are
* arranged in priority order.
*/
intel_ddc_get_modes(connector, intel_sdvo->base.ddc_bus);
intel_ddc_get_modes(connector, intel_sdvo->i2c);
if (list_empty(&connector->probed_modes) == false)
goto end;
......@@ -2004,30 +1999,6 @@ intel_sdvo_get_digital_encoding_mode(struct intel_sdvo *intel_sdvo, int device)
&intel_sdvo->is_hdmi, 1);
}
static int intel_sdvo_master_xfer(struct i2c_adapter *i2c_adap,
struct i2c_msg msgs[], int num)
{
struct intel_sdvo *intel_sdvo;
const struct i2c_algorithm *algo;
int ret;
intel_sdvo = container_of(i2c_adap->algo_data,
struct intel_sdvo,
base);
algo = intel_sdvo->base.i2c_bus->algo;
ret = intel_sdvo_set_control_bus_switch(intel_sdvo,
intel_sdvo->ddc_bus);
if (ret)
return ret;
return algo->master_xfer(i2c_adap, msgs, num);
}
static struct i2c_algorithm intel_sdvo_i2c_bit_algo = {
.master_xfer = intel_sdvo_master_xfer,
};
static u8
intel_sdvo_get_slave_addr(struct drm_device *dev, int sdvo_reg)
{
......@@ -2540,9 +2511,7 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg)
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_encoder *intel_encoder;
struct intel_sdvo *intel_sdvo;
u8 ch[0x40];
int i;
u32 i2c_reg, ddc_reg;
intel_sdvo = kzalloc(sizeof(struct intel_sdvo), GFP_KERNEL);
if (!intel_sdvo)
......@@ -2555,82 +2524,49 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg)
/* encoder type will be decided later */
drm_encoder_init(dev, &intel_encoder->base, &intel_sdvo_enc_funcs, 0);
if (HAS_PCH_SPLIT(dev)) {
i2c_reg = PCH_GPIOE;
ddc_reg = PCH_GPIOE;
} else {
i2c_reg = GPIOE;
ddc_reg = GPIOE;
}
/* setup the DDC bus. */
if (IS_SDVOB(sdvo_reg))
intel_encoder->i2c_bus =
intel_i2c_create(intel_encoder,
i2c_reg, "SDVOCTRL_E for SDVOB");
else
intel_encoder->i2c_bus =
intel_i2c_create(intel_encoder,
i2c_reg, "SDVOCTRL_E for SDVOC");
if (!intel_encoder->i2c_bus)
goto err_inteloutput;
intel_sdvo->i2c = &dev_priv->gmbus[GMBUS_PORT_DPB].adapter;
intel_sdvo->slave_addr = intel_sdvo_get_slave_addr(dev, sdvo_reg);
/* Save the bit-banging i2c functionality for use by the DDC wrapper */
intel_sdvo_i2c_bit_algo.functionality = intel_encoder->i2c_bus->algo->functionality;
/* Read the regs to test if we can talk to the device */
for (i = 0; i < 0x40; i++) {
if (!intel_sdvo_read_byte(intel_sdvo, i, &ch[i])) {
u8 byte;
if (!intel_sdvo_read_byte(intel_sdvo, i, &byte)) {
DRM_DEBUG_KMS("No SDVO device found on SDVO%c\n",
IS_SDVOB(sdvo_reg) ? 'B' : 'C');
goto err_i2c;
goto err;
}
}
/* setup the DDC bus. */
if (IS_SDVOB(sdvo_reg)) {
intel_encoder->ddc_bus =
intel_i2c_create(intel_encoder,
ddc_reg, "SDVOB DDC BUS");
if (IS_SDVOB(sdvo_reg))
dev_priv->hotplug_supported_mask |= SDVOB_HOTPLUG_INT_STATUS;
} else {
intel_encoder->ddc_bus =
intel_i2c_create(intel_encoder,
ddc_reg, "SDVOC DDC BUS");
else
dev_priv->hotplug_supported_mask |= SDVOC_HOTPLUG_INT_STATUS;
}
if (intel_encoder->ddc_bus == NULL)
goto err_i2c;
/* Wrap with our custom algo which switches to DDC mode */
intel_encoder->ddc_bus->algo = &intel_sdvo_i2c_bit_algo;
drm_encoder_helper_add(&intel_encoder->base, &intel_sdvo_helper_funcs);
/* In default case sdvo lvds is false */
if (!intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps))
goto err_i2c;
goto err;
if (intel_sdvo_output_setup(intel_sdvo,
intel_sdvo->caps.output_flags) != true) {
DRM_DEBUG_KMS("SDVO output failed to setup on SDVO%c\n",
IS_SDVOB(sdvo_reg) ? 'B' : 'C');
goto err_i2c;
goto err;
}
intel_sdvo_select_ddc_bus(dev_priv, intel_sdvo, sdvo_reg);
/* Set the input timing to the screen. Assume always input 0. */
if (!intel_sdvo_set_target_input(intel_sdvo))
goto err_i2c;
goto err;
if (!intel_sdvo_get_input_pixel_clock_range(intel_sdvo,
&intel_sdvo->pixel_clock_min,
&intel_sdvo->pixel_clock_max))
goto err_i2c;
goto err;
DRM_DEBUG_KMS("%s device VID/DID: %02X:%02X.%02X, "
"clock range %dMHz - %dMHz, "
......@@ -2650,12 +2586,7 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg)
(SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N');
return true;
err_i2c:
if (intel_encoder->ddc_bus != NULL)
intel_i2c_destroy(intel_encoder->ddc_bus);
if (intel_encoder->i2c_bus != NULL)
intel_i2c_destroy(intel_encoder->i2c_bus);
err_inteloutput:
err:
drm_encoder_cleanup(&intel_encoder->base);
kfree(intel_sdvo);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment