[U-Boot-Users] [PATCH] 83xx: Add support for CFG_I2C_SPEED in fsl_i2c.c

Add support to fsl_i2c.c for setting and querying the I2C bus speed. Current 83xx boards define the CFG_I2C_SPEED, but fsl_i2c.c ignores the value and uses a conservative value of 0x3F when programming the I2C bus speed.
Signed-off-by: Timur Tabi timur@freescale.com ---
Unfortunately, only 83xx calculates and stores the I2C clock frequencies, so this code is compiled on 83xx only.
cpu/mpc83xx/cpu.c | 24 +++++++++++ drivers/i2c/fsl_i2c.c | 90 ++++++++++++++++++++++++++++++++++++++++- include/asm-ppc/fsl_i2c.h | 23 ++++++++++ include/configs/MPC832XEMDS.h | 1 + 4 files changed, 137 insertions(+), 1 deletions(-)
diff --git a/cpu/mpc83xx/cpu.c b/cpu/mpc83xx/cpu.c index f1ea17d..51cb1b7 100644 --- a/cpu/mpc83xx/cpu.c +++ b/cpu/mpc83xx/cpu.c @@ -716,3 +716,27 @@ int dma_xfer(void *dest, u32 count, void *src) return ((int)dma_check()); } #endif /*CONFIG_DDR_ECC*/ + +#ifdef CFG_I2C_SPEED +/* + * Map the frequency divider to the FDR. This data is taken from table 17-5 + * of the MPC8349EA reference manual, with duplicates removed. It also applies + * to the 8360. + */ +struct fsl_i2c_speed_map fsl_i2c_speed_map[] = { + {256, 0x20}, {288, 0x21}, {320, 0x22}, {352, 0x23}, + {384, 0x24}, {416, 0x01}, {448, 0x25}, {480, 0x02}, + {512, 0x26}, {576, 0x27}, {640, 0x28}, {704, 0x05}, + {768, 0x29}, {832, 0x06}, {896, 0x2A}, {1024, 0x2B}, + {1152, 0x08}, {1280, 0x2C}, {1536, 0x2D}, {1792, 0x2E}, + {1920, 0x0B}, {2048, 0x2F}, {2304, 0x0C}, {2560, 0x30}, + {3072, 0x31}, {3584, 0x32}, {3840, 0x0F}, {4096, 0x33}, + {4608, 0x10}, {5120, 0x34}, {6144, 0x35}, {7168, 0x36}, + {7680, 0x13}, {8192, 0x37}, {9216, 0x14}, {10240, 0x38}, + {12288, 0x39}, {14336, 0x3A}, {15360, 0x17}, {16384, 0x3B}, + {18432, 0x18}, {20480, 0x3C}, {24576, 0x3D}, {28672, 0x3E}, + {30720, 0x1B}, {32768, 0x3F}, {36864, 0x1C}, {40960, 0x1D}, + {49152, 0x1E}, {61440, 0x1F}, + {-1, 0x1F} +}; +#endif diff --git a/drivers/i2c/fsl_i2c.c b/drivers/i2c/fsl_i2c.c index 22485ea..bca2c75 100644 --- a/drivers/i2c/fsl_i2c.c +++ b/drivers/i2c/fsl_i2c.c @@ -32,6 +32,8 @@ #define I2C_READ_BIT 1 #define I2C_WRITE_BIT 0
+DECLARE_GLOBAL_DATA_PTR; + /* Initialize the bus pointer to whatever one the SPD EEPROM is on. * Default is bus 0. This is necessary because the DDR initialization * runs from ROM, and we can't switch buses because we can't modify @@ -43,6 +45,8 @@ static unsigned int i2c_bus_num __attribute__ ((section ("data"))) = CFG_SPD_BUS static unsigned int i2c_bus_num __attribute__ ((section ("data"))) = 0; #endif
+static unsigned int i2c_bus_speed[2] = {CFG_I2C_SPEED, CFG_I2C_SPEED}; + static volatile struct fsl_i2c *i2c_dev[2] = { (struct fsl_i2c *) (CFG_IMMR + CFG_I2C_OFFSET), #ifdef CFG_I2C2_OFFSET @@ -50,6 +54,53 @@ static volatile struct fsl_i2c *i2c_dev[2] = { #endif };
+#ifdef CONFIG_MPC83XX +/* Currently, only 83xx determines and stores the I2C clock frequency */ + +#ifdef CFG_I2C_SPEED +/* Define a default I2C speed map if a real map isn't defined elsewhere */ +#pragma weak fsl_i2c_speed_map = default_fsl_i2c_speed_map + +struct fsl_i2c_speed_map default_fsl_i2c_speed_map[] = { + {0, 0x3F}, {-1, 0x3F} +}; +#endif + +/* + * Get the I2C FDR value for a given I2C clock and a given I2C bus speed + */ +static u8 get_fdr(unsigned int i2c_clk, unsigned int speed) +{ +#ifdef CFG_I2C_SPEED + extern struct fsl_i2c_speed_map fsl_i2c_speed_map[]; + unsigned int d; /* The I2C clock divider */ + unsigned int i = 0; + unsigned int low, high; + + d = i2c_clk / speed; + + /* Scan fsl_i2c_speed_map[] for the closest matching divider.*/ + + while (fsl_i2c_speed_map[i].divider != (unsigned int) -1) { + low = fsl_i2c_speed_map[i].divider; + high = fsl_i2c_speed_map[i+1].divider; + + if ((d >= low) && (d <= high)) { + /* Which one is closer? */ + if ((d - low) < (high - d)) + return fsl_i2c_speed_map[i].fdr; + else + return fsl_i2c_speed_map[i+1].fdr; + break; + } + i++; + } +#endif + + return 0x3F; /* Use a conservative value as the default */ +} +#endif /* CONFIG_MPC83XX */ + void i2c_init(int speed, int slaveadd) { @@ -59,23 +110,37 @@ i2c_init(int speed, int slaveadd)
writeb(0, &dev->cr); /* stop I2C controller */ udelay(5); /* let it shutdown in peace */ +#ifdef CONFIG_MPC83XX + /* Currently, only 83xx determines and stores the I2C clock frequency */ + writeb(get_fdr(gd->i2c1_clk, speed), &dev->fdr); /* set bus speed */ +#else writeb(0x3F, &dev->fdr); /* set bus speed */ +#endif writeb(0x3F, &dev->dfsrr); /* set default filter */ writeb(slaveadd << 1, &dev->adr); /* write slave address */ writeb(0x0, &dev->sr); /* clear status register */ writeb(I2C_CR_MEN, &dev->cr); /* start I2C controller */
+ i2c_bus_speed[0] = speed; + #ifdef CFG_I2C2_OFFSET dev = (struct fsl_i2c *) (CFG_IMMR + CFG_I2C2_OFFSET);
writeb(0, &dev->cr); /* stop I2C controller */ udelay(5); /* let it shutdown in peace */ +#ifdef CONFIG_MPC83XX + /* Currently, only 83xx determines and stores the I2C clock frequency */ + writeb(get_fdr(gd->i2c2_clk, speed), &dev->fdr); /* set bus speed */ +#else writeb(0x3F, &dev->fdr); /* set bus speed */ +#endif writeb(0x3F, &dev->dfsrr); /* set default filter */ writeb(slaveadd << 1, &dev->adr); /* write slave address */ writeb(0x0, &dev->sr); /* clear status register */ writeb(I2C_CR_MEN, &dev->cr); /* start I2C controller */ -#endif /* CFG_I2C2_OFFSET */ + + i2c_bus_speed[1] = speed; +#endif }
static __inline__ int @@ -279,7 +344,23 @@ int i2c_set_bus_num(unsigned int bus)
int i2c_set_bus_speed(unsigned int speed) { +#ifdef CONFIG_MPC83XX + /* Currently, only 83xx determines and stores the I2C clock frequency */ + + unsigned int i2c_clk = (i2c_bus_num == 1) ? gd->i2c2_clk : gd->i2c1_clk; + u8 fdr = get_fdr(i2c_clk, speed); + + printf("Writing %x to FDR\n", fdr); + writeb(0, &i2c_dev[i2c_bus_num]->cr); /* stop controller */ + writeb(fdr, &i2c_dev[i2c_bus_num]->fdr); /* set bus speed */ + writeb(I2C_CR_MEN, &i2c_dev[i2c_bus_num]->cr); /* start controller */ + + i2c_bus_speed[i2c_bus_num] = speed; + + return 0; +#else return -1; +#endif }
unsigned int i2c_get_bus_num(void) @@ -289,7 +370,14 @@ unsigned int i2c_get_bus_num(void)
unsigned int i2c_get_bus_speed(void) { +#ifdef CONFIG_MPC83XX + /* Currently, only 83xx determines and stores the I2C clock frequency */ + + return i2c_bus_speed[i2c_bus_num]; +#else return 0; +#endif } + #endif /* CONFIG_HARD_I2C */ #endif /* CONFIG_FSL_I2C */ diff --git a/include/asm-ppc/fsl_i2c.h b/include/asm-ppc/fsl_i2c.h index 4f71341..f84a803 100644 --- a/include/asm-ppc/fsl_i2c.h +++ b/include/asm-ppc/fsl_i2c.h @@ -83,4 +83,27 @@ typedef struct fsl_i2c { u8 res6[0xE8]; } fsl_i2c_t;
+/* + * Map I2C frequency dividers to FDR values + * + * This structure is used to define the elements of a table that maps I2C + * frequency divider (I2C clock rate divided by I2C bus speed) to a value to be + * programmed into the Frequency Divider Ratio (FDR) register. + * + * The actual table should be defined in the board file, and it must be called + * fsl_i2c_speed_map[]. + * + * The first entry must be {0, X}, where X == fsl_i2c_speed_map[1].fdr. + * + * The last entry of the table must have a value of {-1,x}, where x is same + * FDR value as the second-to-last entry. + * + * The values of the divider must be in increasing numerical order, i.e. + * fsl_i2c_speed_map[x+1].divider > fsl_i2c_speed_map[x].divider. + */ +typedef struct fsl_i2c_speed_map { + unsigned int divider; + u8 fdr; +} fsl_i2c_speed_map_t; + #endif /* _ASM_I2C_H_ */ diff --git a/include/configs/MPC832XEMDS.h b/include/configs/MPC832XEMDS.h index c9c6d88..d5e588a 100644 --- a/include/configs/MPC832XEMDS.h +++ b/include/configs/MPC832XEMDS.h @@ -335,6 +335,7 @@ #define CFG_I2C_SLAVE 0x7F #define CFG_I2C_NOPROBES {0x51} /* Don't probe these addrs */ #define CFG_I2C_OFFSET 0x3000 +#define CONFIG_I2C_CMD_TREE
/* * Config on-board RTC

Timur Tabi wrote:
Add support to fsl_i2c.c for setting and querying the I2C bus speed. Current 83xx boards define the CFG_I2C_SPEED, but fsl_i2c.c ignores the value and uses a conservative value of 0x3F when programming the I2C bus speed.
Signed-off-by: Timur Tabi timur@freescale.com
Unfortunately, only 83xx calculates and stores the I2C clock frequencies, so this code is compiled on 83xx only.
I've got another patch that adds this feature to 85xx and 86xx, so if that patch is applied, then I will submit another version of *this* patch that extends the code to 85xx and 86xx.

Hi,
Timur Tabi schrieb:
Timur Tabi wrote:
Add support to fsl_i2c.c for setting and querying the I2C bus speed. Current 83xx boards define the CFG_I2C_SPEED, but fsl_i2c.c ignores the value and uses a conservative value of 0x3F when programming the I2C bus speed.
Signed-off-by: Timur Tabi timur@freescale.com
Unfortunately, only 83xx calculates and stores the I2C clock frequencies, so this code is compiled on 83xx only.
I've got another patch that adds this feature to 85xx and 86xx, so if that patch is applied, then I will submit another version of *this* patch that extends the code to 85xx and 86xx.
When is it planned to apply these patches (especially MPC85xx)?
Regards, Jens

Jens Gehrlein wrote:
When is it planned to apply these patches (especially MPC85xx)?
Well, it's on my to-do list, but I'm currently busy with something else. How important is this feature for you?

Hi Timur,
Timur Tabi schrieb:
Jens Gehrlein wrote:
When is it planned to apply these patches (especially MPC85xx)?
Well, it's on my to-do list, but I'm currently busy with something else. How important is this feature for you?
We started a hack on MPC8548 1.5 years before. Later we found your announcement on the mailing list. Your patches are the better solution. It's not urgent. But it's nice to know, how your "release plans" are.
Best regards Jens

Jens Gehrlein wrote:
We started a hack on MPC8548 1.5 years before. Later we found your announcement on the mailing list. Your patches are the better solution. It's not urgent. But it's nice to know, how your "release plans" are.
Ok, I'll try to get it into 1.3.3
participants (2)
-
Jens Gehrlein
-
Timur Tabi