From 7c7d0b108480be9eec5d2fd9b0f18e8ee1c343b9 Mon Sep 17 00:00:00 2001 From: Daolong Zhu Date: Wed, 3 Mar 2021 16:42:27 +0800 Subject: soc/mediatek/mt8192: adjust i2c "tLOW" and "tSU,STO" The i2c actiming with the default reg setting cannot meet spec, so we need to set some regs. 1. adjust the ratio of SCL high and low level, to adjust "tLOW". 2. modify ext_conf reg to adjust "tSU,STO". BUG=b:179000159 TEST=Test on asurada (MT8192), boot pass, timing pass. Signed-off-by: Daolong Zhu Change-Id: Ifbe97edbc38972af5b782fb93342ee0616127dd8 Reviewed-on: https://review.coreboot.org/c/coreboot/+/51024 Reviewed-by: Yu-Ping Wu Tested-by: build bot (Jenkins) --- src/soc/mediatek/mt8192/i2c.c | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/src/soc/mediatek/mt8192/i2c.c b/src/soc/mediatek/mt8192/i2c.c index e38cbb617d..572c2808d2 100644 --- a/src/soc/mediatek/mt8192/i2c.c +++ b/src/soc/mediatek/mt8192/i2c.c @@ -7,6 +7,10 @@ #include #define I2C_CLK_HZ (UNIVPLL_HZ / 20) +#define I2C_FULL_DUTY 100 +#define I2C_HALF_DUTY 50 +#define I2C_ADJUSTED_DUTY 45 +#define I2C_FS_START_CON 0x601 struct mtk_i2c mtk_i2c_bus_controller[] = { [0] = { .i2c_regs = (void *)(I2C_BASE + 0x250000), @@ -129,25 +133,47 @@ static void mtk_i2c_speed_init(uint8_t bus) const uint8_t clock_div = 5; const uint8_t sample_div = 1; uint32_t i2c_freq; + uint32_t tar_speed = 400; + uint32_t tar_speed_high; + uint32_t tar_speed_low; assert(bus < I2C_BUS_NUMBER); + /* Adjust ratio of high/low level */ + tar_speed_high = tar_speed * I2C_HALF_DUTY / I2C_ADJUSTED_DUTY; + /* Calculate i2c frequency */ step_div = DIV_ROUND_UP(I2C_CLK_HZ, - (400 * KHz * sample_div * 2) * clock_div); + (tar_speed_high * KHz * sample_div * 2) * clock_div); i2c_freq = I2C_CLK_HZ / (step_div * sample_div * 2 * clock_div); - assert(sample_div < 8 && step_div < 64 && i2c_freq <= 400 * KHz && - i2c_freq >= 380 * KHz); + assert(sample_div < 8 && step_div < 64 && + i2c_freq <= tar_speed_high * KHz && + i2c_freq >= (tar_speed_high - 20) * KHz); /* Init i2c bus timing register */ write32(&mtk_i2c_bus_controller[bus].i2c_regs->timing, (sample_div - 1) << 8 | (step_div - 1)); + + /* Adjust ratio of high/low level */ + tar_speed_low = tar_speed * I2C_HALF_DUTY / + (I2C_FULL_DUTY - I2C_ADJUSTED_DUTY); + + /* Calculate i2c frequency */ + step_div = DIV_ROUND_UP(I2C_CLK_HZ, + (tar_speed_low * KHz * sample_div * 2) * clock_div); + i2c_freq = I2C_CLK_HZ / (step_div * sample_div * 2 * clock_div); + assert(sample_div < 8 && step_div < 64 && + i2c_freq <= tar_speed_low * KHz && + i2c_freq >= (tar_speed_low - 20) * KHz); write32(&mtk_i2c_bus_controller[bus].i2c_regs->ltiming, (sample_div - 1) << 6 | (step_div - 1)); /* Init i2c bus clock_div register */ write32(&mtk_i2c_bus_controller[bus].i2c_regs->clock_div, clock_div - 1); + + /* Adjust tSU,STA/tHD,STA/tSU,STO */ + write32(&mtk_i2c_bus_controller[bus].i2c_regs->ext_conf, I2C_FS_START_CON); } void mtk_i2c_bus_init(uint8_t bus) -- cgit v1.2.3