Patchwork [U-Boot,7/9,v2] Exynos: clock: Add generic api to get the clk freq

login
register
mail settings
Submitter Akshay Saraswat
Date Feb. 28, 2013, 10:59 a.m.
Message ID <1362049164-10297-8-git-send-email-akshay.s@samsung.com>
Download mbox | patch
Permalink /patch/223875/
State Changes Requested
Delegated to: Minkyu Kang
Headers show

Comments

Akshay Saraswat - Feb. 28, 2013, 10:59 a.m.
Add generic api to get the frequency of the required peripherial. This
API gets the source clock frequency and returns the required frequency
by dividing with first and second dividers based on the requirement.

Test with command "sf probe 1:0; time sf read 40008000 0 1000".
Try with different numbers of bytes and see that sane values are obtained
Build and boot U-boot with this patch, backlight works properly.

Signed-off-by: Padmavathi Venna <padma.v@samsung.com>
Signed-off-by: Akshay Saraswat <akshay.s@samsung.com>
---
Changes since v1:
        - Fixed few nits.

 arch/arm/cpu/armv7/exynos/clock.c      | 138 +++++++++++++++++++++++++++++++++
 arch/arm/include/asm/arch-exynos/clk.h |  17 ++++
 2 files changed, 155 insertions(+)
Simon Glass - Feb. 28, 2013, 1:37 p.m.
On Thu, Feb 28, 2013 at 2:59 AM, Akshay Saraswat <akshay.s@samsung.com> wrote:
> Add generic api to get the frequency of the required peripherial. This
> API gets the source clock frequency and returns the required frequency
> by dividing with first and second dividers based on the requirement.
>
> Test with command "sf probe 1:0; time sf read 40008000 0 1000".
> Try with different numbers of bytes and see that sane values are obtained
> Build and boot U-boot with this patch, backlight works properly.
>
> Signed-off-by: Padmavathi Venna <padma.v@samsung.com>
> Signed-off-by: Akshay Saraswat <akshay.s@samsung.com>

Acked-by: Simon Glass <sjg@chromium.org>

> ---
> Changes since v1:
>         - Fixed few nits.
>
>  arch/arm/cpu/armv7/exynos/clock.c      | 138 +++++++++++++++++++++++++++++++++
>  arch/arm/include/asm/arch-exynos/clk.h |  17 ++++
>  2 files changed, 155 insertions(+)
>
Minkyu Kang - March 28, 2013, 5:52 a.m.
On 28/02/13 19:59, Akshay Saraswat wrote:
> Add generic api to get the frequency of the required peripherial. This

typo.
peripherial -> peripheral

> API gets the source clock frequency and returns the required frequency
> by dividing with first and second dividers based on the requirement.
> 
> Test with command "sf probe 1:0; time sf read 40008000 0 1000".
> Try with different numbers of bytes and see that sane values are obtained
> Build and boot U-boot with this patch, backlight works properly.
> 
> Signed-off-by: Padmavathi Venna <padma.v@samsung.com>
> Signed-off-by: Akshay Saraswat <akshay.s@samsung.com>
> ---
> Changes since v1:
>         - Fixed few nits.
> 
>  arch/arm/cpu/armv7/exynos/clock.c      | 138 +++++++++++++++++++++++++++++++++
>  arch/arm/include/asm/arch-exynos/clk.h |  17 ++++
>  2 files changed, 155 insertions(+)
> 
> diff --git a/arch/arm/cpu/armv7/exynos/clock.c b/arch/arm/cpu/armv7/exynos/clock.c
> index 956427c..cc101c2 100644
> --- a/arch/arm/cpu/armv7/exynos/clock.c
> +++ b/arch/arm/cpu/armv7/exynos/clock.c
> @@ -27,6 +27,49 @@
>  #include <asm/arch/clk.h>
>  #include <asm/arch/periph.h>
>  
> +/* *
> + * This structure is to store the src bit, div bit and prediv bit
> + * positions of the peripheral clocks of the src and div registers
> + */
> +struct clk_bit_info {
> +	int8_t src_bit;
> +	int8_t div_bit;
> +	int8_t prediv_bit;
> +};
> +
> +/* src_bit div_bit prediv_bit */
> +static struct clk_bit_info clk_bit_info[PERIPH_ID_COUNT] = {
> +	{0,	0,	-1},
> +	{4,	4,	-1},
> +	{8,	8,	-1},
> +	{12,	12,	-1},
> +	{0,	0,	8},
> +	{4,	16,	24},
> +	{8,	0,	8},
> +	{12,	16,	24},
> +	{-1,	-1,	-1},
> +	{16,	0,	8},
> +	{20,	16,	24},
> +	{24,	0,	8},
> +	{0,	0,	4},
> +	{4,	12,	16},
> +	{-1,	-1,	-1},
> +	{-1,	-1,	-1},
> +	{-1,	24,	0},
> +	{-1,	24,	0},
> +	{-1,	24,	0},
> +	{-1,	24,	0},
> +	{-1,	24,	0},
> +	{-1,	24,	0},
> +	{-1,	24,	0},
> +	{-1,	24,	0},
> +	{24,	0,	-1},
> +	{24,	0,	-1},
> +	{24,	0,	-1},
> +	{24,	0,	-1},
> +	{24,	0,	-1},
> +};
> +
>  /* Epll Clock division values to achive different frequency output */
>  static struct set_epll_con_val exynos5_epll_div[] = {
>  	{ 192000000, 0, 48, 3, 1, 0 },
> @@ -201,6 +244,101 @@ static unsigned long exynos5_get_pll_clk(int pllreg)
>  	return fout;
>  }
>  
> +unsigned long exynos5_get_periph_rate(enum periph_id peripheral)

static?
please int instead of enum periph_id.

> +{
> +	struct clk_bit_info *bit_info = &clk_bit_info[peripheral];
> +	unsigned long sclk, sub_clk;
> +	unsigned int src, div, sub_div;
> +	struct exynos5_clock *clk =
> +			(struct exynos5_clock *)samsung_get_base_clock();
> +
> +	switch (peripheral) {
> +	case PERIPH_ID_UART0:
> +	case PERIPH_ID_UART1:
> +	case PERIPH_ID_UART2:
> +	case PERIPH_ID_UART3:
> +		src = readl(&clk->src_peric0);
> +		div = readl(&clk->div_peric0);
> +		break;
> +	case PERIPH_ID_PWM0:
> +	case PERIPH_ID_PWM1:
> +	case PERIPH_ID_PWM2:
> +	case PERIPH_ID_PWM3:
> +	case PERIPH_ID_PWM4:
> +		src = readl(&clk->src_peric0);
> +		div = readl(&clk->div_peric3);
> +		break;
> +	case PERIPH_ID_SPI0:
> +	case PERIPH_ID_SPI1:
> +		src = readl(&clk->src_peric1);
> +		div = readl(&clk->div_peric1);
> +		break;
> +	case PERIPH_ID_SPI2:
> +		src = readl(&clk->src_peric1);
> +		div = readl(&clk->div_peric2);
> +		break;
> +	case PERIPH_ID_SPI3:
> +	case PERIPH_ID_SPI4:
> +		src = readl(&clk->sclk_src_isp);
> +		div = readl(&clk->sclk_div_isp);
> +		break;
> +	case PERIPH_ID_SDMMC0:
> +	case PERIPH_ID_SDMMC1:
> +	case PERIPH_ID_SDMMC2:
> +	case PERIPH_ID_SDMMC3:
> +		src = readl(&clk->src_fsys);
> +		div = readl(&clk->div_fsys1);
> +		break;
> +	case PERIPH_ID_I2C0:
> +	case PERIPH_ID_I2C1:
> +	case PERIPH_ID_I2C2:
> +	case PERIPH_ID_I2C3:
> +	case PERIPH_ID_I2C4:
> +	case PERIPH_ID_I2C5:
> +	case PERIPH_ID_I2C6:
> +	case PERIPH_ID_I2C7:
> +		sclk = exynos5_get_pll_clk(MPLL);
> +		sub_div = ((readl(&clk->div_top1) >> bit_info->div_bit)
> +								& 0x7) + 1;
> +		div = ((readl(&clk->div_top0) >> bit_info->prediv_bit)
> +								& 0x7) + 1;
> +		return (sclk / sub_div) / div;
> +	default:
> +		debug("%s: invalid peripheral %d", __func__, peripheral);
> +		return -1;
> +	};
> +
> +	src = (src >> bit_info->src_bit) & 0xf;

please add a blank line here.

> +	if (src == EXYNOS_SRC_MPLL)
> +		sclk = exynos5_get_pll_clk(MPLL);
> +	else if (src == EXYNOS_SRC_EPLL)
> +		sclk = exynos5_get_pll_clk(EPLL);
> +	else if (src == EXYNOS_SRC_VPLL)
> +		sclk = exynos5_get_pll_clk(VPLL);
> +	else
> +		return 0;

why don't you use switch..case?

> +
> +	/* Ratio clock division for this peripheral */
> +	sub_div = (div >> bit_info->div_bit) & 0xf;
> +	sub_clk = sclk / (sub_div + 1);
> +
> +	/* Pre-ratio clock division for SDMMC0 and 2 */
> +	if (peripheral == PERIPH_ID_SDMMC0 || peripheral == PERIPH_ID_SDMMC2) {
> +		div = (div >> bit_info->prediv_bit) & 0xff;
> +		return sub_clk / (div + 1);
> +	}
> +
> +	return sub_clk;
> +}
> +
> +unsigned long clock_get_periph_rate(enum periph_id peripheral)

please int instead of enum periph_id.

> +{
> +	if (cpu_is_exynos5())
> +		return exynos5_get_periph_rate(peripheral);
> +	else
> +		return 0;
> +}
> +
>  /* exynos4: return ARM clock frequency */
>  static unsigned long exynos4_get_arm_clk(void)
>  {
> diff --git a/arch/arm/include/asm/arch-exynos/clk.h b/arch/arm/include/asm/arch-exynos/clk.h
> index 1935b0b..b72c90e 100644
> --- a/arch/arm/include/asm/arch-exynos/clk.h
> +++ b/arch/arm/include/asm/arch-exynos/clk.h
> @@ -22,6 +22,8 @@
>  #ifndef __ASM_ARM_ARCH_CLK_H_
>  #define __ASM_ARM_ARCH_CLK_H_
>  
> +#include <asm/arch/periph.h>

I don't want got a dependency with other header file.
please remove it.

> +
>  #define APLL	0
>  #define MPLL	1
>  #define EPLL	2
> @@ -29,6 +31,12 @@
>  #define VPLL	4
>  #define BPLL	5
>  
> +enum pll_src_bit {
> +	EXYNOS_SRC_MPLL = 6,
> +	EXYNOS_SRC_EPLL,
> +	EXYNOS_SRC_VPLL,
> +};
> +
>  unsigned long get_pll_clk(int pllreg);
>  unsigned long get_arm_clk(void);
>  unsigned long get_i2c_clk(void);
> @@ -44,4 +52,13 @@ int set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq);
>  int set_epll_clk(unsigned long rate);
>  int set_spi_clk(int periph_id, unsigned int rate);
>  
> +/**
> + * get the clk frequency of the required peripherial
> + *
> + * @param peripherial	Peripherial id
> + *
> + * @return frequency of the peripherial clk
> + */

typo.
peripherial -> peripheral

> +unsigned long clock_get_periph_rate(enum periph_id peripheral);

Please clock_get_periph_rate(int periph_id);

> +
>  #endif
> 

Thanks,
Minkyu Kang.

Patch

diff --git a/arch/arm/cpu/armv7/exynos/clock.c b/arch/arm/cpu/armv7/exynos/clock.c
index 956427c..cc101c2 100644
--- a/arch/arm/cpu/armv7/exynos/clock.c
+++ b/arch/arm/cpu/armv7/exynos/clock.c
@@ -27,6 +27,49 @@ 
 #include <asm/arch/clk.h>
 #include <asm/arch/periph.h>
 
+/* *
+ * This structure is to store the src bit, div bit and prediv bit
+ * positions of the peripheral clocks of the src and div registers
+ */
+struct clk_bit_info {
+	int8_t src_bit;
+	int8_t div_bit;
+	int8_t prediv_bit;
+};
+
+/* src_bit div_bit prediv_bit */
+static struct clk_bit_info clk_bit_info[PERIPH_ID_COUNT] = {
+	{0,	0,	-1},
+	{4,	4,	-1},
+	{8,	8,	-1},
+	{12,	12,	-1},
+	{0,	0,	8},
+	{4,	16,	24},
+	{8,	0,	8},
+	{12,	16,	24},
+	{-1,	-1,	-1},
+	{16,	0,	8},
+	{20,	16,	24},
+	{24,	0,	8},
+	{0,	0,	4},
+	{4,	12,	16},
+	{-1,	-1,	-1},
+	{-1,	-1,	-1},
+	{-1,	24,	0},
+	{-1,	24,	0},
+	{-1,	24,	0},
+	{-1,	24,	0},
+	{-1,	24,	0},
+	{-1,	24,	0},
+	{-1,	24,	0},
+	{-1,	24,	0},
+	{24,	0,	-1},
+	{24,	0,	-1},
+	{24,	0,	-1},
+	{24,	0,	-1},
+	{24,	0,	-1},
+};
+
 /* Epll Clock division values to achive different frequency output */
 static struct set_epll_con_val exynos5_epll_div[] = {
 	{ 192000000, 0, 48, 3, 1, 0 },
@@ -201,6 +244,101 @@  static unsigned long exynos5_get_pll_clk(int pllreg)
 	return fout;
 }
 
+unsigned long exynos5_get_periph_rate(enum periph_id peripheral)
+{
+	struct clk_bit_info *bit_info = &clk_bit_info[peripheral];
+	unsigned long sclk, sub_clk;
+	unsigned int src, div, sub_div;
+	struct exynos5_clock *clk =
+			(struct exynos5_clock *)samsung_get_base_clock();
+
+	switch (peripheral) {
+	case PERIPH_ID_UART0:
+	case PERIPH_ID_UART1:
+	case PERIPH_ID_UART2:
+	case PERIPH_ID_UART3:
+		src = readl(&clk->src_peric0);
+		div = readl(&clk->div_peric0);
+		break;
+	case PERIPH_ID_PWM0:
+	case PERIPH_ID_PWM1:
+	case PERIPH_ID_PWM2:
+	case PERIPH_ID_PWM3:
+	case PERIPH_ID_PWM4:
+		src = readl(&clk->src_peric0);
+		div = readl(&clk->div_peric3);
+		break;
+	case PERIPH_ID_SPI0:
+	case PERIPH_ID_SPI1:
+		src = readl(&clk->src_peric1);
+		div = readl(&clk->div_peric1);
+		break;
+	case PERIPH_ID_SPI2:
+		src = readl(&clk->src_peric1);
+		div = readl(&clk->div_peric2);
+		break;
+	case PERIPH_ID_SPI3:
+	case PERIPH_ID_SPI4:
+		src = readl(&clk->sclk_src_isp);
+		div = readl(&clk->sclk_div_isp);
+		break;
+	case PERIPH_ID_SDMMC0:
+	case PERIPH_ID_SDMMC1:
+	case PERIPH_ID_SDMMC2:
+	case PERIPH_ID_SDMMC3:
+		src = readl(&clk->src_fsys);
+		div = readl(&clk->div_fsys1);
+		break;
+	case PERIPH_ID_I2C0:
+	case PERIPH_ID_I2C1:
+	case PERIPH_ID_I2C2:
+	case PERIPH_ID_I2C3:
+	case PERIPH_ID_I2C4:
+	case PERIPH_ID_I2C5:
+	case PERIPH_ID_I2C6:
+	case PERIPH_ID_I2C7:
+		sclk = exynos5_get_pll_clk(MPLL);
+		sub_div = ((readl(&clk->div_top1) >> bit_info->div_bit)
+								& 0x7) + 1;
+		div = ((readl(&clk->div_top0) >> bit_info->prediv_bit)
+								& 0x7) + 1;
+		return (sclk / sub_div) / div;
+	default:
+		debug("%s: invalid peripheral %d", __func__, peripheral);
+		return -1;
+	};
+
+	src = (src >> bit_info->src_bit) & 0xf;
+	if (src == EXYNOS_SRC_MPLL)
+		sclk = exynos5_get_pll_clk(MPLL);
+	else if (src == EXYNOS_SRC_EPLL)
+		sclk = exynos5_get_pll_clk(EPLL);
+	else if (src == EXYNOS_SRC_VPLL)
+		sclk = exynos5_get_pll_clk(VPLL);
+	else
+		return 0;
+
+	/* Ratio clock division for this peripheral */
+	sub_div = (div >> bit_info->div_bit) & 0xf;
+	sub_clk = sclk / (sub_div + 1);
+
+	/* Pre-ratio clock division for SDMMC0 and 2 */
+	if (peripheral == PERIPH_ID_SDMMC0 || peripheral == PERIPH_ID_SDMMC2) {
+		div = (div >> bit_info->prediv_bit) & 0xff;
+		return sub_clk / (div + 1);
+	}
+
+	return sub_clk;
+}
+
+unsigned long clock_get_periph_rate(enum periph_id peripheral)
+{
+	if (cpu_is_exynos5())
+		return exynos5_get_periph_rate(peripheral);
+	else
+		return 0;
+}
+
 /* exynos4: return ARM clock frequency */
 static unsigned long exynos4_get_arm_clk(void)
 {
diff --git a/arch/arm/include/asm/arch-exynos/clk.h b/arch/arm/include/asm/arch-exynos/clk.h
index 1935b0b..b72c90e 100644
--- a/arch/arm/include/asm/arch-exynos/clk.h
+++ b/arch/arm/include/asm/arch-exynos/clk.h
@@ -22,6 +22,8 @@ 
 #ifndef __ASM_ARM_ARCH_CLK_H_
 #define __ASM_ARM_ARCH_CLK_H_
 
+#include <asm/arch/periph.h>
+
 #define APLL	0
 #define MPLL	1
 #define EPLL	2
@@ -29,6 +31,12 @@ 
 #define VPLL	4
 #define BPLL	5
 
+enum pll_src_bit {
+	EXYNOS_SRC_MPLL = 6,
+	EXYNOS_SRC_EPLL,
+	EXYNOS_SRC_VPLL,
+};
+
 unsigned long get_pll_clk(int pllreg);
 unsigned long get_arm_clk(void);
 unsigned long get_i2c_clk(void);
@@ -44,4 +52,13 @@  int set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq);
 int set_epll_clk(unsigned long rate);
 int set_spi_clk(int periph_id, unsigned int rate);
 
+/**
+ * get the clk frequency of the required peripherial
+ *
+ * @param peripherial	Peripherial id
+ *
+ * @return frequency of the peripherial clk
+ */
+unsigned long clock_get_periph_rate(enum periph_id peripheral);
+
 #endif