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