From 1849ecb22fb3b5d57b65e7369a3957adf9f26f39 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sat, 28 Jan 2012 11:07:09 +0100 Subject: drm/kms: Make i2c buses faster A udelay value of 20 leads to an I2C bus running at only 25 kbps. I2C devices can typically operate faster than this, 50 kbps should be fine for all devices (and compliant devices can always stretch the clock if needed.) FWIW, the vast majority of framebuffer drivers set udelay to 10 already. So set it to 10 in DRM drivers too, this will make EDID block reads faster. We might even lower the udelay value later if no problem is reported. Signed-off-by: Jean Delvare Acked-by: Eugeni Dodonov Cc: Keith Packard Reviewed-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/i915/intel_i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915/intel_i2c.c') diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index d30ccccb9d73..7fa4f640e6fd 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -37,7 +37,7 @@ /* Intel GPIO access functions */ -#define I2C_RISEFALL_TIME 20 +#define I2C_RISEFALL_TIME 10 static inline struct intel_gmbus * to_intel_gmbus(struct i2c_adapter *i2c) -- cgit v1.2.3 From 51a59ac8739b333eaa43a3102b6acaab5037bfa2 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 10 Feb 2012 20:04:52 +0800 Subject: drm: Fix kcalloc parameters swapped The first parameter should be "number of elements" and the second parameter should be "element size". Signed-off-by: Axel Lin Acked-by: Alan Cox Signed-off-by: Dave Airlie --- drivers/gpu/drm/i915/intel_i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915/intel_i2c.c') diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index 7fa4f640e6fd..03573e00471b 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -375,7 +375,7 @@ int intel_setup_gmbus(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; int ret, i; - dev_priv->gmbus = kcalloc(sizeof(struct intel_gmbus), GMBUS_NUM_PORTS, + dev_priv->gmbus = kcalloc(GMBUS_NUM_PORTS, sizeof(struct intel_gmbus), GFP_KERNEL); if (dev_priv->gmbus == NULL) return -ENOMEM; -- cgit v1.2.3 From 8a8ed1f5143b3df312e436ab15290e4a7ca6a559 Mon Sep 17 00:00:00 2001 From: Yufeng Shen Date: Mon, 13 Feb 2012 17:36:54 -0500 Subject: drm/i915: Fix race condition in accessing GMBUS GMBUS has several ports and each has it's own corresponding I2C adpater. When multiple I2C adapters call gmbus_xfer() at the same time there is a race condition in using the underlying GMBUS controller. Fixing this by adding a mutex lock when calling gmbus_xfer(). v2: Moved gmbus_mutex below intel_gmbus and added comments. Rebased to drm-intel-next-queued. Signed-off-by: Yufeng Shen [danvet: Shortened the gmbus_mutex comment a bit and add the patch revision comment to the commit message.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_i2c.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_i2c.c') diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index d30ccccb9d73..fc75d71de53b 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -233,11 +233,15 @@ gmbus_xfer(struct i2c_adapter *adapter, struct intel_gmbus, adapter); struct drm_i915_private *dev_priv = adapter->algo_data; - int i, reg_offset; + int i, reg_offset, ret; - if (bus->force_bit) - return intel_i2c_quirk_xfer(dev_priv, + mutex_lock(&dev_priv->gmbus_mutex); + + if (bus->force_bit) { + ret = intel_i2c_quirk_xfer(dev_priv, bus->force_bit, msgs, num); + goto out; + } reg_offset = HAS_PCH_SPLIT(dev_priv->dev) ? PCH_GMBUS0 - GMBUS0 : 0; @@ -321,7 +325,8 @@ done: * start of the next xfer, till then let it sleep. */ I915_WRITE(GMBUS0 + reg_offset, 0); - return i; + ret = i; + goto out; timeout: DRM_INFO("GMBUS timed out, falling back to bit banging on pin %d [%s]\n", @@ -331,9 +336,12 @@ timeout: /* Hardware may not support GMBUS over these pins? Try GPIO bitbanging instead. */ bus->force_bit = intel_gpio_create(dev_priv, bus->reg0 & 0xff); if (!bus->force_bit) - return -ENOMEM; - - return intel_i2c_quirk_xfer(dev_priv, bus->force_bit, msgs, num); + ret = -ENOMEM; + else + ret = intel_i2c_quirk_xfer(dev_priv, bus->force_bit, msgs, num); +out: + mutex_unlock(&dev_priv->gmbus_mutex); + return ret; } static u32 gmbus_func(struct i2c_adapter *adapter) @@ -380,6 +388,8 @@ int intel_setup_gmbus(struct drm_device *dev) if (dev_priv->gmbus == NULL) return -ENOMEM; + mutex_init(&dev_priv->gmbus_mutex); + for (i = 0; i < GMBUS_NUM_PORTS; i++) { struct intel_gmbus *bus = &dev_priv->gmbus[i]; -- cgit v1.2.3 From caae745a352377f48f6eb43b5040214d803a885f Mon Sep 17 00:00:00 2001 From: Benson Leung Date: Thu, 9 Feb 2012 12:03:17 -0800 Subject: drm/i915: Fix single msg gmbus_xfers writes gmbus_xfer with a single message (particularly a single message write) would set Bus Cycle Select to 100b, the Gen Stop cycle, instead of 101b, No Index, Stop cycle. This would not start single message i2c transactions. Also, gmbus_xfer done: will disable the interface without checking if it is idle. In the case of writes, there will be no wait on status or delay to ensure the write starts and completes before the interface is turned off. Fixed the former issue by using the same cycle selection as used in the I2C_M_RD for the write case. GMBUS_CYCLE_WAIT | (i + 1 == num ? GMBUS_CYCLE_STOP : 0) Fixed the latter by waiting on GMBUS_ACTIVE to deassert before disable. Note from the grumpy d-i-n maintainer: The first hunk that changes the gmbus read path is just cosmetics to align the code with the write path. I.e. the commit message above is slightly lying because the first issue is _only_ with writes (and not simply "particularly"). Signed-off-by: Benson Leung Reviewed-by: Daniel Kurtz Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_i2c.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_i2c.c') diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index 068617f7256a..4e4ddd5d1f51 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -253,7 +253,8 @@ gmbus_xfer(struct i2c_adapter *adapter, if (msgs[i].flags & I2C_M_RD) { I915_WRITE(GMBUS1 + reg_offset, - GMBUS_CYCLE_WAIT | (i + 1 == num ? GMBUS_CYCLE_STOP : 0) | + GMBUS_CYCLE_WAIT | + (i + 1 == num ? GMBUS_CYCLE_STOP : 0) | (len << GMBUS_BYTE_COUNT_SHIFT) | (msgs[i].addr << GMBUS_SLAVE_ADDR_SHIFT) | GMBUS_SLAVE_READ | GMBUS_SW_RDY); @@ -282,7 +283,8 @@ gmbus_xfer(struct i2c_adapter *adapter, I915_WRITE(GMBUS3 + reg_offset, val); I915_WRITE(GMBUS1 + reg_offset, - (i + 1 == num ? GMBUS_CYCLE_STOP : GMBUS_CYCLE_WAIT) | + GMBUS_CYCLE_WAIT | + (i + 1 == num ? GMBUS_CYCLE_STOP : 0) | (msgs[i].len << GMBUS_BYTE_COUNT_SHIFT) | (msgs[i].addr << GMBUS_SLAVE_ADDR_SHIFT) | GMBUS_SLAVE_WRITE | GMBUS_SW_RDY); @@ -321,9 +323,12 @@ clear_err: I915_WRITE(GMBUS1 + reg_offset, 0); done: - /* Mark the GMBUS interface as disabled. We will re-enable it at the - * start of the next xfer, till then let it sleep. + /* Mark the GMBUS interface as disabled after waiting for idle. + * We will re-enable it at the start of the next xfer, + * till then let it sleep. */ + if (wait_for((I915_READ(GMBUS2 + reg_offset) & GMBUS_ACTIVE) == 0, 10)) + DRM_INFO("GMBUS timed out waiting for idle\n"); I915_WRITE(GMBUS0 + reg_offset, 0); ret = i; goto out; -- cgit v1.2.3 From c2b9152f098e213dc5f2e8a4dbbfe090302c58ed Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 14 Feb 2012 22:37:19 +0100 Subject: drm/i915: add dev_priv to intel_gmbus This way we can free up the bus->adaptor.algo_data pointer and make it available for use with the bitbanging fallback algo. Reviewed-by: Eugeni Dodonov Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_i2c.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_i2c.c') diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index 4e4ddd5d1f51..89346cc0bc4b 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -232,7 +232,7 @@ gmbus_xfer(struct i2c_adapter *adapter, struct intel_gmbus *bus = container_of(adapter, struct intel_gmbus, adapter); - struct drm_i915_private *dev_priv = adapter->algo_data; + struct drm_i915_private *dev_priv = bus->dev_priv; int i, reg_offset, ret; mutex_lock(&dev_priv->gmbus_mutex); @@ -406,7 +406,7 @@ int intel_setup_gmbus(struct drm_device *dev) names[i]); bus->adapter.dev.parent = &dev->pdev->dev; - bus->adapter.algo_data = dev_priv; + bus->dev_priv = dev_priv; bus->adapter.algo = &gmbus_algorithm; ret = i2c_add_adapter(&bus->adapter); @@ -447,7 +447,7 @@ void intel_gmbus_force_bit(struct i2c_adapter *adapter, bool force_bit) if (force_bit) { if (bus->force_bit == NULL) { - struct drm_i915_private *dev_priv = adapter->algo_data; + struct drm_i915_private *dev_priv = bus->dev_priv; bus->force_bit = intel_gpio_create(dev_priv, bus->reg0 & 0xff); } -- cgit v1.2.3 From 36c785f051b21728775c9c4f2621d37d586553d0 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 14 Feb 2012 22:37:22 +0100 Subject: drm/i915: merge struct intel_gpio into struct intel_gmbus When we set up the gpio fallback, we always have a 1:1 relationship with an intel_gmbus. Exploit that to store all gpio related data in there, too. This is a preparation step to merge the tw i2c adapters controlling the same bus into one. Just mundane code-munging in this patch. Reviewed-by: Eugeni Dodonov Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_i2c.c | 144 +++++++++++++++++++-------------------- 1 file changed, 71 insertions(+), 73 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_i2c.c') diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index 89346cc0bc4b..9dfedb0e00d4 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -45,13 +45,6 @@ to_intel_gmbus(struct i2c_adapter *i2c) return container_of(i2c, struct intel_gmbus, adapter); } -struct intel_gpio { - struct i2c_adapter adapter; - struct i2c_algo_bit_data algo; - struct drm_i915_private *dev_priv; - u32 reg; -}; - void intel_i2c_reset(struct drm_device *dev) { @@ -78,15 +71,15 @@ static void intel_i2c_quirk_set(struct drm_i915_private *dev_priv, bool enable) I915_WRITE(DSPCLK_GATE_D, val); } -static u32 get_reserved(struct intel_gpio *gpio) +static u32 get_reserved(struct intel_gmbus *bus) { - struct drm_i915_private *dev_priv = gpio->dev_priv; + struct drm_i915_private *dev_priv = bus->dev_priv; struct drm_device *dev = dev_priv->dev; u32 reserved = 0; /* On most chips, these bits must be preserved in software. */ if (!IS_I830(dev) && !IS_845G(dev)) - reserved = I915_READ_NOTRACE(gpio->reg) & + reserved = I915_READ_NOTRACE(bus->gpio_reg) & (GPIO_DATA_PULLUP_DISABLE | GPIO_CLOCK_PULLUP_DISABLE); @@ -95,29 +88,29 @@ static u32 get_reserved(struct intel_gpio *gpio) static int get_clock(void *data) { - struct intel_gpio *gpio = data; - struct drm_i915_private *dev_priv = gpio->dev_priv; - u32 reserved = get_reserved(gpio); - I915_WRITE_NOTRACE(gpio->reg, reserved | GPIO_CLOCK_DIR_MASK); - I915_WRITE_NOTRACE(gpio->reg, reserved); - return (I915_READ_NOTRACE(gpio->reg) & GPIO_CLOCK_VAL_IN) != 0; + struct intel_gmbus *bus = data; + struct drm_i915_private *dev_priv = bus->dev_priv; + u32 reserved = get_reserved(bus); + I915_WRITE_NOTRACE(bus->gpio_reg, reserved | GPIO_CLOCK_DIR_MASK); + I915_WRITE_NOTRACE(bus->gpio_reg, reserved); + return (I915_READ_NOTRACE(bus->gpio_reg) & GPIO_CLOCK_VAL_IN) != 0; } static int get_data(void *data) { - struct intel_gpio *gpio = data; - struct drm_i915_private *dev_priv = gpio->dev_priv; - u32 reserved = get_reserved(gpio); - I915_WRITE_NOTRACE(gpio->reg, reserved | GPIO_DATA_DIR_MASK); - I915_WRITE_NOTRACE(gpio->reg, reserved); - return (I915_READ_NOTRACE(gpio->reg) & GPIO_DATA_VAL_IN) != 0; + struct intel_gmbus *bus = data; + struct drm_i915_private *dev_priv = bus->dev_priv; + u32 reserved = get_reserved(bus); + I915_WRITE_NOTRACE(bus->gpio_reg, reserved | GPIO_DATA_DIR_MASK); + I915_WRITE_NOTRACE(bus->gpio_reg, reserved); + return (I915_READ_NOTRACE(bus->gpio_reg) & GPIO_DATA_VAL_IN) != 0; } static void set_clock(void *data, int state_high) { - struct intel_gpio *gpio = data; - struct drm_i915_private *dev_priv = gpio->dev_priv; - u32 reserved = get_reserved(gpio); + struct intel_gmbus *bus = data; + struct drm_i915_private *dev_priv = bus->dev_priv; + u32 reserved = get_reserved(bus); u32 clock_bits; if (state_high) @@ -126,15 +119,15 @@ static void set_clock(void *data, int state_high) clock_bits = GPIO_CLOCK_DIR_OUT | GPIO_CLOCK_DIR_MASK | GPIO_CLOCK_VAL_MASK; - I915_WRITE_NOTRACE(gpio->reg, reserved | clock_bits); - POSTING_READ(gpio->reg); + I915_WRITE_NOTRACE(bus->gpio_reg, reserved | clock_bits); + POSTING_READ(bus->gpio_reg); } static void set_data(void *data, int state_high) { - struct intel_gpio *gpio = data; - struct drm_i915_private *dev_priv = gpio->dev_priv; - u32 reserved = get_reserved(gpio); + struct intel_gmbus *bus = data; + struct drm_i915_private *dev_priv = bus->dev_priv; + u32 reserved = get_reserved(bus); u32 data_bits; if (state_high) @@ -143,13 +136,14 @@ static void set_data(void *data, int state_high) data_bits = GPIO_DATA_DIR_OUT | GPIO_DATA_DIR_MASK | GPIO_DATA_VAL_MASK; - I915_WRITE_NOTRACE(gpio->reg, reserved | data_bits); - POSTING_READ(gpio->reg); + I915_WRITE_NOTRACE(bus->gpio_reg, reserved | data_bits); + POSTING_READ(bus->gpio_reg); } static struct i2c_adapter * -intel_gpio_create(struct drm_i915_private *dev_priv, u32 pin) +intel_gpio_create(struct intel_gmbus *bus, u32 pin) { + struct drm_i915_private *dev_priv = bus->dev_priv; static const int map_pin_to_reg[] = { 0, GPIOB, @@ -160,65 +154,69 @@ intel_gpio_create(struct drm_i915_private *dev_priv, u32 pin) 0, GPIOF, }; - struct intel_gpio *gpio; + struct i2c_adapter *adapter; + struct i2c_algo_bit_data *algo; if (pin >= ARRAY_SIZE(map_pin_to_reg) || !map_pin_to_reg[pin]) return NULL; - gpio = kzalloc(sizeof(struct intel_gpio), GFP_KERNEL); - if (gpio == NULL) + adapter = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL); + if (adapter == NULL) return NULL; - gpio->reg = map_pin_to_reg[pin]; + algo = kzalloc(sizeof(struct i2c_algo_bit_data), GFP_KERNEL); + if (algo == NULL) + goto out_adap; + + bus->gpio_reg = map_pin_to_reg[pin]; if (HAS_PCH_SPLIT(dev_priv->dev)) - gpio->reg += PCH_GPIOA - GPIOA; - gpio->dev_priv = dev_priv; + bus->gpio_reg += PCH_GPIOA - GPIOA; - snprintf(gpio->adapter.name, sizeof(gpio->adapter.name), + snprintf(adapter->name, sizeof(adapter->name), "i915 GPIO%c", "?BACDE?F"[pin]); - gpio->adapter.owner = THIS_MODULE; - gpio->adapter.algo_data = &gpio->algo; - gpio->adapter.dev.parent = &dev_priv->dev->pdev->dev; - gpio->algo.setsda = set_data; - gpio->algo.setscl = set_clock; - gpio->algo.getsda = get_data; - gpio->algo.getscl = get_clock; - gpio->algo.udelay = I2C_RISEFALL_TIME; - gpio->algo.timeout = usecs_to_jiffies(2200); - gpio->algo.data = gpio; - - if (i2c_bit_add_bus(&gpio->adapter)) - goto out_free; - - return &gpio->adapter; - -out_free: - kfree(gpio); + adapter->owner = THIS_MODULE; + adapter->algo_data = algo; + adapter->dev.parent = &dev_priv->dev->pdev->dev; + algo->setsda = set_data; + algo->setscl = set_clock; + algo->getsda = get_data; + algo->getscl = get_clock; + algo->udelay = I2C_RISEFALL_TIME; + algo->timeout = usecs_to_jiffies(2200); + algo->data = bus; + + if (i2c_bit_add_bus(adapter)) + goto out_algo; + + return adapter; + +out_algo: + kfree(algo); +out_adap: + kfree(adapter); return NULL; } static int -intel_i2c_quirk_xfer(struct drm_i915_private *dev_priv, +intel_i2c_quirk_xfer(struct intel_gmbus *bus, struct i2c_adapter *adapter, struct i2c_msg *msgs, int num) { - struct intel_gpio *gpio = container_of(adapter, - struct intel_gpio, - adapter); + struct drm_i915_private *dev_priv = bus->dev_priv; int ret; intel_i2c_reset(dev_priv->dev); intel_i2c_quirk_set(dev_priv, true); - set_data(gpio, 1); - set_clock(gpio, 1); + set_data(bus, 1); + set_clock(bus, 1); udelay(I2C_RISEFALL_TIME); ret = adapter->algo->master_xfer(adapter, msgs, num); - set_data(gpio, 1); - set_clock(gpio, 1); + set_data(bus, 1); + set_clock(bus, 1); intel_i2c_quirk_set(dev_priv, false); return ret; @@ -238,8 +236,7 @@ gmbus_xfer(struct i2c_adapter *adapter, mutex_lock(&dev_priv->gmbus_mutex); if (bus->force_bit) { - ret = intel_i2c_quirk_xfer(dev_priv, - bus->force_bit, msgs, num); + ret = intel_i2c_quirk_xfer(bus, bus->force_bit, msgs, num); goto out; } @@ -339,11 +336,11 @@ timeout: I915_WRITE(GMBUS0 + reg_offset, 0); /* Hardware may not support GMBUS over these pins? Try GPIO bitbanging instead. */ - bus->force_bit = intel_gpio_create(dev_priv, bus->reg0 & 0xff); + bus->force_bit = intel_gpio_create(bus, bus->reg0 & 0xff); if (!bus->force_bit) ret = -ENOMEM; else - ret = intel_i2c_quirk_xfer(dev_priv, bus->force_bit, msgs, num); + ret = intel_i2c_quirk_xfer(bus, bus->force_bit, msgs, num); out: mutex_unlock(&dev_priv->gmbus_mutex); return ret; @@ -417,7 +414,7 @@ int intel_setup_gmbus(struct drm_device *dev) bus->reg0 = i | GMBUS_RATE_100KHZ; /* XXX force bit banging until GMBUS is fully debugged */ - bus->force_bit = intel_gpio_create(dev_priv, i); + bus->force_bit = intel_gpio_create(bus, i); } intel_i2c_reset(dev_priv->dev); @@ -447,13 +444,13 @@ void intel_gmbus_force_bit(struct i2c_adapter *adapter, bool force_bit) if (force_bit) { if (bus->force_bit == NULL) { - struct drm_i915_private *dev_priv = bus->dev_priv; - bus->force_bit = intel_gpio_create(dev_priv, + bus->force_bit = intel_gpio_create(bus, bus->reg0 & 0xff); } } else { if (bus->force_bit) { i2c_del_adapter(bus->force_bit); + kfree(bus->force_bit->algo); kfree(bus->force_bit); bus->force_bit = NULL; } @@ -472,6 +469,7 @@ void intel_teardown_gmbus(struct drm_device *dev) struct intel_gmbus *bus = &dev_priv->gmbus[i]; if (bus->force_bit) { i2c_del_adapter(bus->force_bit); + kfree(bus->force_bit->algo); kfree(bus->force_bit); } i2c_del_adapter(&bus->adapter); -- cgit v1.2.3 From c167a6fc6ed78a300c29181a6caf9ae1b9993289 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 28 Feb 2012 00:43:09 +0100 Subject: drm/i915: merge gmbus and gpio i2c adpater into one ... and directly call the newly exported i2c bit-banging functions. The code is still pretty convoluted because we only set up the gpio i2c stuff when actually falling back, resulting in more complexity than necessary. This will be fixed up in the next patch. v2: Use exported i2c_bit_algo vtable instead of exported functions. Reviewed-by: Eugeni Dodonov Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_i2c.c | 38 +++++--------------------------------- 1 file changed, 5 insertions(+), 33 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_i2c.c') diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index 9dfedb0e00d4..43dde957a327 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -154,29 +154,18 @@ intel_gpio_create(struct intel_gmbus *bus, u32 pin) 0, GPIOF, }; - struct i2c_adapter *adapter; struct i2c_algo_bit_data *algo; if (pin >= ARRAY_SIZE(map_pin_to_reg) || !map_pin_to_reg[pin]) return NULL; - adapter = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL); - if (adapter == NULL) - return NULL; - - algo = kzalloc(sizeof(struct i2c_algo_bit_data), GFP_KERNEL); - if (algo == NULL) - goto out_adap; + algo = &bus->bit_algo; bus->gpio_reg = map_pin_to_reg[pin]; if (HAS_PCH_SPLIT(dev_priv->dev)) bus->gpio_reg += PCH_GPIOA - GPIOA; - snprintf(adapter->name, sizeof(adapter->name), - "i915 GPIO%c", "?BACDE?F"[pin]); - adapter->owner = THIS_MODULE; - adapter->algo_data = algo; - adapter->dev.parent = &dev_priv->dev->pdev->dev; + bus->adapter.algo_data = algo; algo->setsda = set_data; algo->setscl = set_clock; algo->getsda = get_data; @@ -185,16 +174,7 @@ intel_gpio_create(struct intel_gmbus *bus, u32 pin) algo->timeout = usecs_to_jiffies(2200); algo->data = bus; - if (i2c_bit_add_bus(adapter)) - goto out_algo; - - return adapter; - -out_algo: - kfree(algo); -out_adap: - kfree(adapter); - return NULL; + return &bus->adapter; } static int @@ -213,7 +193,7 @@ intel_i2c_quirk_xfer(struct intel_gmbus *bus, set_clock(bus, 1); udelay(I2C_RISEFALL_TIME); - ret = adapter->algo->master_xfer(adapter, msgs, num); + ret = i2c_bit_algo.master_xfer(adapter, msgs, num); set_data(bus, 1); set_clock(bus, 1); @@ -353,7 +333,7 @@ static u32 gmbus_func(struct i2c_adapter *adapter) adapter); if (bus->force_bit) - bus->force_bit->algo->functionality(bus->force_bit); + i2c_bit_algo.functionality(bus->force_bit); return (I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | /* I2C_FUNC_10BIT_ADDR | */ @@ -449,9 +429,6 @@ void intel_gmbus_force_bit(struct i2c_adapter *adapter, bool force_bit) } } else { if (bus->force_bit) { - i2c_del_adapter(bus->force_bit); - kfree(bus->force_bit->algo); - kfree(bus->force_bit); bus->force_bit = NULL; } } @@ -467,11 +444,6 @@ void intel_teardown_gmbus(struct drm_device *dev) for (i = 0; i < GMBUS_NUM_PORTS; i++) { struct intel_gmbus *bus = &dev_priv->gmbus[i]; - if (bus->force_bit) { - i2c_del_adapter(bus->force_bit); - kfree(bus->force_bit->algo); - kfree(bus->force_bit); - } i2c_del_adapter(&bus->adapter); } -- cgit v1.2.3 From f6f808c8e1c4a3b7e3e0a6cb81541ec615aeb5fd Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 14 Feb 2012 18:58:49 +0100 Subject: drm/i915: i2c: unconditionally set up gpio fallback This way we can simplify the setup and teardown a bit. Because we don't actually allocate anything anymore for the force_bit case, we can now convert that into a boolean. Also and the functionality supported by the bit-banging together with what gmbus can do, so that this doesn't randomly change any more. v2: Chris Wilson noticed that I've mixed up && and & ... v3: Clarify an if block as suggested by Eugeni Dodonov. Reviewed-by: Eugeni Dodonov Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_i2c.c | 51 ++++++++++++++++------------------------ 1 file changed, 20 insertions(+), 31 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_i2c.c') diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index 43dde957a327..8fdc95700218 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -140,8 +140,8 @@ static void set_data(void *data, int state_high) POSTING_READ(bus->gpio_reg); } -static struct i2c_adapter * -intel_gpio_create(struct intel_gmbus *bus, u32 pin) +static bool +intel_gpio_setup(struct intel_gmbus *bus, u32 pin) { struct drm_i915_private *dev_priv = bus->dev_priv; static const int map_pin_to_reg[] = { @@ -157,7 +157,7 @@ intel_gpio_create(struct intel_gmbus *bus, u32 pin) struct i2c_algo_bit_data *algo; if (pin >= ARRAY_SIZE(map_pin_to_reg) || !map_pin_to_reg[pin]) - return NULL; + return false; algo = &bus->bit_algo; @@ -174,12 +174,11 @@ intel_gpio_create(struct intel_gmbus *bus, u32 pin) algo->timeout = usecs_to_jiffies(2200); algo->data = bus; - return &bus->adapter; + return true; } static int intel_i2c_quirk_xfer(struct intel_gmbus *bus, - struct i2c_adapter *adapter, struct i2c_msg *msgs, int num) { @@ -193,7 +192,7 @@ intel_i2c_quirk_xfer(struct intel_gmbus *bus, set_clock(bus, 1); udelay(I2C_RISEFALL_TIME); - ret = i2c_bit_algo.master_xfer(adapter, msgs, num); + ret = i2c_bit_algo.master_xfer(&bus->adapter, msgs, num); set_data(bus, 1); set_clock(bus, 1); @@ -216,7 +215,7 @@ gmbus_xfer(struct i2c_adapter *adapter, mutex_lock(&dev_priv->gmbus_mutex); if (bus->force_bit) { - ret = intel_i2c_quirk_xfer(bus, bus->force_bit, msgs, num); + ret = intel_i2c_quirk_xfer(bus, msgs, num); goto out; } @@ -316,11 +315,12 @@ timeout: I915_WRITE(GMBUS0 + reg_offset, 0); /* Hardware may not support GMBUS over these pins? Try GPIO bitbanging instead. */ - bus->force_bit = intel_gpio_create(bus, bus->reg0 & 0xff); - if (!bus->force_bit) - ret = -ENOMEM; - else - ret = intel_i2c_quirk_xfer(bus, bus->force_bit, msgs, num); + if (!bus->has_gpio) { + ret = -EIO; + } else { + bus->force_bit = true; + ret = intel_i2c_quirk_xfer(bus, msgs, num); + } out: mutex_unlock(&dev_priv->gmbus_mutex); return ret; @@ -328,14 +328,8 @@ out: static u32 gmbus_func(struct i2c_adapter *adapter) { - struct intel_gmbus *bus = container_of(adapter, - struct intel_gmbus, - adapter); - - if (bus->force_bit) - i2c_bit_algo.functionality(bus->force_bit); - - return (I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | + return i2c_bit_algo.functionality(adapter) & + (I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | /* I2C_FUNC_10BIT_ADDR | */ I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL); @@ -393,8 +387,11 @@ int intel_setup_gmbus(struct drm_device *dev) /* By default use a conservative clock rate */ bus->reg0 = i | GMBUS_RATE_100KHZ; + bus->has_gpio = intel_gpio_setup(bus, i); + /* XXX force bit banging until GMBUS is fully debugged */ - bus->force_bit = intel_gpio_create(bus, i); + if (bus->has_gpio) + bus->force_bit = true; } intel_i2c_reset(dev_priv->dev); @@ -422,16 +419,8 @@ void intel_gmbus_force_bit(struct i2c_adapter *adapter, bool force_bit) { struct intel_gmbus *bus = to_intel_gmbus(adapter); - if (force_bit) { - if (bus->force_bit == NULL) { - bus->force_bit = intel_gpio_create(bus, - bus->reg0 & 0xff); - } - } else { - if (bus->force_bit) { - bus->force_bit = NULL; - } - } + if (bus->has_gpio) + bus->force_bit = force_bit; } void intel_teardown_gmbus(struct drm_device *dev) -- cgit v1.2.3 From c3dfefa0a6d235bd465309e12f4c56ea16e71111 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 14 Feb 2012 22:37:25 +0100 Subject: drm/i915: reenable gmbus on gen3+ again With the rework to merge the bit-banging fallback into the gmbus i2c adapter we've gotten rid of the deadlock possibility that originally lead to the disabling of this code. This reverts the revert commit 826c7e4147f902737b281e8a5a7d7aa33fd63316 Author: Jean Delvare Date: Sat Jun 4 19:34:56 2011 +0000 Revert "drm/i915: Enable GMBUS for post-gen2 chipsets" Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=35572 Reviewed-by: Eugeni Dodonov Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915/intel_i2c.c') diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index 8fdc95700218..601c86e664af 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -390,7 +390,7 @@ int intel_setup_gmbus(struct drm_device *dev) bus->has_gpio = intel_gpio_setup(bus, i); /* XXX force bit banging until GMBUS is fully debugged */ - if (bus->has_gpio) + if (bus->has_gpio && IS_GEN2(dev)) bus->force_bit = true; } -- cgit v1.2.3