X-Git-Url: https://git.kernelconcepts.de/?p=karo-tx-uboot.git;a=blobdiff_plain;f=arch%2Farm%2Fcpu%2Farmv7%2Fmx6%2Fclock.c;h=dfd5e08a0276e3dbf7f225926dd37cc889889d02;hp=8a494b48e87c55ed57869d2ef839bf05c58c6f98;hb=8f02caac64980faa73b2bf00462b400c86257d04;hpb=5c7e86ebb3514bdac7ac9ae7c0885879f43b9e95 diff --git a/arch/arm/cpu/armv7/mx6/clock.c b/arch/arm/cpu/armv7/mx6/clock.c index 8a494b48e8..dfd5e08a02 100644 --- a/arch/arm/cpu/armv7/mx6/clock.c +++ b/arch/arm/cpu/armv7/mx6/clock.c @@ -5,6 +5,7 @@ */ #include +#include #include #include #include @@ -14,7 +15,7 @@ enum pll_clocks { PLL_ARM, /* PLL1: ARM PLL */ - PLL_BUS, /* PLL2: System Bus PLL*/ + PLL_528, /* PLL2: System Bus PLL*/ PLL_USBOTG, /* PLL3: OTG USB PLL */ PLL_AUDIO, /* PLL4: Audio PLL */ PLL_VIDEO, /* PLL5: Video PLL */ @@ -33,7 +34,7 @@ int clk_enable(struct clk *clk) if (!clk) return 0; if (clk->usecount == 0) { -debug("%s: Enabling %s clock\n", __func__, clk->name); + debug("%s: Enabling %s clock\n", __func__, clk->name); ret = clk->enable(clk); if (ret) return ret; @@ -51,7 +52,7 @@ void clk_disable(struct clk *clk) assert(clk->usecount > 0); if (!(--clk->usecount)) { if (clk->disable) { -debug("%s: Disabling %s clock\n", __func__, clk->name); + debug("%s: Disabling %s clock\n", __func__, clk->name); clk->disable(clk); } } @@ -129,6 +130,35 @@ void enable_ocotp_clk(unsigned char enable) } #endif +#ifdef CONFIG_NAND_MXS +void setup_gpmi_io_clk(u32 cfg) +{ + /* Disable clocks per ERR007177 from MX6 errata */ + clrbits_le32(&imx_ccm->CCGR4, + MXC_CCM_CCGR4_RAWNAND_U_BCH_INPUT_APB_MASK | + MXC_CCM_CCGR4_RAWNAND_U_GPMI_BCH_INPUT_BCH_MASK | + MXC_CCM_CCGR4_RAWNAND_U_GPMI_BCH_INPUT_GPMI_IO_MASK | + MXC_CCM_CCGR4_RAWNAND_U_GPMI_INPUT_APB_MASK | + MXC_CCM_CCGR4_PL301_MX6QPER1_BCH_MASK); + + clrbits_le32(&imx_ccm->CCGR2, MXC_CCM_CCGR2_IOMUX_IPT_CLK_IO_MASK); + + clrsetbits_le32(&imx_ccm->cs2cdr, + MXC_CCM_CS2CDR_ENFC_CLK_PODF_MASK | + MXC_CCM_CS2CDR_ENFC_CLK_PRED_MASK | + MXC_CCM_CS2CDR_ENFC_CLK_SEL_MASK, + cfg); + + setbits_le32(&imx_ccm->CCGR2, MXC_CCM_CCGR2_IOMUX_IPT_CLK_IO_MASK); + setbits_le32(&imx_ccm->CCGR4, + MXC_CCM_CCGR4_RAWNAND_U_BCH_INPUT_APB_MASK | + MXC_CCM_CCGR4_RAWNAND_U_GPMI_BCH_INPUT_BCH_MASK | + MXC_CCM_CCGR4_RAWNAND_U_GPMI_BCH_INPUT_GPMI_IO_MASK | + MXC_CCM_CCGR4_RAWNAND_U_GPMI_INPUT_APB_MASK | + MXC_CCM_CCGR4_PL301_MX6QPER1_BCH_MASK); +} +#endif + void enable_usboh3_clk(unsigned char enable) { u32 reg; @@ -142,7 +172,68 @@ void enable_usboh3_clk(unsigned char enable) } -#ifdef CONFIG_I2C_MXC +#if defined(CONFIG_FEC_MXC) && !defined(CONFIG_MX6SX) +void enable_enet_clk(unsigned char enable) +{ + u32 mask = MXC_CCM_CCGR1_ENET_CLK_ENABLE_MASK; + + if (enable) + setbits_le32(&imx_ccm->CCGR1, mask); + else + clrbits_le32(&imx_ccm->CCGR1, mask); +} +#endif + +#ifdef CONFIG_MXC_UART +void enable_uart_clk(unsigned char enable) +{ + u32 mask = MXC_CCM_CCGR5_UART_MASK | MXC_CCM_CCGR5_UART_SERIAL_MASK; + + if (enable) + setbits_le32(&imx_ccm->CCGR5, mask); + else + clrbits_le32(&imx_ccm->CCGR5, mask); +} +#endif + +#ifdef CONFIG_SPI +/* spi_num can be from 0 - 4 */ +int enable_cspi_clock(unsigned char enable, unsigned spi_num) +{ + u32 mask; + + if (spi_num > 4) + return -EINVAL; + + mask = MXC_CCM_CCGR_CG_MASK << (spi_num * 2); + if (enable) + setbits_le32(&imx_ccm->CCGR1, mask); + else + clrbits_le32(&imx_ccm->CCGR1, mask); + + return 0; +} +#endif + +#ifdef CONFIG_MMC +int enable_usdhc_clk(unsigned char enable, unsigned bus_num) +{ + u32 mask; + + if (bus_num > 3) + return -EINVAL; + + mask = MXC_CCM_CCGR_CG_MASK << (bus_num * 2 + 2); + if (enable) + setbits_le32(&imx_ccm->CCGR6, mask); + else + clrbits_le32(&imx_ccm->CCGR6, mask); + + return 0; +} +#endif + +#ifdef CONFIG_SYS_I2C_MXC /* i2c_num can be from 0 - 2 */ int enable_i2c_clk(unsigned char enable, unsigned i2c_num) { @@ -164,6 +255,24 @@ int enable_i2c_clk(unsigned char enable, unsigned i2c_num) } #endif +/* spi_num can be from 0 - SPI_MAX_NUM */ +int enable_spi_clk(unsigned char enable, unsigned spi_num) +{ + u32 reg; + u32 mask; + + if (spi_num > SPI_MAX_NUM) + return -EINVAL; + + mask = MXC_CCM_CCGR_CG_MASK << (spi_num << 1); + reg = __raw_readl(&imx_ccm->CCGR1); + if (enable) + reg |= mask; + else + reg &= ~mask; + __raw_writel(reg, &imx_ccm->CCGR1); + return 0; +} static u32 decode_pll(enum pll_clocks pll, u32 infreq) { u32 div; @@ -177,18 +286,18 @@ static u32 decode_pll(enum pll_clocks pll, u32 infreq) div &= BM_ANADIG_PLL_ARM_DIV_SELECT; return infreq * div / 2; - case PLL_BUS: + case PLL_528: div = __raw_readl(&anatop->pll_528); - if (div & BM_ANADIG_PLL_SYS_BYPASS) + if (div & BM_ANADIG_PLL_528_BYPASS) return infreq; - div &= BM_ANADIG_PLL_SYS_DIV_SELECT; + div &= BM_ANADIG_PLL_528_DIV_SELECT; return infreq * (20 + div * 2); case PLL_USBOTG: div = __raw_readl(&anatop->usb1_pll_480_ctrl); - if (div & BM_ANADIG_USB1_PLL_480_CTRL_BYPASS) + if (div & BM_ANADIG_USB_PLL_480_CTRL_BYPASS) return infreq; - div &= BM_ANADIG_USB1_PLL_480_CTRL_DIV_SELECT; + div &= BM_ANADIG_USB_PLL_480_CTRL_DIV_SELECT; return infreq * (20 + div * 2); case PLL_AUDIO: @@ -211,12 +320,12 @@ static u32 decode_pll(enum pll_clocks pll, u32 infreq) return infreq; div &= BM_ANADIG_PLL_ENET_DIV_SELECT; - return (div == 3 ? 125000000 : 25000000 * div * 2); + return 25000000 * (div + (div >> 1) + 1); case PLL_USB2: div = __raw_readl(&anatop->usb2_pll_480_ctrl); - if (div & BM_ANADIG_USB2_PLL_480_CTRL_BYPASS) + if (div & BM_ANADIG_USB_PLL_480_CTRL_BYPASS) return infreq; - div &= BM_ANADIG_USB2_PLL_480_CTRL_DIV_SELECT; + div &= BM_ANADIG_USB_PLL_480_CTRL_DIV_SELECT; return infreq * (20 + div * 2); case PLL_MLB: @@ -228,6 +337,33 @@ static u32 decode_pll(enum pll_clocks pll, u32 infreq) } return 0; } +static u32 mxc_get_pll_pfd(enum pll_clocks pll, int pfd_num) +{ + u32 div; + u64 freq; + struct anatop_regs *anatop = (struct anatop_regs *)ANATOP_BASE_ADDR; + + switch (pll) { + case PLL_528: + if (pfd_num == 3) { + /* No PFD3 on PLL2 */ + return 0; + } + div = __raw_readl(&anatop->pfd_528); + freq = (u64)decode_pll(PLL_528, MXC_HCLK); + break; + case PLL_USBOTG: + div = __raw_readl(&anatop->pfd_480); + freq = (u64)decode_pll(PLL_USBOTG, MXC_HCLK); + break; + default: + /* No PFD on other PLL */ + return 0; + } + + return lldiv(freq * 18, (div & ANATOP_PFD_FRAC_MASK(pfd_num)) >> + ANATOP_PFD_FRAC_SHIFT(pfd_num)); +} static u32 get_mcu_main_clk(void) { @@ -267,16 +403,17 @@ u32 get_periph_clk(void) switch (reg) { case 0: - freq = decode_pll(PLL_BUS, MXC_HCLK); + freq = decode_pll(PLL_528, MXC_HCLK); break; case 1: - freq = PLL2_PFD2_FREQ; + freq = mxc_get_pll_pfd(PLL_528, 2); break; case 2: - freq = PLL2_PFD0_FREQ; + freq = mxc_get_pll_pfd(PLL_528, 0); break; case 3: - freq = PLL2_PFD2_DIV_FREQ; + /* static / 2 divider */ + freq = mxc_get_pll_pfd(PLL_528, 2) / 2; break; } } @@ -300,6 +437,10 @@ static u32 get_ipg_per_clk(void) u32 reg, perclk_podf; reg = __raw_readl(&imx_ccm->cscmr1); +#if (defined(CONFIG_MX6SL) || defined(CONFIG_MX6SX)) + if (reg & MXC_CCM_CSCMR1_PER_CLK_SEL_MASK) + return MXC_HCLK; /* OSC 24Mhz */ +#endif perclk_podf = reg & MXC_CCM_CSCMR1_PERCLK_PODF_MASK; return get_ipg_clk() / (perclk_podf + 1); @@ -308,9 +449,9 @@ static u32 get_ipg_per_clk(void) static u32 get_uart_clk(void) { u32 reg, uart_podf; - u32 freq = PLL3_80M; + u32 freq = decode_pll(PLL_USBOTG, MXC_HCLK) / 6; /* static divider */ reg = __raw_readl(&imx_ccm->cscdr1); -#ifdef CONFIG_MX6SL +#if (defined(CONFIG_MX6SL) || defined(CONFIG_MX6SX)) if (reg & MXC_CCM_CSCDR1_UART_CLK_SEL) freq = MXC_HCLK; #endif @@ -328,7 +469,7 @@ static u32 get_cspi_clk(void) reg &= MXC_CCM_CSCDR2_ECSPI_CLK_PODF_MASK; cspi_podf = reg >> MXC_CCM_CSCDR2_ECSPI_CLK_PODF_OFFSET; - return PLL3_60M / (cspi_podf + 1); + return decode_pll(PLL_USBOTG, MXC_HCLK) / (8 * (cspi_podf + 1)); } static u32 get_axi_clk(void) @@ -341,9 +482,9 @@ static u32 get_axi_clk(void) if (cbcdr & MXC_CCM_CBCDR_AXI_SEL) { if (cbcdr & MXC_CCM_CBCDR_AXI_ALT_SEL) - root_freq = PLL2_PFD2_FREQ; + root_freq = mxc_get_pll_pfd(PLL_528, 2); else - root_freq = PLL3_PFD1_FREQ; + root_freq = mxc_get_pll_pfd(PLL_USBOTG, 1); } else root_freq = get_periph_clk(); @@ -352,13 +493,13 @@ static u32 get_axi_clk(void) static u32 get_emi_slow_clk(void) { - u32 emi_clk_sel, emi_slow_pof, cscmr1, root_freq = 0; + u32 emi_clk_sel, emi_slow_podf, cscmr1, root_freq = 0; cscmr1 = __raw_readl(&imx_ccm->cscmr1); emi_clk_sel = cscmr1 & MXC_CCM_CSCMR1_ACLK_EMI_SLOW_MASK; emi_clk_sel >>= MXC_CCM_CSCMR1_ACLK_EMI_SLOW_OFFSET; - emi_slow_pof = cscmr1 & MXC_CCM_CSCMR1_ACLK_EMI_SLOW_PODF_MASK; - emi_slow_pof >>= MXC_CCM_CSCMR1_ACLK_EMI_PODF_OFFSET; + emi_slow_podf = cscmr1 & MXC_CCM_CSCMR1_ACLK_EMI_SLOW_PODF_MASK; + emi_slow_podf >>= MXC_CCM_CSCMR1_ACLK_EMI_SLOW_PODF_OFFSET; switch (emi_clk_sel) { case 0: @@ -368,14 +509,14 @@ static u32 get_emi_slow_clk(void) root_freq = decode_pll(PLL_USBOTG, MXC_HCLK); break; case 2: - root_freq = PLL2_PFD2_FREQ; + root_freq = mxc_get_pll_pfd(PLL_528, 2); break; case 3: - root_freq = PLL2_PFD0_FREQ; + root_freq = mxc_get_pll_pfd(PLL_528, 0); break; } - return root_freq / (emi_slow_pof + 1); + return root_freq / (emi_slow_podf + 1); } static u32 get_nfc_clk(void) @@ -389,16 +530,16 @@ static u32 get_nfc_clk(void) switch (nfc_clk_sel) { case 0: - root_freq = PLL2_PFD0_FREQ; + root_freq = mxc_get_pll_pfd(PLL_528, 0); break; case 1: - root_freq = decode_pll(PLL_BUS, MXC_HCLK); + root_freq = decode_pll(PLL_528, MXC_HCLK); break; case 2: root_freq = decode_pll(PLL_USBOTG, MXC_HCLK); break; case 3: - root_freq = PLL2_PFD2_FREQ; + root_freq = mxc_get_pll_pfd(PLL_528, 2); break; } @@ -429,23 +570,23 @@ static int set_nfc_clk(u32 ref, u32 freq_khz) switch (nfc_clk_sel) { case 0: - root_freq = PLL2_PFD0_FREQ; + root_freq = mxc_get_pll_pfd(PLL_528, 0); break; case 1: - root_freq = decode_pll(PLL_BUS, MXC_HCLK); + root_freq = decode_pll(PLL_528, MXC_HCLK); break; case 2: root_freq = decode_pll(PLL_USBOTG, MXC_HCLK); break; case 3: - root_freq = PLL2_PFD2_FREQ; + root_freq = mxc_get_pll_pfd(PLL_528, 2); break; } if (root_freq < freq) continue; - podf = min(DIV_ROUND_UP(root_freq, freq), 1 << 6); - pred = min(DIV_ROUND_UP(root_freq / podf, freq), 8); + podf = min(DIV_ROUND_UP(root_freq, freq), 1U << 6); + pred = min(DIV_ROUND_UP(root_freq / podf, freq), 8U); act_freq = root_freq / pred / podf; err = (freq - act_freq) * 100 / freq; debug("root=%d[%u] freq=%u pred=%u podf=%u act=%u err=%d\n", @@ -476,7 +617,7 @@ static int set_nfc_clk(u32 ref, u32 freq_khz) return 0; } -#ifdef CONFIG_MX6SL +#if (defined(CONFIG_MX6SL) || defined(CONFIG_MX6SX)) static u32 get_mmdc_ch0_clk(void) { u32 cbcmr = __raw_readl(&imx_ccm->cbcmr); @@ -489,16 +630,17 @@ static u32 get_mmdc_ch0_clk(void) switch ((cbcmr & MXC_CCM_CBCMR_PRE_PERIPH2_CLK_SEL_MASK) >> MXC_CCM_CBCMR_PRE_PERIPH2_CLK_SEL_OFFSET) { case 0: - freq = decode_pll(PLL_BUS, MXC_HCLK); + freq = decode_pll(PLL_528, MXC_HCLK); break; case 1: - freq = PLL2_PFD2_FREQ; + freq = mxc_get_pll_pfd(PLL_528, 2); break; case 2: - freq = PLL2_PFD0_FREQ; + freq = mxc_get_pll_pfd(PLL_528, 0); break; case 3: - freq = PLL2_PFD2_DIV_FREQ; + /* static / 2 divider */ + freq = mxc_get_pll_pfd(PLL_528, 2) / 2; } return freq / (podf + 1); @@ -515,6 +657,114 @@ static u32 get_mmdc_ch0_clk(void) } #endif +#ifdef CONFIG_MX6SX +/* qspi_num can be from 0 - 1 */ +void enable_qspi_clk(int qspi_num) +{ + u32 reg = 0; + /* Enable QuadSPI clock */ + switch (qspi_num) { + case 0: + /* disable the clock gate */ + clrbits_le32(&imx_ccm->CCGR3, MXC_CCM_CCGR3_QSPI1_MASK); + + /* set 50M : (50 = 396 / 2 / 4) */ + reg = readl(&imx_ccm->cscmr1); + reg &= ~(MXC_CCM_CSCMR1_QSPI1_PODF_MASK | + MXC_CCM_CSCMR1_QSPI1_CLK_SEL_MASK); + reg |= ((1 << MXC_CCM_CSCMR1_QSPI1_PODF_OFFSET) | + (2 << MXC_CCM_CSCMR1_QSPI1_CLK_SEL_OFFSET)); + writel(reg, &imx_ccm->cscmr1); + + /* enable the clock gate */ + setbits_le32(&imx_ccm->CCGR3, MXC_CCM_CCGR3_QSPI1_MASK); + break; + case 1: + /* + * disable the clock gate + * QSPI2 and GPMI_BCH_INPUT_GPMI_IO share the same clock gate, + * disable both of them. + */ + clrbits_le32(&imx_ccm->CCGR4, MXC_CCM_CCGR4_QSPI2_ENFC_MASK | + MXC_CCM_CCGR4_RAWNAND_U_GPMI_BCH_INPUT_GPMI_IO_MASK); + + /* set 50M : (50 = 396 / 2 / 4) */ + reg = readl(&imx_ccm->cs2cdr); + reg &= ~(MXC_CCM_CS2CDR_QSPI2_CLK_PODF_MASK | + MXC_CCM_CS2CDR_QSPI2_CLK_PRED_MASK | + MXC_CCM_CS2CDR_QSPI2_CLK_SEL_MASK); + reg |= (MXC_CCM_CS2CDR_QSPI2_CLK_PRED(0x1) | + MXC_CCM_CS2CDR_QSPI2_CLK_SEL(0x3)); + writel(reg, &imx_ccm->cs2cdr); + + /*enable the clock gate*/ + setbits_le32(&imx_ccm->CCGR4, MXC_CCM_CCGR4_QSPI2_ENFC_MASK | + MXC_CCM_CCGR4_RAWNAND_U_GPMI_BCH_INPUT_GPMI_IO_MASK); + break; + default: + break; + } +} +#endif + +#ifdef CONFIG_FEC_MXC +int enable_fec_anatop_clock(enum enet_freq freq) +{ + u32 reg = 0; + s32 timeout = 100000; + + struct anatop_regs __iomem *anatop = + (struct anatop_regs __iomem *)ANATOP_BASE_ADDR; + + if (freq < ENET_25MHZ || freq > ENET_125MHZ) + return -EINVAL; + + reg = readl(&anatop->pll_enet); + reg &= ~BM_ANADIG_PLL_ENET_DIV_SELECT; + reg |= freq; + + if ((reg & BM_ANADIG_PLL_ENET_POWERDOWN) || + (!(reg & BM_ANADIG_PLL_ENET_LOCK))) { + reg &= ~BM_ANADIG_PLL_ENET_POWERDOWN; + writel(reg, &anatop->pll_enet); + while (timeout--) { + if (readl(&anatop->pll_enet) & BM_ANADIG_PLL_ENET_LOCK) + break; + } + if (timeout < 0) + return -ETIMEDOUT; + } + + /* Enable FEC clock */ + reg |= BM_ANADIG_PLL_ENET_ENABLE; + reg &= ~BM_ANADIG_PLL_ENET_BYPASS; + writel(reg, &anatop->pll_enet); + +#ifdef CONFIG_MX6SX + /* + * Set enet ahb clock to 200MHz + * pll2_pfd2_396m-> ENET_PODF-> ENET_AHB + */ + reg = readl(&imx_ccm->chsccdr); + reg &= ~(MXC_CCM_CHSCCDR_ENET_PRE_CLK_SEL_MASK + | MXC_CCM_CHSCCDR_ENET_PODF_MASK + | MXC_CCM_CHSCCDR_ENET_CLK_SEL_MASK); + /* PLL2 PFD2 */ + reg |= (4 << MXC_CCM_CHSCCDR_ENET_PRE_CLK_SEL_OFFSET); + /* Div = 2*/ + reg |= (1 << MXC_CCM_CHSCCDR_ENET_PODF_OFFSET); + reg |= (0 << MXC_CCM_CHSCCDR_ENET_CLK_SEL_OFFSET); + writel(reg, &imx_ccm->chsccdr); + + /* Enable enet system clock */ + reg = readl(&imx_ccm->CCGR3); + reg |= MXC_CCM_CCGR3_ENET_MASK; + writel(reg, &imx_ccm->CCGR3); +#endif + return 0; +} +#endif + static u32 get_usdhc_clk(u32 port) { u32 root_freq = 0, usdhc_podf = 0, clk_sel = 0; @@ -551,9 +801,9 @@ static u32 get_usdhc_clk(u32 port) } if (clk_sel) - root_freq = PLL2_PFD0_FREQ; + root_freq = mxc_get_pll_pfd(PLL_528, 0); else - root_freq = PLL2_PFD2_FREQ; + root_freq = mxc_get_pll_pfd(PLL_528, 2); return root_freq / (usdhc_podf + 1); } @@ -565,19 +815,14 @@ u32 imx_get_uartclk(void) u32 imx_get_fecclk(void) { - return decode_pll(PLL_ENET, MXC_HCLK); + return mxc_get_clock(MXC_IPG_CLK); } -int enable_sata_clock(void) +static int enable_enet_pll(uint32_t en) { u32 reg; s32 timeout = 100000; - /* Enable sata clock */ - reg = readl(&imx_ccm->CCGR5); /* CCGR5 */ - reg |= MXC_CCM_CCGR5_SATA_MASK; - writel(reg, &imx_ccm->CCGR5); - /* Enable PLLs */ reg = readl(&anatop->pll_enet); reg &= ~BM_ANADIG_PLL_ENET_POWERDOWN; @@ -591,10 +836,150 @@ int enable_sata_clock(void) return -EIO; reg &= ~BM_ANADIG_PLL_ENET_BYPASS; writel(reg, &anatop->pll_enet); - reg |= BM_ANADIG_PLL_ENET_ENABLE_SATA; + reg |= en; writel(reg, &anatop->pll_enet); + return 0; +} + +#ifndef CONFIG_MX6SX +static void ungate_sata_clock(void) +{ + struct mxc_ccm_reg *const imx_ccm = + (struct mxc_ccm_reg *)CCM_BASE_ADDR; - return 0 ; + /* Enable SATA clock. */ + setbits_le32(&imx_ccm->CCGR5, MXC_CCM_CCGR5_SATA_MASK); +} +#endif + +static void ungate_pcie_clock(void) +{ + struct mxc_ccm_reg *const imx_ccm = + (struct mxc_ccm_reg *)CCM_BASE_ADDR; + + /* Enable PCIe clock. */ + setbits_le32(&imx_ccm->CCGR4, MXC_CCM_CCGR4_PCIE_MASK); +} + +#ifndef CONFIG_MX6SX +int enable_sata_clock(void) +{ + ungate_sata_clock(); + return enable_enet_pll(BM_ANADIG_PLL_ENET_ENABLE_SATA); +} + +void disable_sata_clock(void) +{ + struct mxc_ccm_reg *const imx_ccm = + (struct mxc_ccm_reg *)CCM_BASE_ADDR; + + clrbits_le32(&imx_ccm->CCGR5, MXC_CCM_CCGR5_SATA_MASK); +} +#endif + +int enable_pcie_clock(void) +{ + struct anatop_regs *anatop_regs = + (struct anatop_regs *)ANATOP_BASE_ADDR; + struct mxc_ccm_reg *ccm_regs = (struct mxc_ccm_reg *)CCM_BASE_ADDR; + u32 lvds1_clk_sel; + + /* + * Here be dragons! + * + * The register ANATOP_MISC1 is not documented in the Freescale + * MX6RM. The register that is mapped in the ANATOP space and + * marked as ANATOP_MISC1 is actually documented in the PMU section + * of the datasheet as PMU_MISC1. + * + * Switch LVDS clock source to SATA (0xb) on mx6q/dl or PCI (0xa) on + * mx6sx, disable clock INPUT and enable clock OUTPUT. This is important + * for PCI express link that is clocked from the i.MX6. + */ +#define ANADIG_ANA_MISC1_LVDSCLK1_IBEN (1 << 12) +#define ANADIG_ANA_MISC1_LVDSCLK1_OBEN (1 << 10) +#define ANADIG_ANA_MISC1_LVDS1_CLK_SEL_MASK 0x0000001F +#define ANADIG_ANA_MISC1_LVDS1_CLK_SEL_PCIE_REF 0xa +#define ANADIG_ANA_MISC1_LVDS1_CLK_SEL_SATA_REF 0xb + + if (is_cpu_type(MXC_CPU_MX6SX)) + lvds1_clk_sel = ANADIG_ANA_MISC1_LVDS1_CLK_SEL_PCIE_REF; + else + lvds1_clk_sel = ANADIG_ANA_MISC1_LVDS1_CLK_SEL_SATA_REF; + + clrsetbits_le32(&anatop_regs->ana_misc1, + ANADIG_ANA_MISC1_LVDSCLK1_IBEN | + ANADIG_ANA_MISC1_LVDS1_CLK_SEL_MASK, + ANADIG_ANA_MISC1_LVDSCLK1_OBEN | lvds1_clk_sel); + + /* PCIe reference clock sourced from AXI. */ + clrbits_le32(&ccm_regs->cbcmr, MXC_CCM_CBCMR_PCIE_AXI_CLK_SEL); + + /* Party time! Ungate the clock to the PCIe. */ +#ifndef CONFIG_MX6SX + ungate_sata_clock(); +#endif + ungate_pcie_clock(); + + return enable_enet_pll(BM_ANADIG_PLL_ENET_ENABLE_SATA | + BM_ANADIG_PLL_ENET_ENABLE_PCIE); +} + +#ifdef CONFIG_SECURE_BOOT +void hab_caam_clock_enable(unsigned char enable) +{ + u32 reg; + + /* CG4 ~ CG6, CAAM clocks */ + reg = __raw_readl(&imx_ccm->CCGR0); + if (enable) + reg |= (MXC_CCM_CCGR0_CAAM_WRAPPER_IPG_MASK | + MXC_CCM_CCGR0_CAAM_WRAPPER_ACLK_MASK | + MXC_CCM_CCGR0_CAAM_SECURE_MEM_MASK); + else + reg &= ~(MXC_CCM_CCGR0_CAAM_WRAPPER_IPG_MASK | + MXC_CCM_CCGR0_CAAM_WRAPPER_ACLK_MASK | + MXC_CCM_CCGR0_CAAM_SECURE_MEM_MASK); + __raw_writel(reg, &imx_ccm->CCGR0); + + /* EMI slow clk */ + reg = __raw_readl(&imx_ccm->CCGR6); + if (enable) + reg |= MXC_CCM_CCGR6_EMI_SLOW_MASK; + else + reg &= ~MXC_CCM_CCGR6_EMI_SLOW_MASK; + __raw_writel(reg, &imx_ccm->CCGR6); +} +#endif + +static void enable_pll3(void) +{ + struct anatop_regs __iomem *anatop = + (struct anatop_regs __iomem *)ANATOP_BASE_ADDR; + + /* make sure pll3 is enabled */ + if ((readl(&anatop->usb1_pll_480_ctrl) & + BM_ANADIG_USB_PLL_480_CTRL_LOCK) == 0) { + /* enable pll's power */ + writel(BM_ANADIG_USB_PLL_480_CTRL_POWER, + &anatop->usb1_pll_480_ctrl_set); + writel(0x80, &anatop->ana_misc2_clr); + /* wait for pll lock */ + while ((readl(&anatop->usb1_pll_480_ctrl) & + BM_ANADIG_USB_PLL_480_CTRL_LOCK) == 0) + ; + /* disable bypass */ + writel(BM_ANADIG_USB_PLL_480_CTRL_BYPASS, + &anatop->usb1_pll_480_ctrl_clr); + /* enable pll output */ + writel(BM_ANADIG_USB_PLL_480_CTRL_ENABLE, + &anatop->usb1_pll_480_ctrl_set); + } +} + +void enable_thermal_clk(void) +{ + enable_pll3(); } void ipu_clk_enable(void) @@ -725,9 +1110,11 @@ unsigned int mxc_get_clock(enum mxc_clock clk) return get_ahb_clk(); case MXC_NFC_CLK: return get_nfc_clk(); + default: + printf("Unsupported MXC CLK: %d\n", clk); } - return -1; + return 0; } static inline int gcd(int m, int n) @@ -891,7 +1278,7 @@ int mxc_set_clock(u32 ref, u32 freq, enum mxc_clock clk) static void do_mx6_showclocks(void) { print_pll(PLL_ARM); - print_pll(PLL_BUS); + print_pll(PLL_528); print_pll(PLL_USBOTG); print_pll(PLL_AUDIO); print_pll(PLL_VIDEO); @@ -959,7 +1346,7 @@ int do_clocks(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) case MXC_ARM_CLK: if (argc > 3) return CMD_RET_USAGE; - ref = CONFIG_SYS_MX6_HCLK; + ref = MXC_HCLK; break; case MXC_NFC_CLK: @@ -992,6 +1379,16 @@ int do_clocks(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) return CMD_RET_FAILURE; } +#ifndef CONFIG_MX6SX +void enable_ipu_clock(void) +{ + struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR; + int reg; + reg = readl(&mxc_ccm->CCGR3); + reg |= MXC_CCM_CCGR3_IPU1_IPU_MASK; + writel(reg, &mxc_ccm->CCGR3); +} +#endif /***************************************************/ U_BOOT_CMD(