diff options
author | Alex Deucher <alexdeucher@gmail.com> | 2010-02-08 22:34:43 +0300 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2010-02-11 06:39:11 +0300 |
commit | 9dad76e8be982b3c72bc89a72f7d603bae87fa96 (patch) | |
tree | 4de53a19065ae7d6bd2ef6241739246212076530 /drivers/gpu/drm/radeon/radeon_i2c.c | |
parent | bcc1c2a1d22974215e39dc87ce746ba9a39223e5 (diff) | |
download | linux-9dad76e8be982b3c72bc89a72f7d603bae87fa96.tar.xz |
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.c | 95 |
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 272c45db5cec..d15fa5e62bb5 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); |