summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/cpu/armv7/exynos/clock.c144
-rw-r--r--arch/arm/include/asm/arch-exynos/clk.h15
2 files changed, 159 insertions, 0 deletions
diff --git a/arch/arm/cpu/armv7/exynos/clock.c b/arch/arm/cpu/armv7/exynos/clock.c
index 956427c9eb..5860c8fcd9 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,107 @@ static unsigned long exynos5_get_pll_clk(int pllreg)
return fout;
}
+static unsigned long exynos5_get_periph_rate(int 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;
+
+ switch (src) {
+ case EXYNOS_SRC_MPLL:
+ sclk = exynos5_get_pll_clk(MPLL);
+ break;
+ case EXYNOS_SRC_EPLL:
+ sclk = exynos5_get_pll_clk(EPLL);
+ break;
+ case EXYNOS_SRC_VPLL:
+ sclk = exynos5_get_pll_clk(VPLL);
+ break;
+ default:
+ 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(int 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 1935b0b5b8..73f8063048 100644
--- a/arch/arm/include/asm/arch-exynos/clk.h
+++ b/arch/arm/include/asm/arch-exynos/clk.h
@@ -29,6 +29,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 +50,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 peripheral
+ *
+ * @param peripheral Peripheral id
+ *
+ * @return frequency of the peripheral clk
+ */
+unsigned long clock_get_periph_rate(int peripheral);
+
#endif