;/*****************************************************************************/
;/* S3C2440.S: Startup file for Samsung S3C440                                */
;/*****************************************************************************/
;/* <<< Use Configuration Wizard in Context Menu >>>                          */
;/*****************************************************************************/
;/* This file is part of the uVision/ARM development tools.                   */
;/* Copyright (c) 2005-2008 Keil Software. All rights reserved.               */
;/* This software may only be used under the terms of a valid, current,       */
;/* end user licence from KEIL for a compatible version of KEIL software      */
;/* development tools. Nothing else gives you the right to use this software. */
;/*****************************************************************************/


;/*
; *  The S3C2440.S code is executed after CPU Reset. This file may be
; *  translated with the following SET symbols. In uVision these SET
; *  symbols are entered under Options - ASM - Define.
; *
; *  NO_CLOCK_SETUP: when set the startup code will not initialize Clock
; *  (used mostly when clock is aLReady initialized from script .ini
; *  file).
; *
; *  NO_MC_SETUP: when set the startup code will not initialize Memory
; *  Controller (used mostly when clock is aLReady initialized from script
; *  .ini file).
; *
; *  NO_GP_SETUP: when set the startup code will not initialize General Ports
; *  (used mostly when clock is aLReady initialized from script .ini
; *  file).
; *
; *  RAM_INTVEC: when set the startup code copies exception vectors
; *  from execution address to on-chip RAM.
; */

;/*
; * File      : start_rvds.s
; * This file is part of RT-Thread RTOS
; * COPYRIGHT (C) 2006, RT-Thread Development Team
; *
; * The license and diSTRibution terms for this file may be
; * found in the file LICENSE in this diSTRibution or at
; * http://openlab.rt-thread.com/license/LICENSE
; *
; * Change Logs:
; * Date           Author       Notes
; * 2010-01-12     Gary Lee     Change the STRucture of the code, 
;				the configuration file's name is config.inc
; * 2010-01-22	   Gary Lee	Add interrupt config for startup 2440
; * 2010-01-23	   Gary Lee	Add copy myself for startup from nand
; */
		

;  Area Definition and Entry Point
;  Startup Code must be linked first at Address at which it expects to run.
;  Exception Vectors
;  Mapped to Address 0.
;  Absolute addressing mode must be used.
;  Dummy Handlers are implemented as infinite loops which can be modified.

                GET	config.inc

		PRESERVE8


                AREA    RESET, CODE, READONLY
                ARM

		EXPORT Entry_Point
Entry_Point
Vectors         LDR     PC, Reset_Addr
                LDR     PC, Undef_Addr
                LDR     PC, SWI_Addr
                LDR     PC, PAbt_Addr
                LDR     PC, DAbt_Addr
		NOP
                LDR     PC, IRQ_Addr
                LDR     PC, FIQ_Addr

Reset_Addr      DCD     Reset_Handler
Undef_Addr      DCD     Undef_Handler
SWI_Addr        DCD     SWI_Handler
PAbt_Addr       DCD     PAbt_Handler
DAbt_Addr       DCD     DAbt_Handler
                DCD     0                   ; Reserved Address
IRQ_Addr        DCD     IRQ_Handler
FIQ_Addr        DCD     FIQ_Handler

Undef_Handler   B       Undef_Handler
SWI_Handler     B       SWI_Handler
PAbt_Handler    B       PAbt_Handler
DAbt_Handler    B       DAbt_Handler
FIQ_Handler     B       FIQ_Handler

;=========================================================================
; Reset Handler

                EXPORT  Reset_Handler
Reset_Handler

		BL	WatchDog_Config		;  shutdown watchdog
		BL	Interrupt_Config	;  shutdown interrupt
        BL	SysClock_Config		;  setup system clock, default value is 400MHz
        BL	SDRAM_Config		;  setup sdram clock, default value is 100MHz
		;BL	Copymyself_Config	;  copy myself from 0x1000 with size of 1MB to sdram address of 0x30000000
		BL	GPIO_Config			;  setup gpio	
		BL	RAM_INTVEC_Config	;  install interrupt handler to sdram
		BL	Stack_Config		;  setup stack for every mode

								;  a technology about trampoline
		LDR	R1, =ON_THE_RAM
		ADD	PC, R1, #0
		NOP
		NOP
1
		B	%B1

ON_THE_RAM
								; setup by APCS
		MOV	FP, #0				; no previous frame, so fp=0
		MOV	a2, #0				; set argv to NULL
		
		IMPORT  __main
		BL	__main				; call main
		MOV	R0, #FLASH_BASE_ADDR 
		MOV	PC, R0				; otherwise, reboot

;=========================================================================
                IMPORT rt_interrupt_enter
                IMPORT rt_interrupt_leave
                IMPORT rt_thread_switch_interrput_flag
                IMPORT rt_interrupt_from_thread
                IMPORT rt_interrupt_to_thread
                IMPORT rt_hw_trap_irq
				IMPORT nand_read_ll

IRQ_Handler     PROC

                EXPORT IRQ_Handler
                STMFD   SP!, {R0-R12,LR}
                BL  rt_interrupt_enter
                BL  rt_hw_trap_irq
                BL  rt_interrupt_leave

                LDR R0, =rt_thread_switch_interrput_flag
                LDR R1, [R0]
                CMP R1, #1
                BEQ rt_hw_context_switch_interrupt_do

                LDMFD   SP!, {R0-R12,LR}
                SUBS    PC, LR, #4
                ENDP

rt_hw_context_switch_interrupt_do   PROC

                EXPORT rt_hw_context_switch_interrupt_do
                MOV     R1,  #0         ; clear flag
                STR     R1,  [R0]

                LDMFD   SP!, {R0-R12,LR}; reload saved registers
                STMFD   SP!, {R0-R3}    ; save R0-R3
                MOV     R1,  SP
                ADD     SP,  SP, #16    ; restore SP
                SUB     R2,  LR, #4     ; save old task's PC to R2

                MRS     R3,  SPSR       ; get cpsr of interrupt thread

                ; switch to SVC mode and no interrupt
                MSR     cpsr_c, #I_Bit|F_Bit|Mode_SVC

                STMFD   SP!, {R2}       ; push old task's PC
                STMFD   SP!, {r4-R12,LR}; push old task's LR,R12-r4
                MOV     r4,  R1         ; SPecial optimised code below
                MOV     r5,  R3
                LDMFD   r4!, {R0-R3}
                STMFD   SP!, {R0-R3}    ; push old task's R3-R0
                STMFD   SP!, {r5}       ; push old task's cpsr
                MRS     r4,  SPSR
                STMFD   SP!, {r4}       ; push old task's SPsr

                LDR     r4,  =rt_interrupt_from_thread
                LDR     r5,  [r4]
                STR     SP,  [r5]       ; store SP in preempted tasks's TCB

                LDR     r6,  =rt_interrupt_to_thread
                LDR     r6,  [r6]
                LDR     SP,  [r6]       ; get new task's stack pointer

                LDMFD   SP!, {r4}       ; pop new task's SPsr
                MSR     SPSR_cxsf, r4
                LDMFD   SP!, {r4}       ; pop new task's psr
                MSR     cpsr_cxsf, r4

                LDMFD   SP!, {R0-R12,LR} ; pop new task's R0-R12,LR & PC
				LDMFD	SP!, {PC}

                ENDP

; Use microlib
                IF      :DEF:__MICROLIB

                EXPORT  __heap_base
                EXPORT  __heap_limit

                ELSE

; User Initial Stack & Heap
                AREA    |.text|, CODE, READONLY

                IMPORT  __use_two_region_memory
                EXPORT  __user_initial_stackheap
__user_initial_stackheap

                LDR     R0, =  Heap_Mem
                LDR     R1, =(Stack_Mem + USR_Stack_Size)
                LDR     R2, = (Heap_Mem +      Heap_Size)
                LDR     R3, = Stack_Mem
                BX      LR
                ENDIF

;=========================================================================
; Subroutines 
WatchDog_Config	PROC
		IF      WT_SETUP != 0
                LDR     R0, =WT_BASE
                LDR     R1, =WTCON_Val
                LDR     R2, =WTDAT_Val
                STR     R2, [R0, #WTCNT_OFS]
                STR     R2, [R0, #WTDAT_OFS]
                STR     R1, [R0, #WTCON_OFS]
                ENDIF
		
		BX	LR
		ENDP

Interrupt_Config PROC

				LDR		R0,=INTMSK
				LDR		R1,=0xffffffff			;/*all interrupt disable关闭所有中断	*/
				STR		R1,[R0]

				LDR		R0,=INTSUBMSK
				LDR		R1,=0x7fff			;/*all sub interrupt disable关闭子中断	*/
				STR		R1,[R0]
		
				BX		LR
		ENDP
		

SysClock_Config	PROC
		IF      (:LNOT:(:DEF:NO_CLOCK_SETUP)):LAND:(CLOCK_SETUP != 0)
                LDR     R0, =CLOCK_BASE
                LDR     R1,      =LOCKTIME_Val
                STR     R1, [R0, #LOCKTIME_OFS]
                MOV     R1,      #CLKDIVN_Val
                STR     R1, [R0, #CLKDIVN_OFS]
                LDR     R1,      =CAMDIVN_Val
                STR     R1, [R0, #CAMDIVN_OFS]
                LDR     R1,      =MPLLCON_Val
                STR     R1, [R0, #MPLLCON_OFS]
                LDR     R1,      =UPLLCON_Val
                STR     R1, [R0, #UPLLCON_OFS]
                MOV     R1,      #CLKSLOW_Val
                STR     R1, [R0, #CLKSLOW_OFS]
                LDR     R1,      =CLKCON_Val
                STR     R1, [R0, #CLKCON_OFS]
                ENDIF
		
		BX	LR
		ENDP

Copymyself_Config PROC
						
				MOV		R1, #NAND_CTL_BASE				; inital       NAND初始化
				LDR		R2, =((7<<12)|(7<<8)|(7<<4)|(0<<0))	; initial value
				STR		R2, [R1, #oNFCONF]

				; reset nand flash						; 复位NAND
				LDR		R2, [R1, #oNFCONF]
				LDR		R2, =((1<<4)|(0<<1)|(1<<0))		; nFCE active
				STR		R2, [R1, #oNFCONT]
				LDR		R2, [R1, #oNFCONT]

				LDR		R2, =(0x6)						; RnB Clear
				STR		R2, [R1, #oNFSTAT]
				LDR		R2, [R1, #oNFSTAT]
				MOV		R2, #0xff						; reset command
				STRB	R2, [R1, #oNFCMD]

								; 延时
				MOV		R3, #0x0A
1
				SUBS	R3, R3, #1
				BNE		%B1

								; wait idle state 就绪	
2
				LDR		R2, [R1, #oNFSTAT]
				TST		R2, #0x04
				BEQ		%B2

				LDR		R2, [R1, #oNFCONF]
				ORR		R2, R2, #0x2					; nFCE inactive
				STR		R2, [R1, #oNFCONF]	

				LDR		SP, =4096						; nand_read.c needed
				LDR		R0, =0x30000000					; nand_read_ll argument 1  buffer addr
				MOV		R1, #4096						; nand_read_ll argument 2  start addr
				MOV		R2, #0x100000					; nand_read_ll argument 3  copy size
														; 1MB enough for this example
				BL		nand_read_ll

				BX		LR
		ENDP


SDRAM_Config	PROC
                IF      (:LNOT:(:DEF:NO_MC_SETUP)):LAND:(CLOCK_SETUP != 0)
                LDR     R0, =MC_BASE
                LDR     R1,      =BWSCON_Val
                STR     R1, [R0, #BWSCON_OFS]
                LDR     R1,      =BANKCON0_Val
                STR     R1, [R0, #BANKCON0_OFS]
                LDR     R1,      =BANKCON1_Val
                STR     R1, [R0, #BANKCON1_OFS]
                LDR     R1,      =BANKCON2_Val
                STR     R1, [R0, #BANKCON2_OFS]
                LDR     R1,      =BANKCON3_Val
                STR     R1, [R0, #BANKCON3_OFS]
                LDR     R1,      =BANKCON4_Val
                STR     R1, [R0, #BANKCON4_OFS]
                LDR     R1,      =BANKCON5_Val
                STR     R1, [R0, #BANKCON5_OFS]
                LDR     R1,      =BANKCON6_Val
                STR     R1, [R0, #BANKCON6_OFS]
                LDR     R1,      =BANKCON7_Val
                STR     R1, [R0, #BANKCON7_OFS]
                LDR     R1,      =REFRESH_Val
                STR     R1, [R0, #REFRESH_OFS]
                MOV     R1,      #BANKSIZE_Val
                STR     R1, [R0, #BANKSIZE_OFS]
                MOV     R1,      #MRSRB6_Val
                STR     R1, [R0, #MRSRB6_OFS]
                MOV     R1,      #MRSRB7_Val
                STR     R1, [R0, #MRSRB7_OFS]
                ENDIF
		
		BX	LR
		ENDP

GPIO_Config	PROC

		IF      (:LNOT:(:DEF:NO_GP_SETUP)):LAND:(GP_SETUP != 0)

                IF      GPA_SETUP != 0
                LDR     R0, =GPA_BASE
                LDR     R1, =GPACON_Val
                STR     R1, [R0, #GPCON_OFS]
                ENDIF

                IF      GPB_SETUP != 0
                LDR     R0, =GPB_BASE
                LDR     R1, =GPBCON_Val
                STR     R1, [R0, #GPCON_OFS]
                LDR     R1, =GPBUP_Val
                STR     R1, [R0, #GPUP_OFS]
                ENDIF

                IF      GPC_SETUP != 0
                LDR     R0, =GPC_BASE
                LDR     R1, =GPCCON_Val
                STR     R1, [R0, #GPCON_OFS]
                LDR     R1, =GPCUP_Val
                STR     R1, [R0, #GPUP_OFS]
                ENDIF

                IF      GPD_SETUP != 0
                LDR     R0, =GPD_BASE
                LDR     R1, =GPDCON_Val
                STR     R1, [R0, #GPCON_OFS]
                LDR     R1, =GPDUP_Val
                STR     R1, [R0, #GPUP_OFS]
                ENDIF

                IF      GPE_SETUP != 0
                LDR     R0, =GPE_BASE
                LDR     R1, =GPECON_Val
                STR     R1, [R0, #GPCON_OFS]
                LDR     R1, =GPEUP_Val
                STR     R1, [R0, #GPUP_OFS]
                ENDIF

                IF      GPF_SETUP != 0
                LDR     R0, =GPF_BASE
                LDR     R1, =GPFCON_Val
                STR     R1, [R0, #GPCON_OFS]
                LDR     R1, =GPFUP_Val
                STR     R1, [R0, #GPUP_OFS]
                ENDIF

                IF      GPG_SETUP != 0
                LDR     R0, =GPG_BASE
                LDR     R1, =GPGCON_Val
                STR     R1, [R0, #GPCON_OFS]
                LDR     R1, =GPGUP_Val
                STR     R1, [R0, #GPUP_OFS]
                ENDIF

                IF      GPH_SETUP != 0
                LDR     R0, =GPH_BASE
                LDR     R1, =GPHCON_Val
                STR     R1, [R0, #GPCON_OFS]
                LDR     R1, =GPHUP_Val
                STR     R1, [R0, #GPUP_OFS]
                ENDIF

                IF      GPJ_SETUP != 0
                LDR     R0, =GPJ_BASE
                LDR     R1, =GPJCON_Val
                STR     R1, [R0, #GPCON_OFS]
                LDR     R1, =GPJUP_Val
                STR     R1, [R0, #GPUP_OFS]
                ENDIF

                ENDIF
		
		BX	LR
		ENDP

RAM_INTVEC_Config	PROC		
		IF      :DEF:RAM_INTVEC
                ADR     R8,  Vectors    ; Source
                LDR     R9, =IRAM_BASE  ; Destination
                LDMIA   R8!, {R0-R7}    ; Load Vectors
                STMIA   R9!, {R0-R7}    ; Store Vectors
                LDMIA   R8!, {R0-R7}    ; Load Handler Addresses
                STMIA   R9!, {R0-R7}    ; Store Handler Addresses
                ENDIF
		
		BX	LR
		ENDP

Stack_Config	PROC
		LDR     R0, =Stack_Top

                MSR     CPSR_c, #Mode_UND:OR:I_Bit:OR:F_Bit
                MOV     SP, R0
                SUB     R0, R0, #UND_Stack_Size

                MSR     CPSR_c, #Mode_ABT:OR:I_Bit:OR:F_Bit
                MOV     SP, R0
                SUB     R0, R0, #ABT_Stack_Size

                MSR     CPSR_c, #Mode_FIQ:OR:I_Bit:OR:F_Bit
                MOV     SP, R0
                SUB     R0, R0, #FIQ_Stack_Size

                MSR     CPSR_c, #Mode_IRQ:OR:I_Bit:OR:F_Bit
                MOV     SP, R0
                SUB     R0, R0, #IRQ_Stack_Size

                MSR     CPSR_c, #Mode_SVC:OR:I_Bit:OR:F_Bit
                MOV     SP, R0
                SUB     R0, R0, #SVC_Stack_Size

                ; MSR     CPSR_c, #Mode_USR
                MOV     SP, R0
                SUB     SL, SP, #USR_Stack_Size
		
		BX	LR
		ENDP

                END
