summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-imx/speed-imx6.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-imx/speed-imx6.c')
-rw-r--r--arch/arm/mach-imx/speed-imx6.c393
1 files changed, 393 insertions, 0 deletions
diff --git a/arch/arm/mach-imx/speed-imx6.c b/arch/arm/mach-imx/speed-imx6.c
new file mode 100644
index 0000000000..4cc9fdbbc4
--- /dev/null
+++ b/arch/arm/mach-imx/speed-imx6.c
@@ -0,0 +1,393 @@
+#include <common.h>
+#include <asm/io.h>
+#include <asm-generic/div64.h>
+#include <mach/imx-regs.h>
+#include <mach/clock-imx6.h>
+#include <mach/imx6-anadig.h>
+
+enum pll_clocks {
+ CPU_PLL1, /* System PLL */
+ BUS_PLL2, /* System Bus PLL*/
+ USBOTG_PLL3, /* OTG USB PLL */
+ AUD_PLL4, /* Audio PLL */
+ VID_PLL5, /* Video PLL */
+ MLB_PLL6, /* MLB PLL */
+ USBHOST_PLL7, /* Host USB PLL */
+ ENET_PLL8, /* ENET PLL */
+};
+
+#define SZ_DEC_1M 1000000
+
+/* Out-of-reset PFDs and clock source definitions */
+#define PLL2_PFD0_FREQ 352000000
+#define PLL2_PFD1_FREQ 594000000
+#define PLL2_PFD2_FREQ 400000000
+#define PLL2_PFD2_DIV_FREQ 200000000
+#define PLL3_PFD0_FREQ 720000000
+#define PLL3_PFD1_FREQ 540000000
+#define PLL3_PFD2_FREQ 508200000
+#define PLL3_PFD3_FREQ 454700000
+#define PLL3_80M 80000000
+#define PLL3_60M 60000000
+
+#define AHB_CLK_ROOT 132000000
+#define IPG_CLK_ROOT 66000000
+#define ENET_FREQ_0 25000000
+#define ENET_FREQ_1 50000000
+#define ENET_FREQ_2 100000000
+#define ENET_FREQ_3 125000000
+
+#define CONFIG_MX6_HCLK_FREQ 24000000
+
+static u32 __decode_pll(enum pll_clocks pll, u32 infreq)
+{
+ u32 div;
+
+ switch (pll) {
+ case CPU_PLL1:
+ div = readl(MX6_ANATOP_BASE_ADDR + HW_ANADIG_PLL_SYS) &
+ BM_ANADIG_PLL_SYS_DIV_SELECT;
+ return infreq * (div >> 1);
+ case BUS_PLL2:
+ div = readl(MX6_ANATOP_BASE_ADDR + HW_ANADIG_PLL_528) &
+ BM_ANADIG_PLL_528_DIV_SELECT;
+ return infreq * (20 + (div << 1));
+ case USBOTG_PLL3:
+ div = readl(MX6_ANATOP_BASE_ADDR + HW_ANADIG_USB2_PLL_480_CTRL) &
+ BM_ANADIG_USB2_PLL_480_CTRL_DIV_SELECT;
+ return infreq * (20 + (div << 1));
+ case ENET_PLL8:
+ div = readl(MX6_ANATOP_BASE_ADDR + HW_ANADIG_PLL_ENET) &
+ BM_ANADIG_PLL_ENET_DIV_SELECT;
+ switch (div) {
+ default:
+ case 0:
+ return ENET_FREQ_0;
+ case 1:
+ return ENET_FREQ_1;
+ case 2:
+ return ENET_FREQ_2;
+ case 3:
+ return ENET_FREQ_3;
+ }
+ case AUD_PLL4:
+ case VID_PLL5:
+ case MLB_PLL6:
+ case USBHOST_PLL7:
+ default:
+ return 0;
+ }
+}
+
+static u32 __get_mcu_main_clk(void)
+{
+ u32 reg, freq;
+ reg = (__REG(MXC_CCM_CACRR) & MXC_CCM_CACRR_ARM_PODF_MASK) >>
+ MXC_CCM_CACRR_ARM_PODF_OFFSET;
+ freq = __decode_pll(CPU_PLL1, CONFIG_MX6_HCLK_FREQ);
+ return freq / (reg + 1);
+}
+
+static u32 __get_periph_clk(void)
+{
+ u32 reg;
+ reg = __REG(MXC_CCM_CBCDR);
+ if (reg & MXC_CCM_CBCDR_PERIPH_CLK_SEL) {
+ reg = __REG(MXC_CCM_CBCMR);
+ switch ((reg & MXC_CCM_CBCMR_PERIPH_CLK2_SEL_MASK) >>
+ MXC_CCM_CBCMR_PERIPH_CLK2_SEL_OFFSET) {
+ case 0:
+ return __decode_pll(USBOTG_PLL3, CONFIG_MX6_HCLK_FREQ);
+ case 1:
+ case 2:
+ return CONFIG_MX6_HCLK_FREQ;
+ default:
+ return 0;
+ }
+ } else {
+ reg = __REG(MXC_CCM_CBCMR);
+ switch ((reg & MXC_CCM_CBCMR_PRE_PERIPH_CLK_SEL_MASK) >>
+ MXC_CCM_CBCMR_PRE_PERIPH_CLK_SEL_OFFSET) {
+ default:
+ case 0:
+ return __decode_pll(BUS_PLL2, CONFIG_MX6_HCLK_FREQ);
+ case 1:
+ return PLL2_PFD2_FREQ;
+ case 2:
+ return PLL2_PFD0_FREQ;
+ case 3:
+ return PLL2_PFD2_DIV_FREQ;
+ }
+ }
+}
+
+static u32 __get_ipg_clk(void)
+{
+ u32 ahb_podf, ipg_podf;
+
+ ahb_podf = __REG(MXC_CCM_CBCDR);
+ ipg_podf = (ahb_podf & MXC_CCM_CBCDR_IPG_PODF_MASK) >>
+ MXC_CCM_CBCDR_IPG_PODF_OFFSET;
+ ahb_podf = (ahb_podf & MXC_CCM_CBCDR_AHB_PODF_MASK) >>
+ MXC_CCM_CBCDR_AHB_PODF_OFFSET;
+ return __get_periph_clk() / ((ahb_podf + 1) * (ipg_podf + 1));
+}
+
+u32 imx_get_gptclk(void)
+{
+ return __get_ipg_clk();
+}
+
+static u32 __get_ipg_per_clk(void)
+{
+ u32 podf;
+ u32 clk_root = __get_ipg_clk();
+
+ podf = __REG(MXC_CCM_CSCMR1) & MXC_CCM_CSCMR1_PERCLK_PODF_MASK;
+ return clk_root / (podf + 1);
+}
+
+u32 imx_get_uartclk(void)
+{
+ u32 freq = PLL3_80M, reg, podf;
+
+ reg = __REG(MXC_CCM_CSCDR1);
+ podf = (reg & MXC_CCM_CSCDR1_UART_CLK_PODF_MASK) >>
+ MXC_CCM_CSCDR1_UART_CLK_PODF_OFFSET;
+ freq /= (podf + 1);
+
+ return freq;
+}
+
+static u32 __get_cspi_clk(void)
+{
+ u32 freq = PLL3_60M, reg, podf;
+
+ reg = __REG(MXC_CCM_CSCDR2);
+ podf = (reg & MXC_CCM_CSCDR2_ECSPI_CLK_PODF_MASK) >>
+ MXC_CCM_CSCDR2_ECSPI_CLK_PODF_OFFSET;
+ freq /= (podf + 1);
+
+ return freq;
+}
+
+static u32 __get_axi_clk(void)
+{
+ u32 clkroot;
+ u32 cbcdr = __REG(MXC_CCM_CBCDR);
+ u32 podf = (cbcdr & MXC_CCM_CBCDR_AXI_PODF_MASK) >>
+ MXC_CCM_CBCDR_AXI_PODF_OFFSET;
+
+ if (cbcdr & MXC_CCM_CBCDR_AXI_SEL) {
+ if (cbcdr & MXC_CCM_CBCDR_AXI_ALT_SEL)
+ clkroot = PLL2_PFD2_FREQ;
+ else
+ clkroot = PLL3_PFD1_FREQ;;
+ } else
+ clkroot = __get_periph_clk();
+
+ return clkroot / (podf + 1);
+}
+
+static u32 __get_ahb_clk(void)
+{
+ u32 cbcdr = __REG(MXC_CCM_CBCDR);
+ u32 podf = (cbcdr & MXC_CCM_CBCDR_AHB_PODF_MASK) \
+ >> MXC_CCM_CBCDR_AHB_PODF_OFFSET;
+
+ return __get_periph_clk() / (podf + 1);
+}
+
+static u32 __get_emi_slow_clk(void)
+{
+ u32 cscmr1 = __REG(MXC_CCM_CSCMR1);
+ u32 emi_clk_sel = (cscmr1 & MXC_CCM_CSCMR1_ACLK_EMI_SLOW_MASK) >>
+ MXC_CCM_CSCMR1_ACLK_EMI_SLOW_OFFSET;
+ u32 podf = (cscmr1 & MXC_CCM_CSCMR1_ACLK_EMI_SLOW_PODF_MASK) >>
+ MXC_CCM_CSCMR1_ACLK_EMI_PODF_OFFSET;
+
+ switch (emi_clk_sel) {
+ default:
+ case 0:
+ return __get_axi_clk() / (podf + 1);
+ case 1:
+ return __decode_pll(USBOTG_PLL3, CONFIG_MX6_HCLK_FREQ) /
+ (podf + 1);
+ case 2:
+ return PLL2_PFD2_FREQ / (podf + 1);
+ case 3:
+ return PLL2_PFD0_FREQ / (podf + 1);
+ }
+}
+
+static u32 __get_nfc_clk(void)
+{
+ u32 clkroot;
+ u32 cs2cdr = __REG(MXC_CCM_CS2CDR);
+ u32 podf = (cs2cdr & MXC_CCM_CS2CDR_ENFC_CLK_PODF_MASK) \
+ >> MXC_CCM_CS2CDR_ENFC_CLK_PODF_OFFSET;
+ u32 pred = (cs2cdr & MXC_CCM_CS2CDR_ENFC_CLK_PRED_MASK) \
+ >> MXC_CCM_CS2CDR_ENFC_CLK_PRED_OFFSET;
+
+ switch ((cs2cdr & MXC_CCM_CS2CDR_ENFC_CLK_SEL_MASK) >>
+ MXC_CCM_CS2CDR_ENFC_CLK_SEL_OFFSET) {
+ default:
+ case 0:
+ clkroot = PLL2_PFD0_FREQ;
+ break;
+ case 1:
+ clkroot = __decode_pll(BUS_PLL2, CONFIG_MX6_HCLK_FREQ);
+ break;
+ case 2:
+ clkroot = __decode_pll(USBOTG_PLL3, CONFIG_MX6_HCLK_FREQ);
+ break;
+ case 3:
+ clkroot = PLL2_PFD2_FREQ;
+ break;
+ }
+
+ return clkroot / (pred+1) / (podf+1);
+}
+
+static u32 __get_ddr_clk(void)
+{
+ u32 cbcdr = __REG(MXC_CCM_CBCDR);
+ u32 podf = (cbcdr & MXC_CCM_CBCDR_MMDC_CH0_PODF_MASK) >>
+ MXC_CCM_CBCDR_MMDC_CH0_PODF_OFFSET;
+
+ return __get_periph_clk() / (podf + 1);
+}
+
+static u32 __get_usdhc1_clk(void)
+{
+ u32 clkroot;
+ u32 cscmr1 = __REG(MXC_CCM_CSCMR1);
+ u32 cscdr1 = __REG(MXC_CCM_CSCDR1);
+ u32 podf = (cscdr1 & MXC_CCM_CSCDR1_USDHC1_PODF_MASK) >>
+ MXC_CCM_CSCDR1_USDHC1_PODF_OFFSET;
+
+ if (cscmr1 & MXC_CCM_CSCMR1_USDHC1_CLK_SEL)
+ clkroot = PLL2_PFD0_FREQ;
+ else
+ clkroot = PLL2_PFD2_FREQ;
+
+ return clkroot / (podf + 1);
+}
+
+static u32 __get_usdhc2_clk(void)
+{
+ u32 clkroot;
+ u32 cscmr1 = __REG(MXC_CCM_CSCMR1);
+ u32 cscdr1 = __REG(MXC_CCM_CSCDR1);
+ u32 podf = (cscdr1 & MXC_CCM_CSCDR1_USDHC2_PODF_MASK) >>
+ MXC_CCM_CSCDR1_USDHC2_PODF_OFFSET;
+
+ if (cscmr1 & MXC_CCM_CSCMR1_USDHC2_CLK_SEL)
+ clkroot = PLL2_PFD0_FREQ;
+ else
+ clkroot = PLL2_PFD2_FREQ;
+
+ return clkroot / (podf + 1);
+}
+
+static u32 __get_usdhc3_clk(void)
+{
+ u32 clkroot;
+ u32 cscmr1 = __REG(MXC_CCM_CSCMR1);
+ u32 cscdr1 = __REG(MXC_CCM_CSCDR1);
+ u32 podf = (cscdr1 & MXC_CCM_CSCDR1_USDHC3_PODF_MASK) >>
+ MXC_CCM_CSCDR1_USDHC3_PODF_OFFSET;
+
+ if (cscmr1 & MXC_CCM_CSCMR1_USDHC3_CLK_SEL)
+ clkroot = PLL2_PFD0_FREQ;
+ else
+ clkroot = PLL2_PFD2_FREQ;
+
+ return clkroot / (podf + 1);
+}
+
+static u32 __get_usdhc4_clk(void)
+{
+ u32 clkroot;
+ u32 cscmr1 = __REG(MXC_CCM_CSCMR1);
+ u32 cscdr1 = __REG(MXC_CCM_CSCDR1);
+ u32 podf = (cscdr1 & MXC_CCM_CSCDR1_USDHC4_PODF_MASK) >>
+ MXC_CCM_CSCDR1_USDHC4_PODF_OFFSET;
+
+ if (cscmr1 & MXC_CCM_CSCMR1_USDHC4_CLK_SEL)
+ clkroot = PLL2_PFD0_FREQ;
+ else
+ clkroot = PLL2_PFD2_FREQ;
+
+ return clkroot / (podf + 1);
+}
+
+u32 imx_get_mmcclk(void)
+{
+ return __get_usdhc3_clk();
+}
+
+u32 imx_get_fecclk(void)
+{
+ return __get_ipg_clk();
+}
+
+void imx_dump_clocks(void)
+{
+ u32 freq;
+
+ freq = __decode_pll(CPU_PLL1, CONFIG_MX6_HCLK_FREQ);
+ printf("mx6q pll1: %d\n", freq);
+ freq = __decode_pll(BUS_PLL2, CONFIG_MX6_HCLK_FREQ);
+ printf("mx6q pll2: %d\n", freq);
+ freq = __decode_pll(USBOTG_PLL3, CONFIG_MX6_HCLK_FREQ);
+ printf("mx6q pll3: %d\n", freq);
+ freq = __decode_pll(ENET_PLL8, CONFIG_MX6_HCLK_FREQ);
+ printf("mx6q pll8: %d\n", freq);
+ printf("mcu main: %d\n", __get_mcu_main_clk());
+ printf("periph: %d\n", __get_periph_clk());
+ printf("ipg: %d\n", __get_ipg_clk());
+ printf("ipg per: %d\n", __get_ipg_per_clk());
+ printf("cspi: %d\n", __get_cspi_clk());
+ printf("axi: %d\n", __get_axi_clk());
+ printf("ahb: %d\n", __get_ahb_clk());
+ printf("emi slow: %d\n", __get_emi_slow_clk());
+ printf("nfc: %d\n", __get_nfc_clk());
+ printf("ddr: %d\n", __get_ddr_clk());
+ printf("usdhc1: %d\n", __get_usdhc1_clk());
+ printf("usdhc2: %d\n", __get_usdhc2_clk());
+ printf("usdhc3: %d\n", __get_usdhc3_clk());
+ printf("usdhc4: %d\n", __get_usdhc4_clk());
+}
+
+void imx6_ipu_clk_enable(int di)
+{
+ u32 reg;
+
+ if (di == 1) {
+ reg = readl(MXC_CCM_CCGR3);
+ reg |= 0xC033;
+ writel(reg, MXC_CCM_CCGR3);
+ } else {
+ reg = readl(MXC_CCM_CCGR3);
+ reg |= 0x300F;
+ writel(reg, MXC_CCM_CCGR3);
+ }
+
+ reg = readl(MX6_ANATOP_BASE_ADDR + 0xF0);
+ reg &= ~0x00003F00;
+ reg |= 0x00001300;
+ writel(reg, MX6_ANATOP_BASE_ADDR + 0xF4);
+
+ reg = readl(MXC_CCM_CS2CDR);
+ reg &= ~0x00007E00;
+ reg |= 0x00001200;
+ writel(reg, MXC_CCM_CS2CDR);
+
+ reg = readl(MXC_CCM_CSCMR2);
+ reg |= 0x00000C00;
+ writel(reg, MXC_CCM_CSCMR2);
+
+ reg = 0x0002A953;
+ writel(reg, MXC_CCM_CHSCDR);
+}