ARM: keystone2: clock: add K2E clock support

This patch adds clock definitions and commands to support Keystone2
K2E SOC.

Signed-off-by: Hao Zhang <hzhang@ti.com>
Signed-off-by: Ivan Khoronzhuk <ivan.khoronzhuk@ti.com>
diff --git a/arch/arm/cpu/armv7/keystone/Makefile b/arch/arm/cpu/armv7/keystone/Makefile
index 74c5160..f8519c0 100644
--- a/arch/arm/cpu/armv7/keystone/Makefile
+++ b/arch/arm/cpu/armv7/keystone/Makefile
@@ -9,6 +9,7 @@
 obj-y	+= psc.o
 obj-y	+= clock.o
 obj-$(CONFIG_SOC_K2HK) += clock-k2hk.o
+obj-$(CONFIG_SOC_K2E) += clock-k2e.o
 obj-y	+= cmd_clock.o
 obj-y	+= cmd_mon.o
 obj-$(CONFIG_DRIVER_TI_KEYSTONE_NET) += keystone_nav.o
diff --git a/arch/arm/cpu/armv7/keystone/clock-k2e.c b/arch/arm/cpu/armv7/keystone/clock-k2e.c
new file mode 100644
index 0000000..42092e1
--- /dev/null
+++ b/arch/arm/cpu/armv7/keystone/clock-k2e.c
@@ -0,0 +1,101 @@
+/*
+ * Keystone2: get clk rate for K2E
+ *
+ * (C) Copyright 2012-2014
+ *     Texas Instruments Incorporated, <www.ti.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/clock_defs.h>
+
+const struct keystone_pll_regs keystone_pll_regs[] = {
+	[CORE_PLL] = {KS2_MAINPLLCTL0, KS2_MAINPLLCTL1},
+	[PASS_PLL] = {KS2_PASSPLLCTL0, KS2_PASSPLLCTL1},
+	[DDR3_PLL] = {KS2_DDR3APLLCTL0, KS2_DDR3APLLCTL1},
+};
+
+/**
+ * pll_freq_get - get pll frequency
+ * Fout = Fref * NF(mult) / NR(prediv) / OD
+ * @pll:	pll identifier
+ */
+static unsigned long pll_freq_get(int pll)
+{
+	unsigned long mult = 1, prediv = 1, output_div = 2;
+	unsigned long ret;
+	u32 tmp, reg;
+
+	if (pll == CORE_PLL) {
+		ret = external_clk[sys_clk];
+		if (pllctl_reg_read(pll, ctl) & PLLCTL_PLLEN) {
+			/* PLL mode */
+			tmp = __raw_readl(KS2_MAINPLLCTL0);
+			prediv = (tmp & PLL_DIV_MASK) + 1;
+			mult = (((tmp & PLLM_MULT_HI_SMASK) >> 6) |
+				(pllctl_reg_read(pll, mult) &
+				PLLM_MULT_LO_MASK)) + 1;
+			output_div = ((pllctl_reg_read(pll, secctl) >>
+				       PLL_CLKOD_SHIFT) & PLL_CLKOD_MASK) + 1;
+
+			ret = ret / prediv / output_div * mult;
+		}
+	} else {
+		switch (pll) {
+		case PASS_PLL:
+			ret = external_clk[pa_clk];
+			reg = KS2_PASSPLLCTL0;
+			break;
+		case DDR3_PLL:
+			ret = external_clk[ddr3_clk];
+			reg = KS2_DDR3APLLCTL0;
+			break;
+		default:
+			return 0;
+		}
+
+		tmp = __raw_readl(reg);
+
+		if (!(tmp & PLLCTL_BYPASS)) {
+			/* Bypass disabled */
+			prediv = (tmp & PLL_DIV_MASK) + 1;
+			mult = ((tmp >> PLL_MULT_SHIFT) & PLL_MULT_MASK) + 1;
+			output_div = ((tmp >> PLL_CLKOD_SHIFT) &
+				      PLL_CLKOD_MASK) + 1;
+			ret = ((ret / prediv) * mult) / output_div;
+		}
+	}
+
+	return ret;
+}
+
+unsigned long clk_get_rate(unsigned int clk)
+{
+	switch (clk) {
+	case core_pll_clk:      return pll_freq_get(CORE_PLL);
+	case pass_pll_clk:      return pll_freq_get(PASS_PLL);
+	case ddr3_pll_clk:      return pll_freq_get(DDR3_PLL);
+	case sys_clk0_1_clk:
+	case sys_clk0_clk:      return pll_freq_get(CORE_PLL) / pll0div_read(1);
+	case sys_clk1_clk:      return pll_freq_get(CORE_PLL) / pll0div_read(2);
+	case sys_clk2_clk:      return pll_freq_get(CORE_PLL) / pll0div_read(3);
+	case sys_clk3_clk:      return pll_freq_get(CORE_PLL) / pll0div_read(4);
+	case sys_clk0_2_clk:    return clk_get_rate(sys_clk0_clk) / 2;
+	case sys_clk0_3_clk:    return clk_get_rate(sys_clk0_clk) / 3;
+	case sys_clk0_4_clk:    return clk_get_rate(sys_clk0_clk) / 4;
+	case sys_clk0_6_clk:    return clk_get_rate(sys_clk0_clk) / 6;
+	case sys_clk0_8_clk:    return clk_get_rate(sys_clk0_clk) / 8;
+	case sys_clk0_12_clk:   return clk_get_rate(sys_clk0_clk) / 12;
+	case sys_clk0_24_clk:   return clk_get_rate(sys_clk0_clk) / 24;
+	case sys_clk1_3_clk:    return clk_get_rate(sys_clk1_clk) / 3;
+	case sys_clk1_4_clk:    return clk_get_rate(sys_clk1_clk) / 4;
+	case sys_clk1_6_clk:    return clk_get_rate(sys_clk1_clk) / 6;
+	case sys_clk1_12_clk:   return clk_get_rate(sys_clk1_clk) / 12;
+	default:
+		break;
+	}
+
+	return 0;
+}
diff --git a/arch/arm/cpu/armv7/keystone/clock.c b/arch/arm/cpu/armv7/keystone/clock.c
index 42b664b..03c1d9f 100644
--- a/arch/arm/cpu/armv7/keystone/clock.c
+++ b/arch/arm/cpu/armv7/keystone/clock.c
@@ -106,6 +106,7 @@
 
 		tmp = pllctl_reg_setbits(data->pll, ctl, PLLCTL_PLLEN);
 
+#ifndef CONFIG_SOC_K2E
 	} else if (data->pll == TETRIS_PLL) {
 		bwadj = pllm >> 1;
 		/* 1.5 Set PLLCTL0[BYPASS] =1 (enable bypass), */
@@ -156,6 +157,7 @@
 		 * only applicable for Kepler
 		 */
 		setbits_le32(KS2_MISC_CTRL, KS2_ARM_PLL_EN);
+#endif
 	} else {
 		setbits_le32(keystone_pll_regs[data->pll].reg1, PLLCTL_ENSAT);
 		/*
diff --git a/arch/arm/cpu/armv7/keystone/cmd_clock.c b/arch/arm/cpu/armv7/keystone/cmd_clock.c
index afd30f3..d97c95b 100644
--- a/arch/arm/cpu/armv7/keystone/cmd_clock.c
+++ b/arch/arm/cpu/armv7/keystone/cmd_clock.c
@@ -14,10 +14,10 @@
 #include <asm/arch/psc_defs.h>
 
 struct pll_init_data cmd_pll_data = {
-	.pll			= MAIN_PLL,
-	.pll_m			= 16,
-	.pll_d			= 1,
-	.pll_od			= 2,
+	.pll = MAIN_PLL,
+	.pll_m = 16,
+	.pll_d = 1,
+	.pll_od = 2,
 };
 
 int do_pll_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
@@ -27,12 +27,19 @@
 
 	if (strncmp(argv[1], "pa", 2) == 0)
 		cmd_pll_data.pll = PASS_PLL;
+#ifndef CONFIG_SOC_K2E
 	else if (strncmp(argv[1], "arm", 3) == 0)
 		cmd_pll_data.pll = TETRIS_PLL;
+#endif
+#ifdef CONFIG_SOC_K2HK
 	else if (strncmp(argv[1], "ddr3a", 5) == 0)
 		cmd_pll_data.pll = DDR3A_PLL;
 	else if (strncmp(argv[1], "ddr3b", 5) == 0)
 		cmd_pll_data.pll = DDR3B_PLL;
+#else
+	else if (strncmp(argv[1], "ddr3", 4) == 0)
+		cmd_pll_data.pll = DDR3_PLL;
+#endif
 	else
 		goto pll_cmd_usage;
 
@@ -51,11 +58,20 @@
 	return cmd_usage(cmdtp);
 }
 
+#ifdef CONFIG_SOC_K2HK
 U_BOOT_CMD(
 	pllset,	5,	0,	do_pll_cmd,
 	"set pll multiplier and pre divider",
 	"<pa|arm|ddr3a|ddr3b> <mult> <div> <OD>\n"
 );
+#endif
+#ifdef CONFIG_SOC_K2E
+U_BOOT_CMD(
+	pllset, 5,      0,      do_pll_cmd,
+	"set pll multiplier and pre divider",
+	"<pa|ddr3> <mult> <div> <OD>\n"
+);
+#endif
 
 int do_getclk_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
@@ -79,7 +95,12 @@
 	getclk,	2,	0,	do_getclk_cmd,
 	"get clock rate",
 	"<clk index>\n"
-	"See the 'enum clk_e' in the k2hk clock.h for clk indexes\n"
+#ifdef CONFIG_SOC_K2HK
+	"See the 'enum clk_e' in the clock-k2hk.h for clk indexes\n"
+#endif
+#ifdef CONFIG_SOC_K2E
+	"See the 'enum clk_e' in the clock-k2e.h for clk indexes\n"
+#endif
 );
 
 int do_psc_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])