/*bsp_970fx/bootlib/init_core.s, pibs_970, pibs_970_1.0 1/14/05 14:58:41*/
/*----------------------------------------------------------------------------+
|       COPYRIGHT   I B M   CORPORATION 2002, 2004
|       LICENSED MATERIAL  -  PROGRAM PROPERTY OF I B M
|	US Government Users Restricted Rights - Use, duplication or
|       disclosure restricted by GSA ADP Schedule Contract with
|	IBM Corp.
+----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------+
| PPC970FX BSP for EPOS
| Author: Maciej P. Tyrlik
| Component: Boot library.
| File: init_core.s
| Purpose: Basic PPC405 core initialization.
| Changes:
| Date:         Comment:
| -----         --------
| 29-Jan-02     Created                                                     MPT
| 30-Jan-02     Completed                                                   MPT
| 19-Apr-02     Changed some instructions to macros so that new GCC AS worksMPT
| 23-Apr-02     Removed critical interrupt enabling after rfi               MPT
| 31-Jul-02     Fixed data cache invalidate code                            MPT
| 01-Feb-03     Ported to Argan 7XXFX                                       CRB
| 07-Aug-03     Ported to PPC7XXGX                                          CRB
| 12-Sep-03     Removed PVR definitions, now in board include file          MCG
| 16-Sep-03     Do not enable HID0[MUM] or L2CR[L2CE] if 7XXGX DD1.0        MCG
| 31-Oct-03     Enable cache for MV64460 integrated SRAM                    MCG
| 07-Jan-04     Initialize FPRs to avoid errata.                            MCG
| 10-Feb-04     Port to PPC970FX					    MPT
+----------------------------------------------------------------------------*/

#include <ppc970.h>

/*----------------------------------------------------------------------------+
| Local defines.
+----------------------------------------------------------------------------*/
#define INITIAL_SLB_VSID_VAL		0x0000000000000C00
#define INITIAL_SLB_ESID_VAL		0x0000000008000000
#define INITIAL_SLB_INVA_VAL		0x0000000000000000

/*----------------------------------------------------------------------------+
| Init_core.  Assumption: hypervisor on, 64-bit on, HID1[10]=0, HID4[23]=0.
| Data cahability must be turned on.  Instruction cahability must be off.
+----------------------------------------------------------------------------*/
        /*--------------------------------------------------------------------+
        | Set time base to 0.
        +--------------------------------------------------------------------*/
	addi	r4,r0,0x0000
	mtspr	SPR_TBU_WRITE,r4
	mtspr	SPR_TBL_WRITE,r4
        /*--------------------------------------------------------------------+
        | Set HID1[10] to 0 (instruction cache off) and set HID4[23] to 0 (data
        | cache on), set HID4[DC_SET1] and HID4[DC_SET2] to 0.
        +--------------------------------------------------------------------*/
        LOAD_64BIT_VAL(r4,HID1_EN_IC)
	nor	r4,r4,r4
	mfspr	r5,SPR_HID1
	isync
	and	r5,r5,r4
	mtspr	SPR_HID1,r5	
	mtspr	SPR_HID1,r5	
	isync
        LOAD_64BIT_VAL(r4,HID4_RM_CI|HID4_DC_SET1|HID4_DC_SET2)
	nor	r4,r4,r4
	mfspr	r5,SPR_HID4
        LOAD_64BIT_VAL(r6,HID4_L1DC_FLSH)
	isync
	and	r5,r5,r4
	or	r5,r5,r6
	sync
	mtspr	SPR_HID4,r5	
	isync
        /*--------------------------------------------------------------------+
        | Clear the flash invalidate L1 data cache bit in HID4.
        +--------------------------------------------------------------------*/
	nor	r6,r6,r6
	and	r5,r5,r6
	sync
	mtspr	SPR_HID4,r5	
	isync
        /*--------------------------------------------------------------------+
        | Clear and set up some registers.
        +--------------------------------------------------------------------*/
	addi    r4,r0,0x0000
        mtxer   r4
        /*--------------------------------------------------------------------+
        | Invalidate SLB.  First load SLB with known values then perform 
        | invalidate.  Invalidate will clear the D-ERAT and I-ERAT.  The SLB
	| is 64 entry fully associative.  On power on D-ERAT and I-ERAT are all
        | set to invalid values.
        +--------------------------------------------------------------------*/
	addi	r5,r0,SLB_SIZE
	mtctr	r5
	LOAD_64BIT_VAL(r6,INITIAL_SLB_VSID_VAL)
	LOAD_64BIT_VAL(r7,INITIAL_SLB_ESID_VAL)
	addis	r8,r0,0x1000
0:	slbmte	r6,r7
	addi	r6,r6,0x1000
	add  	r7,r7,r8
	addi	r7,r7,0x0001
	bdnz	0b
	mtctr	r5
	LOAD_64BIT_VAL(r6,INITIAL_SLB_INVA_VAL)
1:	slbie	r6
	add  	r6,r6,r8
	bdnz	1b
        /*--------------------------------------------------------------------+
        | Load SLB.  Following is the initial memory map.
	| Entry(6) ESID(36)    VSID
	| 0x0	   0x000000000 0x0000000000000 (large page cachable)
	| 0x1      0x00000000F 0x000000000000F (small non-cachable, G)
	| at 0x00000000 there will be 48MB mapped (SDRAM)
	| at 0xF8000000 there will be 16MB mapped (NB)
	| at 0xF4000000 there will be 64KB mapped (I/O space)
        | at 0xFF000000 there will be 16MB or 1MB mapped (FLASH)
        +--------------------------------------------------------------------*/
	addi	r6,r0,0x0100
	addis	r7,r0,0x0800
	slbmte	r6,r7
	addi	r6,r0,0x0000
	ori  	r6,r6,0xF000
	addi 	r7,r0,0x0001
	oris	r7,r7,0xF800
	slbmte	r6,r7
        /*--------------------------------------------------------------------+
        | Invalidate all 1024 instruction and data TLBs (4 way)
        +--------------------------------------------------------------------*/
        addi    r8,r0,0x0100
        mtspr   CTR,r8
        addi    r8,r0,0x0000
2:	TLBIEL(r8)
        addi    r8,r8,0x1000
        bdnz   2b
        ptesync
        /*--------------------------------------------------------------------+
        | Dcbz the page table space.   Calculate SDR1 address.  Store SDR1
        | address in r30.
        +--------------------------------------------------------------------*/
	mfspr	r3,SPR_PIR
	cmpi	cr0,1,r3,0x0000
	bne	3f
        addis   r3,r0,INITIAL_PAGE_TABLE_ADDR_CPU0@h
        ori     r3,r3,INITIAL_PAGE_TABLE_ADDR_CPU0@l
	b	4f
3:	addis   r3,r0,INITIAL_PAGE_TABLE_ADDR_CPU1@h
        ori     r3,r3,INITIAL_PAGE_TABLE_ADDR_CPU1@l
4:	addis   r4,r0,INITIAL_PAGE_TABLE_SIZE@h
        ori     r4,r4,INITIAL_PAGE_TABLE_SIZE@l
	rlwinm	r5,r4,14,14,31 
	cntlzw	r5,r5
	subfic	r5,r5,31
	or	r30,r3,r5
        bl      .ppcDcbz_area
        /*--------------------------------------------------------------------+
        | Setup 0x00000000FFFFFFFF mask in r29. 
        +--------------------------------------------------------------------*/
	addi	r29,r0,0x0001
	rldicl	r29,r29,32,31
	addi	r29,r29,-1
        /*--------------------------------------------------------------------+
        | Setup 48MB of addresses in DRAM in page table (3 large PTE).  The 
        | parameters to p_ptegg are: r3 = lp, r4 = ea, r5 = sdr1, r6 = vsid.
        +--------------------------------------------------------------------*/
	addi	r3,r0,0x0001
	addi	r4,r0,0x0000
        ori     r5,r30,0x0000
	addi	r6,r0,0x0000
	bl	.p_ptegg
	addi	r4,r0,0x0001
	stw	r4,0x0004(r3)
	addi	r4,r0,0x0180
	stw	r4,0x000C(r3)
        /*--------------------------------------------------------------------+
        | Second 16MB is mapped here.
        +--------------------------------------------------------------------*/
	addi	r3,r0,0x0001
	addis	r4,r0,0x0100
        ori     r5,r30,0x0000
	addi	r6,r0,0x0000
	bl	.p_ptegg
	addi	r4,r0,0x0101
	stw	r4,0x0004(r3)
	addis	r4,r0,0x0100
	ori     r4,r4,0x0180
	stw	r4,0x000C(r3)
        /*--------------------------------------------------------------------+
        | Third 16MB is mapped here.
        +--------------------------------------------------------------------*/
	addi	r3,r0,0x0001
	addis	r4,r0,0x0200
        ori     r5,r30,0x0000
	addi	r6,r0,0x0000
	bl	.p_ptegg
	addi	r4,r0,0x0201
	stw	r4,0x0004(r3)
	addis	r4,r0,0x0200
	ori     r4,r4,0x0180
	stw	r4,0x000C(r3)
        /*--------------------------------------------------------------------+
        | Setup 64KB of addresses in I/O space (0xF4000000).
        +--------------------------------------------------------------------*/
	addi	r3,r0,0x0010
	mtctr	r3
	addis	r31,r0,0xF400
	and	r31,r31,r29
5:	addi	r3,r0,0x0000
	ori	r4,r31,0x0000
	ori	r5,r30,0x0000
	addi	r6,r0,0x000F
	bl	.p_ptegg
	addi	r6,r3,0x0080
6:	lwz	r4,0x0004(r3)
	cmpli	cr0,1,r4,0x0000
	beq	8f
	addi	r3,r3,0x0010
	cmp	cr0,1,r3,r6
	blt	6b
7:	b	7b
8:	rlwinm  r4,r31,16,4,24
	ori	r4,r4,0x0001
	stw	r4,0x0004(r3)
	ori	r4,r31,0x01AC
	stw	r4,0x000C(r3)
	addi	r31,r31,0x1000
	bdnz	5b
        /*--------------------------------------------------------------------+
        | Setup 16MB of addresses in NB register space (0xF8000000).
        +--------------------------------------------------------------------*/
	addi	r3,r0,0x1000
	mtctr	r3
	addis	r31,r0,0xF800
	and	r31,r31,r29
9:	addi	r3,r0,0x0000
	ori	r4,r31,0x0000
	ori	r5,r30,0x0000
	addi	r6,r0,0x000F
	bl	.p_ptegg
	addi	r6,r3,0x0080
10:	lwz	r4,0x0004(r3)
	cmpli	cr0,1,r4,0x0000
	beq	12f
	addi	r3,r3,0x0010
	cmp	cr0,1,r3,r6
	blt	10b
11:	b	11b
12:	rlwinm	r4,r31,16,4,24
	ori	r4,r4,0x0001
	stw	r4,0x0004(r3)
	ori	r4,r31,0x01AC
	stw	r4,0x000C(r3)
	addi	r31,r31,0x1000
	bdnz	9b
        /*--------------------------------------------------------------------+
        | Setup 16MB or 1MB of addresses in ROM (at 0xFF000000 or 0xFFF00000).
        +--------------------------------------------------------------------*/
	mfspr	r3,SPR_HIOR
	LOAD_64BIT_VAL(r4,BOOT_BASE_AS)
	cmpd	cr0,r3,r4
	beq	13f
	addi	r3,r0,0x0100
	mtctr	r3
	addis	r31,r0,0xFFF0
	b	14f
13:	addi	r3,r0,0x1000
	mtctr	r3
	addis	r31,r0,0xFF00
14:	and	r31,r31,r29
15:	addi	r3,r0,0x0000
	ori	r4,r31,0x0000
	ori	r5,r30,0x0000
	addi	r6,r0,0x000F
	bl	.p_ptegg
	addi	r6,r3,0x0080
16:	lwz	r4,0x0004(r3)
	cmpli	cr0,1,r4,0x0000
	beq	18f
	addi	r3,r3,0x0010
	cmp	cr0,1,r3,r6
	blt	16b
17:	b	17b
18:	rlwinm	r4,r31,16,4,24
	ori	r4,r4,0x0001
	stw	r4,0x0004(r3)
	ori	r4,r31,0x01A3
	stw	r4,0x000C(r3)
	addi	r31,r31,0x1000
	bdnz	15b
        /*--------------------------------------------------------------------+
        | Synchronize after setting up page table.
        +--------------------------------------------------------------------*/
	ptesync
        /*--------------------------------------------------------------------+
        | Set the SDR1 register.
        +--------------------------------------------------------------------*/
	mtspr	SPR_SDR1,r30
        /*--------------------------------------------------------------------+
        | Clear SRR0, SRR1.
        +--------------------------------------------------------------------*/
        addi    r0,r0,0x0000
        mtspr   SPR_SRR0,r0
        mtspr   SPR_SRR1,r0
        /*--------------------------------------------------------------------+
        | Setup for subsequent MSR[ME] initialization to enable machine checks
        | and translation.
        +--------------------------------------------------------------------*/
        mfmsr   r3
        ori     r3,r3,(MSR_ME|MSR_IS|MSR_DS|MSR_FP)
        mtsrr1  r3
	mtmsrd	r3,0
	isync
        /*--------------------------------------------------------------------+
        | Setup HID registers (HID0, HID1, HID4, HID5).  When HIOR is set to
        | 0 HID0 external time base bit is inherited from current HID0. When
	| HIOR is set to FLASH_BASE_INTEL_AS then HID0 external time base bit
        | is set to 1 in order to indicate that the tiembase is driven by
        | external source. When HIOR is greater than FLASH_BASE_INTEL_AS then
        | HID0 external time base bit is set to 0 in order to indicate that the
        | tiembase is driven from internal clock.
        +--------------------------------------------------------------------*/
	LOAD_64BIT_VAL(r6,HID0_EXT_TB_EN)
	LOAD_64BIT_VAL(r7,FLASH_BASE_INTEL_AS)
	mfspr	r5,SPR_HIOR
	cmpdi	cr0,r5,0x0000
	beq	19f
	cmpd	cr0,r5,r7
	beq	20f
	addi	r8,r0,0x0000	
	b	21f
20: 	ori	r8,r6,0x0000
	b	21f
19:	mfspr	r5,SPR_HID0
	and 	r8,r5,r6
21:	LOAD_64BIT_VAL(r4,HID0_PREFEAR)
       	andc	r4,r4,r6
	or	r4,r4,r8 
	sync
	mtspr	SPR_HID0,r4
	mfspr	r4,SPR_HID0
	mfspr	r4,SPR_HID0
	mfspr	r4,SPR_HID0
	mfspr	r4,SPR_HID0
	mfspr	r4,SPR_HID0
	mfspr	r4,SPR_HID0
	LOAD_64BIT_VAL(r4,HID1_PREFEAR)
	mtspr	SPR_HID1,r4
	mtspr	SPR_HID1,r4
	isync
	LOAD_64BIT_VAL(r4,HID4_PREFEAR)
	sync	
	mtspr	SPR_HID4,r4
	isync
	sync
	LOAD_64BIT_VAL(r4,HID5_PREFEAR)
	mtspr   SPR_HID5,r4
	isync
	/*--------------------------------------------------------------------+
        | Synchronize memory accesses (sync).
        +--------------------------------------------------------------------*/
        sync
	LOAD_64BIT_VAL(r0,.init_chip)
	mfspr	r1,SPR_HIOR
	or	r0,r0,r1
        eieio
        mtspr   SPR_SRR0,r0
        rfid