포럼 회원으로 등록하신분만 다운로드가 가능합니다. 최대 업로드 가능한 용량은 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 (J.A.K.Mouw@its.tudelft.nl) and
 *                     Jan-Derk Bakker (J.D.Bakker@its.tudelft.nl)
 *
 * Modified for the Samsung SMDK2410 by
 * (C) Copyright 2002
 * David Mueller, ELSOFT AG, <d.mueller@elsoft.ch>
 *
 * 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

 


최강산

2009.06.17 01:32:21
*.131.74.195

수고하셨습니다.

다이옥신

2011.06.29 19:43:15
*.94.41.89

잘 보겠습니다.

List of Articles
번호 제목 글쓴이 날짜 조회 수
» lowlevel_init.S 분석자료(aesop6410) [2] 이세종 2009-05-10 11858
29 리눅스 커널 소스 기본 구조 이세종 2009-05-06 15182
28 Hotplugging with udev file 고현철 2009-05-05 14316
27 FATAL: kernel too oldKernel panic - not syncing: Attempt... 고현철 2009-04-28 11856
26 GStreamer on TI DaVinci and OMAP 장석원 2009-04-25 10923
25 Creating a Root File System for Linux on OMAP35x 장석원 2009-04-24 10094
24 start.S 분석(aesop6410) [1] 이세종 2009-04-14 13998
23 u-boot.lds 분석(aesop6410) 이세종 2009-04-13 16138
22 u-boot - config.mk 분석(aesop6410) [3] 이세종 2009-04-09 13116
21 u-boot source tree 구조(aesop-6410) [3] 이세종 2009-04-09 12115
20 mdev and udev 사용 방법 및 적용 가이드 file 김재훈 2009-04-06 16076
19 고현철님의 리눅스 Root File System 만들기 동영상 실습 김재훈 2009-04-05 12645
18 고현철님의 리눅스 Root File System 만들기 동영상 강좌 [2] 김재훈 2009-04-05 15523
17 linux kernel의 ethernet(MAC) address를 자동 지정해 주는 방법 [1] 고현철 2009-03-05 11206
16 embedded linux porting guide(ppcboot & mpc860) file [4] 고현철 2007-12-17 15924
15 uBuntu 8.10에서 Crosstool 0.43 사용 방법 [2] 김재훈 2009-02-18 10766
14 kernel 2.6(S3C64XX)용 kernel image구조 고현철 2009-02-16 10980
13 리눅스 루트 파일 시스템 기본 구조 및 스펙 문서 file [3] 김재훈 2009-02-12 14377
12 2.6.28 kernel에서 sk_buff에서 mac header를 가져오고 찍는 방법 [1] 고현철 2009-02-10 10853
11 Windows CE에서 NK.bin에 포함된 모듈 확인 하는 방법 file [1] 김재훈 2009-02-04 11018

사용자 로그인