#ifndef CYGONCE_HAL_PLATFORM_SETUP_H
#define CYGONCE_HAL_PLATFORM_SETUP_H
/*=============================================================================
//
//      hal_platform_setup.h
//
//      Platform specific support for HAL (assembly code)
//
//=============================================================================
// ####ECOSGPLCOPYRIGHTBEGIN####                                            
// -------------------------------------------                              
// This file is part of eCos, the Embedded Configurable Operating System.   
// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
// Copyright (C) 2003, 2004 eCosCentric Limited                             
//
// eCos 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 or (at your option) any later      
// version.                                                                 
//
// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,    
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
//
// As a special exception, if other files instantiate templates or use      
// macros or inline functions from this file, or you compile this file      
// and link it with other works to produce a work based on this file,       
// this file does not by itself cause the resulting work to be covered by   
// the GNU General Public License. However the source code for this file    
// must still be made available in accordance with section (3) of the GNU   
// General Public License v2.                                               
//
// This exception does not invalidate any other reasons why a work based    
// on this file might be covered by the GNU General Public License.         
// -------------------------------------------                              
// ####ECOSGPLCOPYRIGHTEND####                                              
//=============================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s):    eCosCentric
// Contributors: 
// Date:         2003-09-15
// Purpose:      Cogent CSB337 platform specific support routines
// Description: 
// Usage:        #include <cyg/hal/hal_platform_setup.h>
//     Only used by "vectors.S"         
//
//####DESCRIPTIONEND####
//
//===========================================================================*/

#include <pkgconf/system.h>             // System-wide configuration info
#include CYGBLD_HAL_VARIANT_H           // Variant specific configuration
#include CYGBLD_HAL_PLATFORM_H          // Platform specific configuration
#include <cyg/hal/hal_mmu.h>            // MMU definitions
#include <cyg/hal/csb337.h>             // Platform specific hardware definitions


//===========================================================================*/

// This macro represents the initial startup code for the platform        
// Much of it has been adapted from the "hw_init2.c" code provided 
// with the micro-monitor for the CSB337 (as recommended in the CSB337)
// documentation.

        .macro  _platform_setup1

#ifndef CYG_HAL_STARTUP_RAM
//--------------------------------------------------------------------------------
// From "rom_reset.S"
        ldr     r0, =0x2001           // allow access to all coprocessors
        mcr     p15,0,r0,c15,c1,0
        nop
        nop
        nop

        ldr     r0, =0x00000078
        mcr     p15,0,r0,c1,c0,0      // Disable MMU, caches, write buffer 
        nop
        nop
        nop

        ldr     r0, =0x00000000
        mcr     p15,0,r0,c8,c7,0      // flush TLB's 
        mcr     p15,0,r0,c7,c7,0      // flush Caches 
        mcr     p15,0,r0,c7,c10,4     // Flush Write Buffer 
        nop
        nop
        nop

        mvn     r0, #0                // grant manager access to all domains
        mcr     p15,0,r0,c3,c0,0  

//--------------------------------------------------------------------------------
// From "hw_init2.c"

// 	// switch to the slow clock unless we already are
// 	if (PMC_REG(PMC_MCKR)){
// 		// clear PRES first
// 		PMC_REG(PMC_MCKR) = PMC_REG(PMC_MCKR) & ~PMC_MCKR_PRES_MASK;
// 		// then CSS
// 		PMC_REG(PMC_MCKR) = PMC_REG(PMC_MCKR) & ~PMC_MCKR_CSS_MASK;
// 	}
// 	for (i = 0; i < 100; i++){}

            ldr  r1,=_PMC_MCKR
            ldr  r2,[r1]
            cmp  r2,#0
            beq  10f
            bic  r2,r2,#_PMC_MCKR_PRES
            str  r2,[r1]
            bic  r2,r2,#_PMC_MCKR_CSS
            str  r2,[r1]
10:         mov  r1,#100
11:         sub  r1,r1,#1
            cmp  r1,#0
            bne  11b


// 	// turn on the main oscillator and wait 50ms (~400 
// 	// slow clocks).
// 	PMC_REG(PMC_MOR) = PMC_MOR_MOSCEN;
// 	for (i = 0; i < 100; i++){}

            ldr  r1,=_CKGR_MOR
            mov  r2,#_CKGR_MOR_MOSCEN	
            str  r2,[r1]
            mov  r1,#400
20:         sub  r1,r1,#1
            cmp  r1,#0
            bne  20b

// 	// enable PLLA for 184.32Mhz
// 	// 3.6864 Main/2 x 100
// 	PMC_REG(PMC_PLLAR) = 0x20633E02;
// //	PMC_REG(PMC_PLLAR) = PMC_PLLAR_MUST_SET	// bit must be set according to PLLA docs
// //		   			   | PMC_PLLAR_MUL(99)	// actual is MUL + 1
// //		   			   | PMC_PLLAR_DIV(1)	// actual is DIV + 1
// //		   			   | PMC_PLLAR_OUT_150_240;

            ldr  r1,=_CKGR_PLLAR
//??//            ldr  r2,=0x2063BE02
            ldr  r2,=0x20633E02
            str  r2,[r1]	

// 	// wait for PLLA lock bit
// 	for (i = 0; i < 1000; i++){
// 		if (PMC_REG(PMC_SR) & PMC_INT_LCKA) break;
// 	}

            ldr r1,=_PMC_SR
22:         ldr r2,[r1]
            tst r2,#_PMC_IER_LOCKA
            beq 22b

// 	INIT_DBG = d++;

// 	// set CS0 to 8 wait states, 16-bits, 1 clock
// 	// address and strobe delay
// 	SMC_REG(SMC_CSR0) = 0x1100318a;
// //	SMC_REG(SMC_CSR0) = (SMC_CSR_RWHOLD(0)	// 1 clock CS to address delay at end
// //					  | SMC_CSR_RWSETUP(0)	// 1 clock address to CS delay at start
// //					  | SMC_CSR_DBW_16		// 16-Bit width
// //					  | SMC_CSR_BAT_16_1	// Flash is 16-bits, no byte enables
// //					  | SMC_CSR_TDF(0)
// //					  | SMC_CSR_WSEN
// //					  | SMC_CSR_NWS(1));

	ldr r1,=_EBI_SMC2_CSR0
	ldr r2,=0x1100318A
	str r2,[r1]

// 	INIT_DBG = d++;

// 	// first switch MCK to slow clock
// 	PMC_REG(PMC_MCKR) = PMC_MCKR_CSS_SLOW;

        ldr  r1,=_PMC_MCKR
	ldr  r2,=_PMC_MCKR_CSS_SLOW_CLK
	str  r2,[r1]

// 	// wait for MCK ready bit
// 	for (i = 0; i < 100; i++){
// //		if (PMC_REG(PMC_SR) & 0x00000008) break;
// //		if (PMC_REG(PMC_SR) & PMC_INT_MCK_RDY) break;
// 	}

            mov  r1,#100
24:         sub  r1,r1,#1
            cmp  r1,#0
            bne  24b

// 	INIT_DBG = d++;

// 	// set MCK = core/3
// //	PMC_REG(PMC_MCKR) = (PMC_MCKR_CSS_PLLA
// //					  | PMC_MCKR_PRES_1		// Divide by 1
// //					  | PMC_MCKR_MDIV_3);	// MCK = core/3
// 	PMC_REG(PMC_MCKR) = 0x0302;

        ldr  r1,=_PMC_MCKR
//??//	ldr  r2,=0x0202 // 0x0302 is actually core/4
	ldr  r2,=0x0302
	str  r2,[r1]

// 	// wait for MCK ready bit
// 	for (i = 0; i < 1000; i++){
// //		if (PMC_REG(PMC_SR) & 0x00000008) break;
// //		if (PMC_REG(PMC_SR) & PMC_INT_MCK_RDY) break;
// 	}

            mov  r1,#100
26:         sub  r1,r1,#1
            cmp  r1,#0
            bne  26b

// 	INIT_DBG = d++;

// 	// Enable system clocks, PCK0, MCK and core clock
// 	PMC_REG(PMC_SCER) = (PMC_SCR_PCK0		// Peripheral Clock 0
// 					  | PMC_SCR_UHP			// USB Host Port		
// 					  | PMC_SCR_UDP);		// USB Data Port

	ldr r1,=_PMC_SCER
	ldr r2,=(_PMC_SCER_PCK0|_PMC_SCER_UHP|_PMC_SCER_UDP)
        str r2,[r1]

// 	INIT_DBG = d++;

// 	// Enable the clocks to all the on-chip peripherals
// 	PMC_REG(PMC_PCER) = 0x01fffffc;
// 	for (i = 0; i < 1000; i++){}

	ldr r1,=_PMC_PCER
	ldr r2,=0x01FFFFFC;
	str r2,[r1]
            mov  r1,#1000
28:         sub  r1,r1,#1
            cmp  r1,#0
            bne  28b

// 	INIT_DBG = d++;

// 	// set PCK0 to PLLA/4 - 45Mhz
// 	// It will be enabled in cpuio.c
// 	PMC_REG(PMC_PCKR0) = (PMC_PCKR_PRES_4		// divide by 4
// 					   | PMC_PCKR_CSS_PLLA);

	ldr r1,=_PMC_PCKR0
	ldr r2,=(_PMC_MCKR_CSS_PLLA_CLK|_PMC_MCKR_PRES_CLK_4)
	str r2,[r1]

// 	INIT_DBG = d++;
// #endif

// 	//***************************************************************************
// 	// GPIO Initialization
// 	//***************************************************************************
// #if 1
// 	// Initialize the GPIO - just the basics for now

// 	// enable d16-31 on portc to be alternate function a (databus)
// 	// also enable *wait (pc6)
// 	// portc a function, pc6 = wait function a
// 	PIOC_REG(PIO_ASR) = 0xffff0000;
// 	PIOC_REG(PIO_PDR) = 0xffff0000;
// 	PIOC_REG(PIO_PER) = ~(0xffff0000);

	ldr	r1,=AT91RM9200_PIOC
	ldr	r2,=0xFFFF0000
	str	r2,[r1,#_PIO_ASR]
	str	r2,[r1,#_PIO_PDR]
	mvn	r2,r2
	str	r2,[r1,#_PIO_PER]

// 	// pio_odr: all gpio = input
// 	PIOC_REG(PIO_ODR) = 0xffffffff;

	ldr	r2,=0xFFFFFFFF
	str	r2,[r1,#_PIO_ODR]

// 	// enable ethernet and DTXD/DRXD on Port A
// 	// ethernet = PA16-7, DTXD = PA31
// 	PIOA_REG(PIO_ASR) = 0xC001FF80;		// PORTA Function A
// 	PIOA_REG(PIO_PDR) = 0xC001FF80;		// remove PA31, and PA16-7 as GPIO

	ldr	r1,=AT91RM9200_PIOA
	ldr	r2,=0xC001FF80
	str	r2,[r1,#_PIO_ASR]
	str	r2,[r1,#_PIO_PDR]

// 	// PIO_PDR: PB27 = peripheral, PB19-12 = Ethernet, all else = GPIO
// 	PIOB_REG(PIO_PDR) = 0x080ff000;
// 	PIOB_REG(PIO_PER) = ~(0x080ff000);
//      PIOB_REG(PIO_PDR) = 0x07D00000; // also set UART2 lines to peripheral use
            
	ldr	r1,=AT91RM9200_PIOB
	ldr	r2,=0x0fDFF000
	str	r2,[r1,#_PIO_PDR]
	mvn	r2,r2
	str	r2,[r1,#_PIO_PER]

// 	// PortB Function A, PB27 = PCK0
// 	PIOB_REG(PIO_ASR) = 0x08000000;		// PORTB Function A
// 	// PortB Function B, PB19-12 = Ethernet
// 	PIOB_REG(PIO_BSR) = 0x000ff000;		// PORTB Function B

	ldr	r2,=0x08000000
	str	r2,[r1,#_PIO_ASR]
	ldr	r2,=0x000FF000
	str	r2,[r1,#_PIO_BSR]

// 	PIOB_REG(PIO_OER) = 0x00000007; 	// PIO_OER: all GPIO = input, except PB0-2
// 	PIOB_REG(PIO_SODR) = 0x00000007;	// PIO_SODR: first drive PB0-2 high
// 	PIOB_REG(PIO_CODR) = 0x00000004;	// PIO_CODR: then drive PB0 low

	ldr	r2,=0x00000007
	str	r2,[r1,#_PIO_OER]
	str	r2,[r1,#_PIO_SODR]
	ldr	r2,=0x00000004
	str	r2,[r1,#_PIO_CODR]

// 	INIT_DBG = d++;
// #endif
	
// 	//***************************************************************************
// 	// SDRAM Initialization
// 	//***************************************************************************

// 	// do not intialize the SDRAM if it is already running
// 	// (such as when we are loaded into ram via JTAG)
// #if 1
// 	if ((EBI_REG(EBI_CSA) & EBI_CSA_CS1_SDRAM) == 0)	
// 	{
// 		// assign sdram_cs to cs1, all others to  sram
// 		EBI_REG(EBI_CSA) = EBI_CSA_CS1_SDRAM;

	ldr	r1,=_EBI_CSA
	ldr	r2,[r1]
	tst	r2,#_EBI_CSA_CS1A_SDRAMC
	bne	sdram_running
	ldr     r2,=_EBI_CSA_CS1A_SDRAMC
	str	r2,[r1]

// 		// disable databus D0-D15 pullups and bus sharing
// 		EBI_REG(EBI_CFGR) = 0;

	ldr	r1,=_EBI_CFGR
	mov	r2,#0
	str	r2,[r1]

// 		INIT_DBG = d++;

// 		// write sdram configuration register - values assume
// 		// a minimum SDRAM rating of 100Mhz, CL2.
// 	//	if (MCK > 70){	// optimized values for ~92Mhz operation
// 			SDRC_REG(SDRC_CR) = SDRC_CR_TXSR(4)		// CKE to ACT 
// 							  | SDRC_CR_TRAS(3)		// ACT to PRE Time
// 							  | SDRC_CR_TRCD(1)		// RAS to CAS Time
// 							  | SDRC_CR_TRP(1)		// PRE to ACT Time
// 							  | SDRC_CR_TRC(6)		// REF to ACT Time
// 							  | SDRC_CR_TWR(1)		// Write Recovery Time
// 							  | SDRC_CR_CAS_2		// Cas Delay = 2
// 							  | SDRC_CR_NB_4		// 4 Banks per device
// 							  | SDRC_CR_NR_12		// Number of rows = 12
// 							  | SDRC_CR_NC_9;		// Number of columns = 9

// //			SDRC_REG(SDRC_CR) = 0x2188C155;

	ldr	r1,=_EBI_SDRC_CR
	ldr	r2,=0x2188C155
	str	r2,[r1]

// 	//	}
// 	//	else	// optimized values for ~60Mhz
// 	//	{
// 	//		SDRC_REG(SDRC_CR) = SDRC_CR_TXSR(2)		// CKE to ACT 
// 	//						  | SDRC_CR_TRAS(4)		// ACT to PRE Time
// 	//						  | SDRC_CR_TRCD(2)		// RAS to CAS Time
// 	//						  | SDRC_CR_TRP(2)		// PRE to ACT Time
// 	//						  | SDRC_CR_TRC(5)		// REF to ACT Time
// 	//						  | SDRC_CR_TWR(2)		// Write Recovery Time
// 	//						  | SDRC_CR_CAS_2		// Cas Delay = 2
// 	//						  | SDRC_CR_NB_4		// 4 Banks per device
// 	//						  | SDRC_CR_NR_12		// Number of rows = 12
// 	//						  | SDRC_CR_NC_9;		// Number of columns = 9
// 	//	}

// 		INIT_DBG = d++;

// 		// issue 2 nop's
// 		SDRC_REG(SDRC_MR) = SDRC_MR_NOP;
// 		SDRAM(0) = 0;
// 		SDRAM(0) = 0;
// 		for (i = 0; i < 100; i++){}		// delay for a bit

	ldr	r1,=_EBI_SDRC_MR
	ldr	r2,=_EBI_SDRC_MR_MODE_NOP_CMD
	ldr	r3,=CSB337_SDRAM_PHYS_BASE
	str	r2,[r1]
	mov	r4,#0
	str	r4,[r3]
	str	r4,[r3]
	mov	r5,#100
30:	sub	r5,r5,#1
	cmp	r5,#0
	bne	30b

// 		// issue precharge all
// 		SDRC_REG(SDRC_MR) = SDRC_MR_PRE;
// 		SDRAM(0) = 0;
// 		for (i = 0; i < 100; i++){}		// delay for a bit

	ldr	r2,=_EBI_SDRC_MR_MODE_PRCGALL_CMD
	str	r2,[r1]
	str	r4,[r3]
	mov	r5,#100
32:	sub	r5,r5,#1
	cmp	r5,#0
	bne	32b


// 		// issue 8 refresh cycles
// 		SDRC_REG(SDRC_MR) = SDRC_MR_REF;
// 		for (i = 0; i < 8; i++){
// 			SDRAM(0) = 0;
// 		}
// 		for (i = 0; i < 100; i++){}		// delay for a bit

	ldr	r2,=_EBI_SDRC_MR_MODE_RFSH_CMD
	str	r2,[r1]
	str	r4,[r3]
	str	r4,[r3]
	str	r4,[r3]
	str	r4,[r3]
	str	r4,[r3]
	str	r4,[r3]
	str	r4,[r3]
	str	r4,[r3]
	mov	r5,#100
34:	sub	r5,r5,#1
	cmp	r5,#0
	bne	34b

// 		// issue mode register set
// 		SDRC_REG(SDRC_MR) = SDRC_MR_MRS;
// 		SDRAM(0x80) = 0;

	ldr	r2,=_EBI_SDRC_MR_MODE_LMR_CMD
	str	r2,[r1]
	str	r4,[r3,#0x80]

// 		INIT_DBG = d++;

// 		// set normal mode
// 		SDRC_REG(SDRC_MR) = SDRC_MR_NORM;
// 		SDRAM(0) = 0;

	ldr	r2,=_EBI_SDRC_MR_MODE_NORMAL_CMD
	str	r2,[r1]
	str	r4,[r3]

// 		INIT_DBG = d++;

// 		// set refresh to 14usec 
// //		SDRC_REG(SDRC_TR) = ((MCK/1000000) * 14);
// 		SDRC_REG(SDRC_TR) = 0x200;
// 		SDRAM(0) = 0;

	ldr	r1,=_EBI_SDRC_TR
	ldr	r2,=0x200
	str	r2,[r1]
	str	r4,[r3]

// 		INIT_DBG = d++;

// 	} // if EBI_CSA_CS1_SDRAM == 0

sdram_running:
#endif  // CYG_HAL_STARTUP_RAM

#ifdef CYG_HAL_STARTUP_ROMRAM
        // Compute [logical] base address of this image in ROM
        bl      10f
10:     mov     r9,lr
        ldr     r8,=~0xFF01FFFF         // Bits to ignore
        and     r9,r9,r8
        orr     r9,r9,#0x60000000       // Turn into ROM address
#endif        

        bl      10f
10:     
        ldr     r1,=10b
        cmp     r1,lr
        beq     mmu_ok

        // Set up a stack [for calling C code]
        ldr     r1,=__startup_stack
        ldr     r2,=CSB337_SDRAM_PHYS_BASE
        orr     sp,r1,r2

        // Create MMU tables
        bl      hal_mmu_init

        // Enable MMU
        ldr     r2,=10f
#ifdef CYG_HAL_STARTUP_ROMRAM
        ldr     r1,=__exception_handlers
        sub     r1,r2,r1
        add     r2,r9,r1        // r9 has ROM offset
#endif        
        ldr    r1,=MMU_Control_Init|MMU_Control_M
        mcr    MMU_CP,0,r1,MMU_Control,c0
        mov    pc,r2    /* Change address spaces */
        nop
        nop
        nop
10:

mmu_ok:
        
#ifdef CYG_HAL_STARTUP_ROMRAM
        mov     r0,r9                     // Relocate FLASH/ROM to RAM
        ldr     r1,=__exception_handlers  // ram base & length
        ldr     r2,=__rom_data_end
20:     ldr     r3,[r0],#4
        str     r3,[r1],#4
        cmp     r1,r2
        bne     20b
        ldr     r0,=30f
        mov     pc,r0
        nop
        nop
        nop
        nop
30:             
#endif
        .endm
        
#define CYGHWR_HAL_ARM_HAS_MMU
#define PLATFORM_SETUP1 _platform_setup1
#define CYGSEM_HAL_ROM_RESET_USES_JUMP

//-----------------------------------------------------------------------------
// end of hal_platform_setup.h
#endif // CYGONCE_HAL_PLATFORM_SETUP_H
