From f87fa62af9abd5f8196596d3ea4347999ec40e1e Mon Sep 17 00:00:00 2001 From: Chandan Nath Date: Fri, 14 Oct 2011 02:58:23 +0000 Subject: [PATCH] ARM:AM33XX: Add clock definitions This patch adds basic clock definition of am33xx SoC. Signed-off-by: Chandan Nath Signed-off-by: Sandeep Paulraj --- arch/arm/cpu/armv7/am33xx/Makefile | 1 + arch/arm/cpu/armv7/am33xx/clock.c | 273 +++++++++++++++++++++++ arch/arm/include/asm/arch-am33xx/clock.h | 24 ++ arch/arm/include/asm/arch-am33xx/clocks_am33xx.h | 55 +++++ 4 files changed, 353 insertions(+) create mode 100644 arch/arm/cpu/armv7/am33xx/clock.c create mode 100644 arch/arm/include/asm/arch-am33xx/clock.h create mode 100644 arch/arm/include/asm/arch-am33xx/clocks_am33xx.h diff --git a/arch/arm/cpu/armv7/am33xx/Makefile b/arch/arm/cpu/armv7/am33xx/Makefile index 498df78..fc25587 100644 --- a/arch/arm/cpu/armv7/am33xx/Makefile +++ b/arch/arm/cpu/armv7/am33xx/Makefile @@ -18,6 +18,7 @@ LIB = $(obj)lib$(SOC).o SOBJS := lowlevel_init.o +COBJS += clock.o COBJS += sys_info.o SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) diff --git a/arch/arm/cpu/armv7/am33xx/clock.c b/arch/arm/cpu/armv7/am33xx/clock.c new file mode 100644 index 0000000..4ca6c45 --- /dev/null +++ b/arch/arm/cpu/armv7/am33xx/clock.c @@ -0,0 +1,273 @@ +/* + * 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 +#include +#include +#include +#include + +#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(); +} diff --git a/arch/arm/include/asm/arch-am33xx/clock.h b/arch/arm/include/asm/arch-am33xx/clock.h new file mode 100644 index 0000000..872ff82 --- /dev/null +++ b/arch/arm/include/asm/arch-am33xx/clock.h @@ -0,0 +1,24 @@ +/* + * clock.h + * + * clock header + * + * 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. + */ + +#ifndef _CLOCKS_H_ +#define _CLOCKS_H_ + +#include + +#endif diff --git a/arch/arm/include/asm/arch-am33xx/clocks_am33xx.h b/arch/arm/include/asm/arch-am33xx/clocks_am33xx.h new file mode 100644 index 0000000..abc5b6b --- /dev/null +++ b/arch/arm/include/asm/arch-am33xx/clocks_am33xx.h @@ -0,0 +1,55 @@ +/* + * clocks_am33xx.h + * + * AM33xx clock define + * + * 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. + */ + +#ifndef _CLOCKS_AM33XX_H_ +#define _CLOCKS_AM33XX_H_ + +#define OSC 24 + +/* MAIN PLL Fdll = 550 MHZ, */ +#define MPUPLL_M 550 +#define MPUPLL_N 23 +#define MPUPLL_M2 1 + +/* Core PLL Fdll = 1 GHZ, */ +#define COREPLL_M 1000 +#define COREPLL_N 23 + +#define COREPLL_M4 10 /* CORE_CLKOUTM4 = 200 MHZ */ +#define COREPLL_M5 8 /* CORE_CLKOUTM5 = 250 MHZ */ +#define COREPLL_M6 4 /* CORE_CLKOUTM6 = 500 MHZ */ + +/* + * USB PHY clock is 960 MHZ. Since, this comes directly from Fdll, Fdll + * frequency needs to be set to 960 MHZ. Hence, + * For clkout = 192 MHZ, Fdll = 960 MHZ, divider values are given below + */ +#define PERPLL_M 960 +#define PERPLL_N 23 +#define PERPLL_M2 5 + +/* DDR Freq is 266 MHZ for now */ +/* Set Fdll = 400 MHZ , Fdll = M * 2 * CLKINP/ N + 1; clkout = Fdll /(2 * M2) */ +#define DDRPLL_M 266 +#define DDRPLL_N 23 +#define DDRPLL_M2 1 + +extern void pll_init(void); +extern void enable_emif_clocks(void); + +#endif /* endif _CLOCKS_AM33XX_H_ */ -- 2.7.4