Re: [U-Boot] [PATCH v3 3/9] tegra: Enhance clock support to handle 16-bit clock divisors
Simon, -Original Message- From: Simon Glass [mailto:s...@chromium.org] Sent: Friday, February 03, 2012 6:14 PM To: U-Boot Mailing List Cc: Tom Warren; Stephen Warren; linux-te...@vger.kernel.org; Simon Glass Subject: [PATCH v3 3/9] tegra: Enhance clock support to handle 16-bit clock divisors I2C ports have a 16-bit clock divisor. Add code to handle this special case so that I2C speeds below 150KHz are supported. Signed-off-by: Simon Glass s...@chromium.org --- Changes in v3: - Add new patch to support 16-bit clock divisors required by I2C arch/arm/cpu/armv7/tegra2/clock.c | 63 ++--- --- arch/arm/include/asm/arch-tegra2/clk_rst.h | 10 - 2 files changed, 49 insertions(+), 24 deletions(-) diff --git a/arch/arm/cpu/armv7/tegra2/clock.c b/arch/arm/cpu/armv7/tegra2/clock.c index 11d2346..e58cb3b 100644 --- a/arch/arm/cpu/armv7/tegra2/clock.c +++ b/arch/arm/cpu/armv7/tegra2/clock.c @@ -67,6 +67,7 @@ enum clock_type_id { CLOCK_TYPE_MCPT, CLOCK_TYPE_PCM, CLOCK_TYPE_PCMT, + CLOCK_TYPE_PCMT16, /* CLOCK_TYPE_PCMT with 16-bit divider */ CLOCK_TYPE_PCXTS, CLOCK_TYPE_PDCT, @@ -98,6 +99,7 @@ static enum clock_id clock_source[CLOCK_TYPE_COUNT][CLOCK_MAX_MUX] = { { CLK(MEMORY), CLK(CGENERAL), CLK(PERIPH),CLK(OSC)}, { CLK(PERIPH), CLK(CGENERAL), CLK(MEMORY),CLK(NONE) }, { CLK(PERIPH), CLK(CGENERAL), CLK(MEMORY),CLK(OSC)}, + { CLK(PERIPH), CLK(CGENERAL), CLK(MEMORY),CLK(OSC)}, { CLK(PERIPH), CLK(CGENERAL), CLK(XCPU), CLK(OSC)}, { CLK(PERIPH), CLK(DISPLAY), CLK(CGENERAL), CLK(OSC) }, }; @@ -211,8 +213,8 @@ static enum clock_type_id clock_periph_type[PERIPHC_COUNT] = { /* 0x08 */ TYPE(PERIPHC_XIO, CLOCK_TYPE_PCMT), - TYPE(PERIPHC_I2C1, CLOCK_TYPE_PCMT), - TYPE(PERIPHC_DVC_I2C, CLOCK_TYPE_PCMT), + TYPE(PERIPHC_I2C1, CLOCK_TYPE_PCMT16), + TYPE(PERIPHC_DVC_I2C, CLOCK_TYPE_PCMT16), TYPE(PERIPHC_TWC, CLOCK_TYPE_PCMT), TYPE(PERIPHC_NONE, CLOCK_TYPE_NONE), TYPE(PERIPHC_SPI1, CLOCK_TYPE_PCMT), @@ -246,7 +248,7 @@ static enum clock_type_id clock_periph_type[PERIPHC_COUNT] = { TYPE(PERIPHC_HDMI, CLOCK_TYPE_PDCT), TYPE(PERIPHC_NONE, CLOCK_TYPE_NONE), TYPE(PERIPHC_TVDAC, CLOCK_TYPE_PDCT), - TYPE(PERIPHC_I2C2, CLOCK_TYPE_PCMT), + TYPE(PERIPHC_I2C2, CLOCK_TYPE_PCMT16), TYPE(PERIPHC_EMC, CLOCK_TYPE_MCPT), /* 0x28 */ @@ -256,7 +258,7 @@ static enum clock_type_id clock_periph_type[PERIPHC_COUNT] = { TYPE(PERIPHC_NONE, CLOCK_TYPE_NONE), TYPE(PERIPHC_NONE, CLOCK_TYPE_NONE), TYPE(PERIPHC_SPI4, CLOCK_TYPE_PCMT), - TYPE(PERIPHC_I2C3, CLOCK_TYPE_PCMT), + TYPE(PERIPHC_I2C3, CLOCK_TYPE_PCMT16), TYPE(PERIPHC_SDMMC3,CLOCK_TYPE_PCMT), /* 0x30 */ @@ -518,14 +520,16 @@ void clock_ll_set_source(enum periph_id periph_id, unsigned source) * Given the parent's rate and the required rate for the children, this works * out the peripheral clock divider to use, in 7.1 binary format. * + * @param divider_bits number of divider bits (8 or 16) * @param parent_rateclock rate of parent clock in Hz * @param rate required clock rate for this clock * @return divider which should be used */ -static int clk_div7_1_get_divider(unsigned long parent_rate, - unsigned long rate) +static int clk_get_divider(unsigned divider_bits, unsigned long parent_rate, +unsigned long rate) { u64 divider = parent_rate * 2; + unsigned max_divider = 1 divider_bits; divider += rate - 1; do_div(divider, rate); @@ -533,7 +537,7 @@ static int clk_div7_1_get_divider(unsigned long parent_rate, if ((s64)divider - 2 0) return 0; - if ((s64)divider - 2 255) + if ((s64)divider - 2 = max_divider) return -1; return divider - 2; @@ -571,6 +575,7 @@ unsigned long clock_get_periph_rate(enum periph_id periph_id, * required child clock rate. This function assumes that a second-stage * divisor is available which can divide by powers of 2 from 1 to 256. * + * @param divider_bits number of divider bits (8 or 16) * @param parent_rateclock rate of parent clock in Hz * @param rate required clock rate for this clock * @param extra_div value for the second-stage divisor (not set if this @@ -578,8 +583,8 @@ unsigned long clock_get_periph_rate(enum periph_id periph_id, * @return divider which should be used, or -1 if nothing is valid * */ -static int find_best_divider(unsigned long parent_rate, unsigned long rate, - int *extra_div) +static int
[U-Boot] [PATCH v3 3/9] tegra: Enhance clock support to handle 16-bit clock divisors
I2C ports have a 16-bit clock divisor. Add code to handle this special case so that I2C speeds below 150KHz are supported. Signed-off-by: Simon Glass s...@chromium.org --- Changes in v3: - Add new patch to support 16-bit clock divisors required by I2C arch/arm/cpu/armv7/tegra2/clock.c | 63 ++-- arch/arm/include/asm/arch-tegra2/clk_rst.h | 10 - 2 files changed, 49 insertions(+), 24 deletions(-) diff --git a/arch/arm/cpu/armv7/tegra2/clock.c b/arch/arm/cpu/armv7/tegra2/clock.c index 11d2346..e58cb3b 100644 --- a/arch/arm/cpu/armv7/tegra2/clock.c +++ b/arch/arm/cpu/armv7/tegra2/clock.c @@ -67,6 +67,7 @@ enum clock_type_id { CLOCK_TYPE_MCPT, CLOCK_TYPE_PCM, CLOCK_TYPE_PCMT, + CLOCK_TYPE_PCMT16, /* CLOCK_TYPE_PCMT with 16-bit divider */ CLOCK_TYPE_PCXTS, CLOCK_TYPE_PDCT, @@ -98,6 +99,7 @@ static enum clock_id clock_source[CLOCK_TYPE_COUNT][CLOCK_MAX_MUX] = { { CLK(MEMORY), CLK(CGENERAL), CLK(PERIPH),CLK(OSC)}, { CLK(PERIPH), CLK(CGENERAL), CLK(MEMORY),CLK(NONE) }, { CLK(PERIPH), CLK(CGENERAL), CLK(MEMORY),CLK(OSC)}, + { CLK(PERIPH), CLK(CGENERAL), CLK(MEMORY),CLK(OSC)}, { CLK(PERIPH), CLK(CGENERAL), CLK(XCPU), CLK(OSC)}, { CLK(PERIPH), CLK(DISPLAY), CLK(CGENERAL), CLK(OSC)}, }; @@ -211,8 +213,8 @@ static enum clock_type_id clock_periph_type[PERIPHC_COUNT] = { /* 0x08 */ TYPE(PERIPHC_XIO, CLOCK_TYPE_PCMT), - TYPE(PERIPHC_I2C1, CLOCK_TYPE_PCMT), - TYPE(PERIPHC_DVC_I2C, CLOCK_TYPE_PCMT), + TYPE(PERIPHC_I2C1, CLOCK_TYPE_PCMT16), + TYPE(PERIPHC_DVC_I2C, CLOCK_TYPE_PCMT16), TYPE(PERIPHC_TWC, CLOCK_TYPE_PCMT), TYPE(PERIPHC_NONE, CLOCK_TYPE_NONE), TYPE(PERIPHC_SPI1, CLOCK_TYPE_PCMT), @@ -246,7 +248,7 @@ static enum clock_type_id clock_periph_type[PERIPHC_COUNT] = { TYPE(PERIPHC_HDMI, CLOCK_TYPE_PDCT), TYPE(PERIPHC_NONE, CLOCK_TYPE_NONE), TYPE(PERIPHC_TVDAC, CLOCK_TYPE_PDCT), - TYPE(PERIPHC_I2C2, CLOCK_TYPE_PCMT), + TYPE(PERIPHC_I2C2, CLOCK_TYPE_PCMT16), TYPE(PERIPHC_EMC, CLOCK_TYPE_MCPT), /* 0x28 */ @@ -256,7 +258,7 @@ static enum clock_type_id clock_periph_type[PERIPHC_COUNT] = { TYPE(PERIPHC_NONE, CLOCK_TYPE_NONE), TYPE(PERIPHC_NONE, CLOCK_TYPE_NONE), TYPE(PERIPHC_SPI4, CLOCK_TYPE_PCMT), - TYPE(PERIPHC_I2C3, CLOCK_TYPE_PCMT), + TYPE(PERIPHC_I2C3, CLOCK_TYPE_PCMT16), TYPE(PERIPHC_SDMMC3,CLOCK_TYPE_PCMT), /* 0x30 */ @@ -518,14 +520,16 @@ void clock_ll_set_source(enum periph_id periph_id, unsigned source) * Given the parent's rate and the required rate for the children, this works * out the peripheral clock divider to use, in 7.1 binary format. * + * @param divider_bits number of divider bits (8 or 16) * @param parent_rate clock rate of parent clock in Hz * @param rate required clock rate for this clock * @return divider which should be used */ -static int clk_div7_1_get_divider(unsigned long parent_rate, - unsigned long rate) +static int clk_get_divider(unsigned divider_bits, unsigned long parent_rate, + unsigned long rate) { u64 divider = parent_rate * 2; + unsigned max_divider = 1 divider_bits; divider += rate - 1; do_div(divider, rate); @@ -533,7 +537,7 @@ static int clk_div7_1_get_divider(unsigned long parent_rate, if ((s64)divider - 2 0) return 0; - if ((s64)divider - 2 255) + if ((s64)divider - 2 = max_divider) return -1; return divider - 2; @@ -571,6 +575,7 @@ unsigned long clock_get_periph_rate(enum periph_id periph_id, * required child clock rate. This function assumes that a second-stage * divisor is available which can divide by powers of 2 from 1 to 256. * + * @param divider_bits number of divider bits (8 or 16) * @param parent_rate clock rate of parent clock in Hz * @param rate required clock rate for this clock * @param extra_divvalue for the second-stage divisor (not set if this @@ -578,8 +583,8 @@ unsigned long clock_get_periph_rate(enum periph_id periph_id, * @return divider which should be used, or -1 if nothing is valid * */ -static int find_best_divider(unsigned long parent_rate, unsigned long rate, - int *extra_div) +static int find_best_divider(unsigned divider_bits, unsigned long parent_rate, +unsigned long rate, int *extra_div) { int shift; int best_divider = -1; @@ -588,7 +593,8 @@ static int find_best_divider(unsigned long parent_rate, unsigned long rate, /* try dividers from 1 to 256 and find closest match */ for