1*1c9d674cSDavid du Colombier/* virtex5 ppc440x5 reboot code */ 2*1c9d674cSDavid du Colombier#include "mem.h" 3*1c9d674cSDavid du Colombier 4*1c9d674cSDavid du Colombier#define SPR_SRR0 26 /* Save/Restore Register 0 */ 5*1c9d674cSDavid du Colombier#define SPR_SRR1 27 /* Save/Restore Register 1 */ 6*1c9d674cSDavid du Colombier#define SPR_DBCR0 0x134 /* Debug Control Register 0 */ 7*1c9d674cSDavid du Colombier#define SPR_DBCR1 0x135 /* Debug Control Register 1 */ 8*1c9d674cSDavid du Colombier#define SPR_DBCR2 0x136 /* Debug Control Register 1 */ 9*1c9d674cSDavid du Colombier#define SPR_DBSR 0x130 /* Debug Status Register */ 10*1c9d674cSDavid du Colombier 11*1c9d674cSDavid du Colombier/* special instruction definitions */ 12*1c9d674cSDavid du Colombier#define BDNZ BC 16,0, 13*1c9d674cSDavid du Colombier#define BDNE BC 0,2, 14*1c9d674cSDavid du Colombier 15*1c9d674cSDavid du Colombier#define ICCCI(a,b) WORD $((31<<26)|((a)<<16)|((b)<<11)|(966<<1)) 16*1c9d674cSDavid du Colombier#define DCCCI(a,b) WORD $((31<<26)|((a)<<16)|((b)<<11)|(454<<1)) 17*1c9d674cSDavid du Colombier 18*1c9d674cSDavid du Colombier/* 19*1c9d674cSDavid du Colombier * on the 400 series, the prefetcher madly fetches across RFI, sys call, 20*1c9d674cSDavid du Colombier * and others; use BR 0(PC) to stop. 21*1c9d674cSDavid du Colombier */ 22*1c9d674cSDavid du Colombier#define RFI WORD $((19<<26)|(50<<1)); BR 0(PC) 23*1c9d674cSDavid du Colombier#define RFCI WORD $((19<<26)|(51<<1)); BR 0(PC) 24*1c9d674cSDavid du Colombier 25*1c9d674cSDavid du Colombier/* print progress character. steps on R7 and R8, needs SB set. */ 26*1c9d674cSDavid du Colombier#define PROG(c) MOVW $(Uartlite+4), R7; MOVW $(c), R8; MOVW R8, 0(R7); SYNC 27*1c9d674cSDavid du Colombier 28*1c9d674cSDavid du Colombier/* 29*1c9d674cSDavid du Colombier * copied to REBOOTADDR and executed there. 30*1c9d674cSDavid du Colombier * since it copies the new kernel over the old one, it is 31*1c9d674cSDavid du Colombier * self-contained and does not call any other kernel code. 32*1c9d674cSDavid du Colombier * 33*1c9d674cSDavid du Colombier * Turn off interrupts, then copy the new kernel to its correct location 34*1c9d674cSDavid du Colombier * in physical memory. Then jump to the start of the kernel. 35*1c9d674cSDavid du Colombier * destination and source arguments are virtual addresses. 36*1c9d674cSDavid du Colombier */ 37*1c9d674cSDavid du Colombier 38*1c9d674cSDavid du Colombier NOSCHED 39*1c9d674cSDavid du Colombier 40*1c9d674cSDavid du ColombierTEXT main(SB),1,$-4 41*1c9d674cSDavid du Colombier MOVW $setSB(SB), R2 42*1c9d674cSDavid du Colombier 43*1c9d674cSDavid du Colombier MOVW R3, p1+0(FP) /* destination, passed in R3 */ 44*1c9d674cSDavid du Colombier MOVW R3, R6 /* entry point */ 45*1c9d674cSDavid du Colombier MOVW p2+4(FP), R4 /* source */ 46*1c9d674cSDavid du Colombier MOVW n+8(FP), R5 /* byte count */ 47*1c9d674cSDavid du Colombier 48*1c9d674cSDavid du Colombier /* make it safe to copy over the old kernel */ 49*1c9d674cSDavid du ColombierPROG('R') 50*1c9d674cSDavid du Colombier BL introff(SB) 51*1c9d674cSDavid du Colombier// MOVW $setSB(SB), R2 52*1c9d674cSDavid du Colombier 53*1c9d674cSDavid du ColombierPROG('e') 54*1c9d674cSDavid du Colombier// BL resetcaches(SB) 55*1c9d674cSDavid du Colombier 56*1c9d674cSDavid du Colombier /* disable debug facilities */ 57*1c9d674cSDavid du Colombier ISYNC 58*1c9d674cSDavid du Colombier MOVW R0, SPR(SPR_DBCR0) 59*1c9d674cSDavid du Colombier MOVW R0, SPR(SPR_DBCR1) 60*1c9d674cSDavid du Colombier MOVW R0, SPR(SPR_DBCR2) 61*1c9d674cSDavid du Colombier ISYNC 62*1c9d674cSDavid du Colombier MOVW $~0, R7 63*1c9d674cSDavid du Colombier MOVW R7, SPR(SPR_DBSR) 64*1c9d674cSDavid du Colombier ISYNC 65*1c9d674cSDavid du Colombier 66*1c9d674cSDavid du Colombier MOVW R3, R1 /* tiny trampoline stack before dest */ 67*1c9d674cSDavid du Colombier SUB $0x20, R1 /* bypass a.out header */ 68*1c9d674cSDavid du Colombier 69*1c9d674cSDavid du Colombier /* copy new kernel over the old */ 70*1c9d674cSDavid du Colombier MOVWU R0, -48(R1) /* allocate stack frame */ 71*1c9d674cSDavid du Colombier MOVW R3, 44(R1) /* save dest */ 72*1c9d674cSDavid du Colombier MOVW R5, 40(R1) /* save count */ 73*1c9d674cSDavid du Colombier MOVW R3, 0(R1) 74*1c9d674cSDavid du Colombier MOVW R3, 4(R1) /* push dest */ 75*1c9d674cSDavid du Colombier MOVW R4, 8(R1) /* push src */ 76*1c9d674cSDavid du Colombier MOVW R5, 12(R1) /* push size */ 77*1c9d674cSDavid du ColombierPROG('s') 78*1c9d674cSDavid du Colombier BL memmove(SB) 79*1c9d674cSDavid du Colombier SYNC 80*1c9d674cSDavid du Colombier MOVW 44(R1), R6 /* restore dest */ 81*1c9d674cSDavid du Colombier MOVW p2+4(FP), R4 /* restore source */ 82*1c9d674cSDavid du Colombier MOVW 40(R1), R5 /* restore count */ 83*1c9d674cSDavid du Colombier 84*1c9d674cSDavid du Colombier /* verify that we copied it correctly */ 85*1c9d674cSDavid du ColombierPROG('t') 86*1c9d674cSDavid du Colombier MOVW R4, R10 87*1c9d674cSDavid du Colombier MOVW R6, R11 88*1c9d674cSDavid du Colombier MOVW R5, R12 89*1c9d674cSDavid du Colombier SUB $4, R10 90*1c9d674cSDavid du Colombier SUB $4, R11 91*1c9d674cSDavid du Colombiercmploop: 92*1c9d674cSDavid du Colombier MOVWU 4(R10), R13 93*1c9d674cSDavid du Colombier MOVWU 4(R11), R14 94*1c9d674cSDavid du Colombier CMP R13, R14 95*1c9d674cSDavid du Colombier BNE buggered 96*1c9d674cSDavid du Colombier SUB $4, R12 97*1c9d674cSDavid du Colombier CMP R12, R0 98*1c9d674cSDavid du Colombier BGT cmploop 99*1c9d674cSDavid du Colombier 100*1c9d674cSDavid du ColombierPROG('a') 101*1c9d674cSDavid du Colombier ANDCC $~KZERO, R6, R3 /* physical entry addr */ 102*1c9d674cSDavid du Colombier 103*1c9d674cSDavid du Colombier MOVW R0, R4 104*1c9d674cSDavid du Colombier SUB $(4*2), R4 /* r4 is now points to bootstart */ 105*1c9d674cSDavid du Colombier MOVW R3, 0(R4) /* entry addr into bootstart */ 106*1c9d674cSDavid du Colombier SYNC 107*1c9d674cSDavid du Colombier ISYNC 108*1c9d674cSDavid du Colombier 109*1c9d674cSDavid du ColombierPROG('r') 110*1c9d674cSDavid du Colombier /* 111*1c9d674cSDavid du Colombier * flush data cache 112*1c9d674cSDavid du Colombier */ 113*1c9d674cSDavid du Colombier MOVW R6, R3 /* virtaddr */ 114*1c9d674cSDavid du Colombier MOVW R5, R4 /* count */ 115*1c9d674cSDavid du Colombier RLWNM $0, R3, $~(DCACHELINESZ-1), R5 116*1c9d674cSDavid du Colombier CMP R4, R0 117*1c9d674cSDavid du Colombier BLE dcf1 118*1c9d674cSDavid du Colombier SUB R5, R3 119*1c9d674cSDavid du Colombier ADD R3, R4 120*1c9d674cSDavid du Colombier ADD $(DCACHELINESZ-1), R4 121*1c9d674cSDavid du Colombier SRAW $DCACHELINELOG, R4 122*1c9d674cSDavid du Colombier MOVW R4, CTR 123*1c9d674cSDavid du Colombierdcf0: DCBF (R5) 124*1c9d674cSDavid du Colombier ADD $DCACHELINESZ, R5 125*1c9d674cSDavid du Colombier BDNZ dcf0 126*1c9d674cSDavid du Colombierdcf1: 127*1c9d674cSDavid du Colombier SYNC 128*1c9d674cSDavid du Colombier ISYNC 129*1c9d674cSDavid du Colombier 130*1c9d674cSDavid du Colombier /* be sure icache is cleared */ 131*1c9d674cSDavid du Colombier BL resetcaches(SB) 132*1c9d674cSDavid du Colombier 133*1c9d674cSDavid du Colombier/* 134*1c9d674cSDavid du Colombier * jump to kernel entry point. Note the true kernel entry point is 135*1c9d674cSDavid du Colombier * the virtual address R6, and the MMU is always enabled. 136*1c9d674cSDavid du Colombier */ 137*1c9d674cSDavid du Colombier OR R6, R6 /* NOP: avoid link bug */ 138*1c9d674cSDavid du Colombier MOVW R6, LR 139*1c9d674cSDavid du ColombierPROG('t') 140*1c9d674cSDavid du ColombierPROG('\r') 141*1c9d674cSDavid du ColombierPROG('\n') 142*1c9d674cSDavid du Colombier BL (LR) /* without reset. leaves qtm, dram, etc. intact */ 143*1c9d674cSDavid du Colombier BR 0(PC) 144*1c9d674cSDavid du Colombier 145*1c9d674cSDavid du Colombier// BR reset 146*1c9d674cSDavid du Colombierbuggered: 147*1c9d674cSDavid du Colombier PROG('C') 148*1c9d674cSDavid du Colombier PROG('m') 149*1c9d674cSDavid du Colombier PROG('p') 150*1c9d674cSDavid du Colombier PROG(' ') 151*1c9d674cSDavid du Colombier PROG('f') 152*1c9d674cSDavid du Colombier PROG('a') 153*1c9d674cSDavid du Colombier PROG('i') 154*1c9d674cSDavid du Colombier PROG('l') 155*1c9d674cSDavid du Colombierreset: 156*1c9d674cSDavid du Colombier ISYNC 157*1c9d674cSDavid du Colombier MOVW $(3<<28), R3 158*1c9d674cSDavid du Colombier MOVW R3, SPR(SPR_DBCR0) /* cause a system reset */ 159*1c9d674cSDavid du Colombier ISYNC 160*1c9d674cSDavid du Colombier BR 0(PC) 161*1c9d674cSDavid du Colombier 162*1c9d674cSDavid du ColombierTEXT introff(SB), 1, $-4 163*1c9d674cSDavid du Colombier MOVW LR, R7 164*1c9d674cSDavid du Colombier MOVW R7, SPR(SPR_SRR0) 165*1c9d674cSDavid du Colombier 166*1c9d674cSDavid du Colombier /* 167*1c9d674cSDavid du Colombier * turn off interrupts & MMU 168*1c9d674cSDavid du Colombier * disable machine check 169*1c9d674cSDavid du Colombier */ 170*1c9d674cSDavid du Colombier MOVW MSR, R7 171*1c9d674cSDavid du Colombier RLWNM $0, R7, $~(MSR_EE), R7 172*1c9d674cSDavid du Colombier RLWNM $0, R7, $~(MSR_CE), R7 173*1c9d674cSDavid du Colombier RLWNM $0, R7, $~(MSR_DE), R7 174*1c9d674cSDavid du Colombier RLWNM $0, R7, $~(MSR_ME), R7 175*1c9d674cSDavid du Colombier RLWNM $0, R7, $~(MSR_IS|MSR_DS), R7 176*1c9d674cSDavid du Colombier MOVW R7, SPR(SPR_SRR1) 177*1c9d674cSDavid du Colombier SYNC /* fix 405 errata cpu_210 */ 178*1c9d674cSDavid du Colombier RFI /* resume in kernel mode in caller */ 179*1c9d674cSDavid du Colombier 180*1c9d674cSDavid du Colombier/* 181*1c9d674cSDavid du Colombier * reset the caches 182*1c9d674cSDavid du Colombier * clobbers R7 183*1c9d674cSDavid du Colombier */ 184*1c9d674cSDavid du ColombierTEXT resetcaches(SB),1,$-4 185*1c9d674cSDavid du Colombier ICCCI(0, 2) /* errata cpu_121 reveals that EA is used; we'll use SB */ 186*1c9d674cSDavid du Colombier ISYNC 187*1c9d674cSDavid du Colombier 188*1c9d674cSDavid du Colombier MOVW $(DCACHEWAYSIZE/DCACHELINESZ), R7 189*1c9d674cSDavid du Colombier MOVW R7, CTR 190*1c9d674cSDavid du Colombier MOVW $KZERO, R7 191*1c9d674cSDavid du Colombierdcinv: 192*1c9d674cSDavid du Colombier DCBF (R7) 193*1c9d674cSDavid du Colombier ADD $DCACHELINESZ, R7 194*1c9d674cSDavid du Colombier BDNZ dcinv 195*1c9d674cSDavid du Colombier 196*1c9d674cSDavid du Colombier SYNC; ISYNC 197*1c9d674cSDavid du Colombier 198*1c9d674cSDavid du Colombier BR (LR) 199*1c9d674cSDavid du Colombier BR 0(PC) 200