포럼 회원으로 등록하신분만 다운로드가 가능합니다. 최대 업로드 가능한 용량은 20MB 입니다.
u-boot-1.1.6의
/board / aesop6410 / lowlevel_init.S 분석자료입니다.
김재훈님이 분석하신 자료 http://www.aesop.or.kr/?document_srl=36703 를 참고하였습니다.
/*
* Memory Setup stuff - taken from blob memsetup.S
*
* Copyright (C) 1999 2000 2001 Erik Mouw ([email protected]) and
* Jan-Derk Bakker ([email protected])
*
* Modified for the Samsung SMDK2410 by
* (C) Copyright 2002
* David Mueller, ELSOFT AG, <[email protected]>
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <config.h>
#include <version.h>
#include <s3c6410.h>
#include "smdk6410_val.h"
_TEXT_BASE:
.word TEXT_BASE // TEXT_BASE = 0x c7e0 0000, /board/aesop6410/config.mk
.globl lowlevel_init // lowlevel_init를 전역변수로 선언
lowlevel_init:
mov r12, lr // lr (r14) 링크레지스터 내용을 r12로 옮김
/* LED on only #8 */
ldr r0, =ELFIN_GPIO_BASE // ELFIN_GPIO_BASE = 0x7f00 8000, /include / s3c6410.h GPIO의 베이스 어드레스이다.
ldr r1, =0x55540000 // r1 레지스터에 0x5554 0000 로딩
str r1, [r0, #GPNCON_OFFSET] // GPNCON_OFFSET = 0x830, r1에 있는 내용을 r0 + 0x830 번지에 저장
ldr r1, =0x55555555
str r1, [r0, #GPNPUD_OFFSET] // (0x7f00_8000 + 0x838)번지에 0x5555_5555 저장, s3c6410 datasheet 10-34 참조
// 0101_0101 0101_0101 0101_0101 0101_0101
// pull-down enabled
ldr r1, =0xf000
str r1, [r0, #GPNDAT_OFFSET]
ldr r1, =0x55555555
str r1, [r0, #MEM1DRVCON_OFFSET] // (0x7F00_8000 + 0x1D4), Memory Port 1 Drive strength Control Register
/* Disable Watchdog */
ldr r0, =0x7e000000 @0x7e004000 // r0레지스터에 0x7e00 0000번지 로딩
orr r0, r0, #0x4000 // r0과 0x4000 을 OR연산하여 r0에 저장, 결국 r0 = 0x7e00 4000((s3c6410 데이터시트의 Watch-Dog Timer 어드레스임) 이 된다.
mov r1, #0 // r1에 0 저장
str r1, [r0] // r1의 내용(0)을 r0이 가리키는 번지(0x7e00 4000)에 저장
@ External interrupt pending clear
ldr r0, =(ELFIN_GPIO_BASE+EINTPEND_OFFSET) /*EINTPEND*/
ldr r1, [r0]
str r1, [r0]
ldr r0, =ELFIN_VIC0_BASE_ADDR @0x71200000
ldr r1, =ELFIN_VIC1_BASE_ADDR @0x71300000
@ Disable all interrupts (VIC0 and VIC1) // 모든 인터럽트를 masking한다.(disable)
mvn r3, #0x0 // 0x0을 NOT해서 r3에 저장
str r3, [r0, #oINTMSK] // 0x7120_0000 + 0x14
str r3, [r1, #oINTMSK] // 0x7130_0000 + 0x14
@ Set all interrupts as IRQ
mov r3, #0x0
str r3, [r0, #oINTMOD] // 0x7120_0000 + 0x0C
str r3, [r1, #oINTMOD] // 0x7130_0000 + 0x0C
@ Pending Interrupt Clear
mov r3, #0x0
str r3, [r0, #oVECTADDR] // 0x7120_0000 + 0xF00
str r3, [r1, #oVECTADDR] // 0x7130_0000 + 0xF00
/* init system clock */
bl system_clock_init
/* for UART */
bl uart_asm_init // uart_asm_init로 분기
#if defined(CONFIG_NAND)
/* simple init for NAND */
bl nand_asm_init // nand_asm_init로 분기
#endif
#if 0
ldr r0, =0xff000fff
bic r1, pc, r0 /* r0 <- current base addr of code */
ldr r2, _TEXT_BASE /* r1 <- original base addr in ram */
bic r2, r2, r0 /* r0 <- current base addr of code */
cmp r1, r2 /* compare r0, r1 */
beq 1f /* r0 == r1 then skip sdram init */
#endif
bl mem_ctrl_asm_init
#if 1
ldr r0, =(ELFIN_CLOCK_POWER_BASE+RST_STAT_OFFSET)
ldr r1, [r0]
bic r1, r1, #0xfffffff7
cmp r1, #0x8
beq wakeup_reset
#endif
1:
ldr r0, =ELFIN_UART_BASE // 0x7F00_5000
ldr r1, =0x4b4b4b4b // 문자 'KKKK' 저장
str r1, [r0, #UTXH_OFFSET] // 0x7F00_5000 + 0x20, UART channel 0 transmit 버퍼 레지스터
mov lr, r12
mov pc, lr
#if 1
wakeup_reset:
/*Clear wakeup status register*/
ldr r0, =(ELFIN_CLOCK_POWER_BASE+WAKEUP_STAT_OFFSET)
ldr r1, [r0]
str r1, [r0]
/*LED test*/
ldr r0, =ELFIN_GPIO_BASE // 0x7F00_8000
ldr r1, =0x3000
str r1, [r0, #GPNDAT_OFFSET] // 0x7F00_8000 + 0x834, Port N 데이터 레지스터
/*Load return address and jump to kernel*/
ldr r0, =(ELFIN_CLOCK_POWER_BASE+INF_REG0_OFFSET)
ldr r1, [r0] /* r1 = physical address of s3c6400_cpu_resume function*/
mov pc, r1 /*Jump to kernel (sleep-s3c6400.S)*/
nop
nop
#endif
/*
* system_clock_init: Initialize core clock and bus clock.
* void system_clock_init(void)
*/
system_clock_init:
ldr r0, =ELFIN_CLOCK_POWER_BASE @0x7e00f000 // s3c6410의 클럭설정을 위한 베이스 어드레스
#ifdef CONFIG_SYNC_MODE
ldr r1, [r0, #OTHERS_OFFSET] // r0 + 0x900 번지 로딩, OTHERS 레지스터 어드레스 로딩(0x7E00_F900)
mov r2, #0x40 // r2 = 0x40 (0100 0000) SYNCMUXSEL 비트 세팅
orr r1, r1, r2 // r1 = ? OR r2
str r1, [r0, #OTHERS_OFFSET] // r1을 r0 + 0x900 번지에 저장
// SYNCMUXSEL = 1 이므로 클럭소스는 APLL을 사용(s3c6410 데이터시트, 3.system controller참고)
nop // 클럭을 변경하면 10~20 클럭 정도의 딜레이가 필요하다.
nop
nop
nop
nop
ldr r2, =0x80 // OTHERS 레지스터 0x7E00_F900번지의 32비트중에 7번째비트를 세팅, 0x80 ( [1]000 0000 )
orr r1, r1, r2 // r1 = r1의 내용 OR 0x80
str r1, [r0, #OTHERS_OFFSET]
check_syncack:
ldr r1, [r0, #OTHERS_OFFSET] // r0 + 0x900번지 로딩
ldr r2, =0xf00 // r2 = 0xf00, SYNCACK 레지스터 (6410 데이터시트 3-50 참고)
and r1, r1, r2 // r1 = r1 & r2
cmp r1, #0xf00 // r1이 0xf00인지 체크, SYNC 모드가 설정되었는지 확인
bne check_syncack // r1이 0xf00이 아니면 check_syncack로 이동
#else /* ASYNC Mode */
nop
nop
nop
nop
nop
ldr r1, [r0, #OTHERS_OFFSET] // OTHERS 레지스터의 옵셋은 0x900
bic r1, r1, #0xC0 // 0xC0 = 1100_0000 6, 7번째 비트 클리어, Async모드로 설정, 클럭소스는 MPLL을 사용(s3c6410 데이터시트, 3-50 참조)
orr r1, r1, #0x40 // 0x40 = 0100_0000, 6번째 비트(SYNCMUXSEL) 세팅, 클럭소스를 APLL사용
str r1, [r0, #OTHERS_OFFSET] // r1레지스터의 내용을 (r0 + 0x900) 번지에 저장
wait_for_async:
ldr r1, [r0, #OTHERS_OFFSET] // 0x7E00_F900 + 0x900 번지 로딩
and r1, r1, #0xf00
cmp r1, #0x0 // r1이 0x0인지 확인
bne wait_for_async // r1이 0x0이 아니면 wait_for_sync로 이동
ldr r1, [r0, #OTHERS_OFFSET]
bic r1, r1, #0x40 // 0x40 = 0100_0000, 6번째 비트 클리어, 즉 클럭소스는 MPLL을 사용
str r1, [r0, #OTHERS_OFFSET]
#endif
mov r1, #0xff00
orr r1, r1, #0xff
str r1, [r0, #APLL_LOCK_OFFSET] // APLL_LOCK_OFFSET = 0x00
str r1, [r0, #MPLL_LOCK_OFFSET] // MPLL_LOCK_OFFSET = 0x04
str r1, [r0, #EPLL_LOCK_OFFSET] // EPLL_LOCK_OFFSET = 0x08
/* CLKUART(=66.5Mhz) = CLKUART_input(532/2=266Mhz) / (UART_RATIO(3)+1) */
/* CLKUART(=50Mhz) = CLKUART_input(400/2=200Mhz) / (UART_RATIO(3)+1) */
/* Now, When you use UART CLK SRC by EXT_UCLK1, We support 532MHz & 400MHz value */
#if defined(CONFIG_CLKSRC_CLKUART)
ldr r1, [r0, #CLK_DIV2_OFFSET] // r1 레지스터에 (r0 + 0x28 = 0x7E00_F028) 번지 로딩
bic r1, r1, #0x70000 // 특정비트 클리어, 0xF0000로 해줘야 맞다. UART_RATIO [19:16] 비트 클리어, 6410 데이터시트 3-29참조
orr r1, r1, #0x30000 // UART_RATIO = 3으로 설정
str r1, [r0, #CLK_DIV2_OFFSET]
#endif
ldr r1, [r0, #CLK_DIV0_OFFSET] /*Set Clock Divider*/ // r1레지스터에 (r0 + 0x20 = 0x7E00_0029)번지 로딩
bic r1, r1, #0x30000 // [17:16] 비트 클리어 데이터시트에는 RESERVED 영역이라고 되어 있어 손댈 수 없는 곳인데..
bic r1, r1, #0xff00 // [15:8] 비트 클리어, PCLK, HCLK2, HCLK 클럭 설정위해 값을 초기화
bic r1, r1, #0xff // [7:0] 비트 클리어, MPLL, APLL 클럭 분주값을 초기화
ldr r2, =CLK_DIV_VAL // include/Configs/Aesop6410.h에 정의되어 있음, 이 값을 가지고 클럭분주 설정(CLK_DIV0)
orr r1, r1, r2
str r1, [r0, #CLK_DIV0_OFFSET]
ldr r1, =APLL_VAL // include/Configs/Aesop6410.h에 정의, 12MHz 크리스탈에서 666MHz 클럭을 만들어 낸다.
str r1, [r0, #APLL_CON_OFFSET] // r1레지스터 내용을 (0x7E00_F000 + 0x0C)번지에 저장
ldr r1, =MPLL_VAL // include/Configs/Aesop6410.h에 정의, 12MHz 크리스탈에서 533MHz 클럭 생성
str r1, [r0, #MPLL_CON_OFFSET]
ldr r1, =0x80200203 /* FOUT of EPLL is 96MHz */ // s3c6410 데이터시트 3-24 참조
// [1]000 0000 [0010 0000]_00[00 0010] 0000 0[011]
// MDIV(0x20) PDIV(0x2) SDIV(0x3)
str r1, [r0, #EPLL_CON0_OFFSET] // r1레지스터 값을 (0x7E00_F000 + 0x14) 번지에 저장
ldr r1, =0x0 // r1 레지스터에 0x0 저장
str r1, [r0, #EPLL_CON1_OFFSET] // r1값 0x0을 (0x7E00_F000 + 0x18)번지에 저장
// EPLL 클럭 = (MDIV + KDIV / 2^16) * Fin / (PDIV x 2^SDIV ) // s3c6410 데이터시트 3-24 참조
// = (0x20 + 0 / 2^16) * 12MHz / (0x2 x 2^3 )
// = 24MHz
ldr r1, [r0, #CLK_SRC_OFFSET] /* APLL, MPLL, EPLL select to Fout */ // (0x7E00_F000 + 0x1C)번지에 있는 값을 r1에 저장
#if defined(CONFIG_CLKSRC_CLKUART)
ldr r2, =0x2007 // 0010 0000 0000 0111 s3c6410 데이터시트 3-26 참조
// EPLL_SEL, MPLL_SEL, APLL_SEL = 1 이므로 클럭소스는 PLL통하여 분주한다.
// 0 이면 12MHz로 입력받는다.
// UART 클럭소스는 MPLL을 통해 받는다.
#else
ldr r2, =0x7 // 0000 0000 0000 0111
// EPLL_SEL, MPLL_SEL, APLL_SEL = 0 이므로 12MHz로 입력받는다.
#endif
orr r1, r1, r2
str r1, [r0, #CLK_SRC_OFFSET]
/* wait at least 200us to stablize all clock */
mov r1, #0x10000
1: subs r1, r1, #1 // r1 = r1 - 1
bne 1b // r1이 0이 아니면 loop, 딜레이를 설정하기 위해 사용한다.
#if 0
mrc p15, 0, r0, c1, c0, 0
orr r0, r0, #0xc0000000 /* clock setting in MMU */
mcr p15, 0, r0, c1, c0, 0
#endif
#ifdef CONFIG_SYNC_MODE /* Synchronization for VIC port */
ldr r1, [r0, #OTHERS_OFFSET] // 0x7E00_F000 + 0x900
orr r1, r1, #0x20 // a3c6410 datasheet 3-51에는 RESERVED라고 나와 있어서 변경할 수 없는 부분인데..
str r1, [r0, #OTHERS_OFFSET]
#else
ldr r1, [r0, #OTHERS_OFFSET]
bic r1, r1, #0x20 // 여기도 마찬가지로 RESERVED 영역이라 비트를 변경하면 안되는 부분이다.
str r1, [r0, #OTHERS_OFFSET]
#endif
mov pc, lr
/*
* uart_asm_init: Initialize UART in asm mode, 115200bps fixed.
* void uart_asm_init(void)
*/
uart_asm_init:
/* set GPIO to enable UART */
@ GPIO setting for UART
ldr r0, =ELFIN_GPIO_BASE // 0x7f008000, GPACON 레지스터, s3c6410 datasheet 10-7 참조
ldr r1, =0x220022 // UART 설정
// 0000 0000 0010 0010 0000 0000 0010 0010
// input input UART_TXD[1] UART_RXD[1] input input UART_TXD[0] UART_RXD[0]
str r1, [r0, #GPACON_OFFSET] // (0x7F00_8000 + 0x00)번지에 0x220022 저장
ldr r0, =ELFIN_UART_CONSOLE_BASE @0x7F005000
mov r1, #0x0
str r1, [r0, #UFCON_OFFSET] // 0x08
str r1, [r0, #UMCON_OFFSET] // 0x0C
mov r1, #0x3 @was 0.
str r1, [r0, #ULCON_OFFSET] // (7F00_5000 + 0x00)번지에 0x3 저장
// ULCON0 레지스터 [1:0] Word Length 비트세팅, 전송 또는 수신 데이터 비트를 8bit로 설정
#if defined(CONFIG_CLKSRC_CLKUART)
ldr r1, =0xe45 /* UARTCLK SRC = 11 => EXT_UCLK1*/
// 1110 0100 0101
// clock selection = EXT_UCLK1
#else
ldr r1, =0x245 /* UARTCLK SRC = x0 => PCLK */
// 0010 0100 0101
// cloeck selection = PCLK
#endif
str r1, [r0, #UCON_OFFSET] // (0x7F00_5000 + 0x04)번지에 r1 값 저장, s3c6410 datasheet 31-13 참조
#if defined(CONFIG_UART_50)
ldr r1, =0x1A //
#elif defined(CONFIG_UART_66)
ldr r1, =0x22
#else
ldr r1, =0x1A
#endif
str r1, [r0, #UBRDIV_OFFSET] // (0x7F00_5000 + 0x28), s3c6410 31-23 참조
#if defined(CONFIG_UART_50)
ldr r1, =0x3
#elif defined(CONFIG_UART_66)
ldr r1, =0x1FFF
#else
ldr r1, =0x3
#endif
str r1, [r0, #UDIVSLOT_OFFSET] // 0x7F00_5000 + 0x2C
ldr r1, =0x4f4f4f4f
str r1, [r0, #UTXH_OFFSET] @'O' // (0x7F00_5000 + 0x20), UTXH (UART Transmitting buffer register)에 문자 'O' 저장
mov pc, lr // lr(r14: Link 레지스터)의 값을 pc(프로그램 카운터)에 저장
/*
* Nand Interface Init for SMDK6400 */
nand_asm_init:
ldr r0, =ELFIN_NAND_BASE // 0x7020_0000
ldr r1, [r0, #NFCONF_OFFSET] // (0x7020_0000 + 0x00)번지 로딩
orr r1, r1, #0x70 // 0[111]_0000, TWRPH1 = 7로 설정
orr r1, r1, #0x7700 // 0[111]_0[111]_0000_0000, TACLS와 TWRPH0값을 7로 설정
str r1, [r0, #NFCONF_OFFSET]
ldr r1, [r0, #NFCONT_OFFSET] // 0x7200_0000 + 0x04
orr r1, r1, #0x03 // 0000_00[11], 낸드플래시 콘트롤러를 활성화하고 칩실렉트는 비활성화 한다.
str r1, [r0, #NFCONT_OFFSET]
mov pc, lr
#ifdef CONFIG_ENABLE_MMU
/*
* MMU Table for SMDK6400
*/
/* form a first-level section entry */
.macro FL_SECTION_ENTRY base,ap,d,c,b
.word (base << 20) | (ap << 10) |
(d << 5) | (1<<4) | (c << 3) | (b << 2) | (1<<1)
.endm
.section .mmudata, "a"
.align 14
// the following alignment creates the mmu table at address 0x4000.
.globl mmu_table
mmu_table:
.set __base,0
// 1:1 mapping for debugging
.rept 0xA00
FL_SECTION_ENTRY __base,3,0,0,0
.set __base,__base+1
.endr
// access is not allowed.
.rept 0xC00 - 0xA00
.word 0x00000000
.endr
// 128MB for SDRAM 0xC0000000 -> 0x50000000
.set __base, 0x500
.rept 0xC80 - 0xC00
FL_SECTION_ENTRY __base,3,0,1,1
.set __base,__base+1
.endr
// access is not allowed.
.rept 0x1000 - 0xc80
.word 0x00000000
.endr
#endif