# Runtime support

# Configurable parameters

	# Set PLL ratios - M=4, P=2, 58.9824 MHz clock
	.equ	PLL_M,		4
	.equ	PLL_P,		2

	.equ	FLASHCLOCKS,	3 /* 40-60MHz clock */
	.equ	APB_DIVIDER,	4 /* 1, 2 or 4 */

	.equ	UND_STACK_SIZE,	0x0004
	.equ	SVC_STACK_SIZE,	0x0010
	.equ	ABT_STACK_SIZE,	0x0004
	.equ	FIQ_STACK_SIZE,	0x0004
	.equ	IRQ_STACK_SIZE,	0x0080
	.equ	USR_STACK_SIZE,	0x0400


.global _stack_size

	.equ	_stack_size,  0
	.equ	_stack_size, _stack_size + UND_STACK_SIZE
	.equ	_stack_size, _stack_size + SVC_STACK_SIZE
	.equ	_stack_size, _stack_size + ABT_STACK_SIZE
	.equ	_stack_size, _stack_size + FIQ_STACK_SIZE
	.equ	_stack_size, _stack_size + IRQ_STACK_SIZE
	.equ	_stack_size, _stack_size + USR_STACK_SIZE


# Processor definitions

	.equ    Mode_USR,       0x10
	.equ    Mode_FIQ,       0x11
	.equ    Mode_IRQ,       0x12
	.equ    Mode_SVC,       0x13
	.equ    Mode_ABT,       0x17
	.equ    Mode_UND,       0x1b
	.equ    Mode_SYS,       0x1f

	.equ    I_Bit,          0x80
	.equ    F_Bit,          0x40

# Register definitions

	.equ    MAM_BASE,	0xE01FC000
	.equ	MAMCR,		0
	.equ	MAMTIM,		4

	.equ	PLL_BASE,	0xE01FC080
	.equ	PLLCON,		0x00
	.equ	PLLCFG,		0x04
	.equ	PLLSTAT,	0x08
	.equ	PLLFEED,	0x0c

        .equ	PLLCON_PLLE,	(1<<0)
	.equ	PLLCON_PLLC,	(1<<1)
	.equ	PLLCFG_MSEL,	(0x1F<<0)
	.equ	PLLCFG_PSEL,	(0x03<<5)
	.equ	PLLSTAT_PLOCK,	(1<<10)

	.equ	APBDIV_BASE,	0xE01FC100
	.equ	APBDIV,		0

	# True is -1 so we subtract values together.
	.equ	PLL_LOG_P,	(0-(PLL_P>1)-(PLL_P>2)-(PLL_P>4))
	.equ	PLLCFG_VAL,	(PLL_M-1) | (PLL_LOG_P << 5)

	# 1 => 1, 2 => 2, 4 => 0
	.equ	APB_VAL,	(APB_DIVIDER & 3)

.text
.global	_startup
.func	_startup
_startup:

vectors:
	b	reset_handler
	b	undefined_handler
	b	swi_handler
	b	prefetch_abort_handler
	b	data_abort_handler
	nop	/* reserved */
	ldr	pc, [pc, #-0xff0] /* branch through VICVectAddr register */
	b	fiq_handler


reset_handler:

# MAM and PLL setup
	ldr	r1, =MAM_BASE
	ldr	r2, =PLL_BASE
	mov     r3, #0xAA
	mov     r4, #0x55


# Configure and Enable PLL
	mov     r0, #PLLCFG_VAL
	str     r0, [r2, #PLLCFG]
	mov     r0, #PLLCON_PLLE
	str     r0, [r2, #PLLCON]
	str     r3, [r2, #PLLFEED]
	str     r4, [r2, #PLLFEED]

# Disable MAM until we turn on the PLL
	mov	r0, #0		/* MAM disabled */
	str	r0, [r1, #MAMCR]

# Wait until PLL Locked
lockwait:
	ldr	r0, [r2, #PLLSTAT]
	ands	r0, r0, #PLLSTAT_PLOCK
	beq     lockwait

# Switch to PLL Clock
	mov     r0, #(PLLCON_PLLE | PLLCON_PLLC)
	str     r0, [r2, #PLLCON]
	str     r3, [r2, #PLLFEED]
	str     r4, [r2, #PLLFEED]

# Enable MAM and set up flash timing
	mov	r0, #FLASHCLOCKS
	str	r0, [r1, #MAMTIM]
	mov	r0, #2		/* MAM fully enabled */
	str	r0, [r1, #MAMCR]

# Set APB divider
	ldr	r1, =APBDIV_BASE
	mov	r0, #APB_DIVIDER
	str	r0, [r1, #APBDIV]

# Relocate .data section (Copy from ROM to RAM)
	ldr     r1, =_etext
	ldr     r2, =_data
	ldr     r3, =_edata
lrel:
	cmp     r2, r3
	ldrlo   r0, [r1], #4
	strlo   r0, [r2], #4
	blo     lrel

# Clear .bss section (Zero init)
	mov     r0, #0
	ldr     r1, =_bss_start
	ldr     r2, =_bss_end
lzi:
	cmp     r1, r2
	strlo   r0, [r1], #4
	blo     lzi

# Set up stacks
	ldr	r0, =_stack_end

	msr	CPSR_c, #Mode_UND|I_Bit|F_Bit
	mov	sp, r0
	sub	r0, r0, #UND_STACK_SIZE

	msr	CPSR_c, #Mode_ABT|I_Bit|F_Bit
	mov	sp, r0
	sub	r0, r0, #ABT_STACK_SIZE

	msr	CPSR_c, #Mode_FIQ|I_Bit|F_Bit
	mov	sp, r0
	sub	r0, r0, #FIQ_STACK_SIZE

	msr	CPSR_c, #Mode_IRQ|I_Bit|F_Bit
	mov	sp, r0
	sub	r0, r0, #IRQ_STACK_SIZE

	msr	CPSR_c, #Mode_SVC|I_Bit|F_Bit
	mov	sp, r0
	sub	r0, r0, #SVC_STACK_SIZE

	msr	CPSR_c, #Mode_USR
	mov	sp, r0

# Stack Limit (only when compiled with "-mapcs-stack-check")
	sub	sl, sp, #USR_STACK_SIZE


# Prepare to go!
	mov	r0, #0
	mov	r1, #0
	adr	lr, __back
	b	main

# Undefined handlers can just spin for now
undefined_handler:
prefetch_abort_handler:
data_abort_handler:
fiq_handler:

__back:
	b	__back


	.equ	SWI_MAX, 1

swi_handler:
	stmfd	sp!, {ip, lr}
	ldr	ip, [lr, #-4]
	bic	ip, #0xff000000

	cmp	ip, #SWI_MAX
	ldmhifd	sp!, {ip, pc}^

	add	ip, pc, ip, lsl #2
	ldr	pc, [ip]

swi_branch_table:
	.word	disable_interrupts
	.word	enable_interrupts


disable_interrupts:
	mrs	ip, SPSR
	orr	ip, ip, #I_Bit
	msr	SPSR_c,ip
	ldmfd	sp!, {ip, pc}^

enable_interrupts:
	mrs	ip, SPSR
	bic	ip, ip, #I_Bit
	msr	SPSR_c,ip
	ldmfd	sp!, {ip, pc}^


.endfunc
.end
