From 8a073952cc7ab4ed328cbabe9d88038185c1538c Mon Sep 17 00:00:00 2001
From: Alex Deucher <alexdeucher@gmail.com>
Date: Sat, 6 Feb 2010 16:58:01 -0500
Subject: [PATCH] drm/radeon/kms: protect hw i2c engine with a mutex

Only one hw i2c engine, but it can service several
gpio lines by selecting the line you want to use.

Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
---
 drivers/gpu/drm/radeon/radeon.h        |    1 +
 drivers/gpu/drm/radeon/radeon_device.c |    1 +
 drivers/gpu/drm/radeon/radeon_i2c.c    |   11 +++++++++++
 3 files changed, 13 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 63aadc8..83f8453 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -943,6 +943,7 @@ struct radeon_device {
 	struct work_struct hotplug_work;
 	int num_crtc; /* number of crtcs */
 	bool edid_in_rom; /* hardcoded edid in rom */
+	struct mutex dc_hw_i2c_mutex; /* display controller hw i2c mutex */
 
 	/* audio stuff */
 	struct timer_list	audio_timer;
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index 42cfadd..85d2322 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -641,6 +641,7 @@ int radeon_device_init(struct radeon_device *rdev,
 	mutex_init(&rdev->cs_mutex);
 	mutex_init(&rdev->ib_pool.mutex);
 	mutex_init(&rdev->cp.mutex);
+	mutex_init(&rdev->dc_hw_i2c_mutex);
 	if (rdev->family >= CHIP_R600)
 		spin_lock_init(&rdev->ih.lock);
 	mutex_init(&rdev->gem.mutex);
diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c
index 0ab8523..e0a2017 100644
--- a/drivers/gpu/drm/radeon/radeon_i2c.c
+++ b/drivers/gpu/drm/radeon/radeon_i2c.c
@@ -82,6 +82,7 @@ static void radeon_i2c_do_lock(struct radeon_i2c_chan *i2c, int lock_state)
 			else
 				reg = RADEON_GPIO_CRT2_DDC;
 
+			mutex_lock(&rdev->dc_hw_i2c_mutex);
 			if (rec->a_clk_reg == reg) {
 				WREG32(RADEON_DVI_I2C_CNTL_0, (RADEON_I2C_SOFT_RST |
 							       R200_DVI_I2C_PIN_SEL(R200_SEL_DDC1)));
@@ -89,6 +90,7 @@ static void radeon_i2c_do_lock(struct radeon_i2c_chan *i2c, int lock_state)
 				WREG32(RADEON_DVI_I2C_CNTL_0, (RADEON_I2C_SOFT_RST |
 							       R200_DVI_I2C_PIN_SEL(R200_SEL_DDC3)));
 			}
+			mutex_unlock(&rdev->dc_hw_i2c_mutex);
 		}
 	}
 
@@ -195,6 +197,8 @@ static int r100_hw_i2c_xfer(struct i2c_adapter *i2c_adap,
 	u32 i2c_cntl_0, i2c_cntl_1, i2c_data;
 	u32 tmp, reg;
 
+	mutex_lock(&rdev->dc_hw_i2c_mutex);
+
 	reg = ((prescale << RADEON_I2C_PRESCALE_SHIFT) |
 	       RADEON_I2C_START |
 	       RADEON_I2C_STOP |
@@ -405,6 +409,9 @@ done:
 		tmp &= ~ATOM_S6_HW_I2C_BUSY_STATE;
 		WREG32(RADEON_BIOS_6_SCRATCH, tmp);
 	}
+
+	mutex_unlock(&rdev->dc_hw_i2c_mutex);
+
 	return ret;
 }
 
@@ -425,6 +432,8 @@ static int r500_hw_i2c_xfer(struct i2c_adapter *i2c_adap,
 	u32 tmp, reg;
 	u32 saved1, saved2;
 
+	mutex_lock(&rdev->dc_hw_i2c_mutex);
+
 	/* clear gpio mask bits */
 	tmp = RREG32(rec->mask_clk_reg);
 	tmp &= ~rec->mask_clk_mask;
@@ -639,6 +648,8 @@ done:
 	tmp &= ~ATOM_S6_HW_I2C_BUSY_STATE;
 	WREG32(RADEON_BIOS_6_SCRATCH, tmp);
 
+	mutex_unlock(&rdev->dc_hw_i2c_mutex);
+
 	return ret;
 }
 
-- 
1.5.6.3

