avionic design with actual uboot and tooling

submodule of avionic design uboot bootloader and with included tools to
get you started , read readme.md and readme-tk1-loader.md
This commit is contained in:
2026-03-03 21:46:32 +02:00
parent fe3ba02c96
commit 68d74d3181
11967 changed files with 2221897 additions and 0 deletions

View File

@@ -0,0 +1,5 @@
#
# SPDX-License-Identifier: GPL-2.0+
#
obj- += dummy.o

View File

@@ -0,0 +1,8 @@
#
# (C) Copyright 2000-2006
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
#
# SPDX-License-Identifier: GPL-2.0+
#
obj-y = cpu.o

View File

@@ -0,0 +1,133 @@
/*
* (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>
*
* SPDX-License-Identifier: GPL-2.0+
*/
/*
* CPU specific code
*/
#include <common.h>
#include <command.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));
}
#ifndef CONFIG_SYS_DCACHE_OFF
#ifndef CONFIG_SYS_CACHELINE_SIZE
#define CONFIG_SYS_CACHELINE_SIZE 32
#endif
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));
}
static int check_cache_range(unsigned long start, unsigned long stop)
{
int ok = 1;
if (start & (CONFIG_SYS_CACHELINE_SIZE - 1))
ok = 0;
if (stop & (CONFIG_SYS_CACHELINE_SIZE - 1))
ok = 0;
if (!ok)
debug("CACHE: Misaligned operation at range [%08lx, %08lx]\n",
start, stop);
return ok;
}
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 /* #ifndef CONFIG_SYS_DCACHE_OFF */
void invalidate_dcache_all(void)
{
}
void flush_dcache_all(void)
{
}
#endif /* #ifndef CONFIG_SYS_DCACHE_OFF */
#if !defined(CONFIG_SYS_ICACHE_OFF) || !defined(CONFIG_SYS_DCACHE_OFF)
void enable_caches(void)
{
#ifndef CONFIG_SYS_ICACHE_OFF
icache_enable();
#endif
#ifndef CONFIG_SYS_DCACHE_OFF
dcache_enable();
#endif
}
#endif

View File

@@ -0,0 +1,12 @@
#
# (C) Copyright 2000-2006
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
#
# SPDX-License-Identifier: GPL-2.0+
#
extra-y = start.o
obj-y += ../arm11/
obj-$(CONFIG_MX31) += mx31/
obj-$(CONFIG_MX35) += mx35/

View File

@@ -0,0 +1,14 @@
#
# (C) Copyright 2000-2006
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
#
# SPDX-License-Identifier: GPL-2.0+
#
obj-y += generic.o
obj-y += timer.o
obj-y += devices.o
ifndef CONFIG_SPL_BUILD
obj-y += relocate.o
endif

View File

@@ -0,0 +1,51 @@
/*
*
* (C) Copyright 2009 Magnus Lilja <lilja.magnus@gmail.com>
*
* (c) 2007 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#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

View File

@@ -0,0 +1,219 @@
/*
* (C) Copyright 2007
* Sascha Hauer, Pengutronix
*
* SPDX-License-Identifier: GPL-2.0+
*/
#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

View File

@@ -0,0 +1,23 @@
/*
* relocate - i.MX31-specific vector relocation
*
* Copyright (c) 2013 Albert ARIBAUD <albert.u.boot@aribaud.net>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#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)

View File

@@ -0,0 +1,47 @@
/*
* (C) Copyright 2007
* Sascha Hauer, Pengutronix
*
* SPDX-License-Identifier: GPL-2.0+
*/
#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 */
DECLARE_GLOBAL_DATA_PTR;
/* 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;
}

View File

@@ -0,0 +1,16 @@
#
# (C) Copyright 2000-2006
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
#
# (C) Copyright 2008-2009 Freescale Semiconductor, Inc.
#
# SPDX-License-Identifier: GPL-2.0+
#
obj-y += generic.o
obj-y += timer.o
obj-y += mx35_sdram.o
ifndef CONFIG_SPL_BUILD
obj-y += relocate.o
endif

View File

@@ -0,0 +1,547 @@
/*
* (C) Copyright 2007
* Sascha Hauer, Pengutronix
*
* (C) Copyright 2008-2010 Freescale Semiconductor, Inc.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <div64.h>
#include <asm/io.h>
#include <asm/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
#include <fsl_esdhc.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
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
/*
* 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
#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;
}
#ifdef CONFIG_SPL_BUILD
u32 spl_boot_mode(const u32 boot_device)
{
switch (spl_boot_device()) {
case BOOT_DEVICE_MMC1:
#ifdef CONFIG_SPL_FAT_SUPPORT
return MMCSD_MODE_FS;
#else
return MMCSD_MODE_RAW;
#endif
break;
case BOOT_DEVICE_NAND:
return 0;
break;
default:
puts("spl: ERROR: unsupported device\n");
hang();
}
}
#endif

View File

@@ -0,0 +1,121 @@
/*
* Copyright (C) 2012, Stefano Babic <sbabic@denx.de>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <asm/io.h>
#include <asm/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 */
}

View File

@@ -0,0 +1,23 @@
/*
* relocate - i.MX35-specific vector relocation
*
* Copyright (c) 2013 Albert ARIBAUD <albert.u.boot@aribaud.net>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#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)

View File

@@ -0,0 +1,47 @@
/*
* (C) Copyright 2007
* Sascha Hauer, Pengutronix
*
* (C) Copyright 2008-2009 Freescale Semiconductor, Inc.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <asm/io.h>
#include <asm/arch/imx-regs.h>
#include <asm/arch/crm_regs.h>
DECLARE_GLOBAL_DATA_PTR;
/* 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;
}

View File

@@ -0,0 +1,95 @@
/*
* 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>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#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 */

View File

@@ -0,0 +1,51 @@
/*
* (C) Copyright 2002
* Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
*
* (C) Copyright 2010
* Texas Instruments, <www.ti.com>
* Aneesh V <aneesh@ti.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
MEMORY { .sram : ORIGIN = CONFIG_SPL_TEXT_BASE,\
LENGTH = CONFIG_SPL_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
}

View File

@@ -0,0 +1,14 @@
#
# (C) Copyright 2000-2006
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
#
# (C) Copyright 2008
# Guennadi Liakhovetki, DENX Software Engineering, <lg@denx.de>
#
# SPDX-License-Identifier: GPL-2.0+
#
obj- += dummy.o
extra-y = start.o
obj-y += ../arm11/

View File

@@ -0,0 +1,112 @@
/*
* armboot - Startup Code for ARM1176 CPU-core
*
* Copyright (c) 2007 Samsung Electronics
*
* Copyright (C) 2008
* Guennadi Liakhovetki, DENX Software Engineering, <lg@denx.de>
*
* SPDX-License-Identifier: GPL-2.0+
*
* 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>
#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:
/*
* 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

View File

@@ -0,0 +1,9 @@
#
# (C) Copyright 2000-2006
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
#
# SPDX-License-Identifier: GPL-2.0+
#
extra-y = start.o
obj-y = interrupts.o cpu.o

View File

@@ -0,0 +1,22 @@
/*
* (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>
*
* SPDX-License-Identifier: GPL-2.0+
*/
/*
* 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;
}

View File

@@ -0,0 +1,33 @@
/*
* (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>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#ifdef CONFIG_USE_IRQ
void do_irq (struct pt_regs *pt_regs)
{
}
#endif
#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

View File

@@ -0,0 +1,78 @@
/*
* 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>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#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!
*/
#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:
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 */

View File

@@ -0,0 +1,21 @@
#
# (C) Copyright 2000-2006
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
#
# SPDX-License-Identifier: GPL-2.0+
#
extra-y = start.o
obj-y += cpu.o
obj-$(CONFIG_USE_IRQ) += interrupts.o
obj-$(CONFIG_EP93XX) += ep93xx/
obj-$(CONFIG_IMX) += imx/
obj-$(CONFIG_S3C24X0) += s3c24x0/
# some files can only build in ARM mode
ifdef CONFIG_SYS_THUMB_BUILD
CFLAGS_cpu.o := -marm
endif

View File

@@ -0,0 +1,48 @@
/*
* (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>
*
* SPDX-License-Identifier: GPL-2.0+
*/
/*
* CPU specific code
*/
#include <common.h>
#include <command.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));
}

View File

@@ -0,0 +1,21 @@
#
# 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.
#
# SPDX-License-Identifier: GPL-2.0+
#
obj-y = cpu.o led.o speed.o timer.o
obj-y += lowlevel_init.o

View File

@@ -0,0 +1,37 @@
/*
* 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>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#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 */
}

View File

@@ -0,0 +1,85 @@
/*
* Copyright (C) 2010, 2009 Matthias Kaehlcke <matthias@kaehlcke.net>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <asm/io.h>
#include <asm/arch/ep93xx.h>
#include <config.h>
#include <status_led.h>
static uint8_t saved_state[2] = {STATUS_LED_OFF, STATUS_LED_OFF};
static uint32_t gpio_pin[2] = {1 << STATUS_LED_GREEN,
1 << STATUS_LED_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] = STATUS_LED_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] = STATUS_LED_OFF;
}
void red_led_on(void)
{
switch_LED_on(STATUS_LED_RED);
}
void red_led_off(void)
{
switch_LED_off(STATUS_LED_RED);
}
void green_led_on(void)
{
switch_LED_on(STATUS_LED_GREEN);
}
void green_led_off(void)
{
switch_LED_off(STATUS_LED_GREEN);
}
void __led_init(led_id_t mask, int state)
{
__led_set(mask, state);
}
void __led_toggle(led_id_t mask)
{
if (STATUS_LED_RED == mask) {
if (STATUS_LED_ON == saved_state[STATUS_LED_RED])
red_led_off();
else
red_led_on();
} else if (STATUS_LED_GREEN == mask) {
if (STATUS_LED_ON == saved_state[STATUS_LED_GREEN])
green_led_off();
else
green_led_on();
}
}
void __led_set(led_id_t mask, int state)
{
if (STATUS_LED_RED == mask) {
if (STATUS_LED_ON == state)
red_led_on();
else
red_led_off();
} else if (STATUS_LED_GREEN == mask) {
if (STATUS_LED_ON == state)
green_led_on();
else
green_led_off();
}
}

View File

@@ -0,0 +1,458 @@
/*
* 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.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#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

View File

@@ -0,0 +1,96 @@
/*
* Cirrus Logic EP93xx PLL support.
*
* Copyright (C) 2009 Matthias Kaehlcke <matthias@kaehlcke.net>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#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()
{
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;
}

View File

@@ -0,0 +1,120 @@
/*
* 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.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.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_masked(void)
{
return get_ticks();
}
unsigned long get_timer(unsigned long base)
{
return get_timer_masked() - 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;
}

View File

@@ -0,0 +1,10 @@
#
# (C) Copyright 2000-2006
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
#
# SPDX-License-Identifier: GPL-2.0+
#
obj-y += generic.o
obj-y += speed.o
obj-y += timer.o

View File

@@ -0,0 +1,77 @@
/*
* arch/arm/mach-imx/generic.c
*
* author: Sascha Hauer
* Created: april 20th, 2004
* Copyright: Synertronixx GmbH
*
* Common code for i.MX machines
*
* SPDX-License-Identifier: GPL-2.0+
*/
#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 */

View File

@@ -0,0 +1,86 @@
/*
*
* (c) 2004 Sascha Hauer <sascha@saschahauer.de>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#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) */

View File

@@ -0,0 +1,107 @@
/*
* (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>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.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
*/
ulong get_timer (ulong base)
{
return get_timer_masked() - base;
}
ulong get_timer_masked (void)
{
return TCN1;
}
void udelay_masked (unsigned long usec)
{
ulong endtime = get_timer_masked() + usec;
signed long diff;
do {
ulong now = get_timer_masked ();
diff = endtime - now;
} while (diff >= 0);
}
void __udelay (unsigned long usec)
{
udelay_masked(usec);
}
/*
* 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)
{
ulong tbclk;
tbclk = CONFIG_SYS_HZ;
return tbclk;
}
/*
* 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) */

View File

@@ -0,0 +1,27 @@
/*
* (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>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <asm/proc-armv/ptrace.h>
#if defined (CONFIG_ARCH_INTEGRATOR)
void do_irq (struct pt_regs *pt_regs)
{
/* ASSUMED to be a timer interrupt */
/* Just clear it - count handled in */
/* integratorap.c */
*(volatile ulong *)(CONFIG_SYS_TIMERBASE + 0x0C) = 0;
}
#endif

View File

@@ -0,0 +1,11 @@
#
# (C) Copyright 2000-2006
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
#
# SPDX-License-Identifier: GPL-2.0+
#
obj-$(CONFIG_USE_IRQ) += interrupts.o
obj-$(CONFIG_DISPLAY_CPUINFO) += cpu_info.o
obj-y += speed.o
obj-y += timer.o

View File

@@ -0,0 +1,38 @@
/*
* (C) Copyright 2010
* David Mueller <d.mueller@elsoft.ch>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <asm/io.h>
#include <asm/arch/s3c24x0_cpu.h>
typedef ulong (*getfreq)(void);
static const getfreq freq_f[] = {
get_FCLK,
get_HCLK,
get_PCLK,
};
static const char freq_c[] = { 'F', 'H', 'P' };
int print_cpuinfo(void)
{
int i;
char buf[32];
/* the S3C2400 seems to be lacking a CHIP ID register */
#ifndef CONFIG_S3C2400
ulong cpuid;
struct s3c24x0_gpio * const gpio = s3c24x0_get_base_gpio();
cpuid = readl(&gpio->gstatus1);
printf("CPUID: %8lX\n", cpuid);
#endif
for (i = 0; i < ARRAY_SIZE(freq_f); i++)
printf("%cCLK: %8s MHz\n", freq_c[i], strmhz(buf, freq_f[i]()));
return 0;
}

View File

@@ -0,0 +1,26 @@
/*
* (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>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <asm/arch/s3c24x0_cpu.h>
#include <asm/proc-armv/ptrace.h>
void do_irq (struct pt_regs *pt_regs)
{
struct s3c24x0_interrupt *irq = s3c24x0_get_base_interrupt();
u_int32_t intpnd = readl(&irq->INTPND);
}

View File

@@ -0,0 +1,102 @@
/*
* (C) Copyright 2001-2004
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* (C) Copyright 2002
* David Mueller, ELSOFT AG, d.mueller@elsoft.ch
*
* SPDX-License-Identifier: GPL-2.0+
*/
/* This code should work for both the S3C2400 and the S3C2410
* as they seem to have the same PLL and clock machinery inside.
* The different address mapping is handled by the s3c24xx.h files below.
*/
#include <common.h>
#ifdef CONFIG_S3C24X0
#include <asm/io.h>
#include <asm/arch/s3c24x0_cpu.h>
#define MPLL 0
#define UPLL 1
/* ------------------------------------------------------------------------- */
/* NOTE: This describes the proper use of this file.
*
* 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.
*/
/* ------------------------------------------------------------------------- */
static ulong get_PLLCLK(int pllreg)
{
struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power();
ulong r, m, p, s;
if (pllreg == MPLL)
r = readl(&clk_power->mpllcon);
else if (pllreg == UPLL)
r = readl(&clk_power->upllcon);
else
hang();
m = ((r & 0xFF000) >> 12) + 8;
p = ((r & 0x003F0) >> 4) + 2;
s = r & 0x3;
#if defined(CONFIG_S3C2440)
if (pllreg == MPLL)
return 2 * m * (CONFIG_SYS_CLK_FREQ / (p << s));
#endif
return (CONFIG_SYS_CLK_FREQ * m) / (p << s);
}
/* return FCLK frequency */
ulong get_FCLK(void)
{
return get_PLLCLK(MPLL);
}
/* return HCLK frequency */
ulong get_HCLK(void)
{
struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power();
#ifdef CONFIG_S3C2440
switch (readl(&clk_power->clkdivn) & 0x6) {
default:
case 0:
return get_FCLK();
case 2:
return get_FCLK() / 2;
case 4:
return (readl(&clk_power->camdivn) & (1 << 9)) ?
get_FCLK() / 8 : get_FCLK() / 4;
case 6:
return (readl(&clk_power->camdivn) & (1 << 8)) ?
get_FCLK() / 6 : get_FCLK() / 3;
}
#else
return (readl(&clk_power->clkdivn) & 2) ? get_FCLK() / 2 : get_FCLK();
#endif
}
/* return PCLK frequency */
ulong get_PCLK(void)
{
struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power();
return (readl(&clk_power->clkdivn) & 1) ? get_HCLK() / 2 : get_HCLK();
}
/* return UCLK frequency */
ulong get_UCLK(void)
{
return get_PLLCLK(UPLL);
}
#endif /* CONFIG_S3C24X0 */

View File

@@ -0,0 +1,160 @@
/*
* (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>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#ifdef CONFIG_S3C24X0
#include <asm/io.h>
#include <asm/arch/s3c24x0_cpu.h>
DECLARE_GLOBAL_DATA_PTR;
int timer_init(void)
{
struct s3c24x0_timers *timers = s3c24x0_get_base_timers();
ulong tmr;
/* use PWM Timer 4 because it has no output */
/* prescaler for Timer 4 is 16 */
writel(0x0f00, &timers->tcfg0);
if (gd->arch.tbu == 0) {
/*
* for 10 ms clock period @ PCLK with 4 bit divider = 1/2
* (default) and prescaler = 16. Should be 10390
* @33.25MHz and 15625 @ 50 MHz
*/
gd->arch.tbu = get_PCLK() / (2 * 16 * 100);
gd->arch.timer_rate_hz = get_PCLK() / (2 * 16);
}
/* load value for 10 ms timeout */
writel(gd->arch.tbu, &timers->tcntb4);
/* auto load, manual update of timer 4 */
tmr = (readl(&timers->tcon) & ~0x0700000) | 0x0600000;
writel(tmr, &timers->tcon);
/* auto load, start timer 4 */
tmr = (tmr & ~0x0700000) | 0x0500000;
writel(tmr, &timers->tcon);
gd->arch.lastinc = 0;
gd->arch.tbl = 0;
return 0;
}
/*
* timer without interrupts
*/
ulong get_timer(ulong base)
{
return get_timer_masked() - base;
}
void __udelay (unsigned long usec)
{
ulong tmo;
ulong start = get_ticks();
tmo = usec / 1000;
tmo *= (gd->arch.tbu * 100);
tmo /= 1000;
while ((ulong) (get_ticks() - start) < tmo)
/*NOP*/;
}
ulong get_timer_masked(void)
{
ulong tmr = get_ticks();
return tmr / (gd->arch.timer_rate_hz / CONFIG_SYS_HZ);
}
void udelay_masked(unsigned long usec)
{
ulong tmo;
ulong endtime;
signed long diff;
if (usec >= 1000) {
tmo = usec / 1000;
tmo *= (gd->arch.tbu * 100);
tmo /= 1000;
} else {
tmo = usec * (gd->arch.tbu * 100);
tmo /= (1000 * 1000);
}
endtime = get_ticks() + tmo;
do {
ulong now = get_ticks();
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)
{
struct s3c24x0_timers *timers = s3c24x0_get_base_timers();
ulong now = readl(&timers->tcnto4) & 0xffff;
if (gd->arch.lastinc >= now) {
/* normal mode */
gd->arch.tbl += gd->arch.lastinc - now;
} else {
/* we have an overflow ... */
gd->arch.tbl += gd->arch.lastinc + gd->arch.tbu - now;
}
gd->arch.lastinc = now;
return gd->arch.tbl;
}
/*
* 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)
{
struct s3c24x0_watchdog *watchdog;
watchdog = s3c24x0_get_base_watchdog();
/* Disable watchdog */
writel(0x0000, &watchdog->wtcon);
/* Initialize watchdog timer count register */
writel(0x0001, &watchdog->wtcnt);
/* Enable watchdog timer; assert reset at timer timeout */
writel(0x0021, &watchdog->wtcon);
while (1)
/* loop forever and wait for reset to happen */;
/*NOTREACHED*/
}
#endif /* CONFIG_S3C24X0 */

View File

@@ -0,0 +1,150 @@
/*
* 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>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#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
#ifdef CONFIG_S3C24X0
/* turn off the watchdog */
# if defined(CONFIG_S3C2400)
# define pWTCON 0x15300000
# define INTMSK 0x14400008 /* Interrupt-Controller base addresses */
# define CLKDIVN 0x14800014 /* clock divisor register */
#else
# define pWTCON 0x53000000
# define INTMSK 0x4A000008 /* Interrupt-Controller base addresses */
# define INTSUBMSK 0x4A00001C
# define CLKDIVN 0x4C000014 /* clock divisor register */
# endif
ldr r0, =pWTCON
mov r1, #0x0
str r1, [r0]
/*
* mask all IRQs by setting all bits in the INTMR - default
*/
mov r1, #0xffffffff
ldr r0, =INTMSK
str r1, [r0]
# if defined(CONFIG_S3C2410)
ldr r1, =0x3ff
ldr r0, =INTSUBMSK
str r1, [r0]
# endif
/* FCLK:HCLK:PCLK = 1:2:4 */
/* default FCLK is 120 MHz ! */
ldr r0, =CLKDIVN
mov r1, #3
str r1, [r0]
#endif /* CONFIG_S3C24X0 */
/*
* 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 */

View File

@@ -0,0 +1,33 @@
#
# (C) Copyright 2000-2006
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
#
# SPDX-License-Identifier: GPL-2.0+
#
extra-y = start.o
obj-y = cpu.o cache.o
ifdef CONFIG_SPL_BUILD
ifdef CONFIG_SPL_NO_CPU_SUPPORT_CODE
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_SYS_THUMB_BUILD
ifndef CONFIG_HAS_THUMB2
CFLAGS_cpu.o := -marm
CFLAGS_cache.o := -marm
endif
endif

View File

@@ -0,0 +1,9 @@
#
# (C) Copyright 2010
# Marvell Semiconductor <www.marvell.com>
# Written-by: Prafulla Wadaskar <prafulla@marvell.com>
#
# SPDX-License-Identifier: GPL-2.0+
#
obj-y = cpu.o timer.o dram.o

View File

@@ -0,0 +1,92 @@
/*
* (C) Copyright 2010
* Marvell Semiconductor <www.marvell.com>
* Written-by: Prafulla Wadaskar <prafulla@marvell.com>
* Contributor: Mahavir Jain <mjain@marvell.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.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

View File

@@ -0,0 +1,114 @@
/*
* (C) Copyright 2010
* Marvell Semiconductor <www.marvell.com>
* Written-by: Prafulla Wadaskar <prafulla@marvell.com>,
* Contributor: Mahavir Jain <mjain@marvell.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#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.
*/
void dram_init_banksize(void)
{
dram_init();
}

View File

@@ -0,0 +1,194 @@
/*
* (C) Copyright 2010
* Marvell Semiconductor <www.marvell.com>
* Written-by: Prafulla Wadaskar <prafulla@marvell.com>
* Contributor: Mahavir Jain <mjain@marvell.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.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));
}
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;
}

View File

@@ -0,0 +1,90 @@
/*
* (C) Copyright 2011
* Ilya Yanok, EmCraft Systems
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <linux/types.h>
#include <common.h>
#ifndef CONFIG_SYS_DCACHE_OFF
#ifndef CONFIG_SYS_CACHELINE_SIZE
#define CONFIG_SYS_CACHELINE_SIZE 32
#endif
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"
);
}
static int check_cache_range(unsigned long start, unsigned long stop)
{
int ok = 1;
if (start & (CONFIG_SYS_CACHELINE_SIZE - 1))
ok = 0;
if (stop & (CONFIG_SYS_CACHELINE_SIZE - 1))
ok = 0;
if (!ok)
debug("CACHE: Misaligned operation at range [%08lx, %08lx]\n",
start, stop);
return ok;
}
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 /* #ifndef CONFIG_SYS_DCACHE_OFF */
void invalidate_dcache_all(void)
{
}
void flush_dcache_all(void)
{
}
#endif /* #ifndef CONFIG_SYS_DCACHE_OFF */
/*
* Stub implementations for l2 cache operations
*/
__weak void l2_cache_disable(void) {}
#if defined CONFIG_SYS_THUMB_BUILD
__weak void invalidate_l2_cache(void) {}
#endif

View File

@@ -0,0 +1,53 @@
/*
* (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>
*
* SPDX-License-Identifier: GPL-2.0+
*/
/*
* CPU specific code
*/
#include <common.h>
#include <command.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 !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF))
unsigned long i = 0;
asm ("mcr p15, 0, %0, c7, c7, 0": :"r" (i));
#endif
}

View File

@@ -0,0 +1,10 @@
#
# (C) Copyright 2000-2006
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
#
# SPDX-License-Identifier: GPL-2.0+
#
obj-y = cpu.o clk.o devices.o timer.o
obj-$(CONFIG_SPL_BUILD) += dram.o lowlevel_init.o

View File

@@ -0,0 +1,138 @@
/*
* Copyright (C) 2011 by Vladimir Zapolskiy <vz@mleia.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#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();
}

View File

@@ -0,0 +1,78 @@
/*
* Copyright (C) 2011-2015 by Vladimir Zapolskiy <vz@mleia.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.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

View File

@@ -0,0 +1,138 @@
/*
* Copyright (C) 2011 by Vladimir Zapolskiy <vz@mleia.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#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 },
{ .base = UART4_BASE, .reg_shift = 2, .clock = CONFIG_SYS_NS16550_CLK },
{ .base = UART5_BASE, .reg_shift = 2, .clock = CONFIG_SYS_NS16550_CLK },
{ .base = UART6_BASE, .reg_shift = 2, .clock = CONFIG_SYS_NS16550_CLK },
};
#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);
}

View File

@@ -0,0 +1,77 @@
/*
* 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.
*
* Actual CONFIG_LPC32XX_SDRAM_* parameters must be provided
* by the board configuration file.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#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);
}

View File

@@ -0,0 +1,45 @@
/*
* 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.
*
* SPDX-License-Identifier: GPL-2.0+
*/
.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

View File

@@ -0,0 +1,82 @@
/*
* Copyright (C) 2011 Vladimir Zapolskiy <vz@mleia.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.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);
}
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;
}

View File

@@ -0,0 +1,11 @@
#
# (C) Copyright 2000-2006
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
#
# SPDX-License-Identifier: GPL-2.0+
obj-y = generic.o timer.o reset.o
ifndef CONFIG_SPL_BUILD
obj-y += relocate.o
endif

View File

@@ -0,0 +1,250 @@
/*
* (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>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <div64.h>
#include <netdev.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
#include <fsl_esdhc.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_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 = 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;
}
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
void enable_caches(void)
{
#ifndef CONFIG_SYS_DCACHE_OFF
/* Enable D-cache. I-cache is already enabled in start.S */
dcache_enable();
#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
#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
/*
* 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 */

View File

@@ -0,0 +1,23 @@
/*
* relocate - i.MX25-specific vector relocation
*
* Copyright (c) 2013 Albert ARIBAUD <albert.u.boot@aribaud.net>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#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)

View File

@@ -0,0 +1,40 @@
/*
* (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>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#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) ;
}

View File

@@ -0,0 +1,49 @@
/*
* (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
*
* SPDX-License-Identifier: GPL-2.0+
*/
#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;
}

View File

@@ -0,0 +1,11 @@
#
# (C) Copyright 2000-2006
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
#
# SPDX-License-Identifier: GPL-2.0+
obj-y = generic.o reset.o timer.o
ifndef CONFIG_SPL_BUILD
obj-y += relocate.o
endif

View File

@@ -0,0 +1,385 @@
/*
* Copyright (c) 2008 Eric Jarrige <eric.jarrige@armadeus.org>
* Copyright (c) 2009 Ilya Yanok <yanok@emcraft.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <div64.h>
#include <netdev.h>
#include <asm/io.h>
#include <asm/arch/imx-regs.h>
#include <asm/arch/clock.h>
#include <asm/arch/gpio.h>
#include <asm/imx-common/sys_proto.h>
#ifdef CONFIG_MXC_MMC
#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_MXC_MMC
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_MXC_MMC
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_MXC_MMC */
#ifndef CONFIG_SYS_DCACHE_OFF
void enable_caches(void)
{
/* Enable D-cache. I-cache is already enabled in start.S */
dcache_enable();
}
#endif /* CONFIG_SYS_DCACHE_OFF */

View File

@@ -0,0 +1,51 @@
/*
* relocate - i.MX27-specific vector relocation
*
* Copyright (c) 2013 Albert ARIBAUD <albert.u.boot@aribaud.net>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#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)

View File

@@ -0,0 +1,41 @@
/*
* (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>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#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*/
}

View File

@@ -0,0 +1,162 @@
/*
* (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>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <div64.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;
}
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;
}

View File

@@ -0,0 +1,83 @@
#
# (C) Copyright 2000-2006
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
#
# SPDX-License-Identifier: GPL-2.0+
#
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.mx23.cfg
MKIMAGE_TARGET-$(CONFIG_MX28) = mxsimage.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)

View File

@@ -0,0 +1,436 @@
/*
* 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.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <asm/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;
}

View File

@@ -0,0 +1,97 @@
/*
* 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>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <asm/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;
}

View File

@@ -0,0 +1,297 @@
/*
* 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.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <asm/errno.h>
#include <asm/io.h>
#include <asm/arch/clock.h>
#include <asm/imx-common/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 */
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 (;;)
;
}
void enable_caches(void)
{
#ifndef CONFIG_SYS_ICACHE_OFF
icache_enable();
#endif
#ifndef CONFIG_SYS_DCACHE_OFF
dcache_enable();
#endif
}
/*
* 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 = (struct mxs_spl_data *)
((CONFIG_SYS_TEXT_BASE - sizeof(struct mxs_spl_data)) & ~0xf);
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 = (struct mxs_spl_data *)
((CONFIG_SYS_TEXT_BASE - sizeof(struct mxs_spl_data)) & ~0xf);
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",
""
);

View File

@@ -0,0 +1,29 @@
/*
* Freescale i.MX28 SPL functions
*
* Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
* on behalf of DENX Software Engineering GmbH
*
* SPDX-License-Identifier: GPL-2.0+
*/
#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__ */

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,161 @@
/*
* Freescale i.MX28 Boot setup
*
* Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
* on behalf of DENX Software Engineering GmbH
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <config.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))
;
}
#define MUX_CONFIG_BOOTMODE_PAD (MXS_PAD_3V3 | MXS_PAD_4MA | MXS_PAD_NOPULL)
static const iomux_cfg_t iomux_boot[] = {
#if defined(CONFIG_MX23)
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 = (struct mxs_spl_data *)
((CONFIG_SYS_TEXT_BASE - sizeof(struct mxs_spl_data)) & ~0xf);
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");
}
}
/* Support aparatus */
inline void board_init_f(unsigned long bootflag)
{
for (;;)
;
}
inline void board_init_r(gd_t *id, ulong dest_addr)
{
for (;;)
;
}

View File

@@ -0,0 +1,79 @@
/*
* Freescale i.MX28 Battery measurement init
*
* Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
* on behalf of DENX Software Engineering GmbH
*
* SPDX-License-Identifier: GPL-2.0+
*/
#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");
}

View File

@@ -0,0 +1,360 @@
/*
* Freescale i.MX28 RAM init
*
* Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
* on behalf of DENX Software Engineering GmbH
*
* SPDX-License-Identifier: GPL-2.0+
*/
#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"
static uint32_t 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(dram_vals);
debug("SPL: Applying SDRAM parameters\n");
for (i = 0; i < ARRAY_SIZE(dram_vals); i++)
writel(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(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(dram_vals); i++) {
if (i == 8 || i == 27 || i == 28 || i == 35)
continue;
writel(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

View File

@@ -0,0 +1,96 @@
/*
* 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
*
* SPDX-License-Identifier: GPL-2.0+
*/
#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

View File

@@ -0,0 +1,161 @@
/*
* 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.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.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_masked(void)
{
return tick_to_time(get_ticks());
}
ulong get_timer(ulong base)
{
return get_timer_masked() - 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;
}

View File

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

View File

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

View File

@@ -0,0 +1,69 @@
/*
* 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>
*
* SPDX-License-Identifier: GPL-2.0+
*/
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
. = CONFIG_SPL_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*) }
}

View File

@@ -0,0 +1,10 @@
#
# (C) Copyright 2000-2006
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
#
# SPDX-License-Identifier: GPL-2.0+
#
obj-y = timer.o
obj-$(CONFIG_DISPLAY_CPUINFO) += cpuinfo.o
obj-y += reset.o

View File

@@ -0,0 +1,242 @@
/*
* OMAP1 CPU identification code
*
* Copyright (C) 2004 Nokia Corporation
* Written by Tony Lindgren <tony@atomide.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <common.h>
#include <command.h>
#include <linux/compiler.h>
#if defined(CONFIG_OMAP)
#define omap_readw(x) *(volatile unsigned short *)(x)
#define omap_readl(x) *(volatile unsigned long *)(x)
#define OMAP_DIE_ID_0 0xfffe1800
#define OMAP_DIE_ID_1 0xfffe1804
#define OMAP_PRODUCTION_ID_0 0xfffe2000
#define OMAP_PRODUCTION_ID_1 0xfffe2004
#define OMAP32_ID_0 0xfffed400
#define OMAP32_ID_1 0xfffed404
struct omap_id {
u16 jtag_id; /* Used to determine OMAP type */
u8 die_rev; /* Processor revision */
u32 omap_id; /* OMAP revision */
u32 type; /* Cpu id bits [31:08], cpu class bits [07:00] */
};
/* Register values to detect the OMAP version */
static struct omap_id omap_ids[] = {
{ .jtag_id = 0xb574, .die_rev = 0x2, .omap_id = 0x03310315, .type = 0x03100000},
{ .jtag_id = 0x355f, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x07300100},
{ .jtag_id = 0xb55f, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x07300300},
{ .jtag_id = 0xb470, .die_rev = 0x0, .omap_id = 0x03310100, .type = 0x15100000},
{ .jtag_id = 0xb576, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x16100000},
{ .jtag_id = 0xb576, .die_rev = 0x2, .omap_id = 0x03320100, .type = 0x16110000},
{ .jtag_id = 0xb576, .die_rev = 0x3, .omap_id = 0x03320100, .type = 0x16100c00},
{ .jtag_id = 0xb576, .die_rev = 0x0, .omap_id = 0x03320200, .type = 0x16100d00},
{ .jtag_id = 0xb613, .die_rev = 0x0, .omap_id = 0x03320300, .type = 0x1610ef00},
{ .jtag_id = 0xb613, .die_rev = 0x0, .omap_id = 0x03320300, .type = 0x1610ef00},
{ .jtag_id = 0xb576, .die_rev = 0x1, .omap_id = 0x03320100, .type = 0x16110000},
{ .jtag_id = 0xb58c, .die_rev = 0x2, .omap_id = 0x03320200, .type = 0x16110b00},
{ .jtag_id = 0xb58c, .die_rev = 0x3, .omap_id = 0x03320200, .type = 0x16110c00},
{ .jtag_id = 0xb65f, .die_rev = 0x0, .omap_id = 0x03320400, .type = 0x16212300},
{ .jtag_id = 0xb65f, .die_rev = 0x1, .omap_id = 0x03320400, .type = 0x16212300},
{ .jtag_id = 0xb65f, .die_rev = 0x1, .omap_id = 0x03320500, .type = 0x16212300},
{ .jtag_id = 0xb5f7, .die_rev = 0x0, .omap_id = 0x03330000, .type = 0x17100000},
{ .jtag_id = 0xb5f7, .die_rev = 0x1, .omap_id = 0x03330100, .type = 0x17100000},
{ .jtag_id = 0xb5f7, .die_rev = 0x2, .omap_id = 0x03330100, .type = 0x17100000},
};
/*
* Get OMAP type from PROD_ID.
* 1710 has the PROD_ID in bits 15:00, not in 16:01 as documented in TRM.
* 1510 PROD_ID is empty, and 1610 PROD_ID does not make sense.
* Undocumented register in TEST BLOCK is used as fallback; This seems to
* work on 1510, 1610 & 1710. The official way hopefully will work in future
* processors.
*/
static u16 omap_get_jtag_id(void)
{
u32 prod_id, omap_id;
prod_id = omap_readl(OMAP_PRODUCTION_ID_1);
omap_id = omap_readl(OMAP32_ID_1);
/* Check for unusable OMAP_PRODUCTION_ID_1 on 1611B/5912 and 730 */
if (((prod_id >> 20) == 0) || (prod_id == omap_id))
prod_id = 0;
else
prod_id &= 0xffff;
if (prod_id)
return prod_id;
/* Use OMAP32_ID_1 as fallback */
prod_id = ((omap_id >> 12) & 0xffff);
return prod_id;
}
/*
* Get OMAP revision from DIE_REV.
* Early 1710 processors may have broken OMAP_DIE_ID, it contains PROD_ID.
* Undocumented register in the TEST BLOCK is used as fallback.
* REVISIT: This does not seem to work on 1510
*/
static u8 omap_get_die_rev(void)
{
u32 die_rev;
die_rev = omap_readl(OMAP_DIE_ID_1);
/* Check for broken OMAP_DIE_ID on early 1710 */
if (((die_rev >> 12) & 0xffff) == omap_get_jtag_id())
die_rev = 0;
die_rev = (die_rev >> 17) & 0xf;
if (die_rev)
return die_rev;
die_rev = (omap_readl(OMAP32_ID_1) >> 28) & 0xf;
return die_rev;
}
static unsigned long dpll1(void)
{
unsigned short pll_ctl_val = omap_readw(DPLL_CTL_REG);
unsigned long rate;
rate = CONFIG_SYS_CLK_FREQ; /* Base xtal rate */
if (pll_ctl_val & 0x10) {
/* PLL enabled, apply multiplier and divisor */
if (pll_ctl_val & 0xf80)
rate *= (pll_ctl_val & 0xf80) >> 7;
rate /= ((pll_ctl_val & 0x60) >> 5) + 1;
} else {
/* PLL disabled, apply bypass divisor */
switch (pll_ctl_val & 0xc) {
case 0:
break;
case 0x4:
rate /= 2;
break;
default:
rate /= 4;
break;
}
}
return rate;
}
static unsigned long armcore(void)
{
unsigned short arm_ckctl = omap_readw(ARM_CKCTL);
return (dpll1() >> ((arm_ckctl & 0x0030) >> 4));
}
int print_cpuinfo (void)
{
int i;
u16 jtag_id;
u8 die_rev;
u32 omap_id;
u8 cpu_type;
__maybe_unused u32 system_serial_high;
__maybe_unused u32 system_serial_low;
u32 system_rev = 0;
jtag_id = omap_get_jtag_id();
die_rev = omap_get_die_rev();
omap_id = omap_readl(OMAP32_ID_0);
#ifdef DEBUG
printf("OMAP_DIE_ID_0: 0x%08x\n", omap_readl(OMAP_DIE_ID_0));
printf("OMAP_DIE_ID_1: 0x%08x DIE_REV: %i\n",
omap_readl(OMAP_DIE_ID_1),
(omap_readl(OMAP_DIE_ID_1) >> 17) & 0xf);
printf("OMAP_PRODUCTION_ID_0: 0x%08x\n", omap_readl(OMAP_PRODUCTION_ID_0));
printf("OMAP_PRODUCTION_ID_1: 0x%08x JTAG_ID: 0x%04x\n",
omap_readl(OMAP_PRODUCTION_ID_1),
omap_readl(OMAP_PRODUCTION_ID_1) & 0xffff);
printf("OMAP32_ID_0: 0x%08x\n", omap_readl(OMAP32_ID_0));
printf("OMAP32_ID_1: 0x%08x\n", omap_readl(OMAP32_ID_1));
printf("JTAG_ID: 0x%04x DIE_REV: %i\n", jtag_id, die_rev);
#endif
system_serial_high = omap_readl(OMAP_DIE_ID_0);
system_serial_low = omap_readl(OMAP_DIE_ID_1);
/* First check only the major version in a safe way */
for (i = 0; i < ARRAY_SIZE(omap_ids); i++) {
if (jtag_id == (omap_ids[i].jtag_id)) {
system_rev = omap_ids[i].type;
break;
}
}
/* Check if we can find the die revision */
for (i = 0; i < ARRAY_SIZE(omap_ids); i++) {
if (jtag_id == omap_ids[i].jtag_id && die_rev == omap_ids[i].die_rev) {
system_rev = omap_ids[i].type;
break;
}
}
/* Finally check also the omap_id */
for (i = 0; i < ARRAY_SIZE(omap_ids); i++) {
if (jtag_id == omap_ids[i].jtag_id
&& die_rev == omap_ids[i].die_rev
&& omap_id == omap_ids[i].omap_id) {
system_rev = omap_ids[i].type;
break;
}
}
/* Add the cpu class info (7xx, 15xx, 16xx, 24xx) */
cpu_type = system_rev >> 24;
switch (cpu_type) {
case 0x07:
system_rev |= 0x07;
break;
case 0x03:
case 0x15:
system_rev |= 0x15;
break;
case 0x16:
case 0x17:
system_rev |= 0x16;
break;
case 0x24:
system_rev |= 0x24;
break;
default:
printf("Unknown OMAP cpu type: 0x%02x\n", cpu_type);
}
printf("CPU: OMAP%04x", system_rev >> 16);
if ((system_rev >> 8) & 0xff)
printf("%x", (system_rev >> 8) & 0xff);
#ifdef DEBUG
printf(" revision %i handled as %02xxx id: %08x%08x",
die_rev, system_rev & 0xff, system_serial_low, system_serial_high);
#endif
printf(" at %ld.%01ld MHz (DPLL1=%ld.%01ld MHz)\n",
armcore() / 1000000, (armcore() / 100000) % 10,
dpll1() / 1000000, (dpll1() / 100000) % 10);
return 0;
}
#endif /* #if defined(CONFIG_OMAP) */

View File

@@ -0,0 +1,29 @@
/*
* 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>
*
* SPDX-License-Identifier: GPL-2.0+
*/
.align 5
.globl reset_cpu
reset_cpu:
ldr r1, rstctl1 /* get clkm1 reset ctl */
mov r3, #0x0
strh r3, [r1] /* clear it */
mov r3, #0x8
strh r3, [r1] /* force dsp+arm reset */
_loop_forever:
b _loop_forever
rstctl1:
.word 0xfffece10

View File

@@ -0,0 +1,152 @@
/*
* (C) Copyright 2003
* Texas Instruments <www.ti.com>
*
* (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-2004
* Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
*
* (C) Copyright 2004
* Philippe Robin, ARM Ltd. <philippe.robin@arm.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <asm/io.h>
#define TIMER_CLOCK (CONFIG_SYS_CLK_FREQ / (2 << CONFIG_SYS_PTV))
#define TIMER_LOAD_VAL 0xffffffff
/* macro to read the 32 bit timer */
#define READ_TIMER readl(CONFIG_SYS_TIMERBASE+8) \
/ (TIMER_CLOCK / CONFIG_SYS_HZ)
DECLARE_GLOBAL_DATA_PTR;
#define timestamp gd->arch.tbl
#define lastdec gd->arch.lastinc
int timer_init (void)
{
int32_t val;
/* Start the decrementer ticking down from 0xffffffff */
*((int32_t *) (CONFIG_SYS_TIMERBASE + LOAD_TIM)) = TIMER_LOAD_VAL;
val = MPUTIM_ST | MPUTIM_AR | MPUTIM_CLOCK_ENABLE | (CONFIG_SYS_PTV << MPUTIM_PTV_BIT);
*((int32_t *) (CONFIG_SYS_TIMERBASE + CNTL_TIMER)) = val;
/* init the timestamp and lastdec value */
reset_timer_masked();
return 0;
}
/*
* timer without interrupts
*/
ulong get_timer (ulong base)
{
return get_timer_masked () - base;
}
/* delay x useconds AND preserve advance timestamp value */
void __udelay (unsigned long usec)
{
ulong tmo, tmp;
if(usec >= 1000){ /* if "big" number, spread normalization to seconds */
tmo = usec / 1000; /* start to normalize for usec to ticks per sec */
tmo *= CONFIG_SYS_HZ; /* find number of "ticks" to wait to achieve target */
tmo /= 1000; /* finish normalize. */
}else{ /* else small number, don't kill it prior to HZ multiply */
tmo = usec * CONFIG_SYS_HZ;
tmo /= (1000*1000);
}
tmp = get_timer (0); /* get current timestamp */
if( (tmo + tmp + 1) < tmp ) /* if setting this fordward will roll time stamp */
reset_timer_masked (); /* reset "advancing" timestamp to 0, set lastdec value */
else
tmo += tmp; /* else, set advancing stamp wake up time */
while (get_timer_masked () < tmo)/* loop till event */
/*NOP*/;
}
void reset_timer_masked (void)
{
/* reset time */
lastdec = READ_TIMER; /* capure current decrementer value time */
timestamp = 0; /* start "advancing" time stamp from 0 */
}
ulong get_timer_masked (void)
{
ulong now = READ_TIMER; /* current tick value */
if (lastdec >= now) { /* normal mode (non roll) */
/* normal mode */
timestamp += lastdec - now; /* move stamp fordward with absoulte diff ticks */
} else { /* we have overflow of the count down timer */
/* nts = ts + ld + (TLV - now)
* ts=old stamp, ld=time that passed before passing through -1
* (TLV-now) amount of time after passing though -1
* nts = new "advancing time stamp"...it could also roll and cause problems.
*/
timestamp += lastdec + (TIMER_LOAD_VAL / (TIMER_CLOCK /
CONFIG_SYS_HZ)) - now;
}
lastdec = now;
return timestamp;
}
/* waits specified delay value and resets timestamp */
void udelay_masked (unsigned long usec)
{
ulong tmo;
ulong endtime;
signed long diff;
if (usec >= 1000) { /* if "big" number, spread normalization to seconds */
tmo = usec / 1000; /* start to normalize for usec to ticks per sec */
tmo *= CONFIG_SYS_HZ; /* find number of "ticks" to wait to achieve target */
tmo /= 1000; /* finish normalize. */
} else { /* else small number, don't kill it prior to HZ multiply */
tmo = usec * CONFIG_SYS_HZ;
tmo /= (1000*1000);
}
endtime = get_timer_masked () + tmo;
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;
}

View File

@@ -0,0 +1,61 @@
/*
* (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>
*
* SPDX-License-Identifier: GPL-2.0+
*/
MEMORY { .nor : ORIGIN = CONFIG_SPL_TEXT_BASE,\
LENGTH = CONFIG_SPL_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
}

View File

@@ -0,0 +1,21 @@
#
# (C) Copyright 2000-2006
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
#
# SPDX-License-Identifier: GPL-2.0+
#
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
endif
extra-$(CONFIG_SPL_BUILD) := start.o

View File

@@ -0,0 +1,119 @@
/*
* (C) Copyright 2010
* Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#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
writel(periph1_clken, &misc_p->periph1_clken);
return 0;
}
void enable_caches(void)
{
#ifndef CONFIG_SYS_ICACHE_OFF
icache_enable();
#endif
#ifndef CONFIG_SYS_DCACHE_OFF
dcache_enable();
#endif
}
#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)
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

View File

@@ -0,0 +1,38 @@
/*
* (C) Copyright 2009
* Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#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)
;
}

View File

@@ -0,0 +1,224 @@
/*
* (C) Copyright 2000-2009
* Viresh Kumar, ST Microelectronics, viresh.kumar@st.com
* Vipin Kumar, ST Microelectronics, vipin.kumar@st.com
*
* SPDX-License-Identifier: GPL-2.0+
*/
#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();
}

View File

@@ -0,0 +1,257 @@
/*
* Copyright (C) 2011
* Heiko Schocher, DENX Software Engineering, hs@denx.de.
*
* Copyright (C) 2012 Stefan Roese <sr@denx.de>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#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>
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;
/* Currently only SNOR is supported as the only */
if (snor_boot_selected()) {
/* SNOR-SMI initialization */
snor_init();
mode = BOOT_DEVICE_NOR;
}
return mode;
}
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();
board_init_r(NULL, 0);
}

View File

@@ -0,0 +1,114 @@
/*
* (C) Copyright 2000-2009
* Vipin Kumar, ST Microelectronics, vipin.kumar@st.com
*
* SPDX-License-Identifier: GPL-2.0+
*/
#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

View File

@@ -0,0 +1,119 @@
/*
* (C) Copyright 2000-2009
* Vipin Kumar, ST Microelectronics, vipin.kumar@st.com
*
* SPDX-License-Identifier: GPL-2.0+
*/
#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

View File

@@ -0,0 +1,114 @@
/*
* (C) Copyright 2000-2009
* Vipin Kumar, ST Microelectronics, vipin.kumar@st.com
*
* SPDX-License-Identifier: GPL-2.0+
*/
#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

View File

@@ -0,0 +1,128 @@
/*
* (C) Copyright 2000-2009
* Vipin Kumar, ST Microelectronics, vipin.kumar@st.com
*
* SPDX-License-Identifier: GPL-2.0+
*/
#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

View File

@@ -0,0 +1,80 @@
/*
* 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>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <config.h>
/*
*************************************************************************
*
* Startup Code (reset vector)
*
* Below are the critical initializations already taken place in BootROM.
* So, these are not taken care in Xloader
* 1. Relocation to RAM
* 2. Initializing stacks
*
*************************************************************************
*/
.globl reset
reset:
/*
* Xloader has to return back to BootROM in a few cases.
* eg. Ethernet boot, UART boot, USB boot
* Saving registers for returning back
*/
stmdb sp!, {r0-r12,r14}
bl cpu_init_crit
/*
* Clearing bss area is not done in Xloader.
* BSS area lies in the DDR location which is not yet initialized
* bss is assumed to be uninitialized.
*/
ldmia sp!, {r0-r12,pc}
/*
*************************************************************************
*
* CPU_init_critical registers
*
* setup important registers
* setup memory timing
*
*************************************************************************
*/
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 */
/*
* 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.
*/
stmdb sp!, {lr}
bl _main /* _main will call board_init_f */
ldmia sp!, {pc}

View File

@@ -0,0 +1,123 @@
/*
* (C) Copyright 2009
* Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.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;
#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)
;
}
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;
}
void udelay_masked(unsigned long usec)
{
return udelay(usec);
}
/*
* 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;
}

View File

@@ -0,0 +1,55 @@
/*
* 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>
*
* SPDX-License-Identifier: GPL-2.0+
*/
MEMORY { .sram : ORIGIN = CONFIG_SPL_TEXT_BASE,\
LENGTH = CONFIG_SPL_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
}

View File

@@ -0,0 +1,113 @@
/*
* 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>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#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 CONFIG_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 */
#ifndef CONFIG_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 ip, lr /* perserve 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 */

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