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

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

Comments

Akshay Saraswat - Feb. 27, 2013, 10:02 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=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>
---
 arch/arm/cpu/armv7/exynos/clock.c      | 127 +++++++++++++++++++++++++++++++++
 arch/arm/include/asm/arch-exynos/clk.h |  27 +++++++
 2 files changed, 154 insertions(+)
Simon Glass - Feb. 28, 2013, 1:35 a.m.
Hi Akshay,

On Wed, Feb 27, 2013 at 2:02 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=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.

Please remove the TEST= stuff. patman might do the first line for you
(and will print a warning).

>
> Signed-off-by: Padmavathi Venna <padma.v@samsung.com>
> Signed-off-by: Akshay Saraswat <akshay.s@samsung.com>
> ---
>  arch/arm/cpu/armv7/exynos/clock.c      | 127 +++++++++++++++++++++++++++++++++
>  arch/arm/include/asm/arch-exynos/clk.h |  27 +++++++
>  2 files changed, 154 insertions(+)
>
> diff --git a/arch/arm/cpu/armv7/exynos/clock.c b/arch/arm/cpu/armv7/exynos/clock.c
> index 956427c..a7a3066 100644
> --- a/arch/arm/cpu/armv7/exynos/clock.c
> +++ b/arch/arm/cpu/armv7/exynos/clock.c
> @@ -27,6 +27,39 @@
>  #include <asm/arch/clk.h>
>  #include <asm/arch/periph.h>
>
> +/* 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 +234,100 @@ 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 == SRC_MPLL)
> +               sclk = exynos5_get_pll_clk(MPLL);
> +       else if (src == SRC_EPLL)
> +               sclk = exynos5_get_pll_clk(EPLL);
> +       else if (src == SRC_VPLL)
> +               sclk = exynos5_get_pll_clk(VPLL);
> +       else
> +               return 0;
> +
> +       sub_div = (div >> bit_info->div_bit) & 0xf;
> +       sub_clk = sclk / (sub_div + 1);
> +
> +       if (peripheral == PERIPH_ID_SDMMC0 || peripheral == PERIPH_ID_SDMMC2) {

Please can you add a comment for what this if() is doing?

> +               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 {
> +               if (proid_is_exynos4412())
> +                       return 0;
> +               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..b459b16 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,22 @@
>  #define VPLL   4
>  #define BPLL   5

Suggest EXYNOS_ prefix on these

>
> +enum pll_src_bit {
> +       SRC_MPLL = 6,
> +       SRC_EPLL,
> +       SRC_VPLL,
> +};
> +
> +/* *
> + * 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 {
> +       int src_bit;
> +       int div_bit;
> +       int prediv_bit;

Should these perhaps be int8_t ? Can this structure move to the C file?

> +};
> +
>  unsigned long get_pll_clk(int pllreg);
>  unsigned long get_arm_clk(void);
>  unsigned long get_i2c_clk(void);
> @@ -44,4 +62,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
> --
> 1.8.0
>

Regards,
Simon

Patch

diff --git a/arch/arm/cpu/armv7/exynos/clock.c b/arch/arm/cpu/armv7/exynos/clock.c
index 956427c..a7a3066 100644
--- a/arch/arm/cpu/armv7/exynos/clock.c
+++ b/arch/arm/cpu/armv7/exynos/clock.c
@@ -27,6 +27,39 @@ 
 #include <asm/arch/clk.h>
 #include <asm/arch/periph.h>
 
+/* 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 +234,100 @@  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 == SRC_MPLL)
+		sclk = exynos5_get_pll_clk(MPLL);
+	else if (src == SRC_EPLL)
+		sclk = exynos5_get_pll_clk(EPLL);
+	else if (src == SRC_VPLL)
+		sclk = exynos5_get_pll_clk(VPLL);
+	else
+		return 0;
+
+	sub_div = (div >> bit_info->div_bit) & 0xf;
+	sub_clk = sclk / (sub_div + 1);
+
+	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 {
+		if (proid_is_exynos4412())
+			return 0;
+		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..b459b16 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,22 @@ 
 #define VPLL	4
 #define BPLL	5
 
+enum pll_src_bit {
+	SRC_MPLL = 6,
+	SRC_EPLL,
+	SRC_VPLL,
+};
+
+/* *
+ * 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 {
+	int src_bit;
+	int div_bit;
+	int prediv_bit;
+};
+
 unsigned long get_pll_clk(int pllreg);
 unsigned long get_arm_clk(void);
 unsigned long get_i2c_clk(void);
@@ -44,4 +62,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