From c4b4500910b2dac1dd2e02fb498c059688fb606a Mon Sep 17 00:00:00 2001 From: Scott Branden Date: Mon, 11 Aug 2014 13:58:22 -0700 Subject: [PATCH] arm: iproc: Initial commit of iproc architecture code The iproc architecture code is present in several Broadcom chip architectures, including Cygnus and NSP. Signed-off-by: Scott Branden Signed-off-by: Steve Rae --- arch/arm/cpu/armv7/Makefile | 1 + arch/arm/cpu/armv7/iproc-common/Makefile | 9 + arch/arm/cpu/armv7/iproc-common/armpll.c | 170 ++++++++++++++++++ .../cpu/armv7/iproc-common/hwinit-common.c | 15 ++ arch/arm/cpu/armv7/iproc-common/timer.c | 130 ++++++++++++++ arch/arm/include/asm/iproc-common/armpll.h | 14 ++ arch/arm/include/asm/iproc-common/sysmap.h | 47 +++++ arch/arm/include/asm/iproc-common/timer.h | 37 ++++ 8 files changed, 423 insertions(+) create mode 100644 arch/arm/cpu/armv7/iproc-common/Makefile create mode 100644 arch/arm/cpu/armv7/iproc-common/armpll.c create mode 100644 arch/arm/cpu/armv7/iproc-common/hwinit-common.c create mode 100644 arch/arm/cpu/armv7/iproc-common/timer.c create mode 100644 arch/arm/include/asm/iproc-common/armpll.h create mode 100644 arch/arm/include/asm/iproc-common/sysmap.h create mode 100644 arch/arm/include/asm/iproc-common/timer.h diff --git a/arch/arm/cpu/armv7/Makefile b/arch/arm/cpu/armv7/Makefile index 703ce8c640..afeed4dad8 100644 --- a/arch/arm/cpu/armv7/Makefile +++ b/arch/arm/cpu/armv7/Makefile @@ -28,6 +28,7 @@ ifneq ($(CONFIG_ARMV7_PSCI),) obj-y += psci.o endif +obj-$(CONFIG_IPROC) += iproc-common/ obj-$(CONFIG_KONA) += kona-common/ obj-$(CONFIG_OMAP_COMMON) += omap-common/ obj-$(CONFIG_SYS_ARCH_TIMER) += arch_timer.o diff --git a/arch/arm/cpu/armv7/iproc-common/Makefile b/arch/arm/cpu/armv7/iproc-common/Makefile new file mode 100644 index 0000000000..c071a17e1f --- /dev/null +++ b/arch/arm/cpu/armv7/iproc-common/Makefile @@ -0,0 +1,9 @@ +# +# Copyright 2014 Broadcom Corporation. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y += armpll.o +obj-y += hwinit-common.o +obj-y += timer.o diff --git a/arch/arm/cpu/armv7/iproc-common/armpll.c b/arch/arm/cpu/armv7/iproc-common/armpll.c new file mode 100644 index 0000000000..49b61bf08c --- /dev/null +++ b/arch/arm/cpu/armv7/iproc-common/armpll.c @@ -0,0 +1,170 @@ +/* + * Copyright 2014 Broadcom Corporation. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include + +#define NELEMS(x) (sizeof(x) / sizeof(x[0])) + +struct armpll_parameters { + unsigned int mode; + unsigned int ndiv_int; + unsigned int ndiv_frac; + unsigned int pdiv; + unsigned int freqid; +}; + +struct armpll_parameters armpll_clk_tab[] = { + { 25, 64, 1, 1, 0}, + { 100, 64, 1, 1, 2}, + { 400, 64, 1, 1, 6}, + { 448, 71, 713050, 1, 6}, + { 500, 80, 1, 1, 6}, + { 560, 89, 629145, 1, 6}, + { 600, 96, 1, 1, 6}, + { 800, 64, 1, 1, 7}, + { 896, 71, 713050, 1, 7}, + { 1000, 80, 1, 1, 7}, + { 1100, 88, 1, 1, 7}, + { 1120, 89, 629145, 1, 7}, + { 1200, 96, 1, 1, 7}, +}; + +uint32_t armpll_config(uint32_t clkmhz) +{ + uint32_t freqid; + uint32_t ndiv_frac; + uint32_t pll; + uint32_t status = 1; + uint32_t timeout_countdown; + int i; + + for (i = 0; i < NELEMS(armpll_clk_tab); i++) { + if (armpll_clk_tab[i].mode == clkmhz) { + status = 0; + break; + } + } + + if (status) { + printf("Error: Clock configuration not supported\n"); + goto armpll_config_done; + } + + /* Enable write access */ + writel(IPROC_REG_WRITE_ACCESS, IHOST_PROC_CLK_WR_ACCESS); + + if (clkmhz == 25) + freqid = 0; + else + freqid = 2; + + /* Bypass ARM clock and run on sysclk */ + writel(1 << IHOST_PROC_CLK_POLICY_FREQ__PRIV_ACCESS_MODE | + freqid << IHOST_PROC_CLK_POLICY_FREQ__POLICY3_FREQ_R | + freqid << IHOST_PROC_CLK_POLICY_FREQ__POLICY2_FREQ_R | + freqid << IHOST_PROC_CLK_POLICY_FREQ__POLICY1_FREQ_R | + freqid << IHOST_PROC_CLK_POLICY_FREQ__POLICY0_FREQ_R, + IHOST_PROC_CLK_POLICY_FREQ); + + writel(1 << IHOST_PROC_CLK_POLICY_CTL__GO | + 1 << IHOST_PROC_CLK_POLICY_CTL__GO_AC, + IHOST_PROC_CLK_POLICY_CTL); + + /* Poll CCU until operation complete */ + timeout_countdown = 0x100000; + while (readl(IHOST_PROC_CLK_POLICY_CTL) & + (1 << IHOST_PROC_CLK_POLICY_CTL__GO)) { + timeout_countdown--; + if (timeout_countdown == 0) { + printf("CCU polling timedout\n"); + status = 1; + goto armpll_config_done; + } + } + + if (clkmhz == 25 || clkmhz == 100) { + status = 0; + goto armpll_config_done; + } + + /* Now it is safe to program the PLL */ + pll = readl(IHOST_PROC_CLK_PLLARMB); + pll &= ~((1 << IHOST_PROC_CLK_PLLARMB__PLLARM_NDIV_FRAC_WIDTH) - 1); + ndiv_frac = + ((1 << IHOST_PROC_CLK_PLLARMB__PLLARM_NDIV_FRAC_WIDTH) - 1) & + (armpll_clk_tab[i].ndiv_frac << + IHOST_PROC_CLK_PLLARMB__PLLARM_NDIV_FRAC_R); + pll |= ndiv_frac; + writel(pll, IHOST_PROC_CLK_PLLARMB); + + writel(1 << IHOST_PROC_CLK_PLLARMA__PLLARM_LOCK | + armpll_clk_tab[i].ndiv_int << + IHOST_PROC_CLK_PLLARMA__PLLARM_NDIV_INT_R | + armpll_clk_tab[i].pdiv << + IHOST_PROC_CLK_PLLARMA__PLLARM_PDIV_R | + 1 << IHOST_PROC_CLK_PLLARMA__PLLARM_SOFT_RESETB, + IHOST_PROC_CLK_PLLARMA); + + /* Poll ARM PLL Lock until operation complete */ + timeout_countdown = 0x100000; + while (readl(IHOST_PROC_CLK_PLLARMA) & + (1 << IHOST_PROC_CLK_PLLARMA__PLLARM_LOCK)) { + timeout_countdown--; + if (timeout_countdown == 0) { + printf("ARM PLL lock failed\n"); + status = 1; + goto armpll_config_done; + } + } + + pll = readl(IHOST_PROC_CLK_PLLARMA); + pll |= (1 << IHOST_PROC_CLK_PLLARMA__PLLARM_SOFT_POST_RESETB); + writel(pll, IHOST_PROC_CLK_PLLARMA); + + /* Set the policy */ + writel(1 << IHOST_PROC_CLK_POLICY_FREQ__PRIV_ACCESS_MODE | + armpll_clk_tab[i].freqid << + IHOST_PROC_CLK_POLICY_FREQ__POLICY3_FREQ_R | + armpll_clk_tab[i].freqid << + IHOST_PROC_CLK_POLICY_FREQ__POLICY2_FREQ_R | + armpll_clk_tab[i].freqid << + IHOST_PROC_CLK_POLICY_FREQ__POLICY1_FREQ_R | + armpll_clk_tab[i+4].freqid << + IHOST_PROC_CLK_POLICY_FREQ__POLICY0_FREQ_R, + IHOST_PROC_CLK_POLICY_FREQ); + + writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_CORE0_CLKGATE); + writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_CORE1_CLKGATE); + writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_ARM_SWITCH_CLKGATE); + writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_ARM_PERIPH_CLKGATE); + writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_APB0_CLKGATE); + + writel(1 << IHOST_PROC_CLK_POLICY_CTL__GO | + 1 << IHOST_PROC_CLK_POLICY_CTL__GO_AC, + IHOST_PROC_CLK_POLICY_CTL); + + /* Poll CCU until operation complete */ + timeout_countdown = 0x100000; + while (readl(IHOST_PROC_CLK_POLICY_CTL) & + (1 << IHOST_PROC_CLK_POLICY_CTL__GO)) { + timeout_countdown--; + if (timeout_countdown == 0) { + printf("CCU polling failed\n"); + status = 1; + goto armpll_config_done; + } + } + + status = 0; +armpll_config_done: + /* Disable access to PLL registers */ + writel(0, IHOST_PROC_CLK_WR_ACCESS); + + return status; +} diff --git a/arch/arm/cpu/armv7/iproc-common/hwinit-common.c b/arch/arm/cpu/armv7/iproc-common/hwinit-common.c new file mode 100644 index 0000000000..7131524215 --- /dev/null +++ b/arch/arm/cpu/armv7/iproc-common/hwinit-common.c @@ -0,0 +1,15 @@ +/* + * Copyright 2014 Broadcom Corporation. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include + +#ifndef CONFIG_SYS_DCACHE_OFF +void enable_caches(void) +{ + /* Enable D-cache. I-cache is already enabled in start.S */ + dcache_enable(); +} +#endif diff --git a/arch/arm/cpu/armv7/iproc-common/timer.c b/arch/arm/cpu/armv7/iproc-common/timer.c new file mode 100644 index 0000000000..373d8ec251 --- /dev/null +++ b/arch/arm/cpu/armv7/iproc-common/timer.c @@ -0,0 +1,130 @@ +/* + * Copyright 2014 Broadcom Corporation. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +static inline uint64_t timer_global_read(void) +{ + uint64_t cur_tick; + uint32_t count_h; + uint32_t count_l; + + do { + count_h = readl(IPROC_PERIPH_GLB_TIM_REG_BASE + + TIMER_GLB_HI_OFFSET); + count_l = readl(IPROC_PERIPH_GLB_TIM_REG_BASE + + TIMER_GLB_LOW_OFFSET); + cur_tick = readl(IPROC_PERIPH_GLB_TIM_REG_BASE + + TIMER_GLB_HI_OFFSET); + } while (cur_tick != count_h); + + return (cur_tick << 32) + count_l; +} + +void timer_global_init(void) +{ + writel(0, IPROC_PERIPH_GLB_TIM_REG_BASE + TIMER_GLB_CTRL_OFFSET); + writel(0, IPROC_PERIPH_GLB_TIM_REG_BASE + TIMER_GLB_LOW_OFFSET); + writel(0, IPROC_PERIPH_GLB_TIM_REG_BASE + TIMER_GLB_HI_OFFSET); + writel(TIMER_GLB_TIM_CTRL_TIM_EN, + IPROC_PERIPH_GLB_TIM_REG_BASE + TIMER_GLB_CTRL_OFFSET); +} + +int timer_init(void) +{ + timer_global_init(); + return 0; +} + +unsigned long get_timer(unsigned long base) +{ + uint64_t count; + uint64_t ret; + uint64_t tim_clk; + uint64_t periph_clk; + + count = timer_global_read(); + + /* default arm clk is 1GHz, periph_clk=arm_clk/2, tick per msec */ + periph_clk = 500000; + tim_clk = lldiv(periph_clk, + (((readl(IPROC_PERIPH_GLB_TIM_REG_BASE + + TIMER_GLB_CTRL_OFFSET) & + TIMER_GLB_TIM_CTRL_PRESC_MASK) >> 8) + 1)); + + ret = lldiv(count, (uint32_t)tim_clk); + + /* returns msec */ + return ret - base; +} + +void __udelay(unsigned long usec) +{ + uint64_t cur_tick, end_tick; + uint64_t tim_clk; + uint64_t periph_clk; + + /* default arm clk is 1GHz, periph_clk=arm_clk/2, tick per usec */ + periph_clk = 500; + + tim_clk = lldiv(periph_clk, + (((readl(IPROC_PERIPH_GLB_TIM_REG_BASE + + TIMER_GLB_CTRL_OFFSET) & + TIMER_GLB_TIM_CTRL_PRESC_MASK) >> 8) + 1)); + + cur_tick = timer_global_read(); + + end_tick = tim_clk; + end_tick *= usec; + end_tick += cur_tick; + + do { + cur_tick = timer_global_read(); + + } while (cur_tick < end_tick); +} + +void timer_systick_init(uint32_t tick_ms) +{ + /* Disable timer and clear interrupt status*/ + writel(0, IPROC_PERIPH_PVT_TIM_REG_BASE + TIMER_PVT_CTRL_OFFSET); + writel(TIMER_PVT_TIM_INT_STATUS_SET, + IPROC_PERIPH_PVT_TIM_REG_BASE + TIMER_PVT_STATUS_OFFSET); + writel((PLL_AXI_CLK/1000) * tick_ms, + IPROC_PERIPH_PVT_TIM_REG_BASE + TIMER_PVT_LOAD_OFFSET); + writel(TIMER_PVT_TIM_CTRL_INT_EN | + TIMER_PVT_TIM_CTRL_AUTO_RELD | + TIMER_PVT_TIM_CTRL_TIM_EN, + IPROC_PERIPH_PVT_TIM_REG_BASE + TIMER_PVT_CTRL_OFFSET); +} + +void timer_systick_isr(void *data) +{ + writel(TIMER_PVT_TIM_INT_STATUS_SET, + IPROC_PERIPH_PVT_TIM_REG_BASE + TIMER_PVT_STATUS_OFFSET); +} + +/* + * This function is derived from PowerPC code (read timebase as long long). + * On ARM it just returns the timer value in msec. + */ +unsigned long long get_ticks(void) +{ + return get_timer(0); +} + +/* + * This is used in conjuction with get_ticks, which returns msec as ticks. + * Here we just return ticks/sec = msec/sec = 1000 + */ +ulong get_tbclk(void) +{ + return 1000; +} diff --git a/arch/arm/include/asm/iproc-common/armpll.h b/arch/arm/include/asm/iproc-common/armpll.h new file mode 100644 index 0000000000..1bee350b7b --- /dev/null +++ b/arch/arm/include/asm/iproc-common/armpll.h @@ -0,0 +1,14 @@ +/* + * Copyright 2014 Broadcom Corporation. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __ARMPLL_H +#define __ARMPLL_H + +#include + +uint32_t armpll_config(uint32_t clkmhz); + +#endif /*__ARMPLL_H */ diff --git a/arch/arm/include/asm/iproc-common/sysmap.h b/arch/arm/include/asm/iproc-common/sysmap.h new file mode 100644 index 0000000000..5766dc9e53 --- /dev/null +++ b/arch/arm/include/asm/iproc-common/sysmap.h @@ -0,0 +1,47 @@ +/* + * Copyright 2014 Broadcom Corporation. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __SYSMAP_H +#define __SYSMAP_H + +#define IHOST_PROC_CLK_PLLARMA 0X19000C00 +#define IHOST_PROC_CLK_PLLARMB 0X19000C04 +#define IHOST_PROC_CLK_PLLARMA__PLLARM_PDIV_R 24 + +#define IHOST_PROC_CLK_WR_ACCESS 0X19000000 +#define IHOST_PROC_CLK_POLICY_FREQ 0X19000008 +#define IHOST_PROC_CLK_POLICY_FREQ__PRIV_ACCESS_MODE 31 +#define IHOST_PROC_CLK_POLICY_FREQ__POLICY3_FREQ_R 24 +#define IHOST_PROC_CLK_POLICY_FREQ__POLICY2_FREQ_R 16 +#define IHOST_PROC_CLK_POLICY_FREQ__POLICY1_FREQ_R 8 +#define IHOST_PROC_CLK_POLICY_CTL 0X1900000C +#define IHOST_PROC_CLK_POLICY_CTL__GO 0 +#define IHOST_PROC_CLK_POLICY_CTL__GO_AC 1 +#define IHOST_PROC_CLK_PLLARMB__PLLARM_NDIV_FRAC_R 0 +#define IHOST_PROC_CLK_PLLARMB__PLLARM_NDIV_FRAC_WIDTH 20 +#define IHOST_PROC_CLK_PLLARMA__PLLARM_LOCK 28 +#define IHOST_PROC_CLK_POLICY_FREQ__POLICY0_FREQ_R 0 +#define IHOST_PROC_CLK_PLLARMA__PLLARM_NDIV_INT_R 8 +#define IHOST_PROC_CLK_PLLARMA__PLLARM_SOFT_POST_RESETB 1 +#define IHOST_PROC_CLK_PLLARMA__PLLARM_SOFT_RESETB 0 +#define IHOST_PROC_CLK_CORE0_CLKGATE 0X19000200 +#define IHOST_PROC_CLK_CORE1_CLKGATE 0X19000204 +#define IHOST_PROC_CLK_ARM_SWITCH_CLKGATE 0X19000210 +#define IHOST_PROC_CLK_ARM_PERIPH_CLKGATE 0X19000300 +#define IHOST_PROC_CLK_APB0_CLKGATE 0X19000400 +#define IPROC_CLKCT_HDELAY_SW_EN 0x00000303 + +#define IPROC_REG_WRITE_ACCESS 0x00a5a501 + +#define IPROC_PERIPH_BASE 0x19020000 +#define IPROC_PERIPH_INT_CTRL_REG_BASE (IPROC_PERIPH_BASE + 0x100) +#define IPROC_PERIPH_GLB_TIM_REG_BASE (IPROC_PERIPH_BASE + 0x200) +#define IPROC_PERIPH_PVT_TIM_REG_BASE (IPROC_PERIPH_BASE + 0x600) +#define IPROC_PERIPH_INT_DISTR_REG_BASE (IPROC_PERIPH_BASE + 0x1000) + +#define PLL_AXI_CLK 0x1DCD6500 + +#endif /* __SYSMAP_H */ diff --git a/arch/arm/include/asm/iproc-common/timer.h b/arch/arm/include/asm/iproc-common/timer.h new file mode 100644 index 0000000000..2bc23221a4 --- /dev/null +++ b/arch/arm/include/asm/iproc-common/timer.h @@ -0,0 +1,37 @@ +/* + * Copyright 2014 Broadcom Corporation. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __TIMER_H +#define __TIMER_H + +#include + +void timer_systick_init(uint32_t tick_ms); +void timer_global_init(void); + +/* ARM A9 Private Timer */ +#define TIMER_PVT_LOAD_OFFSET 0x00000000 +#define TIMER_PVT_COUNTER_OFFSET 0x00000004 +#define TIMER_PVT_CTRL_OFFSET 0x00000008 +#define TIMER_PVT_STATUS_OFFSET 0x0000000C +#define TIMER_PVT_TIM_CTRL_TIM_EN 0x00000001 +#define TIMER_PVT_TIM_CTRL_AUTO_RELD 0x00000002 +#define TIMER_PVT_TIM_CTRL_INT_EN 0x00000004 +#define TIMER_PVT_TIM_CTRL_PRESC_MASK 0x0000FF00 +#define TIMER_PVT_TIM_INT_STATUS_SET 0x00000001 + +/* Global timer */ +#define TIMER_GLB_LOW_OFFSET 0x00000000 +#define TIMER_GLB_HI_OFFSET 0x00000004 +#define TIMER_GLB_CTRL_OFFSET 0x00000008 +#define TIMER_GLB_TIM_CTRL_TIM_EN 0x00000001 +#define TIMER_GLB_TIM_CTRL_COMP_EN 0x00000002 +#define TIMER_GLB_TIM_CTRL_INT_EN 0x00000004 +#define TIMER_GLB_TIM_CTRL_AUTO_INC 0x00000008 +#define TIMER_GLB_TIM_CTRL_PRESC_MASK 0x0000FF00 +#define TIMER_GLB_TIM_INT_STATUS_SET 0x00000001 + +#endif /*__TIMER_H */ -- 2.39.5