aboutsummaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/radeon/radeon_i2c.c
diff options
context:
space:
mode:
authorAlex Deucher <alexdeucher@gmail.com>2010-02-08 14:34:43 -0500
committerDave Airlie <airlied@redhat.com>2010-02-11 13:39:11 +1000
commit9dad76e8be982b3c72bc89a72f7d603bae87fa96 (patch)
tree4de53a19065ae7d6bd2ef6241739246212076530 /drivers/gpu/drm/radeon/radeon_i2c.c
parentbcc1c2a1d22974215e39dc87ce746ba9a39223e5 (diff)
drm/radeon/kms: fix prescale calculations
Pre-pcie chips seem to use the reference clock rather than the sclk. Signed-off-by: Alex Deucher <alexdeucher@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/radeon/radeon_i2c.c')
-rw-r--r--drivers/gpu/drm/radeon/radeon_i2c.c95
1 files changed, 85 insertions, 10 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c
index 272c45db5ce..d15fa5e62bb 100644
--- a/drivers/gpu/drm/radeon/radeon_i2c.c
+++ b/drivers/gpu/drm/radeon/radeon_i2c.c
@@ -181,6 +181,87 @@ static void set_data(void *i2c_priv, int data)
WREG32(rec->en_data_reg, val);
}
+static u32 radeon_get_i2c_prescale(struct radeon_device *rdev)
+{
+ struct radeon_pll *spll = &rdev->clock.spll;
+ u32 sclk = radeon_get_engine_clock(rdev);
+ u32 prescale = 0;
+ u32 n, m;
+ u8 loop;
+ int i2c_clock;
+
+ switch (rdev->family) {
+ case CHIP_R100:
+ case CHIP_RV100:
+ case CHIP_RS100:
+ case CHIP_RV200:
+ case CHIP_RS200:
+ case CHIP_R200:
+ case CHIP_RV250:
+ case CHIP_RS300:
+ case CHIP_RV280:
+ case CHIP_R300:
+ case CHIP_R350:
+ case CHIP_RV350:
+ n = (spll->reference_freq) / (4 * 6);
+ for (loop = 1; loop < 255; loop++) {
+ if ((loop * (loop - 1)) > n)
+ break;
+ }
+ m = loop - 1;
+ prescale = m | (loop << 8);
+ break;
+ case CHIP_RV380:
+ case CHIP_RS400:
+ case CHIP_RS480:
+ case CHIP_R420:
+ case CHIP_R423:
+ case CHIP_RV410:
+ sclk = radeon_get_engine_clock(rdev);
+ prescale = (((sclk * 10)/(4 * 128 * 100) + 1) << 8) + 128;
+ break;
+ case CHIP_RS600:
+ case CHIP_RS690:
+ case CHIP_RS740:
+ /* todo */
+ break;
+ case CHIP_RV515:
+ case CHIP_R520:
+ case CHIP_RV530:
+ case CHIP_RV560:
+ case CHIP_RV570:
+ case CHIP_R580:
+ i2c_clock = 50;
+ sclk = radeon_get_engine_clock(rdev);
+ if (rdev->family == CHIP_R520)
+ prescale = (127 << 8) + ((sclk * 10) / (4 * 127 * i2c_clock));
+ else
+ prescale = (((sclk * 10)/(4 * 128 * 100) + 1) << 8) + 128;
+ break;
+ case CHIP_R600:
+ case CHIP_RV610:
+ case CHIP_RV630:
+ case CHIP_RV670:
+ /* todo */
+ break;
+ case CHIP_RV620:
+ case CHIP_RV635:
+ case CHIP_RS780:
+ case CHIP_RS880:
+ case CHIP_RV770:
+ case CHIP_RV730:
+ case CHIP_RV710:
+ case CHIP_RV740:
+ /* todo */
+ break;
+ default:
+ DRM_ERROR("i2c: unhandled radeon chip\n");
+ break;
+ }
+ return prescale;
+}
+
+
/* hw i2c engine for r1xx-4xx hardware
* hw can buffer up to 15 bytes
*/
@@ -192,7 +273,7 @@ static int r100_hw_i2c_xfer(struct i2c_adapter *i2c_adap,
struct radeon_i2c_bus_rec *rec = &i2c->rec;
struct i2c_msg *p;
int i, j, k, ret = num;
- u32 sclk, prescale;
+ u32 prescale;
u32 i2c_cntl_0, i2c_cntl_1, i2c_data;
u32 tmp, reg;
@@ -200,8 +281,7 @@ static int r100_hw_i2c_xfer(struct i2c_adapter *i2c_adap,
/* take the pm lock since we need a constant sclk */
mutex_lock(&rdev->pm.mutex);
- sclk = radeon_get_engine_clock(rdev);
- prescale = (((sclk * 10)/(4 * 128 * 100) + 1) << 8) + 128;
+ prescale = radeon_get_i2c_prescale(rdev);
reg = ((prescale << RADEON_I2C_PRESCALE_SHIFT) |
RADEON_I2C_START |
@@ -444,9 +524,8 @@ static int r500_hw_i2c_xfer(struct i2c_adapter *i2c_adap,
struct radeon_device *rdev = i2c->dev->dev_private;
struct radeon_i2c_bus_rec *rec = &i2c->rec;
struct i2c_msg *p;
- int i2c_clock = 50;
int i, j, remaining, current_count, buffer_offset, ret = num;
- u32 sclk, prescale;
+ u32 prescale;
u32 tmp, reg;
u32 saved1, saved2;
@@ -454,11 +533,7 @@ static int r500_hw_i2c_xfer(struct i2c_adapter *i2c_adap,
/* take the pm lock since we need a constant sclk */
mutex_lock(&rdev->pm.mutex);
- sclk = radeon_get_engine_clock(rdev);
- if (rdev->family == CHIP_R520)
- prescale = (127 << 8) + ((sclk * 10) / (4 * 127 * i2c_clock));
- else
- prescale = (((sclk * 10)/(4 * 128 * 100) + 1) << 8) + 128;
+ prescale = radeon_get_i2c_prescale(rdev);
/* clear gpio mask bits */
tmp = RREG32(rec->mask_clk_reg);