From 9dad76e8be982b3c72bc89a72f7d603bae87fa96 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 8 Feb 2010 14:34:43 -0500 Subject: [PATCH] drm/radeon/kms: fix prescale calculations Pre-pcie chips seem to use the reference clock rather than the sclk. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_i2c.c | 95 ++++++++++++++++++++++++++--- 1 file 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);