#include #include #include #include #include #include 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(); } u32 imx_get_i2cclk(void) { return __get_ipg_per_clk(); } u32 imx_get_cspiclk(void) { return __get_cspi_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("i2c: %d\n", __get_ipg_per_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); }