GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)

This commit is contained in:
lai
2026-09-06 03:52:57 +08:00
commit b1928b41c0
21813 changed files with 4413081 additions and 0 deletions
@@ -0,0 +1,3 @@
# SPDX-License-Identifier: GPL-2.0+
obj- += dummy.o
@@ -0,0 +1,10 @@
# SPDX-License-Identifier: GPL-2.0+
#
# (C) Copyright 2000-2006
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
obj-y = cpu.o
ifneq ($(CONFIG_SPL_BUILD),y)
obj-$(CONFIG_EFI_LOADER) += sctlr.o
endif
@@ -0,0 +1,112 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2004 Texas Insturments
*
* (C) Copyright 2002
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
* Marius Groeger <mgroeger@sysgo.de>
*
* (C) Copyright 2002
* Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
*/
/*
* CPU specific code
*/
#include <common.h>
#include <command.h>
#include <cpu_func.h>
#include <irq_func.h>
#include <asm/system.h>
static void cache_flush(void);
int cleanup_before_linux (void)
{
/*
* this function is called just before we call linux
* it prepares the processor for linux
*
* we turn off caches etc ...
*/
disable_interrupts();
/* turn off I/D-cache */
icache_disable();
dcache_disable();
/* flush I/D-cache */
cache_flush();
return 0;
}
static void cache_flush(void)
{
unsigned long i = 0;
/* clean entire data cache */
asm volatile("mcr p15, 0, %0, c7, c10, 0" : : "r" (i));
/* invalidate both caches and flush btb */
asm volatile("mcr p15, 0, %0, c7, c7, 0" : : "r" (i));
/* mem barrier to sync things */
asm volatile("mcr p15, 0, %0, c7, c10, 4" : : "r" (i));
}
#if !CONFIG_IS_ENABLED(SYS_DCACHE_OFF)
void invalidate_dcache_all(void)
{
asm volatile("mcr p15, 0, %0, c7, c6, 0" : : "r" (0));
}
void flush_dcache_all(void)
{
asm volatile("mcr p15, 0, %0, c7, c10, 0" : : "r" (0));
asm volatile("mcr p15, 0, %0, c7, c10, 4" : : "r" (0));
}
void invalidate_dcache_range(unsigned long start, unsigned long stop)
{
if (!check_cache_range(start, stop))
return;
while (start < stop) {
asm volatile("mcr p15, 0, %0, c7, c6, 1" : : "r" (start));
start += CONFIG_SYS_CACHELINE_SIZE;
}
}
void flush_dcache_range(unsigned long start, unsigned long stop)
{
if (!check_cache_range(start, stop))
return;
while (start < stop) {
asm volatile("mcr p15, 0, %0, c7, c14, 1" : : "r" (start));
start += CONFIG_SYS_CACHELINE_SIZE;
}
asm volatile("mcr p15, 0, %0, c7, c10, 4" : : "r" (0));
}
#else /* #if !CONFIG_IS_ENABLED(SYS_DCACHE_OFF) */
void invalidate_dcache_all(void)
{
}
void flush_dcache_all(void)
{
}
#endif /* #if !CONFIG_IS_ENABLED(SYS_DCACHE_OFF) */
#if !(CONFIG_IS_ENABLED(SYS_ICACHE_OFF) && CONFIG_IS_ENABLED(SYS_DCACHE_OFF))
void enable_caches(void)
{
#if !CONFIG_IS_ENABLED(SYS_ICACHE_OFF)
icache_enable();
#endif
#if !CONFIG_IS_ENABLED(SYS_DCACHE_OFF)
dcache_enable();
#endif
}
#endif
@@ -0,0 +1,25 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Routines to access the system control register
*
* Copyright (c) 2019 Heinrich Schuchardt
*/
#include <linux/linkage.h>
/*
* void allow_unaligned(void) - allow unaligned access
*
* This routine sets the enable unaligned data support flag and clears the
* aligned flag in the system control register.
* After calling this routine unaligned access does no longer leads to a
* data abort or undefined behavior but is handled by the CPU.
* For details see the "ARM Architecture Reference Manual" for ARMv6.
*/
ENTRY(allow_unaligned)
mrc p15, 0, r0, c1, c0, 0 @ load system control register
orr r0, r0, #1 << 22 @ set unaligned data support flag
bic r0, r0, #2 @ clear aligned flag
mcr p15, 0, r0, c1, c0, 0 @ write system control register
bx lr @ return
ENDPROC(allow_unaligned)
@@ -0,0 +1,10 @@
# SPDX-License-Identifier: GPL-2.0+
#
# (C) Copyright 2000-2006
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
extra-y = start.o
obj-y += ../arm11/
obj-$(CONFIG_MX31) += mx31/
obj-$(CONFIG_MX35) += mx35/
@@ -0,0 +1,9 @@
# SPDX-License-Identifier: GPL-2.0+
#
# (C) Copyright 2000-2006
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
obj-y += generic.o
obj-y += timer.o
obj-y += devices.o
obj-y += relocate.o
@@ -0,0 +1,50 @@
// SPDX-License-Identifier: GPL-2.0+
/*
*
* (C) Copyright 2009 Magnus Lilja <lilja.magnus@gmail.com>
*
* (c) 2007 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
*/
#include <common.h>
#include <asm/arch/imx-regs.h>
#include <asm/arch/clock.h>
void mx31_uart1_hw_init(void)
{
/* setup pins for UART1 */
mx31_gpio_mux(MUX_RXD1__UART1_RXD_MUX);
mx31_gpio_mux(MUX_TXD1__UART1_TXD_MUX);
mx31_gpio_mux(MUX_RTS1__UART1_RTS_B);
mx31_gpio_mux(MUX_CTS1__UART1_CTS_B);
}
void mx31_uart2_hw_init(void)
{
/* setup pins for UART2 */
mx31_gpio_mux(MUX_RXD2__UART2_RXD_MUX);
mx31_gpio_mux(MUX_TXD2__UART2_TXD_MUX);
mx31_gpio_mux(MUX_RTS2__UART2_RTS_B);
mx31_gpio_mux(MUX_CTS2__UART2_CTS_B);
}
#ifdef CONFIG_MXC_SPI
/*
* Note: putting several spi setups here makes no sense as they may differ
* at board level (physical pin SS0 of CSPI2 may aswell be used as SS0 of CSPI3)
*/
void mx31_spi2_hw_init(void)
{
/* SPI2 */
mx31_gpio_mux(MUX_CSPI2_SS2__CSPI2_SS2_B);
mx31_gpio_mux(MUX_CSPI2_SCLK__CSPI2_CLK);
mx31_gpio_mux(MUX_CSPI2_SPI_RDY__CSPI2_DATAREADY_B);
mx31_gpio_mux(MUX_CSPI2_MOSI__CSPI2_MOSI);
mx31_gpio_mux(MUX_CSPI2_MISO__CSPI2_MISO);
mx31_gpio_mux(MUX_CSPI2_SS0__CSPI2_SS0_B);
mx31_gpio_mux(MUX_CSPI2_SS1__CSPI2_SS1_B);
/* start SPI2 clock */
__REG(CCM_CGR2) = __REG(CCM_CGR2) | (3 << 4);
}
#endif
@@ -0,0 +1,218 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2007
* Sascha Hauer, Pengutronix
*/
#include <common.h>
#include <div64.h>
#include <asm/arch/imx-regs.h>
#include <asm/arch/clock.h>
#include <asm/io.h>
#include <asm/arch/sys_proto.h>
static u32 mx31_decode_pll(u32 reg, u32 infreq)
{
u32 mfi = GET_PLL_MFI(reg);
s32 mfn = GET_PLL_MFN(reg);
u32 mfd = GET_PLL_MFD(reg);
u32 pd = GET_PLL_PD(reg);
mfi = mfi <= 5 ? 5 : mfi;
mfn = mfn >= 512 ? mfn - 1024 : mfn;
mfd += 1;
pd += 1;
return lldiv(2 * (u64)infreq * (mfi * mfd + mfn),
mfd * pd);
}
static u32 mx31_get_mpl_dpdgck_clk(void)
{
u32 infreq;
if ((readl(CCM_CCMR) & CCMR_PRCS_MASK) == CCMR_FPM)
infreq = MXC_CLK32 * 1024;
else
infreq = MXC_HCLK;
return mx31_decode_pll(readl(CCM_MPCTL), infreq);
}
static u32 mx31_get_mcu_main_clk(void)
{
/* For now we assume mpl_dpdgck_clk == mcu_main_clk
* which should be correct for most boards
*/
return mx31_get_mpl_dpdgck_clk();
}
static u32 mx31_get_ipg_clk(void)
{
u32 freq = mx31_get_mcu_main_clk();
u32 pdr0 = readl(CCM_PDR0);
freq /= GET_PDR0_MAX_PODF(pdr0) + 1;
freq /= GET_PDR0_IPG_PODF(pdr0) + 1;
return freq;
}
/* hsp is the clock for the ipu */
static u32 mx31_get_hsp_clk(void)
{
u32 freq = mx31_get_mcu_main_clk();
u32 pdr0 = readl(CCM_PDR0);
freq /= GET_PDR0_HSP_PODF(pdr0) + 1;
return freq;
}
void mx31_dump_clocks(void)
{
u32 cpufreq = mx31_get_mcu_main_clk();
printf("mx31 cpu clock: %dMHz\n", cpufreq / 1000000);
printf("ipg clock : %dHz\n", mx31_get_ipg_clk());
printf("hsp clock : %dHz\n", mx31_get_hsp_clk());
}
unsigned int mxc_get_clock(enum mxc_clock clk)
{
switch (clk) {
case MXC_ARM_CLK:
return mx31_get_mcu_main_clk();
case MXC_IPG_CLK:
case MXC_IPG_PERCLK:
case MXC_CSPI_CLK:
case MXC_UART_CLK:
case MXC_ESDHC_CLK:
case MXC_I2C_CLK:
return mx31_get_ipg_clk();
case MXC_IPU_CLK:
return mx31_get_hsp_clk();
}
return -1;
}
u32 imx_get_uartclk(void)
{
return mxc_get_clock(MXC_UART_CLK);
}
void mx31_gpio_mux(unsigned long mode)
{
unsigned long reg, shift, tmp;
reg = IOMUXC_BASE + (mode & 0x1fc);
shift = (~mode & 0x3) * 8;
tmp = readl(reg);
tmp &= ~(0xff << shift);
tmp |= ((mode >> IOMUX_MODE_POS) & 0xff) << shift;
writel(tmp, reg);
}
void mx31_set_pad(enum iomux_pins pin, u32 config)
{
u32 field, l, reg;
pin &= IOMUX_PADNUM_MASK;
reg = (IOMUXC_BASE + 0x154) + (pin + 2) / 3 * 4;
field = (pin + 2) % 3;
l = readl(reg);
l &= ~(0x1ff << (field * 10));
l |= config << (field * 10);
writel(l, reg);
}
void mx31_set_gpr(enum iomux_gp_func gp, char en)
{
u32 l;
struct iomuxc_regs *iomuxc = (struct iomuxc_regs *)IOMUXC_BASE;
l = readl(&iomuxc->gpr);
if (en)
l |= gp;
else
l &= ~gp;
writel(l, &iomuxc->gpr);
}
void mxc_setup_weimcs(int cs, const struct mxc_weimcs *weimcs)
{
struct mx31_weim *weim = (struct mx31_weim *) WEIM_BASE;
struct mx31_weim_cscr *cscr = &weim->cscr[cs];
writel(weimcs->upper, &cscr->upper);
writel(weimcs->lower, &cscr->lower);
writel(weimcs->additional, &cscr->additional);
}
struct mx3_cpu_type mx31_cpu_type[] = {
{ .srev = 0x00, .v = 0x10 },
{ .srev = 0x10, .v = 0x11 },
{ .srev = 0x11, .v = 0x11 },
{ .srev = 0x12, .v = 0x1F },
{ .srev = 0x13, .v = 0x1F },
{ .srev = 0x14, .v = 0x12 },
{ .srev = 0x15, .v = 0x12 },
{ .srev = 0x28, .v = 0x20 },
{ .srev = 0x29, .v = 0x20 },
};
u32 get_cpu_rev(void)
{
u32 i, srev;
/* read SREV register from IIM module */
struct iim_regs *iim = (struct iim_regs *)MX31_IIM_BASE_ADDR;
srev = readl(&iim->iim_srev);
for (i = 0; i < ARRAY_SIZE(mx31_cpu_type); i++)
if (srev == mx31_cpu_type[i].srev)
return mx31_cpu_type[i].v | (MXC_CPU_MX31 << 12);
return srev | 0x8000;
}
static char *get_reset_cause(void)
{
/* read RCSR register from CCM module */
struct clock_control_regs *ccm =
(struct clock_control_regs *)CCM_BASE;
u32 cause = readl(&ccm->rcsr) & 0x07;
switch (cause) {
case 0x0000:
return "POR";
case 0x0001:
return "RST";
case 0x0002:
return "WDOG";
case 0x0006:
return "JTAG";
case 0x0007:
return "ARM11P power gating";
default:
return "unknown reset";
}
}
#if defined(CONFIG_DISPLAY_CPUINFO)
int print_cpuinfo(void)
{
u32 srev = get_cpu_rev();
printf("CPU: Freescale i.MX31 rev %d.%d%s at %d MHz.\n",
(srev & 0xF0) >> 4, (srev & 0x0F),
((srev & 0x8000) ? " unknown" : ""),
mx31_get_mcu_main_clk() / 1000000);
printf("Reset cause: %s\n", get_reset_cause());
return 0;
}
#endif
@@ -0,0 +1,22 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* relocate - i.MX31-specific vector relocation
*
* Copyright (c) 2013 Albert ARIBAUD <albert.u.boot@aribaud.net>
*/
#include <linux/linkage.h>
/*
* The i.MX31 SoC is very specific with respect to exceptions: it
* does not provide RAM at the high vectors address (0xFFFF0000),
* thus only the low address (0x00000000) is useable; but that is
* in ROM, so let's avoid relocating the vectors.
*/
.section .text.relocate_vectors,"ax",%progbits
ENTRY(relocate_vectors)
bx lr
ENDPROC(relocate_vectors)
@@ -0,0 +1,44 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2007
* Sascha Hauer, Pengutronix
*/
#include <common.h>
#include <asm/arch/imx-regs.h>
#include <asm/io.h>
#define TIMER_BASE 0x53f90000 /* General purpose timer 1 */
/* General purpose timers registers */
#define GPTCR __REG(TIMER_BASE) /* Control register */
#define GPTPR __REG(TIMER_BASE + 0x4) /* Prescaler register */
#define GPTSR __REG(TIMER_BASE + 0x8) /* Status register */
#define GPTCNT __REG(TIMER_BASE + 0x24) /* Counter register */
/* General purpose timers bitfields */
#define GPTCR_SWR (1 << 15) /* Software reset */
#define GPTCR_FRR (1 << 9) /* Freerun / restart */
#define GPTCR_CLKSOURCE_32 (4 << 6) /* Clock source */
#define GPTCR_TEN 1 /* Timer enable */
/* The 32768Hz 32-bit timer overruns in 131072 seconds */
int timer_init(void)
{
int i;
/* setup GP Timer 1 */
GPTCR = GPTCR_SWR;
for (i = 0; i < 100; i++)
GPTCR = 0; /* We have no udelay by now */
GPTPR = 0; /* 32Khz */
/* Freerun Mode, PERCLK1 input */
GPTCR |= GPTCR_CLKSOURCE_32 | GPTCR_TEN;
return 0;
}
unsigned long timer_read_counter(void)
{
return GPTCNT;
}
@@ -0,0 +1,11 @@
# SPDX-License-Identifier: GPL-2.0+
#
# (C) Copyright 2000-2006
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
#
# (C) Copyright 2008-2009 Freescale Semiconductor, Inc.
obj-y += generic.o
obj-y += timer.o
obj-y += mx35_sdram.o
obj-y += relocate.o
@@ -0,0 +1,525 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2007
* Sascha Hauer, Pengutronix
*
* (C) Copyright 2008-2010 Freescale Semiconductor, Inc.
*/
#include <common.h>
#include <div64.h>
#include <asm/io.h>
#include <linux/errno.h>
#include <asm/arch/imx-regs.h>
#include <asm/arch/crm_regs.h>
#include <asm/arch/clock.h>
#include <asm/arch/sys_proto.h>
#ifdef CONFIG_FSL_ESDHC_IMX
#include <fsl_esdhc_imx.h>
#endif
#include <netdev.h>
#include <spl.h>
#define CLK_CODE(arm, ahb, sel) (((arm) << 16) + ((ahb) << 8) + (sel))
#define CLK_CODE_ARM(c) (((c) >> 16) & 0xFF)
#define CLK_CODE_AHB(c) (((c) >> 8) & 0xFF)
#define CLK_CODE_PATH(c) ((c) & 0xFF)
#define CCM_GET_DIVIDER(x, m, o) (((x) & (m)) >> (o))
#ifdef CONFIG_FSL_ESDHC_IMX
DECLARE_GLOBAL_DATA_PTR;
#endif
static int g_clk_mux_auto[8] = {
CLK_CODE(1, 3, 0), CLK_CODE(1, 2, 1), CLK_CODE(2, 1, 1), -1,
CLK_CODE(1, 6, 0), CLK_CODE(1, 4, 1), CLK_CODE(2, 2, 1), -1,
};
static int g_clk_mux_consumer[16] = {
CLK_CODE(1, 4, 0), CLK_CODE(1, 3, 1), CLK_CODE(1, 3, 1), -1,
-1, -1, CLK_CODE(4, 1, 0), CLK_CODE(1, 5, 0),
CLK_CODE(1, 8, 1), CLK_CODE(1, 6, 1), CLK_CODE(2, 4, 0), -1,
-1, -1, CLK_CODE(4, 2, 0), -1,
};
static int hsp_div_table[3][16] = {
{4, 3, 2, -1, -1, -1, 1, 5, 4, 3, 2, -1, -1, -1, 1, -1},
{-1, -1, -1, -1, -1, -1, -1, -1, 8, 6, 4, -1, -1, -1, 2, -1},
{3, -1, -1, -1, -1, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1},
};
u32 get_cpu_rev(void)
{
int reg;
struct iim_regs *iim =
(struct iim_regs *)IIM_BASE_ADDR;
reg = readl(&iim->iim_srev);
if (!reg) {
reg = readw(ROMPATCH_REV);
reg <<= 4;
} else {
reg += CHIP_REV_1_0;
}
return 0x35000 + (reg & 0xFF);
}
static u32 get_arm_div(u32 pdr0, u32 *fi, u32 *fd)
{
int *pclk_mux;
if (pdr0 & MXC_CCM_PDR0_AUTO_CON) {
pclk_mux = g_clk_mux_consumer +
((pdr0 & MXC_CCM_PDR0_CON_MUX_DIV_MASK) >>
MXC_CCM_PDR0_CON_MUX_DIV_OFFSET);
} else {
pclk_mux = g_clk_mux_auto +
((pdr0 & MXC_CCM_PDR0_AUTO_MUX_DIV_MASK) >>
MXC_CCM_PDR0_AUTO_MUX_DIV_OFFSET);
}
if ((*pclk_mux) == -1)
return -1;
if (fi && fd) {
if (!CLK_CODE_PATH(*pclk_mux)) {
*fi = *fd = 1;
return CLK_CODE_ARM(*pclk_mux);
}
if (pdr0 & MXC_CCM_PDR0_AUTO_CON) {
*fi = 3;
*fd = 4;
} else {
*fi = 2;
*fd = 3;
}
}
return CLK_CODE_ARM(*pclk_mux);
}
static int get_ahb_div(u32 pdr0)
{
int *pclk_mux;
pclk_mux = g_clk_mux_consumer +
((pdr0 & MXC_CCM_PDR0_CON_MUX_DIV_MASK) >>
MXC_CCM_PDR0_CON_MUX_DIV_OFFSET);
if ((*pclk_mux) == -1)
return -1;
return CLK_CODE_AHB(*pclk_mux);
}
static u32 decode_pll(u32 reg, u32 infreq)
{
u32 mfi = (reg >> 10) & 0xf;
s32 mfn = reg & 0x3ff;
u32 mfd = (reg >> 16) & 0x3ff;
u32 pd = (reg >> 26) & 0xf;
mfi = mfi <= 5 ? 5 : mfi;
mfn = mfn >= 512 ? mfn - 1024 : mfn;
mfd += 1;
pd += 1;
return lldiv(2 * (u64)infreq * (mfi * mfd + mfn),
mfd * pd);
}
static u32 get_mcu_main_clk(void)
{
u32 arm_div = 0, fi = 0, fd = 0;
struct ccm_regs *ccm =
(struct ccm_regs *)IMX_CCM_BASE;
arm_div = get_arm_div(readl(&ccm->pdr0), &fi, &fd);
fi *= decode_pll(readl(&ccm->mpctl), MXC_HCLK);
return fi / (arm_div * fd);
}
static u32 get_ipg_clk(void)
{
u32 freq = get_mcu_main_clk();
struct ccm_regs *ccm =
(struct ccm_regs *)IMX_CCM_BASE;
u32 pdr0 = readl(&ccm->pdr0);
return freq / (get_ahb_div(pdr0) * 2);
}
static u32 get_ipg_per_clk(void)
{
u32 freq = get_mcu_main_clk();
struct ccm_regs *ccm =
(struct ccm_regs *)IMX_CCM_BASE;
u32 pdr0 = readl(&ccm->pdr0);
u32 pdr4 = readl(&ccm->pdr4);
u32 div;
if (pdr0 & MXC_CCM_PDR0_PER_SEL) {
div = CCM_GET_DIVIDER(pdr4,
MXC_CCM_PDR4_PER0_PODF_MASK,
MXC_CCM_PDR4_PER0_PODF_OFFSET) + 1;
} else {
div = CCM_GET_DIVIDER(pdr0,
MXC_CCM_PDR0_PER_PODF_MASK,
MXC_CCM_PDR0_PER_PODF_OFFSET) + 1;
div *= get_ahb_div(pdr0);
}
return freq / div;
}
u32 imx_get_uartclk(void)
{
u32 freq;
struct ccm_regs *ccm =
(struct ccm_regs *)IMX_CCM_BASE;
u32 pdr4 = readl(&ccm->pdr4);
if (readl(&ccm->pdr3) & MXC_CCM_PDR3_UART_M_U)
freq = get_mcu_main_clk();
else
freq = decode_pll(readl(&ccm->ppctl), MXC_HCLK);
freq /= CCM_GET_DIVIDER(pdr4,
MXC_CCM_PDR4_UART_PODF_MASK,
MXC_CCM_PDR4_UART_PODF_OFFSET) + 1;
return freq;
}
unsigned int mxc_get_main_clock(enum mxc_main_clock clk)
{
u32 nfc_pdf, hsp_podf;
u32 pll, ret_val = 0, usb_podf;
struct ccm_regs *ccm =
(struct ccm_regs *)IMX_CCM_BASE;
u32 reg = readl(&ccm->pdr0);
u32 reg4 = readl(&ccm->pdr4);
reg |= 0x1;
switch (clk) {
case CPU_CLK:
ret_val = get_mcu_main_clk();
break;
case AHB_CLK:
ret_val = get_mcu_main_clk();
break;
case HSP_CLK:
if (reg & CLKMODE_CONSUMER) {
hsp_podf = (reg >> 20) & 0x3;
pll = get_mcu_main_clk();
hsp_podf = hsp_div_table[hsp_podf][(reg>>16)&0xF];
if (hsp_podf > 0) {
ret_val = pll / hsp_podf;
} else {
puts("mismatch HSP with ARM clock setting\n");
ret_val = 0;
}
} else {
ret_val = get_mcu_main_clk();
}
break;
case IPG_CLK:
ret_val = get_ipg_clk();
break;
case IPG_PER_CLK:
ret_val = get_ipg_per_clk();
break;
case NFC_CLK:
nfc_pdf = (reg4 >> 28) & 0xF;
pll = get_mcu_main_clk();
/* AHB/nfc_pdf */
ret_val = pll / (nfc_pdf + 1);
break;
case USB_CLK:
usb_podf = (reg4 >> 22) & 0x3F;
if (reg4 & 0x200)
pll = get_mcu_main_clk();
else
pll = decode_pll(readl(&ccm->ppctl), MXC_HCLK);
ret_val = pll / (usb_podf + 1);
break;
default:
printf("Unknown clock: %d\n", clk);
break;
}
return ret_val;
}
unsigned int mxc_get_peri_clock(enum mxc_peri_clock clk)
{
u32 ret_val = 0, pdf, pre_pdf, clk_sel;
struct ccm_regs *ccm =
(struct ccm_regs *)IMX_CCM_BASE;
u32 mpdr2 = readl(&ccm->pdr2);
u32 mpdr3 = readl(&ccm->pdr3);
u32 mpdr4 = readl(&ccm->pdr4);
switch (clk) {
case UART1_BAUD:
case UART2_BAUD:
case UART3_BAUD:
clk_sel = mpdr3 & (1 << 14);
pdf = (mpdr4 >> 10) & 0x3F;
ret_val = ((clk_sel != 0) ? mxc_get_main_clock(CPU_CLK) :
decode_pll(readl(&ccm->ppctl), MXC_HCLK)) / (pdf + 1);
break;
case SSI1_BAUD:
pre_pdf = (mpdr2 >> 24) & 0x7;
pdf = mpdr2 & 0x3F;
clk_sel = mpdr2 & (1 << 6);
ret_val = ((clk_sel != 0) ? mxc_get_main_clock(CPU_CLK) :
decode_pll(readl(&ccm->ppctl), MXC_HCLK)) /
((pre_pdf + 1) * (pdf + 1));
break;
case SSI2_BAUD:
pre_pdf = (mpdr2 >> 27) & 0x7;
pdf = (mpdr2 >> 8) & 0x3F;
clk_sel = mpdr2 & (1 << 6);
ret_val = ((clk_sel != 0) ? mxc_get_main_clock(CPU_CLK) :
decode_pll(readl(&ccm->ppctl), MXC_HCLK)) /
((pre_pdf + 1) * (pdf + 1));
break;
case CSI_BAUD:
clk_sel = mpdr2 & (1 << 7);
pdf = (mpdr2 >> 16) & 0x3F;
ret_val = ((clk_sel != 0) ? mxc_get_main_clock(CPU_CLK) :
decode_pll(readl(&ccm->ppctl), MXC_HCLK)) / (pdf + 1);
break;
case MSHC_CLK:
pre_pdf = readl(&ccm->pdr1);
clk_sel = (pre_pdf & 0x80);
pdf = (pre_pdf >> 22) & 0x3F;
pre_pdf = (pre_pdf >> 28) & 0x7;
ret_val = ((clk_sel != 0) ? mxc_get_main_clock(CPU_CLK) :
decode_pll(readl(&ccm->ppctl), MXC_HCLK)) /
((pre_pdf + 1) * (pdf + 1));
break;
case ESDHC1_CLK:
clk_sel = mpdr3 & 0x40;
pdf = mpdr3 & 0x3F;
ret_val = ((clk_sel != 0) ? mxc_get_main_clock(CPU_CLK) :
decode_pll(readl(&ccm->ppctl), MXC_HCLK)) / (pdf + 1);
break;
case ESDHC2_CLK:
clk_sel = mpdr3 & 0x40;
pdf = (mpdr3 >> 8) & 0x3F;
ret_val = ((clk_sel != 0) ? mxc_get_main_clock(CPU_CLK) :
decode_pll(readl(&ccm->ppctl), MXC_HCLK)) / (pdf + 1);
break;
case ESDHC3_CLK:
clk_sel = mpdr3 & 0x40;
pdf = (mpdr3 >> 16) & 0x3F;
ret_val = ((clk_sel != 0) ? mxc_get_main_clock(CPU_CLK) :
decode_pll(readl(&ccm->ppctl), MXC_HCLK)) / (pdf + 1);
break;
case SPDIF_CLK:
clk_sel = mpdr3 & 0x400000;
pre_pdf = (mpdr3 >> 29) & 0x7;
pdf = (mpdr3 >> 23) & 0x3F;
ret_val = ((clk_sel != 0) ? mxc_get_main_clock(CPU_CLK) :
decode_pll(readl(&ccm->ppctl), MXC_HCLK)) /
((pre_pdf + 1) * (pdf + 1));
break;
default:
printf("%s(): This clock: %d not supported yet\n",
__func__, clk);
break;
}
return ret_val;
}
unsigned int mxc_get_clock(enum mxc_clock clk)
{
switch (clk) {
case MXC_ARM_CLK:
return get_mcu_main_clk();
case MXC_AHB_CLK:
break;
case MXC_IPG_CLK:
return get_ipg_clk();
case MXC_IPG_PERCLK:
case MXC_I2C_CLK:
return get_ipg_per_clk();
case MXC_UART_CLK:
return imx_get_uartclk();
case MXC_ESDHC1_CLK:
return mxc_get_peri_clock(ESDHC1_CLK);
case MXC_ESDHC2_CLK:
return mxc_get_peri_clock(ESDHC2_CLK);
case MXC_ESDHC3_CLK:
return mxc_get_peri_clock(ESDHC3_CLK);
case MXC_USB_CLK:
return mxc_get_main_clock(USB_CLK);
case MXC_FEC_CLK:
return get_ipg_clk();
case MXC_CSPI_CLK:
return get_ipg_clk();
}
return -1;
}
#ifdef CONFIG_FEC_MXC
/*
* The MX35 has no fuse for MAC, return a NULL MAC
*/
void imx_get_mac_from_fuse(int dev_id, unsigned char *mac)
{
memset(mac, 0, 6);
}
u32 imx_get_fecclk(void)
{
return mxc_get_clock(MXC_IPG_CLK);
}
#endif
int do_mx35_showclocks(cmd_tbl_t *cmdtp,
int flag, int argc, char * const argv[])
{
u32 cpufreq = get_mcu_main_clk();
printf("mx35 cpu clock: %dMHz\n", cpufreq / 1000000);
printf("ipg clock : %dHz\n", get_ipg_clk());
printf("ipg per clock : %dHz\n", get_ipg_per_clk());
printf("uart clock : %dHz\n", mxc_get_clock(MXC_UART_CLK));
return 0;
}
U_BOOT_CMD(
clocks, CONFIG_SYS_MAXARGS, 1, do_mx35_showclocks,
"display clocks",
""
);
#if defined(CONFIG_DISPLAY_CPUINFO)
static char *get_reset_cause(void)
{
/* read RCSR register from CCM module */
struct ccm_regs *ccm =
(struct ccm_regs *)IMX_CCM_BASE;
u32 cause = readl(&ccm->rcsr) & 0x0F;
switch (cause) {
case 0x0000:
return "POR";
case 0x0002:
return "JTAG";
case 0x0004:
return "RST";
case 0x0008:
return "WDOG";
default:
return "unknown reset";
}
}
int print_cpuinfo(void)
{
u32 srev = get_cpu_rev();
printf("CPU: Freescale i.MX35 rev %d.%d at %d MHz.\n",
(srev & 0xF0) >> 4, (srev & 0x0F),
get_mcu_main_clk() / 1000000);
printf("Reset cause: %s\n", get_reset_cause());
return 0;
}
#endif
/*
* Initializes on-chip ethernet controllers.
* to override, implement board_eth_init()
*/
int cpu_eth_init(bd_t *bis)
{
int rc = -ENODEV;
#if defined(CONFIG_FEC_MXC)
rc = fecmxc_initialize(bis);
#endif
return rc;
}
#ifdef CONFIG_FSL_ESDHC_IMX
/*
* Initializes on-chip MMC controllers.
* to override, implement board_mmc_init()
*/
int cpu_mmc_init(bd_t *bis)
{
return fsl_esdhc_mmc_init(bis);
}
#endif
int get_clocks(void)
{
#ifdef CONFIG_FSL_ESDHC_IMX
#if CONFIG_SYS_FSL_ESDHC_ADDR == MMC_SDHC2_BASE_ADDR
gd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC2_CLK);
#elif CONFIG_SYS_FSL_ESDHC_ADDR == MMC_SDHC3_BASE_ADDR
gd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC3_CLK);
#else
gd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC1_CLK);
#endif
#endif
return 0;
}
#define RCSR_MEM_CTL_WEIM 0
#define RCSR_MEM_CTL_NAND 1
#define RCSR_MEM_CTL_ATA 2
#define RCSR_MEM_CTL_EXPANSION 3
#define RCSR_MEM_TYPE_NOR 0
#define RCSR_MEM_TYPE_ONENAND 2
#define RCSR_MEM_TYPE_SD 0
#define RCSR_MEM_TYPE_I2C 2
#define RCSR_MEM_TYPE_SPI 3
u32 spl_boot_device(void)
{
struct ccm_regs *ccm =
(struct ccm_regs *)IMX_CCM_BASE;
u32 rcsr = readl(&ccm->rcsr);
u32 mem_type, mem_ctl;
/* In external mode, no boot device is returned */
if ((rcsr >> 10) & 0x03)
return BOOT_DEVICE_NONE;
mem_ctl = (rcsr >> 25) & 0x03;
mem_type = (rcsr >> 23) & 0x03;
switch (mem_ctl) {
case RCSR_MEM_CTL_WEIM:
switch (mem_type) {
case RCSR_MEM_TYPE_NOR:
return BOOT_DEVICE_NOR;
case RCSR_MEM_TYPE_ONENAND:
return BOOT_DEVICE_ONENAND;
default:
return BOOT_DEVICE_NONE;
}
case RCSR_MEM_CTL_NAND:
return BOOT_DEVICE_NAND;
case RCSR_MEM_CTL_EXPANSION:
switch (mem_type) {
case RCSR_MEM_TYPE_SD:
return BOOT_DEVICE_MMC1;
case RCSR_MEM_TYPE_I2C:
return BOOT_DEVICE_I2C;
case RCSR_MEM_TYPE_SPI:
return BOOT_DEVICE_SPI;
default:
return BOOT_DEVICE_NONE;
}
}
return BOOT_DEVICE_NONE;
}
@@ -0,0 +1,120 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2012, Stefano Babic <sbabic@denx.de>
*/
#include <asm/io.h>
#include <linux/errno.h>
#include <asm/arch/imx-regs.h>
#include <linux/types.h>
#include <asm/arch/sys_proto.h>
#define ESDCTL_DDR2_EMR2 0x04000000
#define ESDCTL_DDR2_EMR3 0x06000000
#define ESDCTL_PRECHARGE 0x00000400
#define ESDCTL_DDR2_EN_DLL 0x02000400
#define ESDCTL_DDR2_RESET_DLL 0x00000333
#define ESDCTL_DDR2_MR 0x00000233
#define ESDCTL_DDR2_OCD_DEFAULT 0x02000780
enum {
SMODE_NORMAL = 0,
SMODE_PRECHARGE,
SMODE_AUTO_REFRESH,
SMODE_LOAD_REG,
SMODE_MANUAL_REFRESH
};
#define set_mode(x, en, m) (x | (en << 31) | (m << 28))
static inline void dram_wait(unsigned int count)
{
volatile unsigned int wait = count;
while (wait--)
;
}
void mx3_setup_sdram_bank(u32 start_address, u32 ddr2_config,
u32 row, u32 col, u32 dsize, u32 refresh)
{
struct esdc_regs *esdc = (struct esdc_regs *)ESDCTL_BASE_ADDR;
u32 *cfg_reg, *ctl_reg;
u32 val;
u32 ctlval;
switch (start_address) {
case CSD0_BASE_ADDR:
cfg_reg = &esdc->esdcfg0;
ctl_reg = &esdc->esdctl0;
break;
case CSD1_BASE_ADDR:
cfg_reg = &esdc->esdcfg1;
ctl_reg = &esdc->esdctl1;
break;
default:
return;
}
/* The MX35 supports 11 up to 14 rows */
if (row < 11 || row > 14 || col < 8 || col > 10)
return;
ctlval = (row - 11) << 24 | (col - 8) << 20 | (dsize << 16);
/* Initialize MISC register for DDR2 */
val = ESDC_MISC_RST | ESDC_MISC_MDDR_EN | ESDC_MISC_MDDR_DL_RST |
ESDC_MISC_DDR_EN | ESDC_MISC_DDR2_EN;
writel(val, &esdc->esdmisc);
val &= ~(ESDC_MISC_RST | ESDC_MISC_MDDR_DL_RST);
writel(val, &esdc->esdmisc);
/*
* according to DDR2 specs, wait a while before
* the PRECHARGE_ALL command
*/
dram_wait(0x20000);
/* Load DDR2 config and timing */
writel(ddr2_config, cfg_reg);
/* Precharge ALL */
writel(set_mode(ctlval, 1, SMODE_PRECHARGE),
ctl_reg);
writel(0xda, start_address + ESDCTL_PRECHARGE);
/* Load mode */
writel(set_mode(ctlval, 1, SMODE_LOAD_REG),
ctl_reg);
writeb(0xda, start_address + ESDCTL_DDR2_EMR2); /* EMRS2 */
writeb(0xda, start_address + ESDCTL_DDR2_EMR3); /* EMRS3 */
writeb(0xda, start_address + ESDCTL_DDR2_EN_DLL); /* Enable DLL */
writeb(0xda, start_address + ESDCTL_DDR2_RESET_DLL); /* Reset DLL */
/* Precharge ALL */
writel(set_mode(ctlval, 1, SMODE_PRECHARGE),
ctl_reg);
writel(0xda, start_address + ESDCTL_PRECHARGE);
/* Set mode auto refresh : at least two refresh are required */
writel(set_mode(ctlval, 1, SMODE_AUTO_REFRESH),
ctl_reg);
writel(0xda, start_address);
writel(0xda, start_address);
writel(set_mode(ctlval, 1, SMODE_LOAD_REG),
ctl_reg);
writeb(0xda, start_address + ESDCTL_DDR2_MR);
writeb(0xda, start_address + ESDCTL_DDR2_OCD_DEFAULT);
/* OCD mode exit */
writeb(0xda, start_address + ESDCTL_DDR2_EN_DLL); /* Enable DLL */
/* Set normal mode */
writel(set_mode(ctlval, 1, SMODE_NORMAL) | refresh,
ctl_reg);
dram_wait(0x20000);
/* Do not set delay lines, only for MDDR */
}
@@ -0,0 +1,22 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* relocate - i.MX35-specific vector relocation
*
* Copyright (c) 2013 Albert ARIBAUD <albert.u.boot@aribaud.net>
*/
#include <linux/linkage.h>
/*
* The i.MX35 SoC is very specific with respect to exceptions: it
* does not provide RAM at the high vectors address (0xFFFF0000),
* thus only the low address (0x00000000) is useable; but that is
* in ROM, so let's avoid relocating the vectors.
*/
.section .text.relocate_vectors,"ax",%progbits
ENTRY(relocate_vectors)
bx lr
ENDPROC(relocate_vectors)
@@ -0,0 +1,44 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2007
* Sascha Hauer, Pengutronix
*
* (C) Copyright 2008-2009 Freescale Semiconductor, Inc.
*/
#include <common.h>
#include <asm/io.h>
#include <asm/arch/imx-regs.h>
#include <asm/arch/crm_regs.h>
/* General purpose timers bitfields */
#define GPTCR_SWR (1<<15) /* Software reset */
#define GPTCR_FRR (1<<9) /* Freerun / restart */
#define GPTCR_CLKSOURCE_32 (4<<6) /* Clock source */
#define GPTCR_TEN (1) /* Timer enable */
/*
* nothing really to do with interrupts, just starts up a counter.
* The 32KHz 32-bit timer overruns in 134217 seconds
*/
int timer_init(void)
{
int i;
struct gpt_regs *gpt = (struct gpt_regs *)GPT1_BASE_ADDR;
struct ccm_regs *ccm = (struct ccm_regs *)CCM_BASE_ADDR;
/* setup GP Timer 1 */
writel(GPTCR_SWR, &gpt->ctrl);
writel(readl(&ccm->cgr1) | 3 << MXC_CCM_CGR1_GPT_OFFSET, &ccm->cgr1);
for (i = 0; i < 100; i++)
writel(0, &gpt->ctrl); /* We have no udelay by now */
writel(0, &gpt->pre); /* prescaler = 1 */
/* Freerun Mode, 32KHz input */
writel(readl(&gpt->ctrl) | GPTCR_CLKSOURCE_32 | GPTCR_FRR,
&gpt->ctrl);
writel(readl(&gpt->ctrl) | GPTCR_TEN, &gpt->ctrl);
return 0;
}
@@ -0,0 +1,94 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* armboot - Startup Code for OMP2420/ARM1136 CPU-core
*
* Copyright (c) 2004 Texas Instruments <r-woodruff2@ti.com>
*
* Copyright (c) 2001 Marius Gröger <mag@sysgo.de>
* Copyright (c) 2002 Alex Züpke <azu@sysgo.de>
* Copyright (c) 2002 Gary Jennejohn <garyj@denx.de>
* Copyright (c) 2003 Richard Woodruff <r-woodruff2@ti.com>
* Copyright (c) 2003 Kshitij <kshitij@ti.com>
*/
#include <asm-offsets.h>
#include <config.h>
/*
*************************************************************************
*
* Startup Code (reset vector)
*
* do important init only if we don't start from memory!
* setup Memory and board specific bits prior to relocation.
* relocate armboot to ram
* setup stack
*
*************************************************************************
*/
.globl reset
reset:
/*
* set the cpu to SVC32 mode
*/
mrs r0,cpsr
bic r0,r0,#0x1f
orr r0,r0,#0xd3
msr cpsr,r0
/* the mask ROM code should have PLL and others stable */
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_crit
#endif
bl _main
/*------------------------------------------------------------------------------*/
.globl c_runtime_cpu_setup
c_runtime_cpu_setup:
bx lr
/*
*************************************************************************
*
* CPU_init_critical registers
*
* setup important registers
* setup memory timing
*
*************************************************************************
*/
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
cpu_init_crit:
/*
* flush v4 I/D caches
*/
mov r0, #0
mcr p15, 0, r0, c7, c7, 0 /* Invalidate I+D+BTB caches */
mcr p15, 0, r0, c8, c7, 0 /* Invalidate Unified TLB */
/*
* disable MMU stuff and caches
*/
mrc p15, 0, r0, c1, c0, 0
bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS)
bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM)
orr r0, r0, #0x00000002 @ set bit 1 (A) Align
orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache
mcr p15, 0, r0, c1, c0, 0
#ifndef CONFIG_SKIP_LOWLEVEL_INIT_ONLY
/*
* Jump to board specific initialization... The Mask ROM will have already initialized
* basic memory. Go here to bump up clock rate and handle wake up conditions.
*/
mov ip, lr /* persevere link reg across call */
bl lowlevel_init /* go setup pll,mux,memory */
mov lr, ip /* restore link */
#endif
mov pc, lr /* back to my caller */
#endif /* CONFIG_SKIP_LOWLEVEL_INIT */
@@ -0,0 +1,50 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* (C) Copyright 2002
* Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
*
* (C) Copyright 2010
* Texas Instruments, <www.ti.com>
* Aneesh V <aneesh@ti.com>
*/
MEMORY { .sram : ORIGIN = IMAGE_TEXT_BASE,\
LENGTH = IMAGE_MAX_SIZE }
MEMORY { .sdram : ORIGIN = CONFIG_SPL_BSS_START_ADDR, \
LENGTH = CONFIG_SPL_BSS_MAX_SIZE }
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
.text :
{
__start = .;
*(.vectors)
arch/arm/cpu/arm1136/start.o (.text*)
*(.text*)
} >.sram
. = ALIGN(4);
.rodata : { *(SORT_BY_ALIGNMENT(.rodata*)) } >.sram
. = ALIGN(4);
.data : { *(SORT_BY_ALIGNMENT(.data*)) } >.sram
. = ALIGN(4);
__image_copy_end = .;
.end :
{
*(.__end)
}
.bss :
{
. = ALIGN(4);
__bss_start = .;
*(.bss*)
. = ALIGN(4);
__bss_end = .;
} >.sdram
}
@@ -0,0 +1,12 @@
# SPDX-License-Identifier: GPL-2.0+
#
# (C) Copyright 2000-2006
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
#
# (C) Copyright 2008
# Guennadi Liakhovetki, DENX Software Engineering, <lg@denx.de>
obj- += dummy.o
extra-y = start.o
obj-y += ../arm11/
@@ -0,0 +1,121 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* armboot - Startup Code for ARM1176 CPU-core
*
* Copyright (c) 2007 Samsung Electronics
*
* Copyright (C) 2008
* Guennadi Liakhovetki, DENX Software Engineering, <lg@denx.de>
*
* 2007-09-21 - Restructured codes by jsgood (jsgood.yang@samsung.com)
* 2007-09-21 - Added MoviNAND and OneNAND boot codes by
* jsgood (jsgood.yang@samsung.com)
* Base codes by scsuh (sc.suh)
*/
#include <asm-offsets.h>
#include <config.h>
#include <linux/linkage.h>
#ifndef CONFIG_SYS_PHY_UBOOT_BASE
#define CONFIG_SYS_PHY_UBOOT_BASE CONFIG_SYS_UBOOT_BASE
#endif
/*
*************************************************************************
*
* Startup Code (reset vector)
*
* do important init only if we don't start from memory!
* setup Memory and board specific bits prior to relocation.
* relocate armboot to ram
* setup stack
*
*************************************************************************
*/
.globl reset
reset:
/* Allow the board to save important registers */
b save_boot_params
.globl save_boot_params_ret
save_boot_params_ret:
/*
* set the cpu to SVC32 mode
*/
mrs r0, cpsr
bic r0, r0, #0x3f
orr r0, r0, #0xd3
msr cpsr, r0
/*
*************************************************************************
*
* CPU_init_critical registers
*
* setup important registers
* setup memory timing
*
*************************************************************************
*/
/*
* we do sys-critical inits only at reboot,
* not when booting from ram!
*/
cpu_init_crit:
/*
* When booting from NAND - it has definitely been a reset, so, no need
* to flush caches and disable the MMU
*/
#ifndef CONFIG_SPL_BUILD
/*
* flush v4 I/D caches
*/
mov r0, #0
mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */
mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */
/*
* disable MMU stuff and caches
*/
mrc p15, 0, r0, c1, c0, 0
bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS)
bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM)
orr r0, r0, #0x00000002 @ set bit 1 (A) Align
orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache
/* Prepare to disable the MMU */
adr r2, mmu_disable_phys
sub r2, r2, #(CONFIG_SYS_PHY_UBOOT_BASE - CONFIG_SYS_TEXT_BASE)
b mmu_disable
.align 5
/* Run in a single cache-line */
mmu_disable:
mcr p15, 0, r0, c1, c0, 0
nop
nop
mov pc, r2
mmu_disable_phys:
#endif
/*
* Go setup Memory and board specific bits prior to relocation.
*/
bl lowlevel_init /* go setup pll,mux,memory */
bl _main
/*------------------------------------------------------------------------------*/
.globl c_runtime_cpu_setup
c_runtime_cpu_setup:
mov pc, lr
WEAK(save_boot_params)
b save_boot_params_ret /* back to my caller */
ENDPROC(save_boot_params)
@@ -0,0 +1,7 @@
# SPDX-License-Identifier: GPL-2.0+
#
# (C) Copyright 2000-2006
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
extra-y = start.o
obj-y = interrupts.o cpu.o
@@ -0,0 +1,21 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2002
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
* Marius Groeger <mgroeger@sysgo.de>
*
* (C) Copyright 2002
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
* Alex Zuepke <azu@sysgo.de>
*/
/*
* cleanup_before_linux() - Prepare the CPU to jump to Linux
*
* This function is called just before we call Linux, it
* prepares the processor for linux
*/
int cleanup_before_linux(void)
{
return 0;
}
@@ -0,0 +1,26 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2002
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
* Marius Groeger <mgroeger@sysgo.de>
*
* (C) Copyright 2002
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
* Alex Zuepke <azu@sysgo.de>
*/
#include <common.h>
#if defined(CONFIG_TEGRA)
static ulong timestamp;
static ulong lastdec;
int timer_init (void)
{
/* No timer routines for tegra as yet */
lastdec = 0;
timestamp = 0;
return 0;
}
#endif
@@ -0,0 +1,79 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* armboot - Startup Code for ARM720 CPU-core
*
* Copyright (c) 2001 Marius Gröger <mag@sysgo.de>
* Copyright (c) 2002 Alex Züpke <azu@sysgo.de>
*/
#include <asm-offsets.h>
#include <config.h>
/*
*************************************************************************
*
* Startup Code (reset vector)
*
* do important init only if we don't start from RAM!
* relocate armboot to ram
* setup stack
* jump to second stage
*
*************************************************************************
*/
.globl reset
reset:
/*
* set the cpu to SVC32 mode
*/
mrs r0,cpsr
bic r0,r0,#0x1f
orr r0,r0,#0xd3
msr cpsr,r0
/*
* we do sys-critical inits only at reboot,
* not when booting from ram!
*/
#if !defined(CONFIG_SKIP_LOWLEVEL_INIT) && \
!defined(CONFIG_SKIP_LOWLEVEL_INIT_ONLY)
bl cpu_init_crit
#endif
bl _main
/*------------------------------------------------------------------------------*/
.globl c_runtime_cpu_setup
c_runtime_cpu_setup:
mov pc, lr
/*
*************************************************************************
*
* CPU_init_critical registers
*
* setup important registers
* setup memory timing
*
*************************************************************************
*/
#if !defined(CONFIG_SKIP_LOWLEVEL_INIT) && \
!defined(CONFIG_SKIP_LOWLEVEL_INIT_ONLY)
cpu_init_crit:
mov ip, lr
/*
* before relocating, we have to setup RAM timing
* because memory timing is board-dependent, you will
* find a lowlevel_init.S in your board directory.
*/
bl lowlevel_init
mov lr, ip
mov pc, lr
#endif /* CONFIG_SKIP_LOWLEVEL_INIT */
@@ -0,0 +1,17 @@
# SPDX-License-Identifier: GPL-2.0+
#
# (C) Copyright 2000-2006
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
extra-y = start.o
obj-y += cpu.o
obj-$(CONFIG_EP93XX) += ep93xx/
obj-$(CONFIG_IMX) += imx/
# some files can only build in ARM mode
ifdef CONFIG_$(SPL_)SYS_THUMB_BUILD
CFLAGS_cpu.o := -marm
endif
@@ -0,0 +1,49 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2002
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
* Marius Groeger <mgroeger@sysgo.de>
*
* (C) Copyright 2002
* Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
*/
/*
* CPU specific code
*/
#include <common.h>
#include <command.h>
#include <cpu_func.h>
#include <irq_func.h>
#include <asm/system.h>
static void cache_flush(void);
int cleanup_before_linux (void)
{
/*
* this function is called just before we call linux
* it prepares the processor for linux
*
* we turn off caches etc ...
*/
disable_interrupts();
/* turn off I/D-cache */
icache_disable();
dcache_disable();
/* flush I/D-cache */
cache_flush();
return 0;
}
/* flush I/D-cache */
static void cache_flush (void)
{
unsigned long i = 0;
asm ("mcr p15, 0, %0, c7, c7, 0": :"r" (i));
}
@@ -0,0 +1,19 @@
# SPDX-License-Identifier: GPL-2.0+
#
# Cirrus Logic EP93xx CPU-specific Makefile
#
# Copyright (C) 2009 Matthias Kaehlcke <matthias@kaehlcke.net>
#
# Copyright (C) 2004, 2005
# Cory T. Tusar, Videon Central, Inc., <ctusar@videon-central.com>
#
# Copyright (C) 2006
# Dominic Rath <Dominic.Rath@gmx.de>
#
# Based on an original Makefile, which is
#
# (C) Copyright 2000, 2001, 2002
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
obj-y = cpu.o led.o speed.o timer.o
obj-y += lowlevel_init.o
@@ -0,0 +1,36 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Cirrus Logic EP93xx CPU-specific support.
*
* Copyright (C) 2009 Matthias Kaehlcke <matthias@kaehlcke.net>
*
* Copyright (C) 2004, 2005
* Cory T. Tusar, Videon Central, Inc., <ctusar@videon-central.com>
*/
#include <common.h>
#include <asm/arch/ep93xx.h>
#include <asm/io.h>
/* We reset the CPU by generating a 1-->0 transition on DeviceCfg bit 31. */
extern void reset_cpu(ulong addr)
{
struct syscon_regs *syscon = (struct syscon_regs *)SYSCON_BASE;
uint32_t value;
/* Unlock DeviceCfg and set SWRST */
writel(0xAA, &syscon->sysswlock);
value = readl(&syscon->devicecfg);
value |= SYSCON_DEVICECFG_SWRST;
writel(value, &syscon->devicecfg);
/* Unlock DeviceCfg and clear SWRST */
writel(0xAA, &syscon->sysswlock);
value = readl(&syscon->devicecfg);
value &= ~SYSCON_DEVICECFG_SWRST;
writel(value, &syscon->devicecfg);
/* Dying... */
while (1)
; /* noop */
}
@@ -0,0 +1,85 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2010, 2009 Matthias Kaehlcke <matthias@kaehlcke.net>
*/
#include <asm/io.h>
#include <asm/arch/ep93xx.h>
#include <config.h>
#include <status_led.h>
static uint8_t saved_state[2] = {CONFIG_LED_STATUS_OFF, CONFIG_LED_STATUS_OFF};
static uint32_t gpio_pin[2] = {1 << CONFIG_LED_STATUS_GREEN,
1 << CONFIG_LED_STATUS_RED};
static inline void switch_LED_on(uint8_t led)
{
register struct gpio_regs *gpio = (struct gpio_regs *)GPIO_BASE;
writel(readl(&gpio->pedr) | gpio_pin[led], &gpio->pedr);
saved_state[led] = CONFIG_LED_STATUS_ON;
}
static inline void switch_LED_off(uint8_t led)
{
register struct gpio_regs *gpio = (struct gpio_regs *)GPIO_BASE;
writel(readl(&gpio->pedr) & ~gpio_pin[led], &gpio->pedr);
saved_state[led] = CONFIG_LED_STATUS_OFF;
}
void red_led_on(void)
{
switch_LED_on(CONFIG_LED_STATUS_RED);
}
void red_led_off(void)
{
switch_LED_off(CONFIG_LED_STATUS_RED);
}
void green_led_on(void)
{
switch_LED_on(CONFIG_LED_STATUS_GREEN);
}
void green_led_off(void)
{
switch_LED_off(CONFIG_LED_STATUS_GREEN);
}
void __led_init(led_id_t mask, int state)
{
__led_set(mask, state);
}
void __led_toggle(led_id_t mask)
{
if (CONFIG_LED_STATUS_RED == mask) {
if (CONFIG_LED_STATUS_ON == saved_state[CONFIG_LED_STATUS_RED])
red_led_off();
else
red_led_on();
} else if (CONFIG_LED_STATUS_GREEN == mask) {
if (CONFIG_LED_STATUS_ON ==
saved_state[CONFIG_LED_STATUS_GREEN])
green_led_off();
else
green_led_on();
}
}
void __led_set(led_id_t mask, int state)
{
if (CONFIG_LED_STATUS_RED == mask) {
if (CONFIG_LED_STATUS_ON == state)
red_led_on();
else
red_led_off();
} else if (CONFIG_LED_STATUS_GREEN == mask) {
if (CONFIG_LED_STATUS_ON == state)
green_led_on();
else
green_led_off();
}
}
@@ -0,0 +1,457 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Low-level initialization for EP93xx
*
* Copyright (C) 2009 Matthias Kaehlcke <matthias@kaehlcke.net>
* Copyright (C) 2013
* Sergey Kostanabev <sergey.kostanbaev <at> fairwaves.ru>
*
* Copyright (C) 2006 Dominic Rath <Dominic.Rath@gmx.de>
* Copyright (C) 2006 Cirrus Logic Inc.
*
* See file CREDITS for list of people who contributed to this
* project.
*/
#include <config.h>
#include <asm/arch-ep93xx/ep93xx.h>
/*
/* Configure the SDRAM based on the supplied settings.
*
* Input: r0 - SDRAM DEVCFG register
* r2 - configuration for SDRAM chips
* Output: none
* Modifies: r3, r4
*/
ep93xx_sdram_config:
/* Program the SDRAM device configuration register. */
ldr r3, =SDRAM_BASE
#ifdef CONFIG_EDB93XX_SDCS0
str r0, [r3, #SDRAM_OFF_DEVCFG0]
#endif
#ifdef CONFIG_EDB93XX_SDCS1
str r0, [r3, #SDRAM_OFF_DEVCFG1]
#endif
#ifdef CONFIG_EDB93XX_SDCS2
str r0, [r3, #SDRAM_OFF_DEVCFG2]
#endif
#ifdef CONFIG_EDB93XX_SDCS3
str r0, [r3, #SDRAM_OFF_DEVCFG3]
#endif
/* Set the Initialize and MRS bits (issue continuous NOP commands
* (INIT & MRS set))
*/
ldr r4, =(EP93XX_SDRAMCTRL_GLOBALCFG_INIT | \
EP93XX_SDRAMCTRL_GLOBALCFG_MRS | \
EP93XX_SDRAMCTRL_GLOBALCFG_CKE)
str r4, [r3, #SDRAM_OFF_GLCONFIG]
/* Delay for 200us. */
mov r4, #0x3000
delay1:
subs r4, r4, #1
bne delay1
/* Clear the MRS bit to issue a precharge all. */
ldr r4, =(EP93XX_SDRAMCTRL_GLOBALCFG_INIT | \
EP93XX_SDRAMCTRL_GLOBALCFG_CKE)
str r4, [r3, #SDRAM_OFF_GLCONFIG]
/* Temporarily set the refresh timer to 0x10. Make it really low so
* that refresh cycles are generated.
*/
ldr r4, =0x10
str r4, [r3, #SDRAM_OFF_REFRSHTIMR]
/* Delay for at least 80 SDRAM clock cycles. */
mov r4, #80
delay2:
subs r4, r4, #1
bne delay2
/* Set the refresh timer to the fastest required for any device
* that might be used. Set 9.6 ms refresh time.
*/
ldr r4, =0x01e0
str r4, [r3, #SDRAM_OFF_REFRSHTIMR]
/* Select mode register update mode. */
ldr r4, =(EP93XX_SDRAMCTRL_GLOBALCFG_CKE | \
EP93XX_SDRAMCTRL_GLOBALCFG_MRS)
str r4, [r3, #SDRAM_OFF_GLCONFIG]
/* Program the mode register on the SDRAM by performing fake read */
ldr r4, [r2]
/* Select normal operating mode. */
ldr r4, =EP93XX_SDRAMCTRL_GLOBALCFG_CKE
str r4, [r3, #SDRAM_OFF_GLCONFIG]
/* Return to the caller. */
mov pc, lr
/*
* Test to see if the SDRAM has been configured in a usable mode.
*
* Input: r0 - Test address of SDRAM
* Output: r0 - 0 -- Test OK, -1 -- Failed
* Modifies: r0-r5
*/
ep93xx_sdram_test:
/* Load the test patterns to be written to SDRAM. */
ldr r1, =0xf00dface
ldr r2, =0xdeadbeef
ldr r3, =0x08675309
ldr r4, =0xdeafc0ed
/* Store the test patterns to SDRAM. */
stmia r0, {r1-r4}
/* Load the test patterns from SDRAM one at a time and compare them
* to the actual pattern.
*/
ldr r5, [r0]
cmp r5, r1
ldreq r5, [r0, #0x0004]
cmpeq r5, r2
ldreq r5, [r0, #0x0008]
cmpeq r5, r3
ldreq r5, [r0, #0x000c]
cmpeq r5, r4
/* Return -1 if a mismatch was encountered, 0 otherwise. */
mvnne r0, #0xffffffff
moveq r0, #0x00000000
/* Return to the caller. */
mov pc, lr
/*
* Determine the size of the SDRAM. Use data=address for the scan.
*
* Input: r0 - Start SDRAM address
* Return: r0 - Single block size
* r1 - Valid block mask
* r2 - Total block count
* Modifies: r0-r5
*/
ep93xx_sdram_size:
/* Store zero at offset zero. */
str r0, [r0]
/* Start checking for an alias at 1MB into SDRAM. */
ldr r1, =0x00100000
/* Store the offset at the current offset. */
check_block_size:
str r1, [r0, r1]
/* Read back from zero. */
ldr r2, [r0]
/* Stop searching of an alias was found. */
cmp r1, r2
beq found_block_size
/* Advance to the next power of two boundary. */
mov r1, r1, lsl #1
/* Loop back if the size has not reached 256MB. */
cmp r1, #0x10000000
bne check_block_size
/* A full 256MB of memory was found, so return it now. */
ldr r0, =0x10000000
ldr r1, =0x00000000
ldr r2, =0x00000001
mov pc, lr
/* An alias was found. See if the first block is 128MB in size. */
found_block_size:
cmp r1, #0x08000000
/* The first block is 128MB, so there is no further memory. Return it
* now.
*/
ldreq r0, =0x08000000
ldreq r1, =0x00000000
ldreq r2, =0x00000001
moveq pc, lr
/* Save the block size, set the block address bits to zero, and
* initialize the block count to one.
*/
mov r3, r1
ldr r4, =0x00000000
ldr r5, =0x00000001
/* Look for additional blocks of memory by searching for non-aliases. */
find_blocks:
/* Store zero back to address zero. It may be overwritten. */
str r0, [r0]
/* Advance to the next power of two boundary. */
mov r1, r1, lsl #1
/* Store the offset at the current offset. */
str r1, [r0, r1]
/* Read back from zero. */
ldr r2, [r0]
/* See if a non-alias was found. */
cmp r1, r2
/* If a non-alias was found, then or in the block address bit and
* multiply the block count by two (since there are two unique
* blocks, one with this bit zero and one with it one).
*/
orrne r4, r4, r1
movne r5, r5, lsl #1
/* Continue searching if there are more address bits to check. */
cmp r1, #0x08000000
bne find_blocks
/* Return the block size, address mask, and count. */
mov r0, r3
mov r1, r4
mov r2, r5
/* Return to the caller. */
mov pc, lr
.globl lowlevel_init
lowlevel_init:
mov r6, lr
/* Make sure caches are off and invalidated. */
ldr r0, =0x00000000
mcr p15, 0, r0, c1, c0, 0
nop
nop
nop
nop
nop
/* Turn off the green LED and turn on the red LED. If the red LED
* is left on for too long, the external reset circuit described
* by application note AN258 will cause the system to reset.
*/
ldr r1, =EP93XX_LED_DATA
ldr r0, [r1]
bic r0, r0, #EP93XX_LED_GREEN_ON
orr r0, r0, #EP93XX_LED_RED_ON
str r0, [r1]
/* Undo the silly static memory controller programming performed
* by the boot rom.
*/
ldr r0, =SMC_BASE
/* Set WST1 and WST2 to 31 HCLK cycles (slowest access) */
ldr r1, =0x0000fbe0
/* Reset EP93XX_OFF_SMCBCR0 */
ldr r2, [r0]
orr r2, r2, r1
str r2, [r0]
ldr r2, [r0, #EP93XX_OFF_SMCBCR1]
orr r2, r2, r1
str r2, [r0, #EP93XX_OFF_SMCBCR1]
ldr r2, [r0, #EP93XX_OFF_SMCBCR2]
orr r2, r2, r1
str r2, [r0, #EP93XX_OFF_SMCBCR2]
ldr r2, [r0, #EP93XX_OFF_SMCBCR3]
orr r2, r2, r1
str r2, [r0, #EP93XX_OFF_SMCBCR3]
ldr r2, [r0, #EP93XX_OFF_SMCBCR6]
orr r2, r2, r1
str r2, [r0, #EP93XX_OFF_SMCBCR6]
ldr r2, [r0, #EP93XX_OFF_SMCBCR7]
orr r2, r2, r1
str r2, [r0, #EP93XX_OFF_SMCBCR7]
/* Set the PLL1 and processor clock. */
ldr r0, =SYSCON_BASE
#ifdef CONFIG_EDB9301
/* 332MHz, giving a 166MHz processor clock. */
ldr r1, = 0x02b49907
#else
#ifdef CONFIG_EDB93XX_INDUSTRIAL
/* 384MHz, giving a 196MHz processor clock. */
ldr r1, =0x02a4bb38
#else
/* 400MHz, giving a 200MHz processor clock. */
ldr r1, =0x02a4e39e
#endif
#endif
str r1, [r0, #SYSCON_OFF_CLKSET1]
nop
nop
nop
nop
nop
/* Need to make sure that SDRAM is configured correctly before
* coping the code into it.
*/
#ifdef CONFIG_EDB93XX_SDCS0
mov r11, #SDRAM_DEVCFG0_BASE
#endif
#ifdef CONFIG_EDB93XX_SDCS1
mov r11, #SDRAM_DEVCFG1_BASE
#endif
#ifdef CONFIG_EDB93XX_SDCS2
mov r11, #SDRAM_DEVCFG2_BASE
#endif
#ifdef CONFIG_EDB93XX_SDCS3
ldr r0, =SYSCON_BASE
ldr r0, [r0, #SYSCON_OFF_SYSCFG]
ands r0, r0, #SYSCON_SYSCFG_LASDO
moveq r11, #SDRAM_DEVCFG3_ASD0_BASE
movne r11, #SDRAM_DEVCFG3_ASD1_BASE
#endif
/* See Table 13-5 in EP93xx datasheet for more info about DRAM
* register mapping */
/* Try a 32-bit wide configuration of SDRAM. */
ldr r0, =(EP93XX_SDRAMCTRL_DEVCFG_BANKCOUNT | \
EP93XX_SDRAMCTRL_DEVCFG_SROMLL | \
EP93XX_SDRAMCTRL_DEVCFG_CASLAT_2 | \
EP93XX_SDRAMCTRL_DEVCFG_RASTOCAS_2)
/* Set burst count: 4 and CAS: 2
* Burst mode [A11:A10]; CAS [A16:A14]
*/
orr r2, r11, #0x00008800
bl ep93xx_sdram_config
/* Test the SDRAM. */
mov r0, r11
bl ep93xx_sdram_test
cmp r0, #0x00000000
beq ep93xx_sdram_done
/* Try a 16-bit wide configuration of SDRAM. */
ldr r0, =(EP93XX_SDRAMCTRL_DEVCFG_BANKCOUNT | \
EP93XX_SDRAMCTRL_DEVCFG_SROMLL | \
EP93XX_SDRAMCTRL_DEVCFG_CASLAT_2 | \
EP93XX_SDRAMCTRL_DEVCFG_RASTOCAS_2 | \
EP93XX_SDRAMCTRL_DEVCFG_EXTBUSWIDTH)
/* Set burst count: 8, CAS: 2, sequential burst
* Accoring to Table 13-3 for 16bit operations mapping must be shifted.
* Burst mode [A10:A9]; CAS [A15:A13]
*/
orr r2, r11, #0x00004600
bl ep93xx_sdram_config
/* Test the SDRAM. */
mov r0, r11
bl ep93xx_sdram_test
cmp r0, #0x00000000
beq ep93xx_sdram_done
/* Turn off the red LED. */
ldr r0, =EP93XX_LED_DATA
ldr r1, [r0]
bic r1, r1, #EP93XX_LED_RED_ON
str r1, [r0]
/* There is no SDRAM so flash the green LED. */
flash_green:
orr r1, r1, #EP93XX_LED_GREEN_ON
str r1, [r0]
ldr r2, =0x00010000
flash_green_delay_1:
subs r2, r2, #1
bne flash_green_delay_1
bic r1, r1, #EP93XX_LED_GREEN_ON
str r1, [r0]
ldr r2, =0x00010000
flash_green_delay_2:
subs r2, r2, #1
bne flash_green_delay_2
orr r1, r1, #EP93XX_LED_GREEN_ON
str r1, [r0]
ldr r2, =0x00010000
flash_green_delay_3:
subs r2, r2, #1
bne flash_green_delay_3
bic r1, r1, #EP93XX_LED_GREEN_ON
str r1, [r0]
ldr r2, =0x00050000
flash_green_delay_4:
subs r2, r2, #1
bne flash_green_delay_4
b flash_green
ep93xx_sdram_done:
ldr r1, =EP93XX_LED_DATA
ldr r0, [r1]
bic r0, r0, #EP93XX_LED_RED_ON
str r0, [r1]
/* Determine the size of the SDRAM. */
mov r0, r11
bl ep93xx_sdram_size
/* Save the SDRAM characteristics. */
mov r8, r0
mov r9, r1
mov r10, r2
/* Compute total memory size into r1 */
mul r1, r8, r10
#ifdef CONFIG_EDB93XX_SDCS0
ldr r2, [r0, #SDRAM_OFF_DEVCFG0]
#endif
#ifdef CONFIG_EDB93XX_SDCS1
ldr r2, [r0, #SDRAM_OFF_DEVCFG1]
#endif
#ifdef CONFIG_EDB93XX_SDCS2
ldr r2, [r0, #SDRAM_OFF_DEVCFG2]
#endif
#ifdef CONFIG_EDB93XX_SDCS3
ldr r2, [r0, #SDRAM_OFF_DEVCFG3]
#endif
/* Consider small DRAM size as:
* < 32Mb for 32bit bus
* < 64Mb for 16bit bus
*/
tst r2, #EP93XX_SDRAMCTRL_DEVCFG_EXTBUSWIDTH
moveq r1, r1, lsr #1
cmp r1, #0x02000000
#if defined(CONFIG_EDB9301)
/* Set refresh counter to 20ms for small DRAM size, otherwise 9.6ms */
movlt r1, #0x03f0
movge r1, #0x01e0
#else
/* Set refresh counter to 30.7ms for small DRAM size, otherwise 15ms */
movlt r1, #0x0600
movge r1, #0x2f0
#endif
str r1, [r0, #SDRAM_OFF_REFRSHTIMR]
/* Save the memory configuration information. */
orr r0, r11, #UBOOT_MEMORYCNF_BANK_SIZE
stmia r0, {r8-r11}
mov lr, r6
mov pc, lr
@@ -0,0 +1,95 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Cirrus Logic EP93xx PLL support.
*
* Copyright (C) 2009 Matthias Kaehlcke <matthias@kaehlcke.net>
*/
#include <common.h>
#include <asm/arch/ep93xx.h>
#include <asm/io.h>
#include <div64.h>
/*
* CONFIG_SYS_CLK_FREQ should be defined as the input frequency of the PLL.
*
* get_FCLK(), get_HCLK(), get_PCLK() and get_UCLK() return the clock of
* the specified bus in HZ.
*/
/*
* return the PLL output frequency
*
* PLL rate = CONFIG_SYS_CLK_FREQ * (X1FBD + 1) * (X2FBD + 1)
* / (X2IPD + 1) / 2^PS
*/
static ulong get_PLLCLK(uint32_t *pllreg)
{
uint8_t i;
const uint32_t clkset = readl(pllreg);
uint64_t rate = CONFIG_SYS_CLK_FREQ;
rate *= ((clkset >> SYSCON_CLKSET_PLL_X1FBD1_SHIFT) & 0x1f) + 1;
rate *= ((clkset >> SYSCON_CLKSET_PLL_X2FBD2_SHIFT) & 0x3f) + 1;
do_div(rate, (clkset & 0x1f) + 1); /* X2IPD */
for (i = 0; i < ((clkset >> SYSCON_CLKSET_PLL_PS_SHIFT) & 3); i++)
rate >>= 1;
return (ulong)rate;
}
/* return FCLK frequency */
ulong get_FCLK(void)
{
const uint8_t fclk_divisors[] = { 1, 2, 4, 8, 16, 1, 1, 1 };
struct syscon_regs *syscon = (struct syscon_regs *)SYSCON_BASE;
const uint32_t clkset1 = readl(&syscon->clkset1);
const uint8_t fclk_div =
fclk_divisors[(clkset1 >> SYSCON_CLKSET1_FCLK_DIV_SHIFT) & 7];
const ulong fclk_rate = get_PLLCLK(&syscon->clkset1) / fclk_div;
return fclk_rate;
}
/* return HCLK frequency */
ulong get_HCLK(void)
{
const uint8_t hclk_divisors[] = { 1, 2, 4, 5, 6, 8, 16, 32 };
struct syscon_regs *syscon = (struct syscon_regs *)SYSCON_BASE;
const uint32_t clkset1 = readl(&syscon->clkset1);
const uint8_t hclk_div =
hclk_divisors[(clkset1 >> SYSCON_CLKSET1_HCLK_DIV_SHIFT) & 7];
const ulong hclk_rate = get_PLLCLK(&syscon->clkset1) / hclk_div;
return hclk_rate;
}
/* return PCLK frequency */
ulong get_PCLK(void)
{
const uint8_t pclk_divisors[] = { 1, 2, 4, 8 };
struct syscon_regs *syscon = (struct syscon_regs *)SYSCON_BASE;
const uint32_t clkset1 = readl(&syscon->clkset1);
const uint8_t pclk_div =
pclk_divisors[(clkset1 >> SYSCON_CLKSET1_PCLK_DIV_SHIFT) & 3];
const ulong pclk_rate = get_HCLK() / pclk_div;
return pclk_rate;
}
/* return UCLK frequency */
ulong get_UCLK(void)
{
struct syscon_regs *syscon = (struct syscon_regs *)SYSCON_BASE;
ulong uclk_rate;
const uint32_t value = readl(&syscon->pwrcnt);
if (value & SYSCON_PWRCNT_UART_BAUD)
uclk_rate = CONFIG_SYS_CLK_FREQ;
else
uclk_rate = CONFIG_SYS_CLK_FREQ / 2;
return uclk_rate;
}
@@ -0,0 +1,115 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Cirrus Logic EP93xx timer support.
*
* Copyright (C) 2009, 2010 Matthias Kaehlcke <matthias@kaehlcke.net>
*
* Copyright (C) 2004, 2005
* Cory T. Tusar, Videon Central, Inc., <ctusar@videon-central.com>
*
* Based on the original intr.c Cirrus Logic EP93xx Rev D. interrupt support,
* author unknown.
*/
#include <common.h>
#include <time.h>
#include <linux/types.h>
#include <asm/arch/ep93xx.h>
#include <asm/io.h>
#include <div64.h>
#define TIMER_CLKSEL (1 << 3)
#define TIMER_ENABLE (1 << 7)
#define TIMER_FREQ 508469 /* ticks / second */
#define TIMER_MAX_VAL 0xFFFFFFFF
static struct ep93xx_timer
{
unsigned long long ticks;
unsigned long last_read;
} timer;
static inline unsigned long long usecs_to_ticks(unsigned long usecs)
{
unsigned long long ticks = (unsigned long long)usecs * TIMER_FREQ;
do_div(ticks, 1000 * 1000);
return ticks;
}
static inline void read_timer(void)
{
struct timer_regs *timer_regs = (struct timer_regs *)TIMER_BASE;
const unsigned long now = TIMER_MAX_VAL - readl(&timer_regs->timer3.value);
if (now >= timer.last_read)
timer.ticks += now - timer.last_read;
else
/* an overflow occurred */
timer.ticks += TIMER_MAX_VAL - timer.last_read + now;
timer.last_read = now;
}
/*
* Get the number of ticks (in CONFIG_SYS_HZ resolution)
*/
unsigned long long get_ticks(void)
{
unsigned long long sys_ticks;
read_timer();
sys_ticks = timer.ticks * CONFIG_SYS_HZ;
do_div(sys_ticks, TIMER_FREQ);
return sys_ticks;
}
unsigned long get_timer(unsigned long base)
{
return get_ticks() - base;
}
void __udelay(unsigned long usec)
{
unsigned long long target;
read_timer();
target = timer.ticks + usecs_to_ticks(usec);
while (timer.ticks < target)
read_timer();
}
int timer_init(void)
{
struct timer_regs *timer_regs = (struct timer_regs *)TIMER_BASE;
/* use timer 3 with 508KHz and free running, not enabled now */
writel(TIMER_CLKSEL, &timer_regs->timer3.control);
/* set initial timer value */
writel(TIMER_MAX_VAL, &timer_regs->timer3.load);
/* Enable the timer */
writel(TIMER_ENABLE | TIMER_CLKSEL,
&timer_regs->timer3.control);
/* Reset the timer */
read_timer();
timer.ticks = 0;
return 0;
}
/*
* This function is derived from PowerPC code (timebase clock frequency).
* On ARM it returns the number of timer ticks per second.
*/
unsigned long get_tbclk(void)
{
return CONFIG_SYS_HZ;
}
@@ -0,0 +1,8 @@
# SPDX-License-Identifier: GPL-2.0+
#
# (C) Copyright 2000-2006
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
obj-y += generic.o
obj-y += speed.o
obj-y += timer.o
@@ -0,0 +1,76 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* arch/arm/mach-imx/generic.c
*
* author: Sascha Hauer
* Created: april 20th, 2004
* Copyright: Synertronixx GmbH
*
* Common code for i.MX machines
*/
#include <common.h>
#ifdef CONFIG_IMX
#include <asm/arch/imx-regs.h>
void imx_gpio_mode(int gpio_mode)
{
unsigned int pin = gpio_mode & GPIO_PIN_MASK;
unsigned int port = (gpio_mode & GPIO_PORT_MASK) >> 5;
unsigned int ocr = (gpio_mode & GPIO_OCR_MASK) >> 10;
unsigned int tmp;
/* Pullup enable */
if(gpio_mode & GPIO_PUEN)
PUEN(port) |= (1<<pin);
else
PUEN(port) &= ~(1<<pin);
/* Data direction */
if(gpio_mode & GPIO_OUT)
DDIR(port) |= 1<<pin;
else
DDIR(port) &= ~(1<<pin);
/* Primary / alternate function */
if(gpio_mode & GPIO_AF)
GPR(port) |= (1<<pin);
else
GPR(port) &= ~(1<<pin);
/* use as gpio? */
if( ocr == 3 )
GIUS(port) |= (1<<pin);
else
GIUS(port) &= ~(1<<pin);
/* Output / input configuration */
/* FIXME: I'm not very sure about OCR and ICONF, someone
* should have a look over it
*/
if(pin<16) {
tmp = OCR1(port);
tmp &= ~( 3<<(pin*2));
tmp |= (ocr << (pin*2));
OCR1(port) = tmp;
if( gpio_mode & GPIO_AOUT )
ICONFA1(port) &= ~( 3<<(pin*2));
if( gpio_mode & GPIO_BOUT )
ICONFB1(port) &= ~( 3<<(pin*2));
} else {
tmp = OCR2(port);
tmp &= ~( 3<<((pin-16)*2));
tmp |= (ocr << ((pin-16)*2));
OCR2(port) = tmp;
if( gpio_mode & GPIO_AOUT )
ICONFA2(port) &= ~( 3<<((pin-16)*2));
if( gpio_mode & GPIO_BOUT )
ICONFB2(port) &= ~( 3<<((pin-16)*2));
}
}
#endif /* CONFIG_IMX */
@@ -0,0 +1,85 @@
// SPDX-License-Identifier: GPL-2.0+
/*
*
* (c) 2004 Sascha Hauer <sascha@saschahauer.de>
*/
#include <common.h>
#if defined (CONFIG_IMX)
#include <asm/arch/imx-regs.h>
/* ------------------------------------------------------------------------- */
/* NOTE: This describes the proper use of this file.
*
* CONFIG_SYS_CLK_FREQ should be defined as the input frequency of the PLL.
* SH FIXME: 16780000 in our case
* get_FCLK(), get_HCLK(), get_PCLK() and get_UCLK() return the clock of
* the specified bus in HZ.
*/
/* ------------------------------------------------------------------------- */
ulong get_systemPLLCLK(void)
{
/* FIXME: We assume System_SEL = 0 here */
u32 spctl0 = SPCTL0;
u32 mfi = (spctl0 >> 10) & 0xf;
u32 mfn = spctl0 & 0x3f;
u32 mfd = (spctl0 >> 16) & 0x3f;
u32 pd = (spctl0 >> 26) & 0xf;
mfi = mfi<=5 ? 5 : mfi;
return (2*(CONFIG_SYSPLL_CLK_FREQ>>10)*( (mfi<<10) + (mfn<<10)/(mfd+1)))/(pd+1);
}
ulong get_mcuPLLCLK(void)
{
/* FIXME: We assume System_SEL = 0 here */
u32 mpctl0 = MPCTL0;
u32 mfi = (mpctl0 >> 10) & 0xf;
u32 mfn = mpctl0 & 0x3f;
u32 mfd = (mpctl0 >> 16) & 0x3f;
u32 pd = (mpctl0 >> 26) & 0xf;
mfi = mfi<=5 ? 5 : mfi;
return (2*(CONFIG_SYS_CLK_FREQ>>10)*( (mfi<<10) + (mfn<<10)/(mfd+1)))/(pd+1);
}
ulong get_FCLK(void)
{
return (( CSCR>>15)&1) ? get_mcuPLLCLK()>>1 : get_mcuPLLCLK();
}
/* return HCLK frequency */
ulong get_HCLK(void)
{
u32 bclkdiv = (( CSCR >> 10 ) & 0xf) + 1;
printf("bclkdiv: %d\n", bclkdiv);
return get_systemPLLCLK() / bclkdiv;
}
/* return BCLK frequency */
ulong get_BCLK(void)
{
return get_HCLK();
}
ulong get_PERCLK1(void)
{
return get_systemPLLCLK() / (((PCDR) & 0xf)+1);
}
ulong get_PERCLK2(void)
{
return get_systemPLLCLK() / (((PCDR>>4) & 0xf)+1);
}
ulong get_PERCLK3(void)
{
return get_systemPLLCLK() / (((PCDR>>16) & 0x7f)+1);
}
#endif /* defined (CONFIG_IMX) */
@@ -0,0 +1,98 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2002
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
* Marius Groeger <mgroeger@sysgo.de>
*
* (C) Copyright 2002
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
* Alex Zuepke <azu@sysgo.de>
*
* (C) Copyright 2002
* Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
*/
#include <common.h>
#include <time.h>
#if defined (CONFIG_IMX)
#include <asm/arch/imx-regs.h>
int timer_init (void)
{
int i;
/* setup GP Timer 1 */
TCTL1 = TCTL_SWR;
for ( i=0; i<100; i++) TCTL1 = 0; /* We have no udelay by now */
TPRER1 = get_PERCLK1() / 1000000; /* 1 MHz */
TCTL1 |= TCTL_FRR | (1<<1); /* Freerun Mode, PERCLK1 input */
/* Reset the timer */
TCTL1 &= ~TCTL_TEN;
TCTL1 |= TCTL_TEN; /* Enable timer */
return (0);
}
/*
* timer without interrupts
*/
static ulong get_timer_masked (void)
{
return TCN1;
}
ulong get_timer (ulong base)
{
return get_timer_masked() - base;
}
void __udelay (unsigned long usec)
{
ulong endtime = get_timer_masked() + usec;
signed long diff;
do {
ulong now = get_timer_masked ();
diff = endtime - now;
} while (diff >= 0);
}
/*
* This function is derived from PowerPC code (read timebase as long long).
* On ARM it just returns the timer value.
*/
unsigned long long get_ticks(void)
{
return get_timer(0);
}
/*
* This function is derived from PowerPC code (timebase clock frequency).
* On ARM it returns the number of timer ticks per second.
*/
ulong get_tbclk (void)
{
return CONFIG_SYS_HZ;
}
/*
* Reset the cpu by setting up the watchdog timer and let him time out
*/
void reset_cpu (ulong ignored)
{
/* Disable watchdog and set Time-Out field to 0 */
WCR = 0x00000000;
/* Write Service Sequence */
WSR = 0x00005555;
WSR = 0x0000AAAA;
/* Enable watchdog */
WCR = 0x00000001;
while (1);
/*NOTREACHED*/
}
#endif /* defined (CONFIG_IMX) */
@@ -0,0 +1,112 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* armboot - Startup Code for ARM920 CPU-core
*
* Copyright (c) 2001 Marius Gröger <mag@sysgo.de>
* Copyright (c) 2002 Alex Züpke <azu@sysgo.de>
* Copyright (c) 2002 Gary Jennejohn <garyj@denx.de>
*/
#include <asm-offsets.h>
#include <common.h>
#include <config.h>
/*
*************************************************************************
*
* Startup Code (called from the ARM reset exception vector)
*
* do important init only if we don't start from memory!
* relocate armboot to ram
* setup stack
* jump to second stage
*
*************************************************************************
*/
.globl reset
reset:
/*
* set the cpu to SVC32 mode
*/
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0xd3
msr cpsr, r0
#if defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK)
/*
* relocate exception table
*/
ldr r0, =_start
ldr r1, =0x0
mov r2, #16
copyex:
subs r2, r2, #1
ldr r3, [r0], #4
str r3, [r1], #4
bne copyex
#endif
/*
* we do sys-critical inits only at reboot,
* not when booting from ram!
*/
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_crit
#endif
bl _main
/*------------------------------------------------------------------------------*/
.globl c_runtime_cpu_setup
c_runtime_cpu_setup:
mov pc, lr
/*
*************************************************************************
*
* CPU_init_critical registers
*
* setup important registers
* setup memory timing
*
*************************************************************************
*/
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
cpu_init_crit:
/*
* flush v4 I/D caches
*/
mov r0, #0
mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */
mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */
/*
* disable MMU stuff and caches
*/
mrc p15, 0, r0, c1, c0, 0
bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS)
bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM)
orr r0, r0, #0x00000002 @ set bit 1 (A) Align
orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache
mcr p15, 0, r0, c1, c0, 0
#ifndef CONFIG_SKIP_LOWLEVEL_INIT_ONLY
/*
* before relocating, we have to setup RAM timing
* because memory timing is board-dependend, you will
* find a lowlevel_init.S in your board directory.
*/
mov ip, lr
bl lowlevel_init
mov lr, ip
#endif
mov pc, lr
#endif /* CONFIG_SKIP_LOWLEVEL_INIT */
@@ -0,0 +1,31 @@
# SPDX-License-Identifier: GPL-2.0+
#
# (C) Copyright 2000-2006
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
extra-y = start.o
obj-y = cpu.o cache.o
ifdef CONFIG_SPL_BUILD
ifdef CONFIG_SPL_NO_CPU_SUPPORT
extra-y :=
endif
endif
obj-$(CONFIG_ARMADA100) += armada100/
obj-$(if $(filter lpc32xx,$(SOC)),y) += lpc32xx/
obj-$(CONFIG_MX25) += mx25/
obj-$(CONFIG_MX27) += mx27/
obj-$(if $(filter mxs,$(SOC)),y) += mxs/
obj-$(if $(filter spear,$(SOC)),y) += spear/
# some files can only build in ARM or THUMB2, not THUMB1
ifdef CONFIG_$(SPL_)SYS_THUMB_BUILD
ifndef CONFIG_HAS_THUMB2
CFLAGS_cpu.o := -marm
CFLAGS_cache.o := -marm
endif
endif
@@ -0,0 +1,7 @@
# SPDX-License-Identifier: GPL-2.0+
#
# (C) Copyright 2010
# Marvell Semiconductor <www.marvell.com>
# Written-by: Prafulla Wadaskar <prafulla@marvell.com>
obj-y = cpu.o timer.o dram.o
@@ -0,0 +1,92 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2010
* Marvell Semiconductor <www.marvell.com>
* Written-by: Prafulla Wadaskar <prafulla@marvell.com>
* Contributor: Mahavir Jain <mjain@marvell.com>
*/
#include <common.h>
#include <cpu_func.h>
#include <asm/arch/cpu.h>
#include <asm/arch/armada100.h>
#define UARTCLK14745KHZ (APBC_APBCLK | APBC_FNCLK | APBC_FNCLKSEL(1))
#define SET_MRVL_ID (1<<8)
#define L2C_RAM_SEL (1<<4)
int arch_cpu_init(void)
{
u32 val;
struct armd1cpu_registers *cpuregs =
(struct armd1cpu_registers *) ARMD1_CPU_BASE;
struct armd1apb1_registers *apb1clkres =
(struct armd1apb1_registers *) ARMD1_APBC1_BASE;
struct armd1mpmu_registers *mpmu =
(struct armd1mpmu_registers *) ARMD1_MPMU_BASE;
/* set SEL_MRVL_ID bit in ARMADA100_CPU_CONF register */
val = readl(&cpuregs->cpu_conf);
val = val | SET_MRVL_ID;
writel(val, &cpuregs->cpu_conf);
/* Enable Clocks for all hardware units */
writel(0xFFFFFFFF, &mpmu->acgr);
/* Turn on AIB and AIB-APB Functional clock */
writel(APBC_APBCLK | APBC_FNCLK, &apb1clkres->aib);
/* ensure L2 cache is not mapped as SRAM */
val = readl(&cpuregs->cpu_conf);
val = val & ~(L2C_RAM_SEL);
writel(val, &cpuregs->cpu_conf);
/* Enable GPIO clock */
writel(APBC_APBCLK, &apb1clkres->gpio);
#ifdef CONFIG_I2C_MV
/* Enable general I2C clock */
writel(APBC_RST | APBC_FNCLK | APBC_APBCLK, &apb1clkres->twsi0);
writel(APBC_FNCLK | APBC_APBCLK, &apb1clkres->twsi0);
/* Enable power I2C clock */
writel(APBC_RST | APBC_FNCLK | APBC_APBCLK, &apb1clkres->twsi1);
writel(APBC_FNCLK | APBC_APBCLK, &apb1clkres->twsi1);
#endif
/*
* Enable Functional and APB clock at 14.7456MHz
* for configured UART console
*/
#if (CONFIG_SYS_NS16550_COM1 == ARMD1_UART3_BASE)
writel(UARTCLK14745KHZ, &apb1clkres->uart3);
#elif (CONFIG_SYS_NS16550_COM1 == ARMD1_UART2_BASE)
writel(UARTCLK14745KHZ, &apb1clkres->uart2);
#else
writel(UARTCLK14745KHZ, &apb1clkres->uart1);
#endif
icache_enable();
return 0;
}
#if defined(CONFIG_DISPLAY_CPUINFO)
int print_cpuinfo(void)
{
u32 id;
struct armd1cpu_registers *cpuregs =
(struct armd1cpu_registers *) ARMD1_CPU_BASE;
id = readl(&cpuregs->chip_id);
printf("SoC: Armada 88AP%X-%X\n", (id & 0xFFF), (id >> 0x10));
return 0;
}
#endif
#ifdef CONFIG_I2C_MV
void i2c_clk_enable(void)
{
}
#endif
@@ -0,0 +1,115 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2010
* Marvell Semiconductor <www.marvell.com>
* Written-by: Prafulla Wadaskar <prafulla@marvell.com>,
* Contributor: Mahavir Jain <mjain@marvell.com>
*/
#include <common.h>
#include <asm/io.h>
#include <asm/arch/armada100.h>
DECLARE_GLOBAL_DATA_PTR;
/*
* ARMADA100 DRAM controller supports upto 8 banks
* for chip select 0 and 1
*/
/*
* DDR Memory Control Registers
* Refer Datasheet Appendix A.17
*/
struct armd1ddr_map_registers {
u32 cs; /* Memory Address Map Register -CS */
u32 pad[3];
};
struct armd1ddr_registers {
u8 pad[0x100 - 0x000];
struct armd1ddr_map_registers mmap[2];
};
/*
* armd1_sdram_base - reads SDRAM Base Address Register
*/
u32 armd1_sdram_base(int chip_sel)
{
struct armd1ddr_registers *ddr_regs =
(struct armd1ddr_registers *)ARMD1_DRAM_BASE;
u32 result = 0;
u32 CS_valid = 0x01 & readl(&ddr_regs->mmap[chip_sel].cs);
if (!CS_valid)
return 0;
result = readl(&ddr_regs->mmap[chip_sel].cs) & 0xFF800000;
return result;
}
/*
* armd1_sdram_size - reads SDRAM size
*/
u32 armd1_sdram_size(int chip_sel)
{
struct armd1ddr_registers *ddr_regs =
(struct armd1ddr_registers *)ARMD1_DRAM_BASE;
u32 result = 0;
u32 CS_valid = 0x01 & readl(&ddr_regs->mmap[chip_sel].cs);
if (!CS_valid)
return 0;
result = readl(&ddr_regs->mmap[chip_sel].cs);
result = (result >> 16) & 0xF;
if (result < 0x7) {
printf("Unknown DRAM Size\n");
return -1;
} else {
return ((0x8 << (result - 0x7)) * 1024 * 1024);
}
}
int dram_init(void)
{
int i;
gd->ram_size = 0;
for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
gd->bd->bi_dram[i].start = armd1_sdram_base(i);
gd->bd->bi_dram[i].size = armd1_sdram_size(i);
/*
* It is assumed that all memory banks are consecutive
* and without gaps.
* If the gap is found, ram_size will be reported for
* consecutive memory only
*/
if (gd->bd->bi_dram[i].start != gd->ram_size)
break;
gd->ram_size += gd->bd->bi_dram[i].size;
}
for (; i < CONFIG_NR_DRAM_BANKS; i++) {
/* If above loop terminated prematurely, we need to set
* remaining banks' start address & size as 0. Otherwise other
* u-boot functions and Linux kernel gets wrong values which
* could result in crash */
gd->bd->bi_dram[i].start = 0;
gd->bd->bi_dram[i].size = 0;
}
return 0;
}
/*
* If this function is not defined here,
* board.c alters dram bank zero configuration defined above.
*/
int dram_init_banksize(void)
{
dram_init();
return 0;
}
@@ -0,0 +1,194 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2010
* Marvell Semiconductor <www.marvell.com>
* Written-by: Prafulla Wadaskar <prafulla@marvell.com>
* Contributor: Mahavir Jain <mjain@marvell.com>
*/
#include <common.h>
#include <time.h>
#include <asm/arch/cpu.h>
#include <asm/arch/armada100.h>
/*
* Timer registers
* Refer Section A.6 in Datasheet
*/
struct armd1tmr_registers {
u32 clk_ctrl; /* Timer clk control reg */
u32 match[9]; /* Timer match registers */
u32 count[3]; /* Timer count registers */
u32 status[3];
u32 ie[3];
u32 preload[3]; /* Timer preload value */
u32 preload_ctrl[3];
u32 wdt_match_en;
u32 wdt_match_r;
u32 wdt_val;
u32 wdt_sts;
u32 icr[3];
u32 wdt_icr;
u32 cer; /* Timer count enable reg */
u32 cmr;
u32 ilr[3];
u32 wcr;
u32 wfar;
u32 wsar;
u32 cvwr;
};
#define TIMER 0 /* Use TIMER 0 */
/* Each timer has 3 match registers */
#define MATCH_CMP(x) ((3 * TIMER) + x)
#define TIMER_LOAD_VAL 0xffffffff
#define COUNT_RD_REQ 0x1
DECLARE_GLOBAL_DATA_PTR;
/* Using gd->arch.tbu from timestamp and gd->arch.tbl for lastdec */
/* For preventing risk of instability in reading counter value,
* first set read request to register cvwr and then read same
* register after it captures counter value.
*/
ulong read_timer(void)
{
struct armd1tmr_registers *armd1timers =
(struct armd1tmr_registers *) ARMD1_TIMER_BASE;
volatile int loop=100;
writel(COUNT_RD_REQ, &armd1timers->cvwr);
while (loop--);
return(readl(&armd1timers->cvwr));
}
static ulong get_timer_masked(void)
{
ulong now = read_timer();
if (now >= gd->arch.tbl) {
/* normal mode */
gd->arch.tbu += now - gd->arch.tbl;
} else {
/* we have an overflow ... */
gd->arch.tbu += now + TIMER_LOAD_VAL - gd->arch.tbl;
}
gd->arch.tbl = now;
return gd->arch.tbu;
}
ulong get_timer(ulong base)
{
return ((get_timer_masked() / (CONFIG_SYS_HZ_CLOCK / 1000)) -
base);
}
void __udelay(unsigned long usec)
{
ulong delayticks;
ulong endtime;
delayticks = (usec * (CONFIG_SYS_HZ_CLOCK / 1000000));
endtime = get_timer_masked() + delayticks;
while (get_timer_masked() < endtime);
}
/*
* init the Timer
*/
int timer_init(void)
{
struct armd1apb1_registers *apb1clkres =
(struct armd1apb1_registers *) ARMD1_APBC1_BASE;
struct armd1tmr_registers *armd1timers =
(struct armd1tmr_registers *) ARMD1_TIMER_BASE;
/* Enable Timer clock at 3.25 MHZ */
writel(APBC_APBCLK | APBC_FNCLK | APBC_FNCLKSEL(3), &apb1clkres->timers);
/* load value into timer */
writel(0x0, &armd1timers->clk_ctrl);
/* Use Timer 0 Match Resiger 0 */
writel(TIMER_LOAD_VAL, &armd1timers->match[MATCH_CMP(0)]);
/* Preload value is 0 */
writel(0x0, &armd1timers->preload[TIMER]);
/* Enable match comparator 0 for Timer 0 */
writel(0x1, &armd1timers->preload_ctrl[TIMER]);
/* Enable timer 0 */
writel(0x1, &armd1timers->cer);
/* init the gd->arch.tbu and gd->arch.tbl value */
gd->arch.tbl = read_timer();
gd->arch.tbu = 0;
return 0;
}
#define MPMU_APRR_WDTR (1<<4)
#define TMR_WFAR 0xbaba /* WDT Register First key */
#define TMP_WSAR 0xeb10 /* WDT Register Second key */
/*
* This function uses internal Watchdog Timer
* based reset mechanism.
* Steps to write watchdog registers (protected access)
* 1. Write key value to TMR_WFAR reg.
* 2. Write key value to TMP_WSAR reg.
* 3. Perform write operation.
*/
void reset_cpu (unsigned long ignored)
{
struct armd1mpmu_registers *mpmu =
(struct armd1mpmu_registers *) ARMD1_MPMU_BASE;
struct armd1tmr_registers *armd1timers =
(struct armd1tmr_registers *) ARMD1_TIMER_BASE;
u32 val;
/* negate hardware reset to the WDT after system reset */
val = readl(&mpmu->aprr);
val = val | MPMU_APRR_WDTR;
writel(val, &mpmu->aprr);
/* reset/enable WDT clock */
writel(APBC_APBCLK | APBC_FNCLK | APBC_RST, &mpmu->wdtpcr);
readl(&mpmu->wdtpcr);
writel(APBC_APBCLK | APBC_FNCLK, &mpmu->wdtpcr);
readl(&mpmu->wdtpcr);
/* clear previous WDT status */
writel(TMR_WFAR, &armd1timers->wfar);
writel(TMP_WSAR, &armd1timers->wsar);
writel(0, &armd1timers->wdt_sts);
/* set match counter */
writel(TMR_WFAR, &armd1timers->wfar);
writel(TMP_WSAR, &armd1timers->wsar);
writel(0xf, &armd1timers->wdt_match_r);
/* enable WDT reset */
writel(TMR_WFAR, &armd1timers->wfar);
writel(TMP_WSAR, &armd1timers->wsar);
writel(0x3, &armd1timers->wdt_match_en);
while(1);
}
/*
* This function is derived from PowerPC code (read timebase as long long).
* On ARM it just returns the timer value.
*/
unsigned long long get_ticks(void)
{
return get_timer(0);
}
/*
* This function is derived from PowerPC code (timebase clock frequency).
* On ARM it returns the number of timer ticks per second.
*/
ulong get_tbclk (void)
{
return (ulong)CONFIG_SYS_HZ;
}
@@ -0,0 +1,91 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2011
* Ilya Yanok, EmCraft Systems
*/
#include <cpu_func.h>
#include <linux/types.h>
#include <common.h>
#if !CONFIG_IS_ENABLED(SYS_DCACHE_OFF)
void invalidate_dcache_all(void)
{
asm volatile("mcr p15, 0, %0, c7, c6, 0\n" : : "r"(0));
}
void flush_dcache_all(void)
{
asm volatile(
"0:"
"mrc p15, 0, r15, c7, c14, 3\n"
"bne 0b\n"
"mcr p15, 0, %0, c7, c10, 4\n"
: : "r"(0) : "memory"
);
}
void invalidate_dcache_range(unsigned long start, unsigned long stop)
{
if (!check_cache_range(start, stop))
return;
while (start < stop) {
asm volatile("mcr p15, 0, %0, c7, c6, 1\n" : : "r"(start));
start += CONFIG_SYS_CACHELINE_SIZE;
}
}
void flush_dcache_range(unsigned long start, unsigned long stop)
{
if (!check_cache_range(start, stop))
return;
while (start < stop) {
asm volatile("mcr p15, 0, %0, c7, c14, 1\n" : : "r"(start));
start += CONFIG_SYS_CACHELINE_SIZE;
}
asm volatile("mcr p15, 0, %0, c7, c10, 4\n" : : "r"(0));
}
#else /* #if !CONFIG_IS_ENABLED(SYS_DCACHE_OFF) */
void invalidate_dcache_all(void)
{
}
void flush_dcache_all(void)
{
}
#endif /* #if !CONFIG_IS_ENABLED(SYS_DCACHE_OFF) */
/*
* Stub implementations for l2 cache operations
*/
__weak void l2_cache_disable(void) {}
#if CONFIG_IS_ENABLED(SYS_THUMB_BUILD)
__weak void invalidate_l2_cache(void) {}
#endif
#if !CONFIG_IS_ENABLED(SYS_ICACHE_OFF)
/* Invalidate entire I-cache and branch predictor array */
void invalidate_icache_all(void)
{
unsigned long i = 0;
asm ("mcr p15, 0, %0, c7, c5, 0" : : "r" (i));
}
#else
void invalidate_icache_all(void) {}
#endif
void enable_caches(void)
{
#if !CONFIG_IS_ENABLED(SYS_ICACHE_OFF)
icache_enable();
#endif
#if !CONFIG_IS_ENABLED(SYS_DCACHE_OFF)
dcache_enable();
#endif
}
@@ -0,0 +1,54 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2002
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
* Marius Groeger <mgroeger@sysgo.de>
*
* (C) Copyright 2002
* Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
*/
/*
* CPU specific code
*/
#include <common.h>
#include <command.h>
#include <cpu_func.h>
#include <irq_func.h>
#include <asm/system.h>
static void cache_flush(void);
int cleanup_before_linux (void)
{
/*
* this function is called just before we call linux
* it prepares the processor for linux
*
* we turn off caches etc ...
*/
disable_interrupts();
/* turn off I/D-cache */
icache_disable();
dcache_disable();
l2_cache_disable();
/* flush I/D-cache */
cache_flush();
return 0;
}
/* flush I/D-cache */
static void cache_flush (void)
{
#if !(CONFIG_IS_ENABLED(SYS_ICACHE_OFF) && CONFIG_IS_ENABLED(SYS_DCACHE_OFF))
unsigned long i = 0;
asm ("mcr p15, 0, %0, c7, c7, 0": :"r" (i));
#endif
}
@@ -0,0 +1,20 @@
if ARCH_LPC32XX
config SYS_SOC
default "lpc32xx"
choice
prompt "NXP LPC32xx board select"
config TARGET_DEVKIT3250
bool "Timll DevKit3250"
config TARGET_WORK_92105
bool "Work Microwave Work_92105"
endchoice
source "board/timll/devkit3250/Kconfig"
source "board/work-microwave/work_92105/Kconfig"
endif
@@ -0,0 +1,8 @@
# SPDX-License-Identifier: GPL-2.0+
#
# (C) Copyright 2000-2006
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
obj-y = cpu.o clk.o devices.o timer.o
obj-$(CONFIG_SPL_BUILD) += dram.o lowlevel_init.o
@@ -0,0 +1,137 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2011 by Vladimir Zapolskiy <vz@mleia.com>
*/
#include <common.h>
#include <div64.h>
#include <asm/arch/cpu.h>
#include <asm/arch/clk.h>
#include <asm/io.h>
static struct clk_pm_regs *clk = (struct clk_pm_regs *)CLK_PM_BASE;
unsigned int get_sys_clk_rate(void)
{
if (readl(&clk->sysclk_ctrl) & CLK_SYSCLK_PLL397)
return RTC_CLK_FREQUENCY * 397;
else
return OSC_CLK_FREQUENCY;
}
unsigned int get_hclk_pll_rate(void)
{
unsigned long long fin, fref, fcco, fout;
u32 val, m_div, n_div, p_div;
/*
* Valid frequency ranges:
* 1 * 10^6 <= Fin <= 20 * 10^6
* 1 * 10^6 <= Fref <= 27 * 10^6
* 156 * 10^6 <= Fcco <= 320 * 10^6
*/
fref = fin = get_sys_clk_rate();
if (fin > 20000000ULL || fin < 1000000ULL)
return 0;
val = readl(&clk->hclkpll_ctrl);
m_div = ((val & CLK_HCLK_PLL_FEEDBACK_DIV_MASK) >> 1) + 1;
n_div = ((val & CLK_HCLK_PLL_PREDIV_MASK) >> 9) + 1;
if (val & CLK_HCLK_PLL_DIRECT)
p_div = 0;
else
p_div = ((val & CLK_HCLK_PLL_POSTDIV_MASK) >> 11) + 1;
p_div = 1 << p_div;
if (val & CLK_HCLK_PLL_BYPASS) {
do_div(fin, p_div);
return fin;
}
do_div(fref, n_div);
if (fref > 27000000ULL || fref < 1000000ULL)
return 0;
fcco = fref * m_div;
fout = fcco;
if (val & CLK_HCLK_PLL_FEEDBACK)
fcco *= p_div;
else
do_div(fout, p_div);
if (fcco > 320000000ULL || fcco < 156000000ULL)
return 0;
return fout;
}
unsigned int get_hclk_clk_div(void)
{
u32 val;
val = readl(&clk->hclkdiv_ctrl) & CLK_HCLK_ARM_PLL_DIV_MASK;
return 1 << val;
}
unsigned int get_hclk_clk_rate(void)
{
return get_hclk_pll_rate() / get_hclk_clk_div();
}
unsigned int get_periph_clk_div(void)
{
u32 val;
val = readl(&clk->hclkdiv_ctrl) & CLK_HCLK_PERIPH_DIV_MASK;
return (val >> 2) + 1;
}
unsigned int get_periph_clk_rate(void)
{
if (!(readl(&clk->pwr_ctrl) & CLK_PWR_NORMAL_RUN))
return get_sys_clk_rate();
return get_hclk_pll_rate() / get_periph_clk_div();
}
unsigned int get_sdram_clk_rate(void)
{
unsigned int src_clk;
if (!(readl(&clk->pwr_ctrl) & CLK_PWR_NORMAL_RUN))
return get_sys_clk_rate();
src_clk = get_hclk_pll_rate();
if (readl(&clk->sdramclk_ctrl) & CLK_SDRAM_DDR_SEL) {
/* using DDR */
switch (readl(&clk->hclkdiv_ctrl) & CLK_HCLK_DDRAM_MASK) {
case CLK_HCLK_DDRAM_HALF:
return src_clk/2;
case CLK_HCLK_DDRAM_NOMINAL:
return src_clk;
default:
return 0;
}
} else {
/* using SDR */
switch (readl(&clk->hclkdiv_ctrl) & CLK_HCLK_ARM_PLL_DIV_MASK) {
case CLK_HCLK_ARM_PLL_DIV_4:
return src_clk/4;
case CLK_HCLK_ARM_PLL_DIV_2:
return src_clk/2;
case CLK_HCLK_ARM_PLL_DIV_1:
return src_clk;
default:
return 0;
}
}
}
int get_serial_clock(void)
{
return get_periph_clk_rate();
}
@@ -0,0 +1,78 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2011-2015 by Vladimir Zapolskiy <vz@mleia.com>
*/
#include <common.h>
#include <cpu_func.h>
#include <netdev.h>
#include <asm/arch/cpu.h>
#include <asm/arch/clk.h>
#include <asm/arch/wdt.h>
#include <asm/arch/sys_proto.h>
#include <asm/io.h>
static struct clk_pm_regs *clk = (struct clk_pm_regs *)CLK_PM_BASE;
static struct wdt_regs *wdt = (struct wdt_regs *)WDT_BASE;
void reset_cpu(ulong addr)
{
/* Enable watchdog clock */
setbits_le32(&clk->timclk_ctrl, CLK_TIMCLK_WATCHDOG);
/* To be compatible with the original U-Boot code:
* addr: - 0: perform hard reset.
* - !=0: perform a soft reset; i.e. "RESOUT_N" not asserted). */
if (addr == 0) {
/* Reset pulse length is 13005 peripheral clock frames */
writel(13000, &wdt->pulse);
/* Force WDOG_RESET2 and RESOUT_N signal active */
writel(WDTIM_MCTRL_RESFRC2 | WDTIM_MCTRL_RESFRC1
| WDTIM_MCTRL_M_RES2, &wdt->mctrl);
} else {
/* Force match output active */
writel(0x01, &wdt->emr);
/* Internal reset on match output (no pulse on "RESOUT_N") */
writel(WDTIM_MCTRL_M_RES1, &wdt->mctrl);
}
while (1)
/* NOP */;
}
#if defined(CONFIG_ARCH_CPU_INIT)
int arch_cpu_init(void)
{
/*
* It might be necessary to flush data cache, if U-Boot is loaded
* from kickstart bootloader, e.g. from S1L loader
*/
flush_dcache_all();
return 0;
}
#else
#error "You have to select CONFIG_ARCH_CPU_INIT"
#endif
#if defined(CONFIG_DISPLAY_CPUINFO)
int print_cpuinfo(void)
{
printf("CPU: NXP LPC32XX\n");
printf("CPU clock: %uMHz\n", get_hclk_pll_rate() / 1000000);
printf("AHB bus clock: %uMHz\n", get_hclk_clk_rate() / 1000000);
printf("Peripheral clock: %uMHz\n", get_periph_clk_rate() / 1000000);
return 0;
}
#endif
#ifdef CONFIG_LPC32XX_ETH
int cpu_eth_init(bd_t *bis)
{
lpc32xx_eth_initialize(bis);
return 0;
}
#endif
@@ -0,0 +1,141 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2011 by Vladimir Zapolskiy <vz@mleia.com>
*/
#include <common.h>
#include <dm.h>
#include <ns16550.h>
#include <dm/platform_data/lpc32xx_hsuart.h>
#include <asm/arch/clk.h>
#include <asm/arch/uart.h>
#include <asm/arch/mux.h>
#include <asm/io.h>
static struct clk_pm_regs *clk = (struct clk_pm_regs *)CLK_PM_BASE;
static struct uart_ctrl_regs *ctrl = (struct uart_ctrl_regs *)UART_CTRL_BASE;
static struct mux_regs *mux = (struct mux_regs *)MUX_BASE;
void lpc32xx_uart_init(unsigned int uart_id)
{
if (uart_id < 1 || uart_id > 7)
return;
/* Disable loopback mode, if it is set by S1L bootloader */
clrbits_le32(&ctrl->loop,
UART_LOOPBACK(CONFIG_SYS_LPC32XX_UART));
if (uart_id < 3 || uart_id > 6)
return;
/* Enable UART system clock */
setbits_le32(&clk->uartclk_ctrl, CLK_UART(uart_id));
/* Set UART into autoclock mode */
clrsetbits_le32(&ctrl->clkmode,
UART_CLKMODE_MASK(uart_id),
UART_CLKMODE_AUTO(uart_id));
/* Bypass pre-divider of UART clock */
writel(CLK_UART_X_DIV(1) | CLK_UART_Y_DIV(1),
&clk->u3clk + (uart_id - 3));
}
#if !CONFIG_IS_ENABLED(OF_CONTROL)
static const struct ns16550_platdata lpc32xx_uart[] = {
{ .base = UART3_BASE, .reg_shift = 2,
.clock = CONFIG_SYS_NS16550_CLK, .fcr = UART_FCR_DEFVAL, },
{ .base = UART4_BASE, .reg_shift = 2,
.clock = CONFIG_SYS_NS16550_CLK, .fcr = UART_FCR_DEFVAL, },
{ .base = UART5_BASE, .reg_shift = 2,
.clock = CONFIG_SYS_NS16550_CLK, .fcr = UART_FCR_DEFVAL, },
{ .base = UART6_BASE, .reg_shift = 2,
.clock = CONFIG_SYS_NS16550_CLK, .fcr = UART_FCR_DEFVAL, },
};
#if defined(CONFIG_LPC32XX_HSUART)
static const struct lpc32xx_hsuart_platdata lpc32xx_hsuart[] = {
{ HS_UART1_BASE, },
{ HS_UART2_BASE, },
{ HS_UART7_BASE, },
};
#endif
U_BOOT_DEVICES(lpc32xx_uarts) = {
#if defined(CONFIG_LPC32XX_HSUART)
{ "lpc32xx_hsuart", &lpc32xx_hsuart[0], },
{ "lpc32xx_hsuart", &lpc32xx_hsuart[1], },
#endif
{ "ns16550_serial", &lpc32xx_uart[0], },
{ "ns16550_serial", &lpc32xx_uart[1], },
{ "ns16550_serial", &lpc32xx_uart[2], },
{ "ns16550_serial", &lpc32xx_uart[3], },
#if defined(CONFIG_LPC32XX_HSUART)
{ "lpc32xx_hsuart", &lpc32xx_hsuart[2], },
#endif
};
#endif
void lpc32xx_dma_init(void)
{
/* Enable DMA interface */
writel(CLK_DMA_ENABLE, &clk->dmaclk_ctrl);
}
void lpc32xx_mac_init(void)
{
/* Enable MAC interface */
writel(CLK_MAC_REG | CLK_MAC_SLAVE | CLK_MAC_MASTER
#if defined(CONFIG_RMII)
| CLK_MAC_RMII,
#else
| CLK_MAC_MII,
#endif
&clk->macclk_ctrl);
}
void lpc32xx_mlc_nand_init(void)
{
/* Enable NAND interface */
writel(CLK_NAND_MLC | CLK_NAND_MLC_INT, &clk->flashclk_ctrl);
}
void lpc32xx_slc_nand_init(void)
{
/* Enable SLC NAND interface */
writel(CLK_NAND_SLC | CLK_NAND_SLC_SELECT, &clk->flashclk_ctrl);
}
void lpc32xx_usb_init(void)
{
/* Do not route the UART 5 Tx/Rx pins to the USB D+ and USB D- pins. */
clrbits_le32(&ctrl->ctrl, UART_CTRL_UART5_USB_MODE);
}
void lpc32xx_i2c_init(unsigned int devnum)
{
/* Enable I2C interface */
uint32_t ctrl = readl(&clk->i2cclk_ctrl);
if (devnum == 1)
ctrl |= CLK_I2C1_ENABLE;
if (devnum == 2)
ctrl |= CLK_I2C2_ENABLE;
writel(ctrl, &clk->i2cclk_ctrl);
}
U_BOOT_DEVICE(lpc32xx_gpios) = {
.name = "gpio_lpc32xx"
};
/* Mux for SCK0, MISO0, MOSI0. We do not use SSEL0. */
#define P_MUX_SET_SSP0 0x1600
void lpc32xx_ssp_init(void)
{
/* Enable SSP0 interface */
writel(CLK_SSP0_ENABLE_CLOCK, &clk->ssp_ctrl);
/* Mux SSP0 pins */
writel(P_MUX_SET_SSP0, &mux->p_mux_set);
}
@@ -0,0 +1,73 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* LPC32xx dram init
*
* (C) Copyright 2014 DENX Software Engineering GmbH
* Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr>
*
* This is called by SPL to gain access to the SDR DRAM.
*
* This code runs from SRAM.
*/
#include <common.h>
#include <netdev.h>
#include <asm/arch/cpu.h>
#include <asm/arch/clk.h>
#include <asm/arch/wdt.h>
#include <asm/arch/emc.h>
#include <asm/io.h>
static struct clk_pm_regs *clk = (struct clk_pm_regs *)CLK_PM_BASE;
static struct emc_regs *emc = (struct emc_regs *)EMC_BASE;
void ddr_init(struct emc_dram_settings *dram)
{
uint32_t ck;
/* Enable EMC interface and choose little endian mode */
writel(1, &emc->ctrl);
writel(0, &emc->config);
/* Select maximum EMC Dynamic Memory Refresh Time */
writel(0x7FF, &emc->refresh);
/* Determine CLK */
ck = get_sdram_clk_rate();
/* Configure SDRAM */
writel(dram->cmddelay, &clk->sdramclk_ctrl);
writel(dram->config0, &emc->config0);
writel(dram->rascas0, &emc->rascas0);
writel(dram->rdconfig, &emc->read_config);
/* Set timings */
writel((ck / dram->trp) & 0x0000000F, &emc->t_rp);
writel((ck / dram->tras) & 0x0000000F, &emc->t_ras);
writel((ck / dram->tsrex) & 0x0000007F, &emc->t_srex);
writel((ck / dram->twr) & 0x0000000F, &emc->t_wr);
writel((ck / dram->trc) & 0x0000001F, &emc->t_rc);
writel((ck / dram->trfc) & 0x0000001F, &emc->t_rfc);
writel((ck / dram->txsr) & 0x000000FF, &emc->t_xsr);
writel(dram->trrd, &emc->t_rrd);
writel(dram->tmrd, &emc->t_mrd);
writel(dram->tcdlr, &emc->t_cdlr);
/* Dynamic refresh */
writel((((ck / dram->refresh) >> 4) & 0x7FF), &emc->refresh);
udelay(10);
/* Force all clocks, enable inverted ck, issue NOP command */
writel(0x00000193, &emc->control);
udelay(100);
/* Keep all clocks enabled, issue a PRECHARGE ALL command */
writel(0x00000113, &emc->control);
/* Fast dynamic refresh for at least a few SDRAM ck cycles */
writel((((128) >> 4) & 0x7FF), &emc->refresh);
udelay(10);
/* set correct dynamic refresh timing */
writel((((ck / dram->refresh) >> 4) & 0x7FF), &emc->refresh);
udelay(10);
/* set normal mode to CAS=3 */
writel(0x00000093, &emc->control);
readl(EMC_DYCS0_BASE | dram->mode);
/* set extended mode to all zeroes */
writel(0x00000093, &emc->control);
readl(EMC_DYCS0_BASE | dram->emode);
/* stop forcing clocks, keep inverted clock, issue normal mode */
writel(0x00000010, &emc->control);
}
@@ -0,0 +1,44 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* WORK Microwave work_92105 board low level init
*
* (C) Copyright 2014 DENX Software Engineering GmbH
* Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr>
*
* Low level init is called from SPL to set up the clocks.
* On entry, the LPC3250 is in Direct Run mode with all clocks
* running at 13 MHz; on exit, ARM clock is 208 MHz, HCLK is
* 104 MHz and PCLK is 13 MHz.
*
* This code must run from SRAM so that the clock changes do
* not prevent it from executing.
*/
.globl lowlevel_init
lowlevel_init:
/* Set ARM, HCLK, PCLK dividers for normal mode */
ldr r0, =0x0000003D
ldr r1, =0x40004040
str r0, [r1]
/* Start HCLK PLL for 208 MHz */
ldr r0, =0x0001401E
ldr r1, =0x40004058
str r0, [r1]
/* wait for HCLK PLL to lock */
1:
ldr r0, [r1]
ands r0, r0, #1
beq 1b
/* switch to normal mode */
ldr r1, =0x40004044
ldr r0, [r1]
orr r0, #0x00000004
str r0, [r1]
/* Return to U-Boot via saved link register */
mov pc, lr
@@ -0,0 +1,85 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2011 Vladimir Zapolskiy <vz@mleia.com>
*/
#include <common.h>
#include <time.h>
#include <asm/arch/cpu.h>
#include <asm/arch/clk.h>
#include <asm/arch/timer.h>
#include <asm/io.h>
static struct timer_regs *timer0 = (struct timer_regs *)TIMER0_BASE;
static struct timer_regs *timer1 = (struct timer_regs *)TIMER1_BASE;
static struct clk_pm_regs *clk = (struct clk_pm_regs *)CLK_PM_BASE;
static void lpc32xx_timer_clock(u32 bit, int enable)
{
if (enable)
setbits_le32(&clk->timclk_ctrl1, bit);
else
clrbits_le32(&clk->timclk_ctrl1, bit);
}
static void lpc32xx_timer_reset(struct timer_regs *timer, u32 freq)
{
writel(TIMER_TCR_COUNTER_RESET, &timer->tcr);
writel(TIMER_TCR_COUNTER_DISABLE, &timer->tcr);
writel(0, &timer->tc);
writel(0, &timer->pr);
/* Count mode is every rising PCLK edge */
writel(TIMER_CTCR_MODE_TIMER, &timer->ctcr);
/* Set prescale counter value */
writel((get_periph_clk_rate() / freq) - 1, &timer->pr);
/* Ensure that the counter is not reset when matching TC */
writel(0, &timer->mcr);
}
static void lpc32xx_timer_count(struct timer_regs *timer, int enable)
{
if (enable)
writel(TIMER_TCR_COUNTER_ENABLE, &timer->tcr);
else
writel(TIMER_TCR_COUNTER_DISABLE, &timer->tcr);
}
int timer_init(void)
{
lpc32xx_timer_clock(CLK_TIMCLK_TIMER0, 1);
lpc32xx_timer_reset(timer0, CONFIG_SYS_HZ);
lpc32xx_timer_count(timer0, 1);
return 0;
}
ulong get_timer(ulong base)
{
return readl(&timer0->tc) - base;
}
void __udelay(unsigned long usec)
{
lpc32xx_timer_clock(CLK_TIMCLK_TIMER1, 1);
lpc32xx_timer_reset(timer1, CONFIG_SYS_HZ * 1000);
lpc32xx_timer_count(timer1, 1);
while (readl(&timer1->tc) < usec)
/* NOP */;
lpc32xx_timer_count(timer1, 0);
lpc32xx_timer_clock(CLK_TIMCLK_TIMER1, 0);
}
unsigned long long get_ticks(void)
{
return get_timer(0);
}
ulong get_tbclk(void)
{
return CONFIG_SYS_HZ;
}
@@ -0,0 +1,7 @@
# SPDX-License-Identifier: GPL-2.0+
#
# (C) Copyright 2000-2006
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
#
obj-y += generic.o timer.o reset.o relocate.o
@@ -0,0 +1,270 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2009 DENX Software Engineering
* Author: John Rigby <jrigby@gmail.com>
*
* Based on mx27/generic.c:
* Copyright (c) 2008 Eric Jarrige <eric.jarrige@armadeus.org>
* Copyright (c) 2009 Ilya Yanok <yanok@emcraft.com>
*/
#include <common.h>
#include <div64.h>
#include <netdev.h>
#include <vsprintf.h>
#include <asm/io.h>
#include <asm/arch-imx/cpu.h>
#include <asm/arch/imx-regs.h>
#include <asm/arch/clock.h>
#ifdef CONFIG_FSL_ESDHC_IMX
#include <fsl_esdhc_imx.h>
DECLARE_GLOBAL_DATA_PTR;
#endif
/*
* get the system pll clock in Hz
*
* mfi + mfn / (mfd +1)
* f = 2 * f_ref * --------------------
* pd + 1
*/
static unsigned int imx_decode_pll(unsigned int pll, unsigned int f_ref)
{
unsigned int mfi = (pll >> CCM_PLL_MFI_SHIFT)
& CCM_PLL_MFI_MASK;
int mfn = (pll >> CCM_PLL_MFN_SHIFT)
& CCM_PLL_MFN_MASK;
unsigned int mfd = (pll >> CCM_PLL_MFD_SHIFT)
& CCM_PLL_MFD_MASK;
unsigned int pd = (pll >> CCM_PLL_PD_SHIFT)
& CCM_PLL_PD_MASK;
mfi = mfi <= 5 ? 5 : mfi;
mfn = mfn >= 512 ? mfn - 1024 : mfn;
mfd += 1;
pd += 1;
return lldiv(2 * (u64) f_ref * (mfi * mfd + mfn),
mfd * pd);
}
static ulong imx_get_mpllclk(void)
{
struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE;
ulong fref = MXC_HCLK;
return imx_decode_pll(readl(&ccm->mpctl), fref);
}
static ulong imx_get_upllclk(void)
{
struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE;
ulong fref = MXC_HCLK;
return imx_decode_pll(readl(&ccm->upctl), fref);
}
static ulong imx_get_armclk(void)
{
struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE;
ulong cctl = readl(&ccm->cctl);
ulong fref = imx_get_mpllclk();
ulong div;
if (cctl & CCM_CCTL_ARM_SRC)
fref = lldiv((u64) fref * 3, 4);
div = ((cctl >> CCM_CCTL_ARM_DIV_SHIFT)
& CCM_CCTL_ARM_DIV_MASK) + 1;
return fref / div;
}
static ulong imx_get_ahbclk(void)
{
struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE;
ulong cctl = readl(&ccm->cctl);
ulong fref = imx_get_armclk();
ulong div;
div = ((cctl >> CCM_CCTL_AHB_DIV_SHIFT)
& CCM_CCTL_AHB_DIV_MASK) + 1;
return fref / div;
}
static ulong imx_get_ipgclk(void)
{
return imx_get_ahbclk() / 2;
}
static ulong imx_get_perclk(int clk)
{
struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE;
ulong fref = readl(&ccm->mcr) & (1 << clk) ? imx_get_upllclk() :
imx_get_ahbclk();
ulong div;
div = readl(&ccm->pcdr[CCM_PERCLK_REG(clk)]);
div = ((div >> CCM_PERCLK_SHIFT(clk)) & CCM_PERCLK_MASK) + 1;
return fref / div;
}
int imx_set_perclk(enum mxc_clock clk, bool from_upll, unsigned int freq)
{
struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE;
ulong fref = from_upll ? imx_get_upllclk() : imx_get_ahbclk();
ulong div = (fref + freq - 1) / freq;
if (clk > MXC_UART_CLK || !div || --div > CCM_PERCLK_MASK)
return -EINVAL;
clrsetbits_le32(&ccm->pcdr[CCM_PERCLK_REG(clk)],
CCM_PERCLK_MASK << CCM_PERCLK_SHIFT(clk),
div << CCM_PERCLK_SHIFT(clk));
if (from_upll)
setbits_le32(&ccm->mcr, 1 << clk);
else
clrbits_le32(&ccm->mcr, 1 << clk);
return 0;
}
unsigned int mxc_get_clock(enum mxc_clock clk)
{
if (clk >= MXC_CLK_NUM)
return -1;
switch (clk) {
case MXC_ARM_CLK:
return imx_get_armclk();
case MXC_AHB_CLK:
return imx_get_ahbclk();
case MXC_IPG_CLK:
case MXC_CSPI_CLK:
case MXC_FEC_CLK:
return imx_get_ipgclk();
default:
return imx_get_perclk(clk);
}
}
u32 get_cpu_rev(void)
{
u32 srev;
u32 system_rev = 0x25000;
/* read SREV register from IIM module */
struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE;
srev = readl(&iim->iim_srev);
switch (srev) {
case 0x00:
system_rev |= CHIP_REV_1_0;
break;
case 0x01:
system_rev |= CHIP_REV_1_1;
break;
case 0x02:
system_rev |= CHIP_REV_1_2;
break;
default:
system_rev |= 0x8000;
break;
}
return system_rev;
}
#if defined(CONFIG_DISPLAY_CPUINFO)
static char *get_reset_cause(void)
{
/* read RCSR register from CCM module */
struct ccm_regs *ccm =
(struct ccm_regs *)IMX_CCM_BASE;
u32 cause = readl(&ccm->rcsr) & 0x0f;
if (cause == 0)
return "POR";
else if (cause == 1)
return "RST";
else if ((cause & 2) == 2)
return "WDOG";
else if ((cause & 4) == 4)
return "SW RESET";
else if ((cause & 8) == 8)
return "JTAG";
else
return "unknown reset";
}
int print_cpuinfo(void)
{
char buf[32];
u32 cpurev = get_cpu_rev();
printf("CPU: Freescale i.MX25 rev%d.%d%s at %s MHz\n",
(cpurev & 0xF0) >> 4, (cpurev & 0x0F),
((cpurev & 0x8000) ? " unknown" : ""),
strmhz(buf, imx_get_armclk()));
printf("Reset cause: %s\n", get_reset_cause());
return 0;
}
#endif
#if defined(CONFIG_FEC_MXC)
/*
* Initializes on-chip ethernet controllers.
* to override, implement board_eth_init()
*/
int cpu_eth_init(bd_t *bis)
{
struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE;
ulong val;
val = readl(&ccm->cgr0);
val |= (1 << 23);
writel(val, &ccm->cgr0);
return fecmxc_initialize(bis);
}
#endif
int get_clocks(void)
{
#ifdef CONFIG_FSL_ESDHC_IMX
#if CONFIG_SYS_FSL_ESDHC_ADDR == IMX_MMC_SDHC2_BASE
gd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC2_CLK);
#else
gd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC1_CLK);
#endif
#endif
return 0;
}
#ifdef CONFIG_FSL_ESDHC_IMX
/*
* Initializes on-chip MMC controllers.
* to override, implement board_mmc_init()
*/
int cpu_mmc_init(bd_t *bis)
{
return fsl_esdhc_mmc_init(bis);
}
#endif
#ifdef CONFIG_FEC_MXC
void imx_get_mac_from_fuse(int dev_id, unsigned char *mac)
{
int i;
struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE;
struct fuse_bank *bank = &iim->bank[0];
struct fuse_bank0_regs *fuse =
(struct fuse_bank0_regs *)bank->fuse_regs;
for (i = 0; i < 6; i++)
mac[i] = readl(&fuse->mac_addr[i]) & 0xff;
}
#endif /* CONFIG_FEC_MXC */
@@ -0,0 +1,22 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* relocate - i.MX25-specific vector relocation
*
* Copyright (c) 2013 Albert ARIBAUD <albert.u.boot@aribaud.net>
*/
#include <linux/linkage.h>
/*
* The i.MX25 SoC is very specific with respect to exceptions: it
* does not provide RAM at the high vectors address (0xFFFF0000),
* thus only the low address (0x00000000) is useable; but that is
* in ROM, so let's avoid relocating the vectors.
*/
.section .text.relocate_vectors,"ax",%progbits
ENTRY(relocate_vectors)
bx lr
ENDPROC(relocate_vectors)
@@ -0,0 +1,39 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2002
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
* Marius Groeger <mgroeger@sysgo.de>
*
* (C) Copyright 2002
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
* Alex Zuepke <azu@sysgo.de>
*
* (C) Copyright 2002
* Gary Jennejohn, DENX Software Engineering, <gj@denx.de>
*
* (C) Copyright 2009
* Ilya Yanok, Emcraft Systems Ltd, <yanok@emcraft.com>
*/
#include <common.h>
#include <asm/io.h>
#include <asm/arch/imx-regs.h>
/*
* Reset the cpu by setting up the watchdog timer and let it time out
*/
void reset_cpu(ulong ignored)
{
struct wdog_regs *regs = (struct wdog_regs *)IMX_WDT_BASE;
/* Disable watchdog and set Time-Out field to 0 */
writew(0, &regs->wcr);
/* Write Service Sequence */
writew(WSR_UNLOCK1, &regs->wsr);
writew(WSR_UNLOCK2, &regs->wsr);
/* Enable watchdog */
writew(WCR_WDE, &regs->wcr);
while (1) ;
}
@@ -0,0 +1,48 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2002
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
* Marius Groeger <mgroeger@sysgo.de>
*
* (C) Copyright 2002
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
* Alex Zuepke <azu@sysgo.de>
*
* (C) Copyright 2002
* Gary Jennejohn, DENX Software Engineering, <gj@denx.de>
*
* (C) Copyright 2009
* Ilya Yanok, Emcraft Systems Ltd, <yanok@emcraft.com>
*
* (C) Copyright 2009 DENX Software Engineering
* Author: John Rigby <jrigby@gmail.com>
* Add support for MX25
*/
#include <common.h>
#include <asm/io.h>
#include <asm/arch/imx-regs.h>
/* nothing really to do with interrupts, just starts up a counter. */
/* The 32KHz 32-bit timer overruns in 134217 seconds */
int timer_init(void)
{
int i;
struct gpt_regs *gpt = (struct gpt_regs *)IMX_GPT1_BASE;
struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE;
/* setup GP Timer 1 */
writel(GPT_CTRL_SWR, &gpt->ctrl);
writel(readl(&ccm->cgr1) | CCM_CGR1_GPT1, &ccm->cgr1);
for (i = 0; i < 100; i++)
writel(0, &gpt->ctrl); /* We have no udelay by now */
writel(0, &gpt->pre); /* prescaler = 1 */
/* Freerun Mode, 32KHz input */
writel(readl(&gpt->ctrl) | GPT_CTRL_CLKSOURCE_32 | GPT_CTRL_FRR,
&gpt->ctrl);
writel(readl(&gpt->ctrl) | GPT_CTRL_TEN, &gpt->ctrl);
return 0;
}
@@ -0,0 +1,7 @@
# SPDX-License-Identifier: GPL-2.0+
#
# (C) Copyright 2000-2006
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
#
obj-y += generic.o timer.o reset.o relocate.o
@@ -0,0 +1,377 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2008 Eric Jarrige <eric.jarrige@armadeus.org>
* Copyright (c) 2009 Ilya Yanok <yanok@emcraft.com>
*/
#include <common.h>
#include <div64.h>
#include <netdev.h>
#include <vsprintf.h>
#include <asm/io.h>
#include <asm/arch/imx-regs.h>
#include <asm/arch/clock.h>
#include <asm/arch/gpio.h>
#include <asm/mach-imx/sys_proto.h>
#ifdef CONFIG_MMC_MXC
#include <asm/arch/mxcmmc.h>
#endif
/*
* get the system pll clock in Hz
*
* mfi + mfn / (mfd +1)
* f = 2 * f_ref * --------------------
* pd + 1
*/
static unsigned int imx_decode_pll(unsigned int pll, unsigned int f_ref)
{
unsigned int mfi = (pll >> 10) & 0xf;
unsigned int mfn = pll & 0x3ff;
unsigned int mfd = (pll >> 16) & 0x3ff;
unsigned int pd = (pll >> 26) & 0xf;
mfi = mfi <= 5 ? 5 : mfi;
return lldiv(2 * (u64)f_ref * (mfi * (mfd + 1) + mfn),
(mfd + 1) * (pd + 1));
}
static ulong clk_in_32k(void)
{
return 1024 * CONFIG_MX27_CLK32;
}
static ulong clk_in_26m(void)
{
struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE;
if (readl(&pll->cscr) & CSCR_OSC26M_DIV1P5) {
/* divide by 1.5 */
return 26000000 * 2 / 3;
} else {
return 26000000;
}
}
static ulong imx_get_mpllclk(void)
{
struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE;
ulong cscr = readl(&pll->cscr);
ulong fref;
if (cscr & CSCR_MCU_SEL)
fref = clk_in_26m();
else
fref = clk_in_32k();
return imx_decode_pll(readl(&pll->mpctl0), fref);
}
static ulong imx_get_armclk(void)
{
struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE;
ulong cscr = readl(&pll->cscr);
ulong fref = imx_get_mpllclk();
ulong div;
if (!(cscr & CSCR_ARM_SRC_MPLL))
fref = lldiv((fref * 2), 3);
div = ((cscr >> 12) & 0x3) + 1;
return lldiv(fref, div);
}
static ulong imx_get_ahbclk(void)
{
struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE;
ulong cscr = readl(&pll->cscr);
ulong fref = imx_get_mpllclk();
ulong div;
div = ((cscr >> 8) & 0x3) + 1;
return lldiv(fref * 2, 3 * div);
}
static __attribute__((unused)) ulong imx_get_spllclk(void)
{
struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE;
ulong cscr = readl(&pll->cscr);
ulong fref;
if (cscr & CSCR_SP_SEL)
fref = clk_in_26m();
else
fref = clk_in_32k();
return imx_decode_pll(readl(&pll->spctl0), fref);
}
static ulong imx_decode_perclk(ulong div)
{
return lldiv((imx_get_mpllclk() * 2), (div * 3));
}
static ulong imx_get_perclk1(void)
{
struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE;
return imx_decode_perclk((readl(&pll->pcdr1) & 0x3f) + 1);
}
static ulong imx_get_perclk2(void)
{
struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE;
return imx_decode_perclk(((readl(&pll->pcdr1) >> 8) & 0x3f) + 1);
}
static __attribute__((unused)) ulong imx_get_perclk3(void)
{
struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE;
return imx_decode_perclk(((readl(&pll->pcdr1) >> 16) & 0x3f) + 1);
}
static __attribute__((unused)) ulong imx_get_perclk4(void)
{
struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE;
return imx_decode_perclk(((readl(&pll->pcdr1) >> 24) & 0x3f) + 1);
}
unsigned int mxc_get_clock(enum mxc_clock clk)
{
switch (clk) {
case MXC_ARM_CLK:
return imx_get_armclk();
case MXC_I2C_CLK:
return imx_get_ahbclk()/2;
case MXC_UART_CLK:
return imx_get_perclk1();
case MXC_FEC_CLK:
return imx_get_ahbclk();
case MXC_ESDHC_CLK:
return imx_get_perclk2();
}
return -1;
}
u32 get_cpu_rev(void)
{
return MXC_CPU_MX27 << 12;
}
#if defined(CONFIG_DISPLAY_CPUINFO)
int print_cpuinfo (void)
{
char buf[32];
printf("CPU: Freescale i.MX27 at %s MHz\n\n",
strmhz(buf, imx_get_mpllclk()));
return 0;
}
#endif
int cpu_eth_init(bd_t *bis)
{
#if defined(CONFIG_FEC_MXC)
struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE;
/* enable FEC clock */
writel(readl(&pll->pccr1) | PCCR1_HCLK_FEC, &pll->pccr1);
writel(readl(&pll->pccr0) | PCCR0_FEC_EN, &pll->pccr0);
return fecmxc_initialize(bis);
#else
return 0;
#endif
}
/*
* Initializes on-chip MMC controllers.
* to override, implement board_mmc_init()
*/
int cpu_mmc_init(bd_t *bis)
{
#ifdef CONFIG_MMC_MXC
return mxc_mmc_init(bis);
#else
return 0;
#endif
}
void imx_gpio_mode(int gpio_mode)
{
struct gpio_port_regs *regs = (struct gpio_port_regs *)IMX_GPIO_BASE;
unsigned int pin = gpio_mode & GPIO_PIN_MASK;
unsigned int port = (gpio_mode & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT;
unsigned int ocr = (gpio_mode & GPIO_OCR_MASK) >> GPIO_OCR_SHIFT;
unsigned int aout = (gpio_mode & GPIO_AOUT_MASK) >> GPIO_AOUT_SHIFT;
unsigned int bout = (gpio_mode & GPIO_BOUT_MASK) >> GPIO_BOUT_SHIFT;
unsigned int tmp;
/* Pullup enable */
if (gpio_mode & GPIO_PUEN) {
writel(readl(&regs->port[port].puen) | (1 << pin),
&regs->port[port].puen);
} else {
writel(readl(&regs->port[port].puen) & ~(1 << pin),
&regs->port[port].puen);
}
/* Data direction */
if (gpio_mode & GPIO_OUT) {
writel(readl(&regs->port[port].gpio_dir) | 1 << pin,
&regs->port[port].gpio_dir);
} else {
writel(readl(&regs->port[port].gpio_dir) & ~(1 << pin),
&regs->port[port].gpio_dir);
}
/* Primary / alternate function */
if (gpio_mode & GPIO_AF) {
writel(readl(&regs->port[port].gpr) | (1 << pin),
&regs->port[port].gpr);
} else {
writel(readl(&regs->port[port].gpr) & ~(1 << pin),
&regs->port[port].gpr);
}
/* use as gpio? */
if (!(gpio_mode & (GPIO_PF | GPIO_AF))) {
writel(readl(&regs->port[port].gius) | (1 << pin),
&regs->port[port].gius);
} else {
writel(readl(&regs->port[port].gius) & ~(1 << pin),
&regs->port[port].gius);
}
/* Output / input configuration */
if (pin < 16) {
tmp = readl(&regs->port[port].ocr1);
tmp &= ~(3 << (pin * 2));
tmp |= (ocr << (pin * 2));
writel(tmp, &regs->port[port].ocr1);
writel(readl(&regs->port[port].iconfa1) & ~(3 << (pin * 2)),
&regs->port[port].iconfa1);
writel(readl(&regs->port[port].iconfa1) | aout << (pin * 2),
&regs->port[port].iconfa1);
writel(readl(&regs->port[port].iconfb1) & ~(3 << (pin * 2)),
&regs->port[port].iconfb1);
writel(readl(&regs->port[port].iconfb1) | bout << (pin * 2),
&regs->port[port].iconfb1);
} else {
pin -= 16;
tmp = readl(&regs->port[port].ocr2);
tmp &= ~(3 << (pin * 2));
tmp |= (ocr << (pin * 2));
writel(tmp, &regs->port[port].ocr2);
writel(readl(&regs->port[port].iconfa2) & ~(3 << (pin * 2)),
&regs->port[port].iconfa2);
writel(readl(&regs->port[port].iconfa2) | aout << (pin * 2),
&regs->port[port].iconfa2);
writel(readl(&regs->port[port].iconfb2) & ~(3 << (pin * 2)),
&regs->port[port].iconfb2);
writel(readl(&regs->port[port].iconfb2) | bout << (pin * 2),
&regs->port[port].iconfb2);
}
}
#ifdef CONFIG_MXC_UART
void mx27_uart1_init_pins(void)
{
int i;
unsigned int mode[] = {
PE12_PF_UART1_TXD,
PE13_PF_UART1_RXD,
};
for (i = 0; i < ARRAY_SIZE(mode); i++)
imx_gpio_mode(mode[i]);
}
#endif /* CONFIG_MXC_UART */
#ifdef CONFIG_FEC_MXC
void mx27_fec_init_pins(void)
{
int i;
unsigned int mode[] = {
PD0_AIN_FEC_TXD0,
PD1_AIN_FEC_TXD1,
PD2_AIN_FEC_TXD2,
PD3_AIN_FEC_TXD3,
PD4_AOUT_FEC_RX_ER,
PD5_AOUT_FEC_RXD1,
PD6_AOUT_FEC_RXD2,
PD7_AOUT_FEC_RXD3,
PD8_AF_FEC_MDIO,
PD9_AIN_FEC_MDC | GPIO_PUEN,
PD10_AOUT_FEC_CRS,
PD11_AOUT_FEC_TX_CLK,
PD12_AOUT_FEC_RXD0,
PD13_AOUT_FEC_RX_DV,
PD14_AOUT_FEC_CLR,
PD15_AOUT_FEC_COL,
PD16_AIN_FEC_TX_ER,
PF23_AIN_FEC_TX_EN,
};
for (i = 0; i < ARRAY_SIZE(mode); i++)
imx_gpio_mode(mode[i]);
}
void imx_get_mac_from_fuse(int dev_id, unsigned char *mac)
{
int i;
struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE;
struct fuse_bank *bank = &iim->bank[0];
struct fuse_bank0_regs *fuse =
(struct fuse_bank0_regs *)bank->fuse_regs;
for (i = 0; i < 6; i++)
mac[6 - 1 - i] = readl(&fuse->mac_addr[i]) & 0xff;
}
#endif /* CONFIG_FEC_MXC */
#ifdef CONFIG_MMC_MXC
void mx27_sd1_init_pins(void)
{
int i;
unsigned int mode[] = {
PE18_PF_SD1_D0,
PE19_PF_SD1_D1,
PE20_PF_SD1_D2,
PE21_PF_SD1_D3,
PE22_PF_SD1_CMD,
PE23_PF_SD1_CLK,
};
for (i = 0; i < ARRAY_SIZE(mode); i++)
imx_gpio_mode(mode[i]);
}
void mx27_sd2_init_pins(void)
{
int i;
unsigned int mode[] = {
PB4_PF_SD2_D0,
PB5_PF_SD2_D1,
PB6_PF_SD2_D2,
PB7_PF_SD2_D3,
PB8_PF_SD2_CMD,
PB9_PF_SD2_CLK,
};
for (i = 0; i < ARRAY_SIZE(mode); i++)
imx_gpio_mode(mode[i]);
}
#endif /* CONFIG_MMC_MXC */
@@ -0,0 +1,50 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* relocate - i.MX27-specific vector relocation
*
* Copyright (c) 2013 Albert ARIBAUD <albert.u.boot@aribaud.net>
*/
#include <asm-offsets.h>
#include <config.h>
#include <linux/linkage.h>
/*
* The i.MX27 SoC is very specific with respect to exceptions: it
* does not provide RAM at the high vectors address (0xFFFF0000),
* thus only the low address (0x00000000) is useable; but that is
* in ROM. Therefore, vectors cannot be changed at all.
*
* However, these ROM-based vectors actually just perform indirect
* calls through pointers located in RAM at SoC-specific addresses,
* as follows:
*
* Offset Exception Use by ROM code
* 0x00000000 reset indirect branch to [0x00000014]
* 0x00000004 undefined instruction indirect branch to [0xfffffef0]
* 0x00000008 software interrupt indirect branch to [0xfffffef4]
* 0x0000000c prefetch abort indirect branch to [0xfffffef8]
* 0x00000010 data abort indirect branch to [0xfffffefc]
* 0x00000014 (reserved in ARMv5) vector to ROM reset: 0xc0000000
* 0x00000018 IRQ indirect branch to [0xffffff00]
* 0x0000001c FIQ indirect branch to [0xffffff04]
*
* In order to initialize exceptions on i.MX27, we must copy U-Boot's
* indirect (not exception!) vector table into 0xfffffef0..0xffffff04
* taking care not to copy vectors number 5 (reserved exception).
*/
.section .text.relocate_vectors,"ax",%progbits
ENTRY(relocate_vectors)
ldr r0, [r9, #GD_RELOCADDR] /* r0 = gd->relocaddr */
ldr r1, =32 /* size of vector table */
add r0, r0, r1 /* skip to indirect table */
ldr r1, =0xFFFFFEF0 /* i.MX27 indirect table */
ldmia r0!, {r2-r8} /* load indirect vectors 1..7 */
stmia r1!, {r2-r5, r7,r8} /* write all but vector 5 */
bx lr
ENDPROC(relocate_vectors)
@@ -0,0 +1,40 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2002
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
* Marius Groeger <mgroeger@sysgo.de>
*
* (C) Copyright 2002
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
* Alex Zuepke <azu@sysgo.de>
*
* (C) Copyright 2002
* Gary Jennejohn, DENX Software Engineering, <gj@denx.de>
*
* (C) Copyright 2009
* Ilya Yanok, Emcraft Systems Ltd, <yanok@emcraft.com>
*/
#include <common.h>
#include <asm/io.h>
#include <asm/arch/imx-regs.h>
/*
* Reset the cpu by setting up the watchdog timer and let it time out
*/
void reset_cpu(ulong ignored)
{
struct wdog_regs *regs = (struct wdog_regs *)IMX_WDT_BASE;
/* Disable watchdog and set Time-Out field to 0 */
writew(0x0000, &regs->wcr);
/* Write Service Sequence */
writew(0x5555, &regs->wsr);
writew(0xAAAA, &regs->wsr);
/* Enable watchdog */
writew(WCR_WDE, &regs->wcr);
while (1);
/*NOTREACHED*/
}
@@ -0,0 +1,162 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2002
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
* Marius Groeger <mgroeger@sysgo.de>
*
* (C) Copyright 2002
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
* Alex Zuepke <azu@sysgo.de>
*
* (C) Copyright 2002
* Gary Jennejohn, DENX Software Engineering, <gj@denx.de>
*
* (C) Copyright 2009
* Ilya Yanok, Emcraft Systems Ltd, <yanok@emcraft.com>
*/
#include <common.h>
#include <div64.h>
#include <time.h>
#include <asm/io.h>
#include <asm/arch/imx-regs.h>
/* General purpose timers bitfields */
#define GPTCR_SWR (1 << 15) /* Software reset */
#define GPTCR_FRR (1 << 8) /* Freerun / restart */
#define GPTCR_CLKSOURCE_32 (4 << 1) /* Clock source */
#define GPTCR_TEN 1 /* Timer enable */
DECLARE_GLOBAL_DATA_PTR;
#define timestamp (gd->arch.tbl)
#define lastinc (gd->arch.lastinc)
/*
* "time" is measured in 1 / CONFIG_SYS_HZ seconds,
* "tick" is internal timer period
*/
#ifdef CONFIG_MX27_TIMER_HIGH_PRECISION
/* ~0.4% error - measured with stop-watch on 100s boot-delay */
static inline unsigned long long tick_to_time(unsigned long long tick)
{
tick *= CONFIG_SYS_HZ;
do_div(tick, CONFIG_MX27_CLK32);
return tick;
}
static inline unsigned long long time_to_tick(unsigned long long time)
{
time *= CONFIG_MX27_CLK32;
do_div(time, CONFIG_SYS_HZ);
return time;
}
static inline unsigned long long us_to_tick(unsigned long long us)
{
us = us * CONFIG_MX27_CLK32 + 999999;
do_div(us, 1000000);
return us;
}
#else
/* ~2% error */
#define TICK_PER_TIME ((CONFIG_MX27_CLK32 + CONFIG_SYS_HZ / 2) / \
CONFIG_SYS_HZ)
#define US_PER_TICK (1000000 / CONFIG_MX27_CLK32)
static inline unsigned long long tick_to_time(unsigned long long tick)
{
do_div(tick, TICK_PER_TIME);
return tick;
}
static inline unsigned long long time_to_tick(unsigned long long time)
{
return time * TICK_PER_TIME;
}
static inline unsigned long long us_to_tick(unsigned long long us)
{
us += US_PER_TICK - 1;
do_div(us, US_PER_TICK);
return us;
}
#endif
/* nothing really to do with interrupts, just starts up a counter. */
/* The 32768Hz 32-bit timer overruns in 131072 seconds */
int timer_init(void)
{
int i;
struct gpt_regs *regs = (struct gpt_regs *)IMX_TIM1_BASE;
struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE;
/* setup GP Timer 1 */
writel(GPTCR_SWR, &regs->gpt_tctl);
writel(readl(&pll->pccr0) | PCCR0_GPT1_EN, &pll->pccr0);
writel(readl(&pll->pccr1) | PCCR1_PERCLK1_EN, &pll->pccr1);
for (i = 0; i < 100; i++)
writel(0, &regs->gpt_tctl); /* We have no udelay by now */
writel(0, &regs->gpt_tprer); /* 32Khz */
/* Freerun Mode, PERCLK1 input */
writel(readl(&regs->gpt_tctl) | GPTCR_CLKSOURCE_32 | GPTCR_FRR,
&regs->gpt_tctl);
writel(readl(&regs->gpt_tctl) | GPTCR_TEN, &regs->gpt_tctl);
return 0;
}
unsigned long long get_ticks(void)
{
struct gpt_regs *regs = (struct gpt_regs *)IMX_TIM1_BASE;
ulong now = readl(&regs->gpt_tcn); /* current tick value */
if (now >= lastinc) {
/*
* normal mode (non roll)
* move stamp forward with absolut diff ticks
*/
timestamp += (now - lastinc);
} else {
/* we have rollover of incrementer */
timestamp += (0xFFFFFFFF - lastinc) + now;
}
lastinc = now;
return timestamp;
}
static ulong get_timer_masked(void)
{
/*
* get_ticks() returns a long long (64 bit), it wraps in
* 2^64 / CONFIG_MX27_CLK32 = 2^64 / 2^15 = 2^49 ~ 5 * 10^14 (s) ~
* 5 * 10^9 days... and get_ticks() * CONFIG_SYS_HZ wraps in
* 5 * 10^6 days - long enough.
*/
return tick_to_time(get_ticks());
}
ulong get_timer(ulong base)
{
return get_timer_masked() - base;
}
/* delay x useconds AND preserve advance timstamp value */
void __udelay(unsigned long usec)
{
unsigned long long tmp;
ulong tmo;
tmo = us_to_tick(usec);
tmp = get_ticks() + tmo; /* get current timestamp */
while (get_ticks() < tmp) /* loop till event */
/*NOP*/;
}
ulong get_tbclk(void)
{
return CONFIG_MX27_CLK32;
}
@@ -0,0 +1,81 @@
# SPDX-License-Identifier: GPL-2.0+
#
# (C) Copyright 2000-2006
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
extra-$(CONFIG_SPL_BUILD) := start.o
obj-y = clock.o mxs.o iomux.o timer.o
ifdef CONFIG_SPL_BUILD
obj-y += spl_boot.o spl_lradc_init.o spl_mem_init.o spl_power_init.o
endif
# Specify the target for use in elftosb call
MKIMAGE_TARGET-$(CONFIG_MX23) = mxsimage$(CONFIG_SPL_FRAMEWORK:%=-spl).mx23.cfg
MKIMAGE_TARGET-$(CONFIG_MX28) = mxsimage$(CONFIG_SPL_FRAMEWORK:%=-spl).mx28.cfg
# Generate HAB-capable IVT
#
# Note on computing the post-IVT size field value for the U-Boot binary.
# The value is the result of adding the following:
# -> The size of U-Boot binary aligned to 64B (u-boot.bin)
# -> The size of IVT block aligned to 64B (u-boot.ivt)
# -> The size of U-Boot signature (u-boot.sig), 3904 B
# -> The 64B hole in front of U-Boot binary for 'struct mxs_spl_data' passing
#
quiet_cmd_mkivt_mxs = MXSIVT $@
cmd_mkivt_mxs = \
sz=`expr \`stat -c "%s" $^\` + 64 + 3904 + 128` ; \
echo -n "0x402000d1 $2 0 0 0 $3 $4 0 $$sz 0 0 0 0 0 0 0" | \
tr -s " " | xargs -d " " -i printf "%08x\n" "{}" | rev | \
sed "s/\(.\)\(.\)/\\\\\\\\x\2\1\n/g" | xargs -i printf "{}" >$@
# Align binary to 64B
quiet_cmd_mkalign_mxs = MXSALGN $@
cmd_mkalign_mxs = \
dd if=$^ of=$@ ibs=64 conv=sync 2>/dev/null && \
mv $@ $^
# Assemble the CSF file
quiet_cmd_mkcsfreq_mxs = MXSCSFR $@
cmd_mkcsfreq_mxs = \
ivt=$(word 1,$^) ; \
bin=$(word 2,$^) ; \
csf=$(word 3,$^) ; \
sed "s@VENDOR@$(VENDOR)@g;s@BOARD@$(BOARD)@g" "$$csf" | \
sed '/^\#\#Blocks/ d' > $@ ; \
echo " Blocks = $2 0x0 `stat -c '%s' $$bin` \"$$bin\" , \\" >> $@ ; \
echo " $3 0x0 0x40 \"$$ivt\"" >> $@
# Sign files
quiet_cmd_mkcst_mxs = MXSCST $@
cmd_mkcst_mxs = cst -o $@ < $^ \
$(if $(KBUILD_VERBOSE:1=), >/dev/null)
spl/u-boot-spl.ivt: spl/u-boot-spl.bin
$(call if_changed,mkalign_mxs)
$(call if_changed,mkivt_mxs,$(CONFIG_SPL_TEXT_BASE),\
0x00008000,0x00008040)
u-boot.ivt: u-boot.bin
$(call if_changed,mkalign_mxs)
$(call if_changed,mkivt_mxs,$(CONFIG_SYS_TEXT_BASE),\
0x40001000,0x40001040)
spl/u-boot-spl.csf: spl/u-boot-spl.ivt spl/u-boot-spl.bin board/$(VENDOR)/$(BOARD)/sign/u-boot-spl.csf
$(call if_changed,mkcsfreq_mxs,$(CONFIG_SPL_TEXT_BASE),0x8000)
u-boot.csf: u-boot.ivt u-boot.bin board/$(VENDOR)/$(BOARD)/sign/u-boot.csf
$(call if_changed,mkcsfreq_mxs,$(CONFIG_SYS_TEXT_BASE),0x40001000)
%.sig: %.csf
$(call if_changed,mkcst_mxs)
MKIMAGEFLAGS_u-boot.sb = -n $< -T mxsimage
u-boot.sb: $(src)/$(MKIMAGE_TARGET-y) u-boot.bin spl/u-boot-spl.bin FORCE
$(call if_changed,mkimage)
MKIMAGEFLAGS_u-boot-signed.sb = -n $< -T mxsimage
u-boot-signed.sb: $(src)/mxsimage-signed.cfg u-boot.ivt u-boot.sig spl/u-boot-spl.ivt spl/u-boot-spl.sig FORCE
$(call if_changed,mkimage)
@@ -0,0 +1,435 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Freescale i.MX23/i.MX28 clock setup code
*
* Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
* on behalf of DENX Software Engineering GmbH
*
* Based on code from LTIB:
* Copyright (C) 2010 Freescale Semiconductor, Inc.
*/
#include <common.h>
#include <linux/errno.h>
#include <asm/io.h>
#include <asm/arch/clock.h>
#include <asm/arch/imx-regs.h>
/*
* The PLL frequency is 480MHz and XTAL frequency is 24MHz
* iMX23: datasheet section 4.2
* iMX28: datasheet section 10.2
*/
#define PLL_FREQ_KHZ 480000
#define PLL_FREQ_COEF 18
#define XTAL_FREQ_KHZ 24000
#define PLL_FREQ_MHZ (PLL_FREQ_KHZ / 1000)
#define XTAL_FREQ_MHZ (XTAL_FREQ_KHZ / 1000)
#if defined(CONFIG_MX23)
#define MXC_SSPCLK_MAX MXC_SSPCLK0
#elif defined(CONFIG_MX28)
#define MXC_SSPCLK_MAX MXC_SSPCLK3
#endif
static uint32_t mxs_get_pclk(void)
{
struct mxs_clkctrl_regs *clkctrl_regs =
(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
uint32_t clkctrl, clkseq, div;
uint8_t clkfrac, frac;
clkctrl = readl(&clkctrl_regs->hw_clkctrl_cpu);
/* No support of fractional divider calculation */
if (clkctrl &
(CLKCTRL_CPU_DIV_XTAL_FRAC_EN | CLKCTRL_CPU_DIV_CPU_FRAC_EN)) {
return 0;
}
clkseq = readl(&clkctrl_regs->hw_clkctrl_clkseq);
/* XTAL Path */
if (clkseq & CLKCTRL_CLKSEQ_BYPASS_CPU) {
div = (clkctrl & CLKCTRL_CPU_DIV_XTAL_MASK) >>
CLKCTRL_CPU_DIV_XTAL_OFFSET;
return XTAL_FREQ_MHZ / div;
}
/* REF Path */
clkfrac = readb(&clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_CPU]);
frac = clkfrac & CLKCTRL_FRAC_FRAC_MASK;
div = clkctrl & CLKCTRL_CPU_DIV_CPU_MASK;
return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div;
}
static uint32_t mxs_get_hclk(void)
{
struct mxs_clkctrl_regs *clkctrl_regs =
(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
uint32_t div;
uint32_t clkctrl;
clkctrl = readl(&clkctrl_regs->hw_clkctrl_hbus);
/* No support of fractional divider calculation */
if (clkctrl & CLKCTRL_HBUS_DIV_FRAC_EN)
return 0;
div = clkctrl & CLKCTRL_HBUS_DIV_MASK;
return mxs_get_pclk() / div;
}
static uint32_t mxs_get_emiclk(void)
{
struct mxs_clkctrl_regs *clkctrl_regs =
(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
uint32_t clkctrl, clkseq, div;
uint8_t clkfrac, frac;
clkseq = readl(&clkctrl_regs->hw_clkctrl_clkseq);
clkctrl = readl(&clkctrl_regs->hw_clkctrl_emi);
/* XTAL Path */
if (clkseq & CLKCTRL_CLKSEQ_BYPASS_EMI) {
div = (clkctrl & CLKCTRL_EMI_DIV_XTAL_MASK) >>
CLKCTRL_EMI_DIV_XTAL_OFFSET;
return XTAL_FREQ_MHZ / div;
}
/* REF Path */
clkfrac = readb(&clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_EMI]);
frac = clkfrac & CLKCTRL_FRAC_FRAC_MASK;
div = clkctrl & CLKCTRL_EMI_DIV_EMI_MASK;
return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div;
}
static uint32_t mxs_get_gpmiclk(void)
{
struct mxs_clkctrl_regs *clkctrl_regs =
(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
#if defined(CONFIG_MX23)
uint8_t *reg =
&clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_CPU];
#elif defined(CONFIG_MX28)
uint8_t *reg =
&clkctrl_regs->hw_clkctrl_frac1[CLKCTRL_FRAC1_GPMI];
#endif
uint32_t clkctrl, clkseq, div;
uint8_t clkfrac, frac;
clkseq = readl(&clkctrl_regs->hw_clkctrl_clkseq);
clkctrl = readl(&clkctrl_regs->hw_clkctrl_gpmi);
/* XTAL Path */
if (clkseq & CLKCTRL_CLKSEQ_BYPASS_GPMI) {
div = clkctrl & CLKCTRL_GPMI_DIV_MASK;
return XTAL_FREQ_MHZ / div;
}
/* REF Path */
clkfrac = readb(reg);
frac = clkfrac & CLKCTRL_FRAC_FRAC_MASK;
div = clkctrl & CLKCTRL_GPMI_DIV_MASK;
return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div;
}
/*
* Set IO clock frequency, in kHz
*/
void mxs_set_ioclk(enum mxs_ioclock io, uint32_t freq)
{
struct mxs_clkctrl_regs *clkctrl_regs =
(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
uint32_t div;
int io_reg;
if (freq == 0)
return;
if ((io < MXC_IOCLK0) || (io > MXC_IOCLK1))
return;
div = (PLL_FREQ_KHZ * PLL_FREQ_COEF) / freq;
if (div < 18)
div = 18;
if (div > 35)
div = 35;
io_reg = CLKCTRL_FRAC0_IO0 - io; /* Register order is reversed */
writeb(CLKCTRL_FRAC_CLKGATE,
&clkctrl_regs->hw_clkctrl_frac0_set[io_reg]);
writeb(CLKCTRL_FRAC_CLKGATE | (div & CLKCTRL_FRAC_FRAC_MASK),
&clkctrl_regs->hw_clkctrl_frac0[io_reg]);
writeb(CLKCTRL_FRAC_CLKGATE,
&clkctrl_regs->hw_clkctrl_frac0_clr[io_reg]);
}
/*
* Get IO clock, returns IO clock in kHz
*/
static uint32_t mxs_get_ioclk(enum mxs_ioclock io)
{
struct mxs_clkctrl_regs *clkctrl_regs =
(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
uint8_t ret;
int io_reg;
if ((io < MXC_IOCLK0) || (io > MXC_IOCLK1))
return 0;
io_reg = CLKCTRL_FRAC0_IO0 - io; /* Register order is reversed */
ret = readb(&clkctrl_regs->hw_clkctrl_frac0[io_reg]) &
CLKCTRL_FRAC_FRAC_MASK;
return (PLL_FREQ_KHZ * PLL_FREQ_COEF) / ret;
}
/*
* Configure SSP clock frequency, in kHz
*/
void mxs_set_sspclk(enum mxs_sspclock ssp, uint32_t freq, int xtal)
{
struct mxs_clkctrl_regs *clkctrl_regs =
(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
uint32_t clk, clkreg;
if (ssp > MXC_SSPCLK_MAX)
return;
clkreg = (uint32_t)(&clkctrl_regs->hw_clkctrl_ssp0) +
(ssp * sizeof(struct mxs_register_32));
clrbits_le32(clkreg, CLKCTRL_SSP_CLKGATE);
while (readl(clkreg) & CLKCTRL_SSP_CLKGATE)
;
if (xtal)
clk = XTAL_FREQ_KHZ;
else
clk = mxs_get_ioclk(ssp >> 1);
if (freq > clk)
return;
/* Calculate the divider and cap it if necessary */
clk /= freq;
if (clk > CLKCTRL_SSP_DIV_MASK)
clk = CLKCTRL_SSP_DIV_MASK;
clrsetbits_le32(clkreg, CLKCTRL_SSP_DIV_MASK, clk);
while (readl(clkreg) & CLKCTRL_SSP_BUSY)
;
if (xtal)
writel(CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp,
&clkctrl_regs->hw_clkctrl_clkseq_set);
else
writel(CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp,
&clkctrl_regs->hw_clkctrl_clkseq_clr);
}
/*
* Return SSP frequency, in kHz
*/
static uint32_t mxs_get_sspclk(enum mxs_sspclock ssp)
{
struct mxs_clkctrl_regs *clkctrl_regs =
(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
uint32_t clkreg;
uint32_t clk, tmp;
if (ssp > MXC_SSPCLK_MAX)
return 0;
tmp = readl(&clkctrl_regs->hw_clkctrl_clkseq);
if (tmp & (CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp))
return XTAL_FREQ_KHZ;
clkreg = (uint32_t)(&clkctrl_regs->hw_clkctrl_ssp0) +
(ssp * sizeof(struct mxs_register_32));
tmp = readl(clkreg) & CLKCTRL_SSP_DIV_MASK;
if (tmp == 0)
return 0;
clk = mxs_get_ioclk(ssp >> 1);
return clk / tmp;
}
/*
* Set SSP/MMC bus frequency, in kHz)
*/
void mxs_set_ssp_busclock(unsigned int bus, uint32_t freq)
{
struct mxs_ssp_regs *ssp_regs;
const enum mxs_sspclock clk = mxs_ssp_clock_by_bus(bus);
const uint32_t sspclk = mxs_get_sspclk(clk);
uint32_t reg;
uint32_t divide, rate, tgtclk;
ssp_regs = mxs_ssp_regs_by_bus(bus);
/*
* SSP bit rate = SSPCLK / (CLOCK_DIVIDE * (1 + CLOCK_RATE)),
* CLOCK_DIVIDE has to be an even value from 2 to 254, and
* CLOCK_RATE could be any integer from 0 to 255.
*/
for (divide = 2; divide < 254; divide += 2) {
rate = sspclk / freq / divide;
if (rate <= 256)
break;
}
tgtclk = sspclk / divide / rate;
while (tgtclk > freq) {
rate++;
tgtclk = sspclk / divide / rate;
}
if (rate > 256)
rate = 256;
/* Always set timeout the maximum */
reg = SSP_TIMING_TIMEOUT_MASK |
(divide << SSP_TIMING_CLOCK_DIVIDE_OFFSET) |
((rate - 1) << SSP_TIMING_CLOCK_RATE_OFFSET);
writel(reg, &ssp_regs->hw_ssp_timing);
debug("SPI%d: Set freq rate to %d KHz (requested %d KHz)\n",
bus, tgtclk, freq);
}
void mxs_set_lcdclk(uint32_t __maybe_unused lcd_base, uint32_t freq)
{
struct mxs_clkctrl_regs *clkctrl_regs =
(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
uint32_t fp, x, k_rest, k_best, x_best, tk;
int32_t k_best_l = 999, k_best_t = 0, x_best_l = 0xff, x_best_t = 0xff;
if (freq == 0)
return;
#if defined(CONFIG_MX23)
writel(CLKCTRL_CLKSEQ_BYPASS_PIX, &clkctrl_regs->hw_clkctrl_clkseq_clr);
#elif defined(CONFIG_MX28)
writel(CLKCTRL_CLKSEQ_BYPASS_DIS_LCDIF, &clkctrl_regs->hw_clkctrl_clkseq_clr);
#endif
/*
* / 18 \ 1 1
* freq kHz = | 480000000 Hz * -- | * --- * ------
* \ x / k 1000
*
* 480000000 Hz 18
* ------------ * --
* freq kHz x
* k = -------------------
* 1000
*/
fp = ((PLL_FREQ_KHZ * 1000) / freq) * 18;
for (x = 18; x <= 35; x++) {
tk = fp / x;
if ((tk / 1000 == 0) || (tk / 1000 > 255))
continue;
k_rest = tk % 1000;
if (k_rest < (k_best_l % 1000)) {
k_best_l = tk;
x_best_l = x;
}
if (k_rest > (k_best_t % 1000)) {
k_best_t = tk;
x_best_t = x;
}
}
if (1000 - (k_best_t % 1000) > (k_best_l % 1000)) {
k_best = k_best_l;
x_best = x_best_l;
} else {
k_best = k_best_t;
x_best = x_best_t;
}
k_best /= 1000;
#if defined(CONFIG_MX23)
writeb(CLKCTRL_FRAC_CLKGATE,
&clkctrl_regs->hw_clkctrl_frac0_set[CLKCTRL_FRAC0_PIX]);
writeb(CLKCTRL_FRAC_CLKGATE | (x_best & CLKCTRL_FRAC_FRAC_MASK),
&clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_PIX]);
writeb(CLKCTRL_FRAC_CLKGATE,
&clkctrl_regs->hw_clkctrl_frac0_clr[CLKCTRL_FRAC0_PIX]);
writel(CLKCTRL_PIX_CLKGATE,
&clkctrl_regs->hw_clkctrl_pix_set);
clrsetbits_le32(&clkctrl_regs->hw_clkctrl_pix,
CLKCTRL_PIX_DIV_MASK | CLKCTRL_PIX_CLKGATE,
k_best << CLKCTRL_PIX_DIV_OFFSET);
while (readl(&clkctrl_regs->hw_clkctrl_pix) & CLKCTRL_PIX_BUSY)
;
#elif defined(CONFIG_MX28)
writeb(CLKCTRL_FRAC_CLKGATE,
&clkctrl_regs->hw_clkctrl_frac1_set[CLKCTRL_FRAC1_PIX]);
writeb(CLKCTRL_FRAC_CLKGATE | (x_best & CLKCTRL_FRAC_FRAC_MASK),
&clkctrl_regs->hw_clkctrl_frac1[CLKCTRL_FRAC1_PIX]);
writeb(CLKCTRL_FRAC_CLKGATE,
&clkctrl_regs->hw_clkctrl_frac1_clr[CLKCTRL_FRAC1_PIX]);
writel(CLKCTRL_DIS_LCDIF_CLKGATE,
&clkctrl_regs->hw_clkctrl_lcdif_set);
clrsetbits_le32(&clkctrl_regs->hw_clkctrl_lcdif,
CLKCTRL_DIS_LCDIF_DIV_MASK | CLKCTRL_DIS_LCDIF_CLKGATE,
k_best << CLKCTRL_DIS_LCDIF_DIV_OFFSET);
while (readl(&clkctrl_regs->hw_clkctrl_lcdif) & CLKCTRL_DIS_LCDIF_BUSY)
;
#endif
}
uint32_t mxc_get_clock(enum mxc_clock clk)
{
switch (clk) {
case MXC_ARM_CLK:
return mxs_get_pclk() * 1000000;
case MXC_GPMI_CLK:
return mxs_get_gpmiclk() * 1000000;
case MXC_AHB_CLK:
case MXC_IPG_CLK:
return mxs_get_hclk() * 1000000;
case MXC_EMI_CLK:
return mxs_get_emiclk();
case MXC_IO0_CLK:
return mxs_get_ioclk(MXC_IOCLK0);
case MXC_IO1_CLK:
return mxs_get_ioclk(MXC_IOCLK1);
case MXC_XTAL_CLK:
return XTAL_FREQ_KHZ * 1000;
case MXC_SSP0_CLK:
return mxs_get_sspclk(MXC_SSPCLK0);
#ifdef CONFIG_MX28
case MXC_SSP1_CLK:
return mxs_get_sspclk(MXC_SSPCLK1);
case MXC_SSP2_CLK:
return mxs_get_sspclk(MXC_SSPCLK2);
case MXC_SSP3_CLK:
return mxs_get_sspclk(MXC_SSPCLK3);
#endif
}
return 0;
}
@@ -0,0 +1,96 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2004-2006,2010 Freescale Semiconductor, Inc. All Rights Reserved.
* Copyright (C) 2008 by Sascha Hauer <kernel@pengutronix.de>
* Copyright (C) 2009 by Jan Weitzel Phytec Messtechnik GmbH,
* <armlinux@phytec.de>
*/
#include <common.h>
#include <linux/errno.h>
#include <asm/io.h>
#include <asm/arch/clock.h>
#include <asm/arch/iomux.h>
#include <asm/arch/imx-regs.h>
#if defined(CONFIG_MX23)
#define DRIVE_OFFSET 0x200
#define PULL_OFFSET 0x400
#elif defined(CONFIG_MX28)
#define DRIVE_OFFSET 0x300
#define PULL_OFFSET 0x600
#else
#error "Please select CONFIG_MX23 or CONFIG_MX28"
#endif
/*
* configures a single pad in the iomuxer
*/
int mxs_iomux_setup_pad(iomux_cfg_t pad)
{
u32 reg, ofs, bp, bm;
void *iomux_base = (void *)MXS_PINCTRL_BASE;
struct mxs_register_32 *mxs_reg;
/* muxsel */
ofs = 0x100;
ofs += PAD_BANK(pad) * 0x20 + PAD_PIN(pad) / 16 * 0x10;
bp = PAD_PIN(pad) % 16 * 2;
bm = 0x3 << bp;
reg = readl(iomux_base + ofs);
reg &= ~bm;
reg |= PAD_MUXSEL(pad) << bp;
writel(reg, iomux_base + ofs);
/* drive */
ofs = DRIVE_OFFSET;
ofs += PAD_BANK(pad) * 0x40 + PAD_PIN(pad) / 8 * 0x10;
/* mA */
if (PAD_MA_VALID(pad)) {
bp = PAD_PIN(pad) % 8 * 4;
bm = 0x3 << bp;
reg = readl(iomux_base + ofs);
reg &= ~bm;
reg |= PAD_MA(pad) << bp;
writel(reg, iomux_base + ofs);
}
/* vol */
if (PAD_VOL_VALID(pad)) {
bp = PAD_PIN(pad) % 8 * 4 + 2;
mxs_reg = (struct mxs_register_32 *)(iomux_base + ofs);
if (PAD_VOL(pad))
writel(1 << bp, &mxs_reg->reg_set);
else
writel(1 << bp, &mxs_reg->reg_clr);
}
/* pull */
if (PAD_PULL_VALID(pad)) {
ofs = PULL_OFFSET;
ofs += PAD_BANK(pad) * 0x10;
bp = PAD_PIN(pad);
mxs_reg = (struct mxs_register_32 *)(iomux_base + ofs);
if (PAD_PULL(pad))
writel(1 << bp, &mxs_reg->reg_set);
else
writel(1 << bp, &mxs_reg->reg_clr);
}
return 0;
}
int mxs_iomux_setup_multiple_pads(const iomux_cfg_t *pad_list, unsigned count)
{
const iomux_cfg_t *p = pad_list;
int i;
int ret;
for (i = 0; i < count; i++) {
ret = mxs_iomux_setup_pad(*p);
if (ret)
return ret;
p++;
}
return 0;
}
@@ -0,0 +1,284 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Freescale i.MX23/i.MX28 common code
*
* Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
* on behalf of DENX Software Engineering GmbH
*
* Based on code from LTIB:
* Copyright (C) 2010 Freescale Semiconductor, Inc.
*/
#include <common.h>
#include <linux/errno.h>
#include <asm/io.h>
#include <asm/arch/clock.h>
#include <asm/mach-imx/dma.h>
#include <asm/arch/gpio.h>
#include <asm/arch/iomux.h>
#include <asm/arch/imx-regs.h>
#include <asm/arch/sys_proto.h>
#include <linux/compiler.h>
DECLARE_GLOBAL_DATA_PTR;
/* Lowlevel init isn't used on i.MX28, so just have a dummy here */
__weak void lowlevel_init(void) {}
void reset_cpu(ulong ignored) __attribute__((noreturn));
void reset_cpu(ulong ignored)
{
struct mxs_rtc_regs *rtc_regs =
(struct mxs_rtc_regs *)MXS_RTC_BASE;
struct mxs_lcdif_regs *lcdif_regs =
(struct mxs_lcdif_regs *)MXS_LCDIF_BASE;
/*
* Shut down the LCD controller as it interferes with BootROM boot mode
* pads sampling.
*/
writel(LCDIF_CTRL_RUN, &lcdif_regs->hw_lcdif_ctrl_clr);
/* Wait 1 uS before doing the actual watchdog reset */
writel(1, &rtc_regs->hw_rtc_watchdog);
writel(RTC_CTRL_WATCHDOGEN, &rtc_regs->hw_rtc_ctrl_set);
/* Endless loop, reset will exit from here */
for (;;)
;
}
/*
* This function will craft a jumptable at 0x0 which will redirect interrupt
* vectoring to proper location of U-Boot in RAM.
*
* The structure of the jumptable will be as follows:
* ldr pc, [pc, #0x18] ..... for each vector, thus repeated 8 times
* <destination address> ... for each previous ldr, thus also repeated 8 times
*
* The "ldr pc, [pc, #0x18]" instruction above loads address from memory at
* offset 0x18 from current value of PC register. Note that PC is already
* incremented by 4 when computing the offset, so the effective offset is
* actually 0x20, this the associated <destination address>. Loading the PC
* register with an address performs a jump to that address.
*/
void mx28_fixup_vt(uint32_t start_addr)
{
/* ldr pc, [pc, #0x18] */
const uint32_t ldr_pc = 0xe59ff018;
/* Jumptable location is 0x0 */
uint32_t *vt = (uint32_t *)0x0;
int i;
for (i = 0; i < 8; i++) {
/* cppcheck-suppress nullPointer */
vt[i] = ldr_pc;
/* cppcheck-suppress nullPointer */
vt[i + 8] = start_addr + (4 * i);
}
}
#ifdef CONFIG_ARCH_MISC_INIT
int arch_misc_init(void)
{
mx28_fixup_vt(gd->relocaddr);
return 0;
}
#endif
int arch_cpu_init(void)
{
struct mxs_clkctrl_regs *clkctrl_regs =
(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
extern uint32_t _start;
mx28_fixup_vt((uint32_t)&_start);
/*
* Enable NAND clock
*/
/* Clear bypass bit */
writel(CLKCTRL_CLKSEQ_BYPASS_GPMI,
&clkctrl_regs->hw_clkctrl_clkseq_set);
/* Set GPMI clock to ref_gpmi / 12 */
clrsetbits_le32(&clkctrl_regs->hw_clkctrl_gpmi,
CLKCTRL_GPMI_CLKGATE | CLKCTRL_GPMI_DIV_MASK, 1);
udelay(1000);
/*
* Configure GPIO unit
*/
mxs_gpio_init();
#ifdef CONFIG_APBH_DMA
/* Start APBH DMA */
mxs_dma_init();
#endif
return 0;
}
u32 get_cpu_rev(void)
{
struct mxs_digctl_regs *digctl_regs =
(struct mxs_digctl_regs *)MXS_DIGCTL_BASE;
uint8_t rev = readl(&digctl_regs->hw_digctl_chipid) & 0x000000FF;
switch (readl(&digctl_regs->hw_digctl_chipid) & HW_DIGCTL_CHIPID_MASK) {
case HW_DIGCTL_CHIPID_MX23:
switch (rev) {
case 0x0:
case 0x1:
case 0x2:
case 0x3:
case 0x4:
return (MXC_CPU_MX23 << 12) | (rev + 0x10);
default:
return 0;
}
case HW_DIGCTL_CHIPID_MX28:
switch (rev) {
case 0x1:
return (MXC_CPU_MX28 << 12) | 0x12;
default:
return 0;
}
default:
return 0;
}
}
#if defined(CONFIG_DISPLAY_CPUINFO)
const char *get_imx_type(u32 imxtype)
{
switch (imxtype) {
case MXC_CPU_MX23:
return "23";
case MXC_CPU_MX28:
return "28";
default:
return "??";
}
}
int print_cpuinfo(void)
{
u32 cpurev;
struct mxs_spl_data *data = MXS_SPL_DATA;
cpurev = get_cpu_rev();
printf("CPU: Freescale i.MX%s rev%d.%d at %d MHz\n",
get_imx_type((cpurev & 0xFF000) >> 12),
(cpurev & 0x000F0) >> 4,
(cpurev & 0x0000F) >> 0,
mxc_get_clock(MXC_ARM_CLK) / 1000000);
printf("BOOT: %s\n", mxs_boot_modes[data->boot_mode_idx].mode);
return 0;
}
#endif
int do_mx28_showclocks(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
printf("CPU: %3d MHz\n", mxc_get_clock(MXC_ARM_CLK) / 1000000);
printf("BUS: %3d MHz\n", mxc_get_clock(MXC_AHB_CLK) / 1000000);
printf("EMI: %3d MHz\n", mxc_get_clock(MXC_EMI_CLK));
printf("GPMI: %3d MHz\n", mxc_get_clock(MXC_GPMI_CLK) / 1000000);
return 0;
}
/*
* Initializes on-chip ethernet controllers.
*/
#if defined(CONFIG_MX28) && defined(CONFIG_CMD_NET)
int cpu_eth_init(bd_t *bis)
{
struct mxs_clkctrl_regs *clkctrl_regs =
(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
/* Turn on ENET clocks */
clrbits_le32(&clkctrl_regs->hw_clkctrl_enet,
CLKCTRL_ENET_SLEEP | CLKCTRL_ENET_DISABLE);
/* Set up ENET PLL for 50 MHz */
/* Power on ENET PLL */
writel(CLKCTRL_PLL2CTRL0_POWER,
&clkctrl_regs->hw_clkctrl_pll2ctrl0_set);
udelay(10);
/* Gate on ENET PLL */
writel(CLKCTRL_PLL2CTRL0_CLKGATE,
&clkctrl_regs->hw_clkctrl_pll2ctrl0_clr);
/* Enable pad output */
setbits_le32(&clkctrl_regs->hw_clkctrl_enet, CLKCTRL_ENET_CLK_OUT_EN);
return 0;
}
#endif
__weak void mx28_adjust_mac(int dev_id, unsigned char *mac)
{
mac[0] = 0x00;
mac[1] = 0x04; /* Use FSL vendor MAC address by default */
if (dev_id == 1) /* Let MAC1 be MAC0 + 1 by default */
mac[5] += 1;
}
#ifdef CONFIG_MX28_FEC_MAC_IN_OCOTP
#define MXS_OCOTP_MAX_TIMEOUT 1000000
void imx_get_mac_from_fuse(int dev_id, unsigned char *mac)
{
struct mxs_ocotp_regs *ocotp_regs =
(struct mxs_ocotp_regs *)MXS_OCOTP_BASE;
uint32_t data;
memset(mac, 0, 6);
writel(OCOTP_CTRL_RD_BANK_OPEN, &ocotp_regs->hw_ocotp_ctrl_set);
if (mxs_wait_mask_clr(&ocotp_regs->hw_ocotp_ctrl_reg, OCOTP_CTRL_BUSY,
MXS_OCOTP_MAX_TIMEOUT)) {
printf("MXS FEC: Can't get MAC from OCOTP\n");
return;
}
data = readl(&ocotp_regs->hw_ocotp_cust0);
mac[2] = (data >> 24) & 0xff;
mac[3] = (data >> 16) & 0xff;
mac[4] = (data >> 8) & 0xff;
mac[5] = data & 0xff;
mx28_adjust_mac(dev_id, mac);
}
#else
void imx_get_mac_from_fuse(int dev_id, unsigned char *mac)
{
memset(mac, 0, 6);
}
#endif
int mxs_dram_init(void)
{
struct mxs_spl_data *data = MXS_SPL_DATA;
if (data->mem_dram_size == 0) {
printf("MXS:\n"
"Error, the RAM size passed up from SPL is 0!\n");
hang();
}
gd->ram_size = data->mem_dram_size;
return 0;
}
U_BOOT_CMD(
clocks, CONFIG_SYS_MAXARGS, 1, do_mx28_showclocks,
"display clocks",
""
);
@@ -0,0 +1,28 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Freescale i.MX28 SPL functions
*
* Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
* on behalf of DENX Software Engineering GmbH
*/
#ifndef __M28_INIT_H__
#define __M28_INIT_H__
void early_delay(int delay);
void mxs_power_init(void);
#ifdef CONFIG_SPL_MXS_PSWITCH_WAIT
void mxs_power_wait_pswitch(void);
#else
static inline void mxs_power_wait_pswitch(void) { }
#endif
void mxs_mem_init(void);
uint32_t mxs_mem_get_size(void);
void mxs_lradc_init(void);
void mxs_lradc_enable_batt_measurement(void);
#endif /* __M28_INIT_H__ */
@@ -0,0 +1,11 @@
DISPLAYPROGRESS
SECTION 0x0 BOOTABLE
TAG LAST
LOAD 0x1000 spl/u-boot-spl.bin
LOAD 0x8000 spl/u-boot-spl.ivt
LOAD 0x8040 spl/u-boot-spl.sig
CALL HAB 0x8000 0x0
LOAD 0x40002000 u-boot.bin
LOAD 0x40001000 u-boot.ivt
LOAD 0x40001040 u-boot.sig
CALL HAB 0x40001000 0x0
@@ -0,0 +1,5 @@
DISPLAYPROGRESS
SECTION 0x0 BOOTABLE
TAG LAST
LOAD 0x1000 spl/u-boot-spl.bin
CALL 0x1000 0x0
@@ -0,0 +1,6 @@
DISPLAYPROGRESS
SECTION 0x0 BOOTABLE
TAG LAST
LOAD 0x1000 spl/u-boot-spl.bin
LOAD IVT 0x8000 0x1000
CALL HAB 0x8000 0x0
@@ -0,0 +1,7 @@
DISPLAYPROGRESS
SECTION 0x0 BOOTABLE
TAG LAST
LOAD 0x1000 spl/u-boot-spl.bin
CALL 0x1000 0x0
LOAD 0x40002000 u-boot.bin
CALL 0x40002000 0x0
@@ -0,0 +1,9 @@
DISPLAYPROGRESS
SECTION 0x0 BOOTABLE
TAG LAST
LOAD 0x1000 spl/u-boot-spl.bin
LOAD IVT 0x8000 0x1000
CALL HAB 0x8000 0x0
LOAD 0x40002000 u-boot.bin
LOAD IVT 0x8000 0x40002000
CALL HAB 0x8000 0x0
@@ -0,0 +1,162 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Freescale i.MX28 Boot setup
*
* Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
* on behalf of DENX Software Engineering GmbH
*/
#include <common.h>
#include <config.h>
#include <serial.h>
#include <asm/io.h>
#include <asm/arch/imx-regs.h>
#include <asm/arch/sys_proto.h>
#include <asm/gpio.h>
#include <linux/compiler.h>
#include "mxs_init.h"
DECLARE_GLOBAL_DATA_PTR;
static gd_t gdata __section(".data");
#ifdef CONFIG_SPL_SERIAL_SUPPORT
static bd_t bdata __section(".data");
#endif
/*
* This delay function is intended to be used only in early stage of boot, where
* clock are not set up yet. The timer used here is reset on every boot and
* takes a few seconds to roll. The boot doesn't take that long, so to keep the
* code simple, it doesn't take rolling into consideration.
*/
void early_delay(int delay)
{
struct mxs_digctl_regs *digctl_regs =
(struct mxs_digctl_regs *)MXS_DIGCTL_BASE;
uint32_t st = readl(&digctl_regs->hw_digctl_microseconds);
st += delay;
while (st > readl(&digctl_regs->hw_digctl_microseconds))
;
}
#if defined(CONFIG_MX23)
#define MUX_CONFIG_BOOTMODE_PAD (MXS_PAD_3V3 | MXS_PAD_4MA | MXS_PAD_NOPULL)
static const iomux_cfg_t iomux_boot[] = {
MX23_PAD_LCD_D00__GPIO_1_0 | MUX_CONFIG_BOOTMODE_PAD,
MX23_PAD_LCD_D01__GPIO_1_1 | MUX_CONFIG_BOOTMODE_PAD,
MX23_PAD_LCD_D02__GPIO_1_2 | MUX_CONFIG_BOOTMODE_PAD,
MX23_PAD_LCD_D03__GPIO_1_3 | MUX_CONFIG_BOOTMODE_PAD,
MX23_PAD_LCD_D04__GPIO_1_4 | MUX_CONFIG_BOOTMODE_PAD,
MX23_PAD_LCD_D05__GPIO_1_5 | MUX_CONFIG_BOOTMODE_PAD,
};
#endif
static uint8_t mxs_get_bootmode_index(void)
{
uint8_t bootmode = 0;
int i;
uint8_t masked;
#if defined(CONFIG_MX23)
/* Setup IOMUX of bootmode pads to GPIO */
mxs_iomux_setup_multiple_pads(iomux_boot, ARRAY_SIZE(iomux_boot));
/* Setup bootmode pins as GPIO input */
gpio_direction_input(MX23_PAD_LCD_D00__GPIO_1_0);
gpio_direction_input(MX23_PAD_LCD_D01__GPIO_1_1);
gpio_direction_input(MX23_PAD_LCD_D02__GPIO_1_2);
gpio_direction_input(MX23_PAD_LCD_D03__GPIO_1_3);
gpio_direction_input(MX23_PAD_LCD_D05__GPIO_1_5);
/* Read bootmode pads */
bootmode |= (gpio_get_value(MX23_PAD_LCD_D00__GPIO_1_0) ? 1 : 0) << 0;
bootmode |= (gpio_get_value(MX23_PAD_LCD_D01__GPIO_1_1) ? 1 : 0) << 1;
bootmode |= (gpio_get_value(MX23_PAD_LCD_D02__GPIO_1_2) ? 1 : 0) << 2;
bootmode |= (gpio_get_value(MX23_PAD_LCD_D03__GPIO_1_3) ? 1 : 0) << 3;
bootmode |= (gpio_get_value(MX23_PAD_LCD_D05__GPIO_1_5) ? 1 : 0) << 5;
#elif defined(CONFIG_MX28)
/* The global boot mode will be detected by ROM code and its value
* is stored at the fixed address 0x00019BF0 in OCRAM.
*/
#define GLOBAL_BOOT_MODE_ADDR 0x00019BF0
bootmode = __raw_readl(GLOBAL_BOOT_MODE_ADDR);
#endif
for (i = 0; i < ARRAY_SIZE(mxs_boot_modes); i++) {
masked = bootmode & mxs_boot_modes[i].boot_mask;
if (masked == mxs_boot_modes[i].boot_pads)
break;
}
return i;
}
static void mxs_spl_fixup_vectors(void)
{
/*
* Copy our vector table to 0x0, since due to HAB, we cannot
* be loaded to 0x0. We want to have working vectoring though,
* thus this fixup. Our vectoring table is PIC, so copying is
* fine.
*/
extern uint32_t _start;
/* cppcheck-suppress nullPointer */
memcpy(0x0, &_start, 0x60);
}
static void mxs_spl_console_init(void)
{
#ifdef CONFIG_SPL_SERIAL_SUPPORT
gd->bd = &bdata;
gd->baudrate = CONFIG_BAUDRATE;
serial_init();
gd->have_console = 1;
#endif
}
void mxs_common_spl_init(const uint32_t arg, const uint32_t *resptr,
const iomux_cfg_t *iomux_setup,
const unsigned int iomux_size)
{
struct mxs_spl_data *data = MXS_SPL_DATA;
uint8_t bootmode = mxs_get_bootmode_index();
gd = &gdata;
mxs_spl_fixup_vectors();
mxs_iomux_setup_multiple_pads(iomux_setup, iomux_size);
mxs_spl_console_init();
debug("SPL: Serial Console Initialised\n");
mxs_power_init();
mxs_mem_init();
data->mem_dram_size = mxs_mem_get_size();
data->boot_mode_idx = bootmode;
mxs_power_wait_pswitch();
if (mxs_boot_modes[data->boot_mode_idx].boot_pads == MXS_BM_JTAG) {
debug("SPL: Waiting for JTAG user\n");
asm volatile ("x: b x");
}
}
#ifndef CONFIG_SPL_FRAMEWORK
/* Support aparatus */
inline void board_init_f(unsigned long bootflag)
{
for (;;)
;
}
inline void board_init_r(gd_t *id, ulong dest_addr)
{
for (;;)
;
}
#endif
@@ -0,0 +1,78 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Freescale i.MX28 Battery measurement init
*
* Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
* on behalf of DENX Software Engineering GmbH
*/
#include <common.h>
#include <config.h>
#include <asm/io.h>
#include <asm/arch/imx-regs.h>
#include "mxs_init.h"
void mxs_lradc_init(void)
{
struct mxs_lradc_regs *regs = (struct mxs_lradc_regs *)MXS_LRADC_BASE;
debug("SPL: Initialisating LRADC\n");
writel(LRADC_CTRL0_SFTRST, &regs->hw_lradc_ctrl0_clr);
writel(LRADC_CTRL0_CLKGATE, &regs->hw_lradc_ctrl0_clr);
writel(LRADC_CTRL0_ONCHIP_GROUNDREF, &regs->hw_lradc_ctrl0_clr);
clrsetbits_le32(&regs->hw_lradc_ctrl3,
LRADC_CTRL3_CYCLE_TIME_MASK,
LRADC_CTRL3_CYCLE_TIME_6MHZ);
clrsetbits_le32(&regs->hw_lradc_ctrl4,
LRADC_CTRL4_LRADC7SELECT_MASK |
LRADC_CTRL4_LRADC6SELECT_MASK,
LRADC_CTRL4_LRADC7SELECT_CHANNEL7 |
LRADC_CTRL4_LRADC6SELECT_CHANNEL10);
}
void mxs_lradc_enable_batt_measurement(void)
{
struct mxs_lradc_regs *regs = (struct mxs_lradc_regs *)MXS_LRADC_BASE;
debug("SPL: Enabling LRADC battery measurement\n");
/* Check if the channel is present at all. */
if (!(readl(&regs->hw_lradc_status) & LRADC_STATUS_CHANNEL7_PRESENT)) {
debug("SPL: LRADC channel 7 is not present - aborting\n");
return;
}
debug("SPL: LRADC channel 7 is present - configuring\n");
writel(LRADC_CTRL1_LRADC7_IRQ_EN, &regs->hw_lradc_ctrl1_clr);
writel(LRADC_CTRL1_LRADC7_IRQ, &regs->hw_lradc_ctrl1_clr);
clrsetbits_le32(&regs->hw_lradc_conversion,
LRADC_CONVERSION_SCALE_FACTOR_MASK,
LRADC_CONVERSION_SCALE_FACTOR_LI_ION);
writel(LRADC_CONVERSION_AUTOMATIC, &regs->hw_lradc_conversion_set);
/* Configure the channel. */
writel((1 << 7) << LRADC_CTRL2_DIVIDE_BY_TWO_OFFSET,
&regs->hw_lradc_ctrl2_clr);
writel(0xffffffff, &regs->hw_lradc_ch7_clr);
clrbits_le32(&regs->hw_lradc_ch7, LRADC_CH_NUM_SAMPLES_MASK);
writel(LRADC_CH_ACCUMULATE, &regs->hw_lradc_ch7_clr);
/* Schedule the channel. */
writel(1 << 7, &regs->hw_lradc_ctrl0_set);
/* Start the channel sampling. */
writel(((1 << 7) << LRADC_DELAY_TRIGGER_LRADCS_OFFSET) |
((1 << 3) << LRADC_DELAY_TRIGGER_DELAYS_OFFSET) |
100, &regs->hw_lradc_delay3);
writel(0xffffffff, &regs->hw_lradc_ch7_clr);
writel(LRADC_DELAY_KICK, &regs->hw_lradc_delay3_set);
debug("SPL: LRADC channel 7 configuration complete\n");
}
@@ -0,0 +1,359 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Freescale i.MX28 RAM init
*
* Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
* on behalf of DENX Software Engineering GmbH
*/
#include <common.h>
#include <config.h>
#include <asm/io.h>
#include <asm/arch/imx-regs.h>
#include <asm/arch/sys_proto.h>
#include <linux/compiler.h>
#include "mxs_init.h"
__weak uint32_t mxs_dram_vals[] = {
/*
* i.MX28 DDR2 at 200MHz
*/
#if defined(CONFIG_MX28)
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000100, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00010101, 0x01010101,
0x000f0f01, 0x0f02020a, 0x00000000, 0x00010101,
0x00000100, 0x00000100, 0x00000000, 0x00000002,
0x01010000, 0x07080403, 0x06005003, 0x0a0000c8,
0x02009c40, 0x0002030c, 0x0036a609, 0x031a0612,
0x02030202, 0x00c8001c, 0x00000000, 0x00000000,
0x00012100, 0xffff0303, 0x00012100, 0xffff0303,
0x00012100, 0xffff0303, 0x00012100, 0xffff0303,
0x00000003, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000612, 0x01000F02,
0x06120612, 0x00000200, 0x00020007, 0xf4004a27,
0xf4004a27, 0xf4004a27, 0xf4004a27, 0x07000300,
0x07000300, 0x07400300, 0x07400300, 0x00000005,
0x00000000, 0x00000000, 0x01000000, 0x01020408,
0x08040201, 0x000f1133, 0x00000000, 0x00001f04,
0x00001f04, 0x00001f04, 0x00001f04, 0x00001f04,
0x00001f04, 0x00001f04, 0x00001f04, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00010000, 0x00030404,
0x00000003, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x01010000,
0x01000000, 0x03030000, 0x00010303, 0x01020202,
0x00000000, 0x02040303, 0x21002103, 0x00061200,
0x06120612, 0x04420442, 0x04420442, 0x00040004,
0x00040004, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0xffffffff
/*
* i.MX23 DDR at 133MHz
*/
#elif defined(CONFIG_MX23)
0x01010001, 0x00010100, 0x01000101, 0x00000001,
0x00000101, 0x00000000, 0x00010000, 0x01000001,
0x00000000, 0x00000001, 0x07000200, 0x00070202,
0x02020000, 0x04040a01, 0x00000201, 0x02040000,
0x02000000, 0x19000f08, 0x0d0d0000, 0x02021313,
0x02061521, 0x0000000a, 0x00080008, 0x00200020,
0x00200020, 0x00200020, 0x000003f7, 0x00000000,
0x00000000, 0x00000020, 0x00000020, 0x00c80000,
0x000a23cd, 0x000000c8, 0x00006665, 0x00000000,
0x00000101, 0x00040001, 0x00000000, 0x00000000,
0x00010000
#else
#error Unsupported memory initialization
#endif
};
__weak void mxs_adjust_memory_params(uint32_t *dram_vals)
{
debug("SPL: Using default SDRAM parameters\n");
}
#ifdef CONFIG_MX28
static void initialize_dram_values(void)
{
int i;
debug("SPL: Setting mx28 board specific SDRAM parameters\n");
mxs_adjust_memory_params(mxs_dram_vals);
debug("SPL: Applying SDRAM parameters\n");
for (i = 0; i < ARRAY_SIZE(mxs_dram_vals); i++)
writel(mxs_dram_vals[i], MXS_DRAM_BASE + (4 * i));
}
#else
static void initialize_dram_values(void)
{
int i;
debug("SPL: Setting mx23 board specific SDRAM parameters\n");
mxs_adjust_memory_params(mxs_dram_vals);
/*
* HW_DRAM_CTL27, HW_DRAM_CTL28 and HW_DRAM_CTL35 are not initialized as
* per FSL bootlets code.
*
* mx23 Reference Manual marks HW_DRAM_CTL27 and HW_DRAM_CTL28 as
* "reserved".
* HW_DRAM_CTL8 is setup as the last element.
* So skip the initialization of these HW_DRAM_CTL registers.
*/
debug("SPL: Applying SDRAM parameters\n");
for (i = 0; i < ARRAY_SIZE(mxs_dram_vals); i++) {
if (i == 8 || i == 27 || i == 28 || i == 35)
continue;
writel(mxs_dram_vals[i], MXS_DRAM_BASE + (4 * i));
}
/*
* Enable tRAS lockout in HW_DRAM_CTL08 ; it must be the last
* element to be set
*/
writel((1 << 24), MXS_DRAM_BASE + (4 * 8));
}
#endif
static void mxs_mem_init_clock(void)
{
struct mxs_clkctrl_regs *clkctrl_regs =
(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
#if defined(CONFIG_MX23)
/* Fractional divider for ref_emi is 33 ; 480 * 18 / 33 = 266MHz */
const unsigned char divider = 33;
#elif defined(CONFIG_MX28)
/* Fractional divider for ref_emi is 21 ; 480 * 18 / 21 = 411MHz */
const unsigned char divider = 21;
#endif
debug("SPL: Initialising FRAC0\n");
/* Gate EMI clock */
writeb(CLKCTRL_FRAC_CLKGATE,
&clkctrl_regs->hw_clkctrl_frac0_set[CLKCTRL_FRAC0_EMI]);
/* Set fractional divider for ref_emi */
writeb(CLKCTRL_FRAC_CLKGATE | (divider & CLKCTRL_FRAC_FRAC_MASK),
&clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_EMI]);
/* Ungate EMI clock */
writeb(CLKCTRL_FRAC_CLKGATE,
&clkctrl_regs->hw_clkctrl_frac0_clr[CLKCTRL_FRAC0_EMI]);
early_delay(11000);
/* Set EMI clock divider for EMI clock to 411 / 2 = 205MHz */
writel((2 << CLKCTRL_EMI_DIV_EMI_OFFSET) |
(1 << CLKCTRL_EMI_DIV_XTAL_OFFSET),
&clkctrl_regs->hw_clkctrl_emi);
/* Unbypass EMI */
writel(CLKCTRL_CLKSEQ_BYPASS_EMI,
&clkctrl_regs->hw_clkctrl_clkseq_clr);
early_delay(10000);
debug("SPL: FRAC0 Initialised\n");
}
static void mxs_mem_setup_cpu_and_hbus(void)
{
struct mxs_clkctrl_regs *clkctrl_regs =
(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
debug("SPL: Setting CPU and HBUS clock frequencies\n");
/* Set fractional divider for ref_cpu to 480 * 18 / 19 = 454MHz
* and ungate CPU clock */
writeb(19 & CLKCTRL_FRAC_FRAC_MASK,
(uint8_t *)&clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_CPU]);
/* Set CPU bypass */
writel(CLKCTRL_CLKSEQ_BYPASS_CPU,
&clkctrl_regs->hw_clkctrl_clkseq_set);
/* HBUS = 151MHz */
writel(CLKCTRL_HBUS_DIV_MASK, &clkctrl_regs->hw_clkctrl_hbus_set);
writel(((~3) << CLKCTRL_HBUS_DIV_OFFSET) & CLKCTRL_HBUS_DIV_MASK,
&clkctrl_regs->hw_clkctrl_hbus_clr);
early_delay(10000);
/* CPU clock divider = 1 */
clrsetbits_le32(&clkctrl_regs->hw_clkctrl_cpu,
CLKCTRL_CPU_DIV_CPU_MASK, 1);
/* Disable CPU bypass */
writel(CLKCTRL_CLKSEQ_BYPASS_CPU,
&clkctrl_regs->hw_clkctrl_clkseq_clr);
early_delay(15000);
}
static void mxs_mem_setup_vdda(void)
{
struct mxs_power_regs *power_regs =
(struct mxs_power_regs *)MXS_POWER_BASE;
debug("SPL: Configuring VDDA\n");
writel((0xc << POWER_VDDACTRL_TRG_OFFSET) |
(0x7 << POWER_VDDACTRL_BO_OFFSET_OFFSET) |
POWER_VDDACTRL_LINREG_OFFSET_1STEPS_BELOW,
&power_regs->hw_power_vddactrl);
}
uint32_t mxs_mem_get_size(void)
{
uint32_t sz, da;
uint32_t *vt = (uint32_t *)0x20;
/* The following is "subs pc, r14, #4", used as return from DABT. */
const uint32_t data_abort_memdetect_handler = 0xe25ef004;
/* Replace the DABT handler. */
da = vt[4];
vt[4] = data_abort_memdetect_handler;
sz = get_ram_size((long *)PHYS_SDRAM_1, PHYS_SDRAM_1_SIZE);
/* Restore the old DABT handler. */
vt[4] = da;
return sz;
}
#ifdef CONFIG_MX23
static void mx23_mem_setup_vddmem(void)
{
struct mxs_power_regs *power_regs =
(struct mxs_power_regs *)MXS_POWER_BASE;
debug("SPL: Setting mx23 VDDMEM\n");
/* We must wait before and after disabling the current limiter! */
early_delay(10000);
clrbits_le32(&power_regs->hw_power_vddmemctrl,
POWER_VDDMEMCTRL_ENABLE_ILIMIT);
early_delay(10000);
}
static void mx23_mem_init(void)
{
debug("SPL: Initialising mx23 SDRAM Controller\n");
/*
* Reset/ungate the EMI block. This is essential, otherwise the system
* suffers from memory instability. This thing is mx23 specific and is
* no longer present on mx28.
*/
mxs_reset_block((struct mxs_register_32 *)MXS_EMI_BASE);
mx23_mem_setup_vddmem();
/*
* Configure the DRAM registers
*/
/* Clear START and SREFRESH bit from DRAM_CTL8 */
clrbits_le32(MXS_DRAM_BASE + 0x20, (1 << 16) | (1 << 8));
initialize_dram_values();
/* Set START bit in DRAM_CTL8 */
setbits_le32(MXS_DRAM_BASE + 0x20, 1 << 16);
clrbits_le32(MXS_DRAM_BASE + 0x40, 1 << 17);
/* Wait for EMI_STAT bit DRAM_HALTED */
for (;;) {
if (!(readl(MXS_EMI_BASE + 0x10) & (1 << 1)))
break;
early_delay(1000);
}
/* Adjust EMI port priority. */
clrsetbits_le32(0x80020000, 0x1f << 16, 0x2);
early_delay(20000);
setbits_le32(MXS_DRAM_BASE + 0x40, 1 << 19);
setbits_le32(MXS_DRAM_BASE + 0x40, 1 << 11);
}
#endif
#ifdef CONFIG_MX28
static void mx28_mem_init(void)
{
struct mxs_pinctrl_regs *pinctrl_regs =
(struct mxs_pinctrl_regs *)MXS_PINCTRL_BASE;
debug("SPL: Initialising mx28 SDRAM Controller\n");
/* Set DDR2 mode */
writel(PINCTRL_EMI_DS_CTRL_DDR_MODE_DDR2,
&pinctrl_regs->hw_pinctrl_emi_ds_ctrl_set);
/*
* Configure the DRAM registers
*/
/* Clear START bit from DRAM_CTL16 */
clrbits_le32(MXS_DRAM_BASE + 0x40, 1);
initialize_dram_values();
/* Clear SREFRESH bit from DRAM_CTL17 */
clrbits_le32(MXS_DRAM_BASE + 0x44, 1);
/* Set START bit in DRAM_CTL16 */
setbits_le32(MXS_DRAM_BASE + 0x40, 1);
/* Wait for bit 20 (DRAM init complete) in DRAM_CTL58 */
while (!(readl(MXS_DRAM_BASE + 0xe8) & (1 << 20)))
;
}
#endif
void mxs_mem_init(void)
{
early_delay(11000);
mxs_mem_init_clock();
mxs_mem_setup_vdda();
#if defined(CONFIG_MX23)
mx23_mem_init();
#elif defined(CONFIG_MX28)
mx28_mem_init();
#endif
early_delay(10000);
mxs_mem_setup_cpu_and_hbus();
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,95 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* armboot - Startup Code for ARM926EJS CPU-core
*
* Copyright (c) 2003 Texas Instruments
*
* ----- Adapted for OMAP1610 OMAP730 from ARM925t code ------
*
* Copyright (c) 2001 Marius Groger <mag@sysgo.de>
* Copyright (c) 2002 Alex Zupke <azu@sysgo.de>
* Copyright (c) 2002 Gary Jennejohn <garyj@denx.de>
* Copyright (c) 2003 Richard Woodruff <r-woodruff2@ti.com>
* Copyright (c) 2003 Kshitij <kshitij@ti.com>
* Copyright (c) 2010 Albert Aribaud <albert.u.boot@aribaud.net>
*
* Change to support call back into iMX28 bootrom
* Copyright (c) 2011 Marek Vasut <marek.vasut@gmail.com>
* on behalf of DENX Software Engineering GmbH
*/
#include <asm-offsets.h>
#include <config.h>
#include <common.h>
/*
*************************************************************************
*
* Startup Code (reset vector)
*
* do important init only if we don't start from memory!
* setup Memory and board specific bits prior to relocation.
* relocate armboot to ram
* setup stack
*
*************************************************************************
*/
.globl reset
reset:
/*
* If the CPU is configured in "Wait JTAG connection mode", the stack
* pointer is not configured and is zero. This will cause crash when
* trying to push data onto stack right below here. Load the SP and make
* it point to the end of OCRAM if the SP is zero.
*/
cmp sp, #0x00000000
ldreq sp, =CONFIG_SYS_INIT_SP_ADDR
/*
* Store all registers on old stack pointer, this will allow us later to
* return to the BootROM and let the BootROM load U-Boot into RAM.
*
* WARNING: Register r0 and r1 are used by the BootROM to pass data
* to the called code. Register r0 will contain arbitrary
* data that are set in the BootStream. In case this code
* was started with CALL instruction, register r1 will contain
* pointer to the return value this function can then set.
* The code below MUST NOT CHANGE register r0 and r1 !
*/
push {r0-r12,r14}
/* Save control register c1 */
mrc p15, 0, r2, c1, c0, 0
push {r2}
/* Set the cpu to SVC32 mode and store old CPSR register content. */
mrs r2, cpsr
push {r2}
bic r2, r2, #0x1f
orr r2, r2, #0xd3
msr cpsr, r2
bl board_init_ll
/* Restore BootROM's CPU mode (especially FIQ). */
pop {r2}
msr cpsr,r2
/*
* Restore c1 register. Especially set exception vector location
* back to BootROM space which is required by bootrom for USB boot.
*/
pop {r2}
mcr p15, 0, r2, c1, c0, 0
pop {r0-r12,r14}
/*
* In case this code was started by the CALL instruction, the register
* r0 is examined by the BootROM after this code returns. The value in
* r0 must be set to 0 to indicate successful return.
*/
mov r0, #0
bx lr
@@ -0,0 +1,156 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Freescale i.MX28 timer driver
*
* Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
* on behalf of DENX Software Engineering GmbH
*
* Based on code from LTIB:
* (C) Copyright 2009-2010 Freescale Semiconductor, Inc.
*/
#include <common.h>
#include <time.h>
#include <asm/io.h>
#include <asm/arch/imx-regs.h>
#include <asm/arch/sys_proto.h>
/* Maximum fixed count */
#if defined(CONFIG_MX23)
#define TIMER_LOAD_VAL 0xffff
#elif defined(CONFIG_MX28)
#define TIMER_LOAD_VAL 0xffffffff
#endif
DECLARE_GLOBAL_DATA_PTR;
#define timestamp (gd->arch.tbl)
#define lastdec (gd->arch.lastinc)
/*
* This driver uses 1kHz clock source.
*/
#define MXS_INCREMENTER_HZ 1000
static inline unsigned long tick_to_time(unsigned long tick)
{
return tick / (MXS_INCREMENTER_HZ / CONFIG_SYS_HZ);
}
static inline unsigned long time_to_tick(unsigned long time)
{
return time * (MXS_INCREMENTER_HZ / CONFIG_SYS_HZ);
}
/* Calculate how many ticks happen in "us" microseconds */
static inline unsigned long us_to_tick(unsigned long us)
{
return (us * MXS_INCREMENTER_HZ) / 1000000;
}
int timer_init(void)
{
struct mxs_timrot_regs *timrot_regs =
(struct mxs_timrot_regs *)MXS_TIMROT_BASE;
/* Reset Timers and Rotary Encoder module */
mxs_reset_block(&timrot_regs->hw_timrot_rotctrl_reg);
/* Set fixed_count to 0 */
#if defined(CONFIG_MX23)
writel(0, &timrot_regs->hw_timrot_timcount0);
#elif defined(CONFIG_MX28)
writel(0, &timrot_regs->hw_timrot_fixed_count0);
#endif
/* Set UPDATE bit and 1Khz frequency */
writel(TIMROT_TIMCTRLn_UPDATE | TIMROT_TIMCTRLn_RELOAD |
TIMROT_TIMCTRLn_SELECT_1KHZ_XTAL,
&timrot_regs->hw_timrot_timctrl0);
/* Set fixed_count to maximal value */
#if defined(CONFIG_MX23)
writel(TIMER_LOAD_VAL - 1, &timrot_regs->hw_timrot_timcount0);
#elif defined(CONFIG_MX28)
writel(TIMER_LOAD_VAL, &timrot_regs->hw_timrot_fixed_count0);
#endif
return 0;
}
unsigned long long get_ticks(void)
{
struct mxs_timrot_regs *timrot_regs =
(struct mxs_timrot_regs *)MXS_TIMROT_BASE;
uint32_t now;
/* Current tick value */
#if defined(CONFIG_MX23)
/* Upper bits are the valid ones. */
now = readl(&timrot_regs->hw_timrot_timcount0) >>
TIMROT_RUNNING_COUNTn_RUNNING_COUNT_OFFSET;
#elif defined(CONFIG_MX28)
now = readl(&timrot_regs->hw_timrot_running_count0);
#else
#error "Don't know how to read timrot_regs"
#endif
if (lastdec >= now) {
/*
* normal mode (non roll)
* move stamp forward with absolut diff ticks
*/
timestamp += (lastdec - now);
} else {
/* we have rollover of decrementer */
timestamp += (TIMER_LOAD_VAL - now) + lastdec;
}
lastdec = now;
return timestamp;
}
ulong get_timer(ulong base)
{
return tick_to_time(get_ticks()) - base;
}
/* We use the HW_DIGCTL_MICROSECONDS register for sub-millisecond timer. */
#define MXS_HW_DIGCTL_MICROSECONDS 0x8001c0c0
void __udelay(unsigned long usec)
{
uint32_t old, new, incr;
uint32_t counter = 0;
old = readl(MXS_HW_DIGCTL_MICROSECONDS);
while (counter < usec) {
new = readl(MXS_HW_DIGCTL_MICROSECONDS);
/* Check if the timer wrapped. */
if (new < old) {
incr = 0xffffffff - old;
incr += new;
} else {
incr = new - old;
}
/*
* Check if we are close to the maximum time and the counter
* would wrap if incremented. If that's the case, break out
* from the loop as the requested delay time passed.
*/
if (counter + incr < counter)
break;
counter += incr;
old = new;
}
}
ulong get_tbclk(void)
{
return MXS_INCREMENTER_HZ;
}
@@ -0,0 +1,18 @@
options {
driveTag = 0x00;
flags = 0x01;
}
sources {
u_boot_spl="spl/u-boot-spl.bin";
u_boot="u-boot.bin";
}
section (0) {
load u_boot_spl > 0x0000;
load ivt (entry = 0x0014) > 0x8000;
call 0x8000;
load u_boot > 0x40000100;
call 0x40000100;
}
@@ -0,0 +1,14 @@
sources {
u_boot_spl="spl/u-boot-spl.bin";
u_boot="u-boot.bin";
}
section (0) {
load u_boot_spl > 0x0000;
load ivt (entry = 0x0014) > 0x8000;
hab call 0x8000;
load u_boot > 0x40000100;
load ivt (entry = 0x40000100) > 0x8000;
hab call 0x8000;
}
@@ -0,0 +1,68 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
* on behalf of DENX Software Engineering GmbH
*
* January 2004 - Changed to support H4 device
* Copyright (c) 2004-2008 Texas Instruments
*
* (C) Copyright 2002
* Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
*/
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
. = IMAGE_TEXT_BASE;
. = ALIGN(4);
.text :
{
*(.vectors)
arch/arm/cpu/arm926ejs/mxs/start.o (.text*)
*(.text*)
}
. = ALIGN(4);
.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : {
*(.data*)
}
. = ALIGN(4);
.rel.dyn : {
__rel_dyn_start = .;
*(.rel*)
__rel_dyn_end = .;
}
.bss : {
. = ALIGN(4);
__bss_start = .;
*(.bss*)
. = ALIGN(4);
__bss_end = .;
}
.end :
{
*(.__end)
}
_image_binary_end = .;
.dynsym _image_binary_end : { *(.dynsym) }
.dynbss : { *(.dynbss) }
.dynstr : { *(.dynstr*) }
.dynamic : { *(.dynamic*) }
.hash : { *(.hash*) }
.plt : { *(.plt*) }
.interp : { *(.interp*) }
.gnu : { *(.gnu*) }
.ARM.exidx : { *(.ARM.exidx*) }
}
@@ -0,0 +1,60 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* (C) Copyright 2014 Albert ARIBAUD <albert.u.boot@aribaud.net>
*
* Based on:
*
* Allwinner Technology Co., Ltd. <www.allwinnertech.com>
* Tom Cubie <tangliang@allwinnertech.com>
*
* Based on omap-common/u-boot-spl.lds:
*
* (C) Copyright 2002
* Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
*
* (C) Copyright 2010
* Texas Instruments, <www.ti.com>
* Aneesh V <aneesh@ti.com>
*/
MEMORY { .nor : ORIGIN = IMAGE_TEXT_BASE,\
LENGTH = IMAGE_MAX_SIZE }
MEMORY { .bss : ORIGIN = CONFIG_SPL_BSS_START_ADDR, \
LENGTH = CONFIG_SPL_BSS_MAX_SIZE }
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
.text :
{
__start = .;
*(.vectors)
CPUDIR/start.o (.text)
*(.text*)
} > .nor
. = ALIGN(4);
.rodata : { *(SORT_BY_ALIGNMENT(.rodata*)) } >.nor
. = ALIGN(4);
.data : { *(SORT_BY_ALIGNMENT(.data*)) } >.nor
. = ALIGN(4);
.u_boot_list : {
KEEP(*(SORT(.u_boot_list*)));
} > .nor
. = ALIGN(4);
__image_copy_end = .;
_end = .;
.bss :
{
. = ALIGN(4);
__bss_start = .;
*(.bss*)
. = ALIGN(4);
__bss_end = .;
} > .bss
}
@@ -0,0 +1,21 @@
# SPDX-License-Identifier: GPL-2.0+
#
# (C) Copyright 2000-2006
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
obj-y := cpu.o \
reset.o \
timer.o
ifdef CONFIG_SPL_BUILD
obj-y += spl.o
obj-$(CONFIG_SPEAR600) += spear600.o
obj-$(CONFIG_DDR_MT47H64M16) += spr600_mt47h64m16_3_333_cl5_psync.o
obj-$(CONFIG_DDR_MT47H32M16) += spr600_mt47h32m16_333_cl5_psync.o
obj-$(CONFIG_DDR_MT47H32M16) += spr600_mt47h32m16_37e_166_cl4_sync.o
obj-$(CONFIG_DDR_MT47H128M8) += spr600_mt47h128m8_3_266_cl5_async.o
else
obj-y += spr_misc.o spr_lowlevel_init.o
endif
extra-$(CONFIG_SPL_BUILD) := start.o
@@ -0,0 +1,114 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2010
* Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com.
*/
#include <common.h>
#include <asm/io.h>
#include <asm/arch/hardware.h>
#include <asm/arch/spr_misc.h>
int arch_cpu_init(void)
{
struct misc_regs *const misc_p =
(struct misc_regs *)CONFIG_SPEAR_MISCBASE;
u32 periph1_clken, periph_clk_cfg;
periph1_clken = readl(&misc_p->periph1_clken);
#if defined(CONFIG_SPEAR3XX)
periph1_clken |= MISC_GPT2ENB;
#elif defined(CONFIG_SPEAR600)
periph1_clken |= MISC_GPT3ENB;
#endif
#if defined(CONFIG_PL011_SERIAL)
periph1_clken |= MISC_UART0ENB;
periph_clk_cfg = readl(&misc_p->periph_clk_cfg);
periph_clk_cfg &= ~CONFIG_SPEAR_UARTCLKMSK;
periph_clk_cfg |= CONFIG_SPEAR_UART48M;
writel(periph_clk_cfg, &misc_p->periph_clk_cfg);
#endif
#if defined(CONFIG_ETH_DESIGNWARE)
periph1_clken |= MISC_ETHENB;
#endif
#if defined(CONFIG_DW_UDC)
periph1_clken |= MISC_USBDENB;
#endif
#if defined(CONFIG_SYS_I2C_DW)
periph1_clken |= MISC_I2CENB;
#endif
#if defined(CONFIG_ST_SMI)
periph1_clken |= MISC_SMIENB;
#endif
#if defined(CONFIG_NAND_FSMC)
periph1_clken |= MISC_FSMCENB;
#endif
#if defined(CONFIG_USB_EHCI_SPEAR)
periph1_clken |= PERIPH_USBH1 | PERIPH_USBH2;
#endif
#if defined(CONFIG_SPEAR_GPIO)
periph1_clken |= MISC_GPIO3ENB | MISC_GPIO4ENB;
#endif
#if defined(CONFIG_PL022_SPI)
periph1_clken |= MISC_SSP1ENB | MISC_SSP2ENB | MISC_SSP3ENB;
#endif
writel(periph1_clken, &misc_p->periph1_clken);
return 0;
}
#ifdef CONFIG_DISPLAY_CPUINFO
int print_cpuinfo(void)
{
#ifdef CONFIG_SPEAR300
printf("CPU: SPEAr300\n");
#elif defined(CONFIG_SPEAR310)
printf("CPU: SPEAr310\n");
#elif defined(CONFIG_SPEAR320)
printf("CPU: SPEAr320\n");
#elif defined(CONFIG_SPEAR600)
printf("CPU: SPEAr600\n");
#else
#error CPU not supported in spear platform
#endif
return 0;
}
#endif
#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_NAND_ECC_BCH) && defined(CONFIG_NAND_FSMC)
static int do_switch_ecc(cmd_tbl_t *cmdtp, int flag, int argc,
char *const argv[])
{
if (argc != 2)
goto usage;
if (strncmp(argv[1], "hw", 2) == 0) {
/* 1-bit HW ECC */
printf("Switching to 1-bit HW ECC\n");
fsmc_nand_switch_ecc(1);
} else if (strncmp(argv[1], "bch4", 2) == 0) {
/* 4-bit SW ECC BCH4 */
printf("Switching to 4-bit SW ECC (BCH4)\n");
fsmc_nand_switch_ecc(4);
} else {
goto usage;
}
return 0;
usage:
printf("Usage: nandecc %s\n", cmdtp->usage);
return 1;
}
U_BOOT_CMD(
nandecc, 2, 0, do_switch_ecc,
"switch NAND ECC calculation algorithm",
"hw|bch4 - Switch between NAND hardware 1-bit HW and"
" 4-bit SW BCH\n"
);
#endif
@@ -0,0 +1,37 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2009
* Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com.
*/
#include <common.h>
#include <asm/io.h>
#include <asm/arch/hardware.h>
#include <asm/arch/spr_syscntl.h>
void reset_cpu(ulong ignored)
{
struct syscntl_regs *syscntl_regs_p =
(struct syscntl_regs *)CONFIG_SPEAR_SYSCNTLBASE;
printf("System is going to reboot ...\n");
/*
* This 1 second delay will allow the above message
* to be printed before reset
*/
udelay((1000 * 1000));
/* Going into slow mode before resetting SOC */
writel(0x02, &syscntl_regs_p->scctrl);
/*
* Writing any value to the system status register will
* reset the SoC
*/
writel(0x00, &syscntl_regs_p->scsysstat);
/* system will restart */
while (1)
;
}
@@ -0,0 +1,223 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2000-2009
* Viresh Kumar, ST Microelectronics, viresh.kumar@st.com
* Vipin Kumar, ST Microelectronics, vipin.kumar@st.com
*/
#include <common.h>
#include <asm/hardware.h>
#include <asm/io.h>
#include <asm/arch/spr_misc.h>
#include <asm/arch/spr_defs.h>
void spear_late_init(void)
{
struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE;
writel(0x80000007, &misc_p->arb_icm_ml1);
writel(0x80000007, &misc_p->arb_icm_ml2);
writel(0x80000007, &misc_p->arb_icm_ml3);
writel(0x80000007, &misc_p->arb_icm_ml4);
writel(0x80000007, &misc_p->arb_icm_ml5);
writel(0x80000007, &misc_p->arb_icm_ml6);
writel(0x80000007, &misc_p->arb_icm_ml7);
writel(0x80000007, &misc_p->arb_icm_ml8);
writel(0x80000007, &misc_p->arb_icm_ml9);
}
static void sel_1v8(void)
{
struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE;
u32 ddr1v8, ddr2v5;
ddr2v5 = readl(&misc_p->ddr_2v5_compensation);
ddr2v5 &= 0x8080ffc0;
ddr2v5 |= 0x78000003;
writel(ddr2v5, &misc_p->ddr_2v5_compensation);
ddr1v8 = readl(&misc_p->ddr_1v8_compensation);
ddr1v8 &= 0x8080ffc0;
ddr1v8 |= 0x78000010;
writel(ddr1v8, &misc_p->ddr_1v8_compensation);
while (!(readl(&misc_p->ddr_1v8_compensation) & DDR_COMP_ACCURATE))
;
}
static void sel_2v5(void)
{
struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE;
u32 ddr1v8, ddr2v5;
ddr1v8 = readl(&misc_p->ddr_1v8_compensation);
ddr1v8 &= 0x8080ffc0;
ddr1v8 |= 0x78000003;
writel(ddr1v8, &misc_p->ddr_1v8_compensation);
ddr2v5 = readl(&misc_p->ddr_2v5_compensation);
ddr2v5 &= 0x8080ffc0;
ddr2v5 |= 0x78000010;
writel(ddr2v5, &misc_p->ddr_2v5_compensation);
while (!(readl(&misc_p->ddr_2v5_compensation) & DDR_COMP_ACCURATE))
;
}
/*
* plat_ddr_init:
*/
void plat_ddr_init(void)
{
struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE;
u32 ddrpad;
u32 core3v3, ddr1v8, ddr2v5;
/* DDR pad register configurations */
ddrpad = readl(&misc_p->ddr_pad);
ddrpad &= ~DDR_PAD_CNF_MSK;
#if (CONFIG_DDR_HCLK)
ddrpad |= 0xEAAB;
#elif (CONFIG_DDR_2HCLK)
ddrpad |= 0xEAAD;
#elif (CONFIG_DDR_PLL2)
ddrpad |= 0xEAAD;
#endif
writel(ddrpad, &misc_p->ddr_pad);
/* Compensation register configurations */
core3v3 = readl(&misc_p->core_3v3_compensation);
core3v3 &= 0x8080ffe0;
core3v3 |= 0x78000002;
writel(core3v3, &misc_p->core_3v3_compensation);
ddr1v8 = readl(&misc_p->ddr_1v8_compensation);
ddr1v8 &= 0x8080ffc0;
ddr1v8 |= 0x78000004;
writel(ddr1v8, &misc_p->ddr_1v8_compensation);
ddr2v5 = readl(&misc_p->ddr_2v5_compensation);
ddr2v5 &= 0x8080ffc0;
ddr2v5 |= 0x78000004;
writel(ddr2v5, &misc_p->ddr_2v5_compensation);
if ((readl(&misc_p->ddr_pad) & DDR_PAD_SW_CONF) == DDR_PAD_SW_CONF) {
/* Software memory configuration */
if (readl(&misc_p->ddr_pad) & DDR_PAD_SSTL_SEL)
sel_1v8();
else
sel_2v5();
} else {
/* Hardware memory configuration */
if (readl(&misc_p->ddr_pad) & DDR_PAD_DRAM_TYPE)
sel_1v8();
else
sel_2v5();
}
}
/*
* xxx_boot_selected:
*
* return true if the particular booting option is selected
* return false otherwise
*/
static u32 read_bootstrap(void)
{
return (readl(CONFIG_SPEAR_BOOTSTRAPCFG) >> CONFIG_SPEAR_BOOTSTRAPSHFT)
& CONFIG_SPEAR_BOOTSTRAPMASK;
}
int snor_boot_selected(void)
{
u32 bootstrap = read_bootstrap();
if (SNOR_BOOT_SUPPORTED) {
/* Check whether SNOR boot is selected */
if ((bootstrap & CONFIG_SPEAR_ONLYSNORBOOT) ==
CONFIG_SPEAR_ONLYSNORBOOT)
return true;
if ((bootstrap & CONFIG_SPEAR_NORNANDBOOT) ==
CONFIG_SPEAR_NORNAND8BOOT)
return true;
if ((bootstrap & CONFIG_SPEAR_NORNANDBOOT) ==
CONFIG_SPEAR_NORNAND16BOOT)
return true;
}
return false;
}
int nand_boot_selected(void)
{
u32 bootstrap = read_bootstrap();
if (NAND_BOOT_SUPPORTED) {
/* Check whether NAND boot is selected */
if ((bootstrap & CONFIG_SPEAR_NORNANDBOOT) ==
CONFIG_SPEAR_NORNAND8BOOT)
return true;
if ((bootstrap & CONFIG_SPEAR_NORNANDBOOT) ==
CONFIG_SPEAR_NORNAND16BOOT)
return true;
}
return false;
}
int pnor_boot_selected(void)
{
/* Parallel NOR boot is not selected in any SPEAr600 revision */
return false;
}
int usb_boot_selected(void)
{
u32 bootstrap = read_bootstrap();
if (USB_BOOT_SUPPORTED) {
/* Check whether USB boot is selected */
if (!(bootstrap & CONFIG_SPEAR_USBBOOT))
return true;
}
return false;
}
int tftp_boot_selected(void)
{
/* TFTP boot is not selected in any SPEAr600 revision */
return false;
}
int uart_boot_selected(void)
{
/* UART boot is not selected in any SPEAr600 revision */
return false;
}
int spi_boot_selected(void)
{
/* SPI boot is not selected in any SPEAr600 revision */
return false;
}
int i2c_boot_selected(void)
{
/* I2C boot is not selected in any SPEAr600 revision */
return false;
}
int mmc_boot_selected(void)
{
return false;
}
void plat_late_init(void)
{
spear_late_init();
}
@@ -0,0 +1,300 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2011
* Heiko Schocher, DENX Software Engineering, hs@denx.de.
*
* Copyright (C) 2012 Stefan Roese <sr@denx.de>
*/
#include <common.h>
#include <spl.h>
#include <version.h>
#include <asm/io.h>
#include <asm/arch/hardware.h>
#include <asm/arch/spr_defs.h>
#include <asm/arch/spr_misc.h>
#include <asm/arch/spr_syscntl.h>
#include <linux/mtd/st_smi.h>
/* Reserve some space to store the BootROM's stack pointer during SPL operation.
* The BSS cannot be used for this purpose because it will be zeroed after
* having stored the pointer, so force the location to the data section.
*/
u32 bootrom_stash_sp __attribute__((section(".data")));
static void ddr_clock_init(void)
{
struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE;
u32 clkenb, ddrpll;
clkenb = readl(&misc_p->periph1_clken);
clkenb &= ~PERIPH_MPMCMSK;
clkenb |= PERIPH_MPMC_WE;
/* Intentionally done twice */
writel(clkenb, &misc_p->periph1_clken);
writel(clkenb, &misc_p->periph1_clken);
ddrpll = readl(&misc_p->pll_ctr_reg);
ddrpll &= ~MEM_CLK_SEL_MSK;
#if (CONFIG_DDR_HCLK)
ddrpll |= MEM_CLK_HCLK;
#elif (CONFIG_DDR_2HCLK)
ddrpll |= MEM_CLK_2HCLK;
#elif (CONFIG_DDR_PLL2)
ddrpll |= MEM_CLK_PLL2;
#else
#error "please define one of CONFIG_DDR_(HCLK|2HCLK|PLL2)"
#endif
writel(ddrpll, &misc_p->pll_ctr_reg);
writel(readl(&misc_p->periph1_clken) | PERIPH_MPMC_EN,
&misc_p->periph1_clken);
}
static void mpmc_init_values(void)
{
u32 i;
u32 *mpmc_reg_p = (u32 *)CONFIG_SPEAR_MPMCBASE;
u32 *mpmc_val_p = &mpmc_conf_vals[0];
for (i = 0; i < CONFIG_SPEAR_MPMCREGS; i++, mpmc_reg_p++, mpmc_val_p++)
writel(*mpmc_val_p, mpmc_reg_p);
mpmc_reg_p = (u32 *)CONFIG_SPEAR_MPMCBASE;
/*
* MPMC controller start
* MPMC waiting for DLLLOCKREG high
*/
writel(0x01000100, &mpmc_reg_p[7]);
while (!(readl(&mpmc_reg_p[3]) & 0x10000))
;
}
static void mpmc_init(void)
{
/* Clock related settings for DDR */
ddr_clock_init();
/*
* DDR pad register bits are different for different SoCs
* Compensation values are also handled separately
*/
plat_ddr_init();
/* Initialize mpmc register values */
mpmc_init_values();
}
static void pll_init(void)
{
struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE;
/* Initialize PLLs */
writel(FREQ_332, &misc_p->pll1_frq);
writel(0x1C0A, &misc_p->pll1_cntl);
writel(0x1C0E, &misc_p->pll1_cntl);
writel(0x1C06, &misc_p->pll1_cntl);
writel(0x1C0E, &misc_p->pll1_cntl);
writel(FREQ_332, &misc_p->pll2_frq);
writel(0x1C0A, &misc_p->pll2_cntl);
writel(0x1C0E, &misc_p->pll2_cntl);
writel(0x1C06, &misc_p->pll2_cntl);
writel(0x1C0E, &misc_p->pll2_cntl);
/* wait for pll locks */
while (!(readl(&misc_p->pll1_cntl) & 0x1))
;
while (!(readl(&misc_p->pll2_cntl) & 0x1))
;
}
static void mac_init(void)
{
struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE;
writel(readl(&misc_p->periph1_clken) & (~PERIPH_GMAC),
&misc_p->periph1_clken);
writel(SYNTH23, &misc_p->gmac_synth_clk);
switch (get_socrev()) {
case SOC_SPEAR600_AA:
case SOC_SPEAR600_AB:
case SOC_SPEAR600_BA:
case SOC_SPEAR600_BB:
case SOC_SPEAR600_BC:
case SOC_SPEAR600_BD:
writel(0x0, &misc_p->gmac_ctr_reg);
break;
case SOC_SPEAR300:
case SOC_SPEAR310:
case SOC_SPEAR320:
writel(0x4, &misc_p->gmac_ctr_reg);
break;
}
writel(readl(&misc_p->periph1_clken) | PERIPH_GMAC,
&misc_p->periph1_clken);
writel(readl(&misc_p->periph1_rst) | PERIPH_GMAC,
&misc_p->periph1_rst);
writel(readl(&misc_p->periph1_rst) & (~PERIPH_GMAC),
&misc_p->periph1_rst);
}
static void sys_init(void)
{
struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE;
struct syscntl_regs *syscntl_p =
(struct syscntl_regs *)CONFIG_SPEAR_SYSCNTLBASE;
/* Set system state to SLOW */
writel(SLOW, &syscntl_p->scctrl);
writel(PLL_TIM << 3, &syscntl_p->scpllctrl);
/* Initialize PLLs */
pll_init();
/*
* Ethernet configuration
* To be done only if the tftp boot is not selected already
* Boot code ensures the correct configuration in tftp booting
*/
if (!tftp_boot_selected())
mac_init();
writel(RTC_DISABLE | PLLTIMEEN, &misc_p->periph_clk_cfg);
writel(0x555, &misc_p->amba_clk_cfg);
writel(NORMAL, &syscntl_p->scctrl);
/* Wait for system to switch to normal mode */
while (((readl(&syscntl_p->scctrl) >> MODE_SHIFT) & MODE_MASK)
!= NORMAL)
;
}
/*
* get_socrev
*
* Get SoC Revision.
* @return SOC_SPEARXXX
*/
int get_socrev(void)
{
#if defined(CONFIG_SPEAR600)
struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE;
u32 soc_id = readl(&misc_p->soc_core_id);
u32 pri_socid = (soc_id >> SOC_PRI_SHFT) & 0xFF;
u32 sec_socid = (soc_id >> SOC_SEC_SHFT) & 0xFF;
if ((pri_socid == 'B') && (sec_socid == 'B'))
return SOC_SPEAR600_BB;
else if ((pri_socid == 'B') && (sec_socid == 'C'))
return SOC_SPEAR600_BC;
else if ((pri_socid == 'B') && (sec_socid == 'D'))
return SOC_SPEAR600_BD;
else if (soc_id == 0)
return SOC_SPEAR600_BA;
else
return SOC_SPEAR_NA;
#elif defined(CONFIG_SPEAR300)
return SOC_SPEAR300;
#elif defined(CONFIG_SPEAR310)
return SOC_SPEAR310;
#elif defined(CONFIG_SPEAR320)
return SOC_SPEAR320;
#endif
}
/*
* SNOR (Serial NOR flash) related functions
*/
static void snor_init(void)
{
struct smi_regs *const smicntl =
(struct smi_regs * const)CONFIG_SYS_SMI_BASE;
/* Setting the fast mode values. SMI working at 166/4 = 41.5 MHz */
writel(HOLD1 | FAST_MODE | BANK_EN | DSEL_TIME | PRESCAL4,
&smicntl->smi_cr1);
}
u32 spl_boot_device(void)
{
u32 mode = 0;
if (usb_boot_selected()) {
mode = BOOT_DEVICE_BOOTROM;
} else if (snor_boot_selected()) {
/* SNOR-SMI initialization */
snor_init();
mode = BOOT_DEVICE_NOR;
}
return mode;
}
void board_boot_order(u32 *spl_boot_list)
{
spl_boot_list[0] = spl_boot_device();
/*
* If the main boot device (eg. NOR) is empty, try to jump back into the
* BootROM for USB boot process.
*/
if (USB_BOOT_SUPPORTED)
spl_boot_list[1] = BOOT_DEVICE_BOOTROM;
}
void board_init_f(ulong dummy)
{
struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE;
/* Initialize PLLs */
sys_init();
preloader_console_init();
arch_cpu_init();
/* Enable IPs (release reset) */
writel(PERIPH_RST_ALL, &misc_p->periph1_rst);
/* Initialize MPMC */
puts("Configure DDR\n");
mpmc_init();
spear_late_init();
}
/*
* In a few cases (Ethernet, UART or USB boot, we might want to go back into the
* BootROM code right after having initialized a few components like the DRAM).
* The following function is called from SPL common code (board_init_r).
*/
int board_return_to_bootrom(struct spl_image_info *spl_image,
struct spl_boot_device *bootdev)
{
/*
* Retrieve the BootROM's stack pointer and jump back to the start of
* the SPL, where we can easily branch back into the BootROM. Don't do
* it right here because SPL might be compiled in Thumb mode while the
* BootROM expects ARM mode.
*/
asm volatile ("ldr r0, =bootrom_stash_sp;"
"ldr r0, [r0];"
"mov sp, r0;"
#if defined(CONFIG_SPL_SYS_THUMB_BUILD)
"blx back_to_bootrom;"
#else
"bl back_to_bootrom;"
#endif
);
return 0;
}
@@ -0,0 +1,113 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2000-2009
* Vipin Kumar, ST Microelectronics, vipin.kumar@st.com
*/
#include <common.h>
#if (CONFIG_DDR_PLL2)
const u32 mpmc_conf_vals[CONFIG_SPEAR_MPMCREGS] = {
0x00000001,
0x00000000,
0x01000000,
0x00000101,
0x00000001,
0x01000000,
0x00010001,
0x00000100,
0x00010001,
0x00000003,
0x01000201,
0x06000202,
0x06060106,
0x03050502,
0x03040404,
0x02020503,
0x02010106,
0x03000404,
0x02030202,
0x03000204,
0x0707073f,
0x07070707,
0x06060607,
0x06060606,
0x05050506,
0x05050505,
0x04040405,
0x04040404,
0x03030304,
0x03030303,
0x02020203,
0x02020202,
0x01010102,
0x01010101,
0x08080a01,
0x0000023f,
0x00040800,
0x00000000,
0x00000f02,
0x00001b1b,
0x7f000000,
0x005f0000,
0x1c040b6a,
0x00640064,
0x00640064,
0x00640064,
0x00000064,
0x00200020,
0x00200020,
0x00200020,
0x00200020,
0x00200020,
0x00200020,
0x00200020,
0x000007ff,
0x00000000,
0x47ec00c8,
0x00c8001f,
0x00000000,
0x0000cd98,
0x00000000,
0x03030100,
0x03030303,
0x03030303,
0x03030303,
0x00270000,
0x00250027,
0x00300000,
0x008900b7,
0x003fffff,
0x003fffff,
0x00000000,
0x00000000,
0x003fffff,
0x003fffff,
0x00000000,
0x00000000,
0x003fffff,
0x003fffff,
0x00000000,
0x00000000,
0x003fffff,
0x003fffff,
0x00000000,
0x00000000,
0x003fffff,
0x003fffff,
0x00000000,
0x00000000,
0x003fffff,
0x003fffff,
0x00000000,
0x00000000,
0x003fffff,
0x003fffff,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000
};
#endif
@@ -0,0 +1,118 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2000-2009
* Vipin Kumar, ST Microelectronics, vipin.kumar@st.com
*/
#include <common.h>
#if (CONFIG_DDR_PLL2 || CONFIG_DDR_2HCLK)
const u32 mpmc_conf_vals[CONFIG_SPEAR_MPMCREGS] = {
#if (CONFIG_DDR_PLL2)
0x00000001,
0x00000000,
#elif (CONFIG_DDR_2HCLK)
0x02020201,
0x02020202,
#endif
0x01000000,
0x00000101,
0x00000101,
0x01000000,
0x00010001,
0x00000100,
0x01010001,
0x00000201,
0x01000101,
0x06000002,
0x06060106,
0x03050502,
0x03040404,
0x02020503,
0x02010106,
0x03000405,
0x03040202,
0x04000305,
0x0707073f,
0x07070707,
0x06060607,
0x06060606,
0x05050506,
0x05050505,
0x04040405,
0x04040404,
0x03030304,
0x03030303,
0x02020203,
0x02020202,
0x01010102,
0x01010101,
0x0a0a0a01,
0x0000023f,
0x00050a00,
0x11000000,
0x00001302,
0x00000A0A,
0x72000000,
0x00550000,
0x2b050e86,
0x00640064,
0x00640064,
0x00640064,
0x00000064,
0x00200020,
0x00200020,
0x00200020,
0x00200020,
0x00200020,
0x00200020,
0x00200020,
0x00000a24,
0x43C20000,
0x5b1c00c8,
0x00c8002e,
0x00000000,
0x0001046b,
0x00000000,
0x03030100,
0x03030303,
0x03030303,
0x03030303,
0x00210000,
0x00010021,
0x00200000,
0x006c0090,
0x003fffff,
0x003fffff,
0x00000000,
0x00000000,
0x003fffff,
0x003fffff,
0x00000000,
0x00000000,
0x003fffff,
0x003fffff,
0x00000000,
0x00000000,
0x003fffff,
0x003fffff,
0x00000000,
0x00000000,
0x003fffff,
0x003fffff,
0x00000000,
0x00000000,
0x003fffff,
0x003fffff,
0x00000000,
0x00000000,
0x003fffff,
0x003fffff,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000
};
#endif
@@ -0,0 +1,113 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2000-2009
* Vipin Kumar, ST Microelectronics, vipin.kumar@st.com
*/
#include <common.h>
#if (CONFIG_DDR_HCLK)
const u32 mpmc_conf_vals[CONFIG_SPEAR_MPMCREGS] = {
0x03030301,
0x03030303,
0x01000000,
0x00000101,
0x00000001,
0x01000000,
0x00010001,
0x00000100,
0x00010001,
0x00000003,
0x01000201,
0x06000202,
0x06060106,
0x03050502,
0x03040404,
0x02020503,
0x02010106,
0x03000404,
0x02020202,
0x03000203,
0x0707073f,
0x07070707,
0x06060607,
0x06060606,
0x05050506,
0x05050505,
0x04040405,
0x04040404,
0x03030304,
0x03030303,
0x02020203,
0x02020202,
0x01010102,
0x01010101,
0x08080a01,
0x0000023f,
0x00030600,
0x00000000,
0x00000a02,
0x00001c1c,
0x7f000000,
0x005f0000,
0x12030743,
0x00640064,
0x00640064,
0x00640064,
0x00000064,
0x00200020,
0x00200020,
0x00200020,
0x00200020,
0x00200020,
0x00200020,
0x00200020,
0x0000050e,
0x00000000,
0x2d8900c8,
0x00c80014,
0x00000000,
0x00008236,
0x00000000,
0x03030100,
0x03030303,
0x03030303,
0x03030303,
0x00400000,
0x003a0040,
0x00680000,
0x00d80120,
0x003fffff,
0x003fffff,
0x00000000,
0x00000000,
0x003fffff,
0x003fffff,
0x00000000,
0x00000000,
0x003fffff,
0x003fffff,
0x00000000,
0x00000000,
0x003fffff,
0x003fffff,
0x00000000,
0x00000000,
0x003fffff,
0x003fffff,
0x00000000,
0x00000000,
0x003fffff,
0x003fffff,
0x00000000,
0x00000000,
0x003fffff,
0x003fffff,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000
};
#endif
@@ -0,0 +1,127 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2000-2009
* Vipin Kumar, ST Microelectronics, vipin.kumar@st.com
*/
#include <common.h>
#if (CONFIG_DDR_PLL2 || CONFIG_DDR_2HCLK)
const u32 mpmc_conf_vals[CONFIG_SPEAR_MPMCREGS] = {
#if (CONFIG_DDR_PLL2)
0x00000001,
0x00000000,
#elif (CONFIG_DDR_2HCLK)
0x02020201,
0x02020202,
#endif
0x01000000,
0x00000101,
0x00000101,
0x01000000,
0x00010001,
0x00000100,
0x01010001,
0x00000201,
0x01000101,
0x06000002,
0x06060106,
0x03050502,
0x03040404,
0x02020503,
#ifdef CONFIG_X600
0x02030206,
#else
0x02010106,
#endif
0x03000405,
0x03040202,
0x04000305,
0x0707073f,
0x07070707,
0x06060607,
0x06060606,
0x05050506,
0x05050505,
0x04040405,
0x04040404,
0x03030304,
0x03030303,
0x02020203,
0x02020202,
0x01010102,
0x01010101,
0x0a0a0a01,
0x0000023f,
0x00050a00,
0x11000000,
0x00001302,
0x00000A0A,
#ifdef CONFIG_X600
0x7f000000,
0x005c0000,
#else
0x72000000,
0x00550000,
#endif
0x2b050e86,
0x00640064,
0x00640064,
0x00640064,
0x00000064,
0x00200020,
0x00200020,
0x00200020,
0x00200020,
0x00200020,
0x00200020,
0x00200020,
0x00000a24,
0x43C20000,
0x5b1c00c8,
0x00c8002e,
0x00000000,
0x0001046b,
0x00000000,
0x03030100,
0x03030303,
0x03030303,
0x03030303,
0x00210000,
0x00010021,
0x00200000,
0x006c0090,
0x003fffff,
0x003fffff,
0x00000000,
0x00000000,
0x003fffff,
0x003fffff,
0x00000000,
0x00000000,
0x003fffff,
0x003fffff,
0x00000000,
0x00000000,
0x003fffff,
0x003fffff,
0x00000000,
0x00000000,
0x003fffff,
0x003fffff,
0x00000000,
0x00000000,
0x003fffff,
0x003fffff,
0x00000000,
0x00000000,
0x003fffff,
0x003fffff,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000
};
#endif
@@ -0,0 +1,173 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* (C) Copyright 2006
* Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com.
*/
#include <config.h>
/*
* platform specific initializations are already done in Xloader
* Initializations already done include
* DDR, PLLs, IP's clock enable and reset release etc
*/
.globl lowlevel_init
lowlevel_init:
mov pc, lr
/* void setfreq(unsigned int device, unsigned int frequency) */
.global setfreq
setfreq:
stmfd sp!,{r14}
stmfd sp!,{r0-r12}
mov r8,sp
ldr sp,SRAM_STACK_V
/* Saving the function arguements for later use */
mov r4,r0
mov r5,r1
/* Putting DDR into self refresh */
ldr r0,DDR_07_V
ldr r1,[r0]
ldr r2,DDR_ACTIVE_V
bic r1, r1, r2
str r1,[r0]
ldr r0,DDR_57_V
ldr r1,[r0]
ldr r2,CYCLES_MASK_V
bic r1, r1, r2
ldr r2,REFRESH_CYCLES_V
orr r1, r1, r2, lsl #16
str r1,[r0]
ldr r0,DDR_07_V
ldr r1,[r0]
ldr r2,SREFRESH_MASK_V
orr r1, r1, r2
str r1,[r0]
/* flush pipeline */
b flush
.align 5
flush:
/* Delay to ensure self refresh mode */
ldr r0,SREFRESH_DELAY_V
delay:
sub r0,r0,#1
cmp r0,#0
bne delay
/* Putting system in slow mode */
ldr r0,SCCTRL_V
mov r1,#2
str r1,[r0]
/* Changing PLL(1/2) frequency */
mov r0,r4
mov r1,r5
cmp r4,#0
beq pll1_freq
/* Change PLL2 (DDR frequency) */
ldr r6,PLL2_FREQ_V
ldr r7,PLL2_CNTL_V
b pll2_freq
pll1_freq:
/* Change PLL1 (CPU frequency) */
ldr r6,PLL1_FREQ_V
ldr r7,PLL1_CNTL_V
pll2_freq:
mov r0,r6
ldr r1,[r0]
ldr r2,PLLFREQ_MASK_V
bic r1,r1,r2
mov r2,r5,lsr#1
orr r1,r1,r2,lsl#24
str r1,[r0]
mov r0,r7
ldr r1,P1C0A_V
str r1,[r0]
ldr r1,P1C0E_V
str r1,[r0]
ldr r1,P1C06_V
str r1,[r0]
ldr r1,P1C0E_V
str r1,[r0]
lock:
ldr r1,[r0]
and r1,r1,#1
cmp r1,#0
beq lock
/* Putting system back to normal mode */
ldr r0,SCCTRL_V
mov r1,#4
str r1,[r0]
/* Putting DDR back to normal */
ldr r0,DDR_07_V
ldr r1,[R0]
ldr r2,SREFRESH_MASK_V
bic r1, r1, r2
str r1,[r0]
ldr r2,DDR_ACTIVE_V
orr r1, r1, r2
str r1,[r0]
/* Delay to ensure self refresh mode */
ldr r0,SREFRESH_DELAY_V
1:
sub r0,r0,#1
cmp r0,#0
bne 1b
mov sp,r8
/* Resuming back to code */
ldmia sp!,{r0-r12}
ldmia sp!,{pc}
SCCTRL_V:
.word 0xfca00000
PLL1_FREQ_V:
.word 0xfca8000C
PLL1_CNTL_V:
.word 0xfca80008
PLL2_FREQ_V:
.word 0xfca80018
PLL2_CNTL_V:
.word 0xfca80014
PLLFREQ_MASK_V:
.word 0xff000000
P1C0A_V:
.word 0x1C0A
P1C0E_V:
.word 0x1C0E
P1C06_V:
.word 0x1C06
SREFRESH_DELAY_V:
.word 0x9999
SRAM_STACK_V:
.word 0xD2800600
DDR_07_V:
.word 0xfc60001c
DDR_ACTIVE_V:
.word 0x01000000
DDR_57_V:
.word 0xfc6000e4
CYCLES_MASK_V:
.word 0xffff0000
REFRESH_CYCLES_V:
.word 0xf0f0
SREFRESH_MASK_V:
.word 0x00010000
.global setfreq_sz
setfreq_sz:
.word setfreq_sz - setfreq
@@ -0,0 +1,250 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2009
* Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com.
*/
#include <common.h>
#include <command.h>
#include <cpu_func.h>
#include <env.h>
#include <i2c.h>
#include <net.h>
#include <linux/mtd/st_smi.h>
#include <asm/io.h>
#include <asm/arch/hardware.h>
#include <asm/arch/spr_emi.h>
#include <asm/arch/spr_defs.h>
#define CPU 0
#define DDR 1
#define SRAM_REL 0xD2801000
DECLARE_GLOBAL_DATA_PTR;
#if defined(CONFIG_CMD_NET)
static int i2c_read_mac(uchar *buffer);
#endif
int dram_init(void)
{
/* Store complete RAM size and return */
gd->ram_size = get_ram_size(PHYS_SDRAM_1, PHYS_SDRAM_1_MAXSIZE);
return 0;
}
int dram_init_banksize(void)
{
gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
gd->bd->bi_dram[0].size = gd->ram_size;
return 0;
}
int board_early_init_f()
{
#if defined(CONFIG_ST_SMI)
smi_init();
#endif
return 0;
}
int misc_init_r(void)
{
#if defined(CONFIG_CMD_NET)
uchar mac_id[6];
if (!eth_env_get_enetaddr("ethaddr", mac_id) && !i2c_read_mac(mac_id))
eth_env_set_enetaddr("ethaddr", mac_id);
#endif
env_set("verify", "n");
#if defined(CONFIG_SPEAR_USBTTY)
env_set("stdin", "usbtty");
env_set("stdout", "usbtty");
env_set("stderr", "usbtty");
#ifndef CONFIG_SYS_NO_DCACHE
dcache_enable();
#endif
#endif
return 0;
}
#ifdef CONFIG_SPEAR_EMI
struct cust_emi_para {
unsigned int tap;
unsigned int tsdp;
unsigned int tdpw;
unsigned int tdpr;
unsigned int tdcs;
};
/* EMI timing setting of m28w640hc of linux kernel */
const struct cust_emi_para emi_timing_m28w640hc = {
.tap = 0x10,
.tsdp = 0x05,
.tdpw = 0x0a,
.tdpr = 0x0a,
.tdcs = 0x05,
};
/* EMI timing setting of bootrom */
const struct cust_emi_para emi_timing_bootrom = {
.tap = 0xf,
.tsdp = 0x0,
.tdpw = 0xff,
.tdpr = 0x111,
.tdcs = 0x02,
};
void spear_emi_init(void)
{
const struct cust_emi_para *p = &emi_timing_m28w640hc;
struct emi_regs *emi_regs_p = (struct emi_regs *)CONFIG_SPEAR_EMIBASE;
unsigned int cs;
unsigned int val, tmp;
val = readl(CONFIG_SPEAR_RASBASE);
if (val & EMI_ACKMSK)
tmp = 0x3f;
else
tmp = 0x0;
writel(tmp, &emi_regs_p->ack);
for (cs = 0; cs < CONFIG_SYS_MAX_FLASH_BANKS; cs++) {
writel(p->tap, &emi_regs_p->bank_regs[cs].tap);
writel(p->tsdp, &emi_regs_p->bank_regs[cs].tsdp);
writel(p->tdpw, &emi_regs_p->bank_regs[cs].tdpw);
writel(p->tdpr, &emi_regs_p->bank_regs[cs].tdpr);
writel(p->tdcs, &emi_regs_p->bank_regs[cs].tdcs);
writel(EMI_CNTL_ENBBYTERW | ((val & 0x18) >> 3),
&emi_regs_p->bank_regs[cs].control);
}
}
#endif
int spear_board_init(ulong mach_type)
{
gd->bd->bi_arch_number = mach_type;
/* adress of boot parameters */
gd->bd->bi_boot_params = CONFIG_BOOT_PARAMS_ADDR;
#ifdef CONFIG_SPEAR_EMI
spear_emi_init();
#endif
return 0;
}
#if defined(CONFIG_CMD_NET)
static int i2c_read_mac(uchar *buffer)
{
u8 buf[2];
i2c_read(CONFIG_I2C_CHIPADDRESS, MAGIC_OFF, 1, buf, MAGIC_LEN);
/* Check if mac in i2c memory is valid */
if ((buf[0] == MAGIC_BYTE0) && (buf[1] == MAGIC_BYTE1)) {
/* Valid mac address is saved in i2c eeprom */
i2c_read(CONFIG_I2C_CHIPADDRESS, MAC_OFF, 1, buffer, MAC_LEN);
return 0;
}
return -1;
}
static int write_mac(uchar *mac)
{
u8 buf[2];
buf[0] = (u8)MAGIC_BYTE0;
buf[1] = (u8)MAGIC_BYTE1;
i2c_write(CONFIG_I2C_CHIPADDRESS, MAGIC_OFF, 1, buf, MAGIC_LEN);
buf[0] = (u8)~MAGIC_BYTE0;
buf[1] = (u8)~MAGIC_BYTE1;
i2c_read(CONFIG_I2C_CHIPADDRESS, MAGIC_OFF, 1, buf, MAGIC_LEN);
/* check if valid MAC address is saved in I2C EEPROM or not? */
if ((buf[0] == MAGIC_BYTE0) && (buf[1] == MAGIC_BYTE1)) {
i2c_write(CONFIG_I2C_CHIPADDRESS, MAC_OFF, 1, mac, MAC_LEN);
puts("I2C EEPROM written with mac address \n");
return 0;
}
puts("I2C EEPROM writing failed\n");
return -1;
}
#endif
int do_chip_config(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
void (*sram_setfreq) (unsigned int, unsigned int);
unsigned int frequency;
#if defined(CONFIG_CMD_NET)
unsigned char mac[6];
#endif
if ((argc > 3) || (argc < 2))
return cmd_usage(cmdtp);
if ((!strcmp(argv[1], "cpufreq")) || (!strcmp(argv[1], "ddrfreq"))) {
frequency = simple_strtoul(argv[2], NULL, 0);
if (frequency > 333) {
printf("Frequency is limited to 333MHz\n");
return 1;
}
sram_setfreq = memcpy((void *)SRAM_REL, setfreq, setfreq_sz);
if (!strcmp(argv[1], "cpufreq")) {
sram_setfreq(CPU, frequency);
printf("CPU frequency changed to %u\n", frequency);
} else {
sram_setfreq(DDR, frequency);
printf("DDR frequency changed to %u\n", frequency);
}
return 0;
#if defined(CONFIG_CMD_NET)
} else if (!strcmp(argv[1], "ethaddr")) {
u32 reg;
char *e, *s = argv[2];
for (reg = 0; reg < 6; ++reg) {
mac[reg] = s ? simple_strtoul(s, &e, 16) : 0;
if (s)
s = (*e) ? e + 1 : e;
}
write_mac(mac);
return 0;
#endif
} else if (!strcmp(argv[1], "print")) {
#if defined(CONFIG_CMD_NET)
if (!i2c_read_mac(mac)) {
printf("Ethaddr (from i2c mem) = %pM\n", mac);
} else {
printf("Ethaddr (from i2c mem) = Not set\n");
}
#endif
return 0;
}
return cmd_usage(cmdtp);
}
U_BOOT_CMD(chip_config, 3, 1, do_chip_config,
"configure chip",
"chip_config cpufreq/ddrfreq frequency\n"
#if defined(CONFIG_CMD_NET)
"chip_config ethaddr XX:XX:XX:XX:XX:XX\n"
#endif
"chip_config print");
@@ -0,0 +1,65 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* armboot - Startup Code for ARM926EJS CPU-core
*
* Copyright (c) 2003 Texas Instruments
*
* ----- Adapted for OMAP1610 OMAP730 from ARM925t code ------
*
* Copyright (c) 2001 Marius Gröger <mag@sysgo.de>
* Copyright (c) 2002 Alex Züpke <azu@sysgo.de>
* Copyright (c) 2002 Gary Jennejohn <garyj@denx.de>
* Copyright (c) 2003 Richard Woodruff <r-woodruff2@ti.com>
* Copyright (c) 2003 Kshitij <kshitij@ti.com>
*/
#include <config.h>
/*
*************************************************************************
*
* Startup Code (reset vector)
*
* The BootROM already initialized its own stack in the [0-0xb00] reserved
* range of the SRAM. The SPL (in _main) will update the stack pointer to
* its own SRAM area (right before the gd section).
*
*************************************************************************
*/
.globl reset
.globl back_to_bootrom
reset:
/*
* SPL has to return back to BootROM in a few cases (eg. Ethernet boot,
* UART boot, USB boot): save registers in BootROM's stack and then the
* BootROM's stack pointer in the SPL's data section.
*/
push {r0-r12,lr}
ldr r0, =bootrom_stash_sp
str sp, [r0]
/*
* Flush v4 I/D caches
*/
mov r0, #0
mcr p15, 0, r0, c7, c7, 0 /* Flush v3/v4 cache */
mcr p15, 0, r0, c8, c7, 0 /* Flush v4 TLB */
/*
* Enable instruction cache
*/
mrc p15, 0, r0, c1, c0, 0
orr r0, r0, #0x00001000 /* set bit 12 (I) I-Cache */
mcr p15, 0, r0, c1, c0, 0
/*
* Go setup Memory and board specific bits prior to relocation.
* This call is not supposed to return.
*/
b _main /* _main will call board_init_f */
back_to_bootrom:
pop {r0-r12,pc}
@@ -0,0 +1,120 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2009
* Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com.
*/
#include <common.h>
#include <time.h>
#include <asm/io.h>
#include <asm/arch/hardware.h>
#include <asm/arch/spr_gpt.h>
#include <asm/arch/spr_misc.h>
#define GPT_RESOLUTION (CONFIG_SPEAR_HZ_CLOCK / CONFIG_SPEAR_HZ)
#define READ_TIMER() (readl(&gpt_regs_p->count) & GPT_FREE_RUNNING)
static struct gpt_regs *const gpt_regs_p =
(struct gpt_regs *)CONFIG_SPEAR_TIMERBASE;
static struct misc_regs *const misc_regs_p =
(struct misc_regs *)CONFIG_SPEAR_MISCBASE;
DECLARE_GLOBAL_DATA_PTR;
static ulong get_timer_masked(void);
#define timestamp gd->arch.tbl
#define lastdec gd->arch.lastinc
int timer_init(void)
{
u32 synth;
/* Prescaler setting */
#if defined(CONFIG_SPEAR3XX)
writel(MISC_PRSC_CFG, &misc_regs_p->prsc2_clk_cfg);
synth = MISC_GPT4SYNTH;
#elif defined(CONFIG_SPEAR600)
writel(MISC_PRSC_CFG, &misc_regs_p->prsc1_clk_cfg);
synth = MISC_GPT3SYNTH;
#else
# error Incorrect config. Can only be SPEAR{600|300|310|320}
#endif
writel(readl(&misc_regs_p->periph_clk_cfg) | synth,
&misc_regs_p->periph_clk_cfg);
/* disable timers */
writel(GPT_PRESCALER_1 | GPT_MODE_AUTO_RELOAD, &gpt_regs_p->control);
/* load value for free running */
writel(GPT_FREE_RUNNING, &gpt_regs_p->compare);
/* auto reload, start timer */
writel(readl(&gpt_regs_p->control) | GPT_ENABLE, &gpt_regs_p->control);
/* Reset the timer */
lastdec = READ_TIMER();
timestamp = 0;
return 0;
}
/*
* timer without interrupts
*/
ulong get_timer(ulong base)
{
return (get_timer_masked() / GPT_RESOLUTION) - base;
}
void __udelay(unsigned long usec)
{
ulong tmo;
ulong start = get_timer_masked();
ulong tenudelcnt = CONFIG_SPEAR_HZ_CLOCK / (1000 * 100);
ulong rndoff;
rndoff = (usec % 10) ? 1 : 0;
/* tenudelcnt timer tick gives 10 microsecconds delay */
tmo = ((usec / 10) + rndoff) * tenudelcnt;
while ((ulong) (get_timer_masked() - start) < tmo)
;
}
static ulong get_timer_masked(void)
{
ulong now = READ_TIMER();
if (now >= lastdec) {
/* normal mode */
timestamp += now - lastdec;
} else {
/* we have an overflow ... */
timestamp += now + GPT_FREE_RUNNING - lastdec;
}
lastdec = now;
return timestamp;
}
/*
* This function is derived from PowerPC code (read timebase as long long).
* On ARM it just returns the timer value.
*/
unsigned long long get_ticks(void)
{
return get_timer(0);
}
/*
* This function is derived from PowerPC code (timebase clock frequency).
* On ARM it returns the number of timer ticks per second.
*/
ulong get_tbclk(void)
{
return CONFIG_SPEAR_HZ;
}
@@ -0,0 +1,54 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) 2015 Stefan Roese <sr@denx.de>
*
* Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
* on behalf of DENX Software Engineering GmbH
*
* January 2004 - Changed to support H4 device
* Copyright (c) 2004-2008 Texas Instruments
*
* (C) Copyright 2002
* Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
*/
MEMORY { .sram : ORIGIN = IMAGE_TEXT_BASE,\
LENGTH = IMAGE_MAX_SIZE }
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
.text :
{
__start = .;
*(.vectors)
CPUDIR/spear/start.o (.text*)
*(.text*)
} > .sram
. = ALIGN(4);
.rodata : { *(SORT_BY_ALIGNMENT(.rodata*)) } >.sram
. = ALIGN(4);
.data : { *(SORT_BY_ALIGNMENT(.data*)) } >.sram
. = ALIGN(4);
.u_boot_list : {
KEEP(*(SORT(.u_boot_list*)));
} > .sram
. = ALIGN(4);
__image_copy_end = .;
_end = .;
.bss :
{
. = ALIGN(4);
__bss_start = .;
*(.bss*)
. = ALIGN(4);
__bss_end = .;
} > .sram
}
@@ -0,0 +1,112 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* armboot - Startup Code for ARM926EJS CPU-core
*
* Copyright (c) 2003 Texas Instruments
*
* ----- Adapted for OMAP1610 OMAP730 from ARM925t code ------
*
* Copyright (c) 2001 Marius Gröger <mag@sysgo.de>
* Copyright (c) 2002 Alex Züpke <azu@sysgo.de>
* Copyright (c) 2002 Gary Jennejohn <garyj@denx.de>
* Copyright (c) 2003 Richard Woodruff <r-woodruff2@ti.com>
* Copyright (c) 2003 Kshitij <kshitij@ti.com>
* Copyright (c) 2010 Albert Aribaud <albert.u.boot@aribaud.net>
*/
#include <asm-offsets.h>
#include <config.h>
#include <common.h>
/*
*************************************************************************
*
* Startup Code (reset vector)
*
* do important init only if we don't start from memory!
* setup Memory and board specific bits prior to relocation.
* relocate armboot to ram
* setup stack
*
*************************************************************************
*/
.globl reset
reset:
/*
* set the cpu to SVC32 mode
*/
mrs r0,cpsr
bic r0,r0,#0x1f
orr r0,r0,#0xd3
msr cpsr,r0
/*
* we do sys-critical inits only at reboot,
* not when booting from ram!
*/
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_crit
#endif
bl _main
/*------------------------------------------------------------------------------*/
.globl c_runtime_cpu_setup
c_runtime_cpu_setup:
bx lr
/*
*************************************************************************
*
* CPU_init_critical registers
*
* setup important registers
* setup memory timing
*
*************************************************************************
*/
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
cpu_init_crit:
/*
* flush D cache before disabling it
*/
mov r0, #0
flush_dcache:
mrc p15, 0, r15, c7, c10, 3
bne flush_dcache
mcr p15, 0, r0, c8, c7, 0 /* invalidate TLB */
mcr p15, 0, r0, c7, c5, 0 /* invalidate I Cache */
/*
* disable MMU and D cache
* enable I cache if SYS_ICACHE_OFF is not defined
*/
mrc p15, 0, r0, c1, c0, 0
bic r0, r0, #0x00000300 /* clear bits 9:8 (---- --RS) */
bic r0, r0, #0x00000087 /* clear bits 7, 2:0 (B--- -CAM) */
#ifdef CONFIG_SYS_EXCEPTION_VECTORS_HIGH
orr r0, r0, #0x00002000 /* set bit 13 (--V- ----) */
#else
bic r0, r0, #0x00002000 /* clear bit 13 (--V- ----) */
#endif
orr r0, r0, #0x00000002 /* set bit 1 (A) Align */
#if !CONFIG_IS_ENABLED(SYS_ICACHE_OFF)
orr r0, r0, #0x00001000 /* set bit 12 (I) I-Cache */
#endif
mcr p15, 0, r0, c1, c0, 0
#ifndef CONFIG_SKIP_LOWLEVEL_INIT_ONLY
/*
* Go setup Memory and board specific bits prior to relocation.
*/
mov r4, lr /* perserve link reg across call */
bl lowlevel_init /* go setup pll,mux,memory */
mov lr, r4 /* restore link */
#endif
mov pc, lr /* back to my caller */
#endif /* CONFIG_SKIP_LOWLEVEL_INIT */
@@ -0,0 +1,8 @@
# SPDX-License-Identifier: GPL-2.0+
#
# (C) Copyright 2000-2006
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
extra-y = start.o
obj-y = cpu.o
@@ -0,0 +1,67 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2002
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
* Marius Groeger <mgroeger@sysgo.de>
*
* (C) Copyright 2002
* Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
*/
/*
* CPU specific code
*/
#include <common.h>
#include <command.h>
#include <cpu_func.h>
#include <irq_func.h>
#include <asm/system.h>
#include <asm/io.h>
static void cache_flush(void);
int cleanup_before_linux (void)
{
/*
* this function is called just before we call linux
* it prepares the processor for linux
*
* we turn off caches etc ...
*/
disable_interrupts();
/* ARM926E-S needs the protection unit enabled for the icache to have
* been enabled - left for possible later use
* should turn off the protection unit as well....
*/
/* turn off I/D-cache */
icache_disable();
dcache_disable();
/* flush I/D-cache */
cache_flush();
return 0;
}
/* flush I/D-cache */
static void cache_flush (void)
{
unsigned long i = 0;
asm ("mcr p15, 0, %0, c7, c5, 0": :"r" (i));
asm ("mcr p15, 0, %0, c7, c6, 0": :"r" (i));
}
#ifndef CONFIG_ARCH_INTEGRATOR
__attribute__((noreturn)) void reset_cpu(ulong addr __attribute__((unused)))
{
writew(0x0, 0xfffece10);
writew(0x8, 0xfffece10);
for (;;)
;
}
#endif /* #ifdef CONFIG_ARCH_INTEGRATOR */
@@ -0,0 +1,101 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* armboot - Startup Code for ARM926EJS CPU-core
*
* Copyright (c) 2003 Texas Instruments
*
* ----- Adapted for OMAP1610 OMAP730 from ARM925t code ------
*
* Copyright (c) 2001 Marius Gröger <mag@sysgo.de>
* Copyright (c) 2002 Alex Züpke <azu@sysgo.de>
* Copyright (c) 2002 Gary Jennejohn <garyj@denx.de>
* Copyright (c) 2003 Richard Woodruff <r-woodruff2@ti.com>
* Copyright (c) 2003 Kshitij <kshitij@ti.com>
* Copyright (c) 2010 Albert Aribaud <albert.u.boot@aribaud.net>
*/
#include <asm-offsets.h>
#include <config.h>
/*
*************************************************************************
*
* Startup Code (reset vector)
*
* do important init only if we don't start from memory!
* setup Memory and board specific bits prior to relocation.
* relocate armboot to ram
* setup stack
*
*************************************************************************
*/
.globl reset
reset:
/*
* set the cpu to SVC32 mode
*/
mrs r0,cpsr
bic r0,r0,#0x1f
orr r0,r0,#0xd3
msr cpsr,r0
/*
* we do sys-critical inits only at reboot,
* not when booting from ram!
*/
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_crit
#endif
bl _main
/*------------------------------------------------------------------------------*/
.globl c_runtime_cpu_setup
c_runtime_cpu_setup:
mov pc, lr
/*
*************************************************************************
*
* CPU_init_critical registers
*
* setup important registers
* setup memory timing
*
*************************************************************************
*/
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
cpu_init_crit:
/*
* flush v4 I/D caches
*/
mov r0, #0
mcr p15, 0, r0, c7, c5, 0 /* flush v4 I-cache */
mcr p15, 0, r0, c7, c6, 0 /* flush v4 D-cache */
/*
* disable MMU stuff and caches
*/
mrc p15, 0, r0, c1, c0, 0
bic r0, r0, #0x00002300 /* clear bits 13, 9:8 (--V- --RS) */
bic r0, r0, #0x00000087 /* clear bits 7, 2:0 (B--- -CAM) */
orr r0, r0, #0x00000002 /* set bit 1 (A) Align */
orr r0, r0, #0x00001000 /* set bit 12 (I) I-Cache */
mcr p15, 0, r0, c1, c0, 0
#ifndef CONFIG_SKIP_LOWLEVEL_INIT_ONLY
/*
* Go setup Memory and board specific bits prior to relocation.
*/
mov ip, lr /* perserve link reg across call */
bl lowlevel_init /* go setup memory */
mov lr, ip /* restore link */
#endif
mov pc, lr /* back to my caller */
#endif
@@ -0,0 +1,61 @@
if CPU_V7A
config CPU_V7_HAS_NONSEC
bool
config CPU_V7_HAS_VIRT
bool
config ARCH_SUPPORT_PSCI
bool
config ARMV7_NONSEC
bool "Enable support for booting in non-secure mode" if EXPERT
depends on CPU_V7_HAS_NONSEC
default y
---help---
Say Y here to enable support for booting in non-secure / SVC mode.
config ARMV7_BOOT_SEC_DEFAULT
bool "Boot in secure mode by default" if EXPERT
depends on ARMV7_NONSEC
default y if TEGRA
---help---
Say Y here to boot in secure mode by default even if non-secure mode
is supported. This option is useful to boot kernels which do not
suppport booting in non-secure mode. Only set this if you need it.
This can be overridden at run-time by setting the bootm_boot_mode env.
variable to "sec" or "nonsec".
config ARMV7_VIRT
bool "Enable support for hardware virtualization" if EXPERT
depends on CPU_V7_HAS_VIRT && ARMV7_NONSEC
default y
---help---
Say Y here to boot in hypervisor (HYP) mode when booting non-secure.
config ARMV7_PSCI
bool "Enable PSCI support" if EXPERT
depends on ARMV7_NONSEC && ARCH_SUPPORT_PSCI
default y
help
Say Y here to enable PSCI support.
config ARMV7_PSCI_NR_CPUS
int "Maximum supported CPUs for PSCI"
depends on ARMV7_NONSEC
default 4
help
The maximum number of CPUs supported in the PSCI firmware.
It is no problem to set a larger value than the number of
CPUs in the actual hardware implementation.
config ARMV7_LPAE
bool "Use LPAE page table format" if EXPERT
depends on CPU_V7A
default y if ARMV7_VIRT
---help---
Say Y here to use the long descriptor page table format. This is
required if U-Boot runs in HYP mode.
endif

Some files were not shown because too many files have changed in this diff Show More