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 <sbranden@broadcom.com>
Signed-off-by: Steve Rae <srae@broadcom.com>
This commit is contained in:
Scott Branden 2014-08-11 13:58:22 -07:00 committed by Tom Rini
parent b0e31c7b66
commit c4b4500910
8 changed files with 423 additions and 0 deletions

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,170 @@
/*
* Copyright 2014 Broadcom Corporation.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <asm/io.h>
#include <asm/iproc-common/armpll.h>
#include <asm/iproc-common/sysmap.h>
#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;
}

View File

@ -0,0 +1,15 @@
/*
* Copyright 2014 Broadcom Corporation.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#ifndef CONFIG_SYS_DCACHE_OFF
void enable_caches(void)
{
/* Enable D-cache. I-cache is already enabled in start.S */
dcache_enable();
}
#endif

View File

@ -0,0 +1,130 @@
/*
* Copyright 2014 Broadcom Corporation.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <div64.h>
#include <asm/io.h>
#include <asm/iproc-common/timer.h>
#include <asm/iproc-common/sysmap.h>
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;
}

View File

@ -0,0 +1,14 @@
/*
* Copyright 2014 Broadcom Corporation.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef __ARMPLL_H
#define __ARMPLL_H
#include <linux/types.h>
uint32_t armpll_config(uint32_t clkmhz);
#endif /*__ARMPLL_H */

View File

@ -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 */

View File

@ -0,0 +1,37 @@
/*
* Copyright 2014 Broadcom Corporation.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef __TIMER_H
#define __TIMER_H
#include <linux/types.h>
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 */