123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273 |
- /*
- * clock.c
- *
- * clocks for AM33XX based boards
- *
- * Copyright (C) 2011, Texas Instruments, Incorporated - http://www.ti.com/
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE. See the
- * GNU General Public License for more details.
- */
- #include <common.h>
- #include <asm/arch/cpu.h>
- #include <asm/arch/clock.h>
- #include <asm/arch/hardware.h>
- #include <asm/io.h>
- #define PRCM_MOD_EN 0x2
- #define PRCM_FORCE_WAKEUP 0x2
- #define PRCM_EMIF_CLK_ACTIVITY BIT(2)
- #define PRCM_L3_GCLK_ACTIVITY BIT(4)
- #define PLL_BYPASS_MODE 0x4
- #define ST_MN_BYPASS 0x00000100
- #define ST_DPLL_CLK 0x00000001
- #define CLK_SEL_MASK 0x7ffff
- #define CLK_DIV_MASK 0x1f
- #define CLK_DIV2_MASK 0x7f
- #define CLK_SEL_SHIFT 0x8
- #define CLK_MODE_SEL 0x7
- #define CLK_MODE_MASK 0xfffffff8
- #define CLK_DIV_SEL 0xFFFFFFE0
- const struct cm_perpll *cmper = (struct cm_perpll *)CM_PER;
- const struct cm_wkuppll *cmwkup = (struct cm_wkuppll *)CM_WKUP;
- const struct cm_dpll *cmdpll = (struct cm_dpll *)CM_DPLL;
- static void enable_interface_clocks(void)
- {
- /* Enable all the Interconnect Modules */
- writel(PRCM_MOD_EN, &cmper->l3clkctrl);
- while (readl(&cmper->l3clkctrl) != PRCM_MOD_EN)
- ;
- writel(PRCM_MOD_EN, &cmper->l4lsclkctrl);
- while (readl(&cmper->l4lsclkctrl) != PRCM_MOD_EN)
- ;
- writel(PRCM_MOD_EN, &cmper->l4fwclkctrl);
- while (readl(&cmper->l4fwclkctrl) != PRCM_MOD_EN)
- ;
- writel(PRCM_MOD_EN, &cmwkup->wkl4wkclkctrl);
- while (readl(&cmwkup->wkl4wkclkctrl) != PRCM_MOD_EN)
- ;
- writel(PRCM_MOD_EN, &cmper->l3instrclkctrl);
- while (readl(&cmper->l3instrclkctrl) != PRCM_MOD_EN)
- ;
- writel(PRCM_MOD_EN, &cmper->l4hsclkctrl);
- while (readl(&cmper->l4hsclkctrl) != PRCM_MOD_EN)
- ;
- }
- /*
- * Force power domain wake up transition
- * Ensure that the corresponding interface clock is active before
- * using the peripheral
- */
- static void power_domain_wkup_transition(void)
- {
- writel(PRCM_FORCE_WAKEUP, &cmper->l3clkstctrl);
- writel(PRCM_FORCE_WAKEUP, &cmper->l4lsclkstctrl);
- writel(PRCM_FORCE_WAKEUP, &cmwkup->wkclkstctrl);
- writel(PRCM_FORCE_WAKEUP, &cmper->l4fwclkstctrl);
- writel(PRCM_FORCE_WAKEUP, &cmper->l3sclkstctrl);
- }
- /*
- * Enable the peripheral clock for required peripherals
- */
- static void enable_per_clocks(void)
- {
- /* Enable the control module though RBL would have done it*/
- writel(PRCM_MOD_EN, &cmwkup->wkctrlclkctrl);
- while (readl(&cmwkup->wkctrlclkctrl) != PRCM_MOD_EN)
- ;
- /* Enable the module clock */
- writel(PRCM_MOD_EN, &cmper->timer2clkctrl);
- while (readl(&cmper->timer2clkctrl) != PRCM_MOD_EN)
- ;
- /* UART0 */
- writel(PRCM_MOD_EN, &cmwkup->wkup_uart0ctrl);
- while (readl(&cmwkup->wkup_uart0ctrl) != PRCM_MOD_EN)
- ;
- }
- static void mpu_pll_config(void)
- {
- u32 clkmode, clksel, div_m2;
- clkmode = readl(&cmwkup->clkmoddpllmpu);
- clksel = readl(&cmwkup->clkseldpllmpu);
- div_m2 = readl(&cmwkup->divm2dpllmpu);
- /* Set the PLL to bypass Mode */
- writel(PLL_BYPASS_MODE, &cmwkup->clkmoddpllmpu);
- while (readl(&cmwkup->idlestdpllmpu) != ST_MN_BYPASS)
- ;
- clksel = clksel & (~CLK_SEL_MASK);
- clksel = clksel | ((MPUPLL_M << CLK_SEL_SHIFT) | MPUPLL_N);
- writel(clksel, &cmwkup->clkseldpllmpu);
- div_m2 = div_m2 & ~CLK_DIV_MASK;
- div_m2 = div_m2 | MPUPLL_M2;
- writel(div_m2, &cmwkup->divm2dpllmpu);
- clkmode = clkmode | CLK_MODE_SEL;
- writel(clkmode, &cmwkup->clkmoddpllmpu);
- while (readl(&cmwkup->idlestdpllmpu) != ST_DPLL_CLK)
- ;
- }
- static void core_pll_config(void)
- {
- u32 clkmode, clksel, div_m4, div_m5, div_m6;
- clkmode = readl(&cmwkup->clkmoddpllcore);
- clksel = readl(&cmwkup->clkseldpllcore);
- div_m4 = readl(&cmwkup->divm4dpllcore);
- div_m5 = readl(&cmwkup->divm5dpllcore);
- div_m6 = readl(&cmwkup->divm6dpllcore);
- /* Set the PLL to bypass Mode */
- writel(PLL_BYPASS_MODE, &cmwkup->clkmoddpllcore);
- while (readl(&cmwkup->idlestdpllcore) != ST_MN_BYPASS)
- ;
- clksel = clksel & (~CLK_SEL_MASK);
- clksel = clksel | ((COREPLL_M << CLK_SEL_SHIFT) | COREPLL_N);
- writel(clksel, &cmwkup->clkseldpllcore);
- div_m4 = div_m4 & ~CLK_DIV_MASK;
- div_m4 = div_m4 | COREPLL_M4;
- writel(div_m4, &cmwkup->divm4dpllcore);
- div_m5 = div_m5 & ~CLK_DIV_MASK;
- div_m5 = div_m5 | COREPLL_M5;
- writel(div_m5, &cmwkup->divm5dpllcore);
- div_m6 = div_m6 & ~CLK_DIV_MASK;
- div_m6 = div_m6 | COREPLL_M6;
- writel(div_m6, &cmwkup->divm6dpllcore);
- clkmode = clkmode | CLK_MODE_SEL;
- writel(clkmode, &cmwkup->clkmoddpllcore);
- while (readl(&cmwkup->idlestdpllcore) != ST_DPLL_CLK)
- ;
- }
- static void per_pll_config(void)
- {
- u32 clkmode, clksel, div_m2;
- clkmode = readl(&cmwkup->clkmoddpllper);
- clksel = readl(&cmwkup->clkseldpllper);
- div_m2 = readl(&cmwkup->divm2dpllper);
- /* Set the PLL to bypass Mode */
- writel(PLL_BYPASS_MODE, &cmwkup->clkmoddpllper);
- while (readl(&cmwkup->idlestdpllper) != ST_MN_BYPASS)
- ;
- clksel = clksel & (~CLK_SEL_MASK);
- clksel = clksel | ((PERPLL_M << CLK_SEL_SHIFT) | PERPLL_N);
- writel(clksel, &cmwkup->clkseldpllper);
- div_m2 = div_m2 & ~CLK_DIV2_MASK;
- div_m2 = div_m2 | PERPLL_M2;
- writel(div_m2, &cmwkup->divm2dpllper);
- clkmode = clkmode | CLK_MODE_SEL;
- writel(clkmode, &cmwkup->clkmoddpllper);
- while (readl(&cmwkup->idlestdpllper) != ST_DPLL_CLK)
- ;
- }
- static void ddr_pll_config(void)
- {
- u32 clkmode, clksel, div_m2;
- clkmode = readl(&cmwkup->clkmoddpllddr);
- clksel = readl(&cmwkup->clkseldpllddr);
- div_m2 = readl(&cmwkup->divm2dpllddr);
- /* Set the PLL to bypass Mode */
- clkmode = (clkmode & CLK_MODE_MASK) | PLL_BYPASS_MODE;
- writel(clkmode, &cmwkup->clkmoddpllddr);
- /* Wait till bypass mode is enabled */
- while ((readl(&cmwkup->idlestdpllddr) & ST_MN_BYPASS)
- != ST_MN_BYPASS)
- ;
- clksel = clksel & (~CLK_SEL_MASK);
- clksel = clksel | ((DDRPLL_M << CLK_SEL_SHIFT) | DDRPLL_N);
- writel(clksel, &cmwkup->clkseldpllddr);
- div_m2 = div_m2 & CLK_DIV_SEL;
- div_m2 = div_m2 | DDRPLL_M2;
- writel(div_m2, &cmwkup->divm2dpllddr);
- clkmode = (clkmode & CLK_MODE_MASK) | CLK_MODE_SEL;
- writel(clkmode, &cmwkup->clkmoddpllddr);
- /* Wait till dpll is locked */
- while ((readl(&cmwkup->idlestdpllddr) & ST_DPLL_CLK) != ST_DPLL_CLK)
- ;
- }
- void enable_emif_clocks(void)
- {
- /* Enable the EMIF_FW Functional clock */
- writel(PRCM_MOD_EN, &cmper->emiffwclkctrl);
- /* Enable EMIF0 Clock */
- writel(PRCM_MOD_EN, &cmper->emifclkctrl);
- /* Poll for emif_gclk & L3_G clock are active */
- while ((readl(&cmper->l3clkstctrl) & (PRCM_EMIF_CLK_ACTIVITY |
- PRCM_L3_GCLK_ACTIVITY)) != (PRCM_EMIF_CLK_ACTIVITY |
- PRCM_L3_GCLK_ACTIVITY))
- ;
- /* Poll if module is functional */
- while ((readl(&cmper->emifclkctrl)) != PRCM_MOD_EN)
- ;
- }
- /*
- * Configure the PLL/PRCM for necessary peripherals
- */
- void pll_init()
- {
- mpu_pll_config();
- core_pll_config();
- per_pll_config();
- ddr_pll_config();
- /* Enable the required interconnect clocks */
- enable_interface_clocks();
- /* Power domain wake up transition */
- power_domain_wkup_transition();
- /* Enable the required peripherals */
- enable_per_clocks();
- }
|