| 1 | /* | 
|---|
| 2 |  * \file  : reset.S | 
|---|
| 3 |  * \date  : 01/12/2012 | 
|---|
| 4 |  * \author: Cesar FUGUET & Manuel BOUYER & Alain Greiner | 
|---|
| 5 |  * | 
|---|
| 6 |  * This is a generic reset code for a generic multi-clusters / multi-processors | 
|---|
| 7 |  * TSAR architecture (up to 256 clusters / up to 4  processors per cluster). | 
|---|
| 8 |  * | 
|---|
| 9 |  * There is one XICU, one TTY, one DMA, and one memory bank per cluster. | 
|---|
| 10 |  * | 
|---|
| 11 |  * This preloader uses a stack segment allocated in cluster 0, defined | 
|---|
| 12 |  * by the seg_reset_stack_base parameters in ldscript, of size 0x10000 (64k) | 
|---|
| 13 |  * - Processor 0 uses a larger stack:         64 Kbytes. | 
|---|
| 14 |  * - Other processors use a smaller stack:    512 bytes. | 
|---|
| 15 |  *     => the stack size cannot be smaller than 0x90000 bytes (576 K). | 
|---|
| 16 |  * Those stacks can be used by both the preloader and the boot-loader code. | 
|---|
| 17 |  *  | 
|---|
| 18 |  * The replicated XICU is used to awake the sleeping processors: | 
|---|
| 19 |  *      xicu_paddr_base = ICU_PADDR_BASE + (cluster_xy << 32) | 
|---|
| 20 |  * | 
|---|
| 21 |  * It is intended to be used with various operating systems or nano kernels, | 
|---|
| 22 |  * including NetBSD, ALMOS, and GIET_VM. | 
|---|
| 23 |  * | 
|---|
| 24 |  * - Each processor initializes its Status Register (SR) to disable interrupts. | 
|---|
| 25 |  * - Each processor initializes its Count Register. | 
|---|
| 26 |  * - Each processor initialises its private XICU WTI mask register. | 
|---|
| 27 |  * - Each processor initializes its Stack Pointer. | 
|---|
| 28 |  * - Only processor 0 executes the reset_load_elf function to load into memory  | 
|---|
| 29 |  *   the system specific boot-loader stored on disk at BOOT_LOADER_LBA  | 
|---|
| 30 |  * - All other processors wait in a low power consumption mode that the | 
|---|
| 31 |  *   processor 0 wakes them using an IPI (Inter Processor Interruption) | 
|---|
| 32 |  */ | 
|---|
| 33 |  | 
|---|
| 34 |     #include <defs.h> | 
|---|
| 35 |     #include <mips32_registers.h> | 
|---|
| 36 |  | 
|---|
| 37 |     /* These define should be consistent with values defined in map.xml file  */ | 
|---|
| 38 |  | 
|---|
| 39 |     .extern seg_reset_stack_base   | 
|---|
| 40 |  | 
|---|
| 41 |     .section .reset,"ax",@progbits | 
|---|
| 42 |  | 
|---|
| 43 |     .extern dtb_addr | 
|---|
| 44 |     .extern reset_putc | 
|---|
| 45 |     .extern reset_getc | 
|---|
| 46 |     .extern reset_ioc_read | 
|---|
| 47 |     .extern reset_elf_loader | 
|---|
| 48 |     .extern memcpy | 
|---|
| 49 |     .extern reset_puts | 
|---|
| 50 |     .extern reset_putx | 
|---|
| 51 |     .extern reset_putd | 
|---|
| 52 |     .extern reset_ioc_init | 
|---|
| 53 |     .extern versionstr | 
|---|
| 54 |  | 
|---|
| 55 |     .globl  reset                    /* Makes reset an external symbol */ | 
|---|
| 56 |     .ent    reset | 
|---|
| 57 |  | 
|---|
| 58 |     .align  2 | 
|---|
| 59 |     .set noreorder | 
|---|
| 60 |  | 
|---|
| 61 | reset: | 
|---|
| 62 |     b       _reset                  /* 0xbfc0000 */ | 
|---|
| 63 |     nop                             /* 0xbfc0004 */ | 
|---|
| 64 |  | 
|---|
| 65 |     /*  Addresses of the functions provided by this reset code */ | 
|---|
| 66 |  | 
|---|
| 67 | preloader_vector: | 
|---|
| 68 |     .word   RESET_VERSION           /* 0xbfc0008 */ | 
|---|
| 69 |     .word   dtb_addr                /* 0xbfc000c */ | 
|---|
| 70 |     .word   reset_putc              /* 0xbfc0010 */ | 
|---|
| 71 |     .word   reset_getc              /* 0xbfc0014 */ | 
|---|
| 72 |     .word   reset_ioc_read          /* 0xbfc0018 */ | 
|---|
| 73 |     .word   reset_elf_loader        /* 0xbfc001C */ | 
|---|
| 74 |     .word   memcpy                  /* 0xbfc0020 */ | 
|---|
| 75 |     .word   reset_puts              /* 0xbfc0024 */ | 
|---|
| 76 |     .word   reset_putx              /* 0xbfc0028 */ | 
|---|
| 77 |     .word   reset_putd              /* 0xbfc002C */ | 
|---|
| 78 |  | 
|---|
| 79 | _reset: | 
|---|
| 80 |  | 
|---|
| 81 |     /* All processors Disable interruptions, keep STATUSbev enabled */ | 
|---|
| 82 |  | 
|---|
| 83 |     li      k0,     (1 << 22) | 
|---|
| 84 |     mtc0    k0,     CP0_STATUS | 
|---|
| 85 |  | 
|---|
| 86 |     /* All processors compute proc_id, lpid, cluster_xy */ | 
|---|
| 87 |  | 
|---|
| 88 |     mfc0    k0,     CP0_EBASE | 
|---|
| 89 |     andi    t0,     k0,     0x3FF   /* t0 <= proc_id (at most 1024 processors)    */ | 
|---|
| 90 |  | 
|---|
| 91 |     move    t3,     t0 | 
|---|
| 92 |  | 
|---|
| 93 |     la      k0,     NB_PROCS        /* k0 <= number of processors per cluster     */ | 
|---|
| 94 |     divu    t3,     k0 | 
|---|
| 95 |     mfhi    t1                      /* t1 <= lpid       = proc_id % NB_PROCS      */ | 
|---|
| 96 |     mflo    t2                      /* t2 <= cluster_xy = proc_id / NB_PROCS      */ | 
|---|
| 97 |  | 
|---|
| 98 |     /* All processors initialise the count register in CP0 */ | 
|---|
| 99 |  | 
|---|
| 100 |     mtc0    zero,   CP0_COUNT | 
|---|
| 101 |  | 
|---|
| 102 |     /* | 
|---|
| 103 |      * All processors enable the WTI for XICU  | 
|---|
| 104 |      * Each processor may have IRQ_PER_PROC irq outputs from the XICU | 
|---|
| 105 |      * In each cluster, the XICU base address depends on the cluster_xy  | 
|---|
| 106 |      */ | 
|---|
| 107 |  | 
|---|
| 108 |     la      t3,     ICU_PADDR_BASE  /* t3 <= ICU base address                     */ | 
|---|
| 109 |     move    t4,     t1              /* t4 <= local_id                             */ | 
|---|
| 110 |     li      t5,     IRQ_PER_PROC    /* t5 <= IRQ_PER_PROC                         */ | 
|---|
| 111 |     multu   t4,     t5               | 
|---|
| 112 |     mflo    t6                      /* t6 <= IRQ_PER_PROC * local_id              */ | 
|---|
| 113 |     sll     t4,     t6,     2       /* t4 <= OUT_INDEX = t6 * 4                   */ | 
|---|
| 114 |  | 
|---|
| 115 |     li      t5,     (0xC << 7)      /* t5 <= FUNC      = XICU_MSK_WTI             */ | 
|---|
| 116 |     or      t4,     t4,     t5      /* t4 <= FUNC | INDEX | 00                    */ | 
|---|
| 117 |     or      t5,     t3,     t4      /* t5 <= &XICU[MSK_WTI][OUT_INDEX]            */ | 
|---|
| 118 |      | 
|---|
| 119 |     /* All processors set WTI mask using the physical address extension    */ | 
|---|
| 120 |  | 
|---|
| 121 |     li      t4,     1 | 
|---|
| 122 |     sllv    t4,     t4,     t1      /* Set XICU[MSK_WTI][INDEX][local_id]         */ | 
|---|
| 123 |  | 
|---|
| 124 |     mtc2    t2,     CP2_PADDR_EXT   /* set PADDR extension                        */ | 
|---|
| 125 |     sw      t4,     0(t5)           /* XICU[MSK_WTI][INDEX] <= t4                 */ | 
|---|
| 126 |     mtc2    zero,   CP2_PADDR_EXT   /* reset PADDR extension                      */ | 
|---|
| 127 |  | 
|---|
| 128 |     /* All processors initializes stack pointer, depending on proc_id */ | 
|---|
| 129 |  | 
|---|
| 130 |    la      k0,      seg_reset_stack_base | 
|---|
| 131 |    li      k1,      0x10000         /* k1 <= P0 stack size == 64 Kbytes           */ | 
|---|
| 132 |    addu    sp,      k0,     k1      /* P0 stack from base to (base + 64K)         */ | 
|---|
| 133 |  | 
|---|
| 134 |    li      k1,      0x200           /* k1 <= Pi stack size == 512 bytes           */ | 
|---|
| 135 |    multu   k1,      t0               | 
|---|
| 136 |    mflo    k0                       /* k0 <= 256 * proc_id                        */ | 
|---|
| 137 |    addu    sp,      sp,     k1 | 
|---|
| 138 |    addu    sp,      sp,     k0      /* Pi stacks from base + 64K + proc_id*256    */ | 
|---|
| 139 |  | 
|---|
| 140 |     /* | 
|---|
| 141 |      * Only processor 0 in cluster 0 loads and executes the boot-loader  | 
|---|
| 142 |      * We have: | 
|---|
| 143 |      * t0: global proc_id | 
|---|
| 144 |      * t1: local proc_id | 
|---|
| 145 |      * t2: cluster_xy | 
|---|
| 146 |      * t3: xicu physical base address in cluster 0 | 
|---|
| 147 |      */ | 
|---|
| 148 |  | 
|---|
| 149 |     bne     zero,   t0,     _reset_wait | 
|---|
| 150 |     nop | 
|---|
| 151 |  | 
|---|
| 152 |     /* Processor 0 displays version for this reset code */ | 
|---|
| 153 |  | 
|---|
| 154 |     la      a0,     versionstr | 
|---|
| 155 |     la      k0,     reset_puts | 
|---|
| 156 |     jalr    k0 | 
|---|
| 157 |     nop | 
|---|
| 158 |  | 
|---|
| 159 |  | 
|---|
| 160 | #if USE_SPI | 
|---|
| 161 |  | 
|---|
| 162 |     /* Processor 0 Initialize the SPI controller */ | 
|---|
| 163 |  | 
|---|
| 164 |     la      k0,     reset_ioc_init | 
|---|
| 165 |     jalr    k0 | 
|---|
| 166 |     nop | 
|---|
| 167 |  | 
|---|
| 168 | #endif | 
|---|
| 169 |  | 
|---|
| 170 |     /* | 
|---|
| 171 |      * Processor 0 jumps to the reset_elf_loader routine  | 
|---|
| 172 |      * Passing as argument the block number in which is loaded the .elf file | 
|---|
| 173 |      */ | 
|---|
| 174 |  | 
|---|
| 175 |     la      k0,     reset_elf_loader | 
|---|
| 176 |     li      a0,     BOOT_LOADER_LBA | 
|---|
| 177 |     jalr    k0 | 
|---|
| 178 |     nop | 
|---|
| 179 |  | 
|---|
| 180 |     /*  | 
|---|
| 181 |      * Processor O jumps to the entry address defined in the .elf file, | 
|---|
| 182 |      * and returned by reset_elf_loader function. | 
|---|
| 183 |      * First argument is pointer to the preloader function vectors | 
|---|
| 184 |      * other function arguments are 0 | 
|---|
| 185 |      */ | 
|---|
| 186 |  | 
|---|
| 187 |     la      a0,     preloader_vector | 
|---|
| 188 |     move    a1,     zero | 
|---|
| 189 |     move    a2,     zero | 
|---|
| 190 |     move    a3,     zero | 
|---|
| 191 |     jr      v0 | 
|---|
| 192 |     nop | 
|---|
| 193 |  | 
|---|
| 194 |     /* | 
|---|
| 195 |      * All processor (but processor 0) wait in low power mode  | 
|---|
| 196 |      * until processor 0 wakes them using an IPI. | 
|---|
| 197 |      * We have: | 
|---|
| 198 |      * t0: global id | 
|---|
| 199 |      * t1: local id | 
|---|
| 200 |      * t2: cluster id | 
|---|
| 201 |      * t3: xicu physical base address in cluster 0 | 
|---|
| 202 |      */ | 
|---|
| 203 |  | 
|---|
| 204 | _reset_wait: | 
|---|
| 205 |  | 
|---|
| 206 |     sll     t4,     t1,     2       /* t4 <= local_id * 4                 */ | 
|---|
| 207 |     addu    t5,     t4,     t3      /* t5 <= &XICU[WTI_REG][local_id]     */ | 
|---|
| 208 |  | 
|---|
| 209 |     wait | 
|---|
| 210 |  | 
|---|
| 211 |     /*  | 
|---|
| 212 |      * All other processors, when exiting wait mode, | 
|---|
| 213 |      * read from XICU the address to jump. | 
|---|
| 214 |      * This address is the boot-loader entry address that has been | 
|---|
| 215 |      * written in the mailbox by the IPI sent by processor 0 | 
|---|
| 216 |      */ | 
|---|
| 217 |  | 
|---|
| 218 |     mtc2    t2,     CP2_PADDR_EXT   /* set PADDR extension                */ | 
|---|
| 219 |     lw      k0,     0(t5)           /* k0 <= XICU[WTI_REG][local_id]      */ | 
|---|
| 220 |     mtc2    zero,   CP2_PADDR_EXT   /* reset PADDR extension              */ | 
|---|
| 221 |  | 
|---|
| 222 |     jr      k0 | 
|---|
| 223 |     nop | 
|---|
| 224 |  | 
|---|
| 225 | /* Exception entry point */ | 
|---|
| 226 |  | 
|---|
| 227 | .org 0x0380 | 
|---|
| 228 | _excep: | 
|---|
| 229 |     mfc0    a0, CP0_STATUS          /* first arg is status                */ | 
|---|
| 230 |     mfc0    a1, CP0_CAUSE           /* second arg is cause                */ | 
|---|
| 231 |     mfc0    a2, CP0_EPC             /* third argc is epc                  */ | 
|---|
| 232 |     mfc2    a3, CP2_DBVAR           /* fourth argc is dbvar               */ | 
|---|
| 233 |     nop | 
|---|
| 234 |     j       handle_except | 
|---|
| 235 |     nop | 
|---|
| 236 |  | 
|---|
| 237 |     .end reset | 
|---|
| 238 |  | 
|---|
| 239 |     .set reorder | 
|---|
| 240 |  | 
|---|
| 241 | /* | 
|---|
| 242 |  * vim: tabstop=4 : shiftwidth=4 : expandtab | 
|---|
| 243 |  */ | 
|---|