| 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 and seg_reset_stack_size parameters in ldscript. | 
|---|
| 13 | * - Processor 0 uses a larger stack:         64 Kbytes. | 
|---|
| 14 | * - Other processors use a smaller stack:    512 bytes. | 
|---|
| 15 | *     => the seg_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 | .extern seg_reset_stack_size | 
|---|
| 41 |  | 
|---|
| 42 | .section .reset,"ax",@progbits | 
|---|
| 43 |  | 
|---|
| 44 | .extern dtb_addr | 
|---|
| 45 | .extern reset_putc | 
|---|
| 46 | .extern reset_getc | 
|---|
| 47 | .extern reset_ioc_read | 
|---|
| 48 | .extern reset_elf_loader | 
|---|
| 49 | .extern memcpy | 
|---|
| 50 | .extern reset_puts | 
|---|
| 51 | .extern reset_putx | 
|---|
| 52 | .extern reset_putd | 
|---|
| 53 | .extern reset_ioc_init | 
|---|
| 54 | .extern versionstr | 
|---|
| 55 |  | 
|---|
| 56 | .globl  reset                    /* Makes reset an external symbol */ | 
|---|
| 57 | .ent    reset | 
|---|
| 58 |  | 
|---|
| 59 | .align  2 | 
|---|
| 60 | .set noreorder | 
|---|
| 61 |  | 
|---|
| 62 | reset: | 
|---|
| 63 | b       _reset                  /* 0xbfc0000 */ | 
|---|
| 64 | nop                             /* 0xbfc0004 */ | 
|---|
| 65 |  | 
|---|
| 66 | /*  Addresses of the functions provided by this reset code */ | 
|---|
| 67 |  | 
|---|
| 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 | #ifndef SOCLIB_IOC | 
|---|
| 161 |  | 
|---|
| 162 | /* Processor 0 Initialize the block device if required */ | 
|---|
| 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 | * All function arguments are 0 | 
|---|
| 184 | */ | 
|---|
| 185 |  | 
|---|
| 186 | move    a0,     zero | 
|---|
| 187 | move    a1,     zero | 
|---|
| 188 | move    a2,     zero | 
|---|
| 189 | move    a3,     zero | 
|---|
| 190 | jr      v0 | 
|---|
| 191 | nop | 
|---|
| 192 |  | 
|---|
| 193 | /* | 
|---|
| 194 | * All processor (but processor 0) wait in low power mode | 
|---|
| 195 | * until processor 0 wakes them using an IPI. | 
|---|
| 196 | * We have: | 
|---|
| 197 | * t0: global id | 
|---|
| 198 | * t1: local id | 
|---|
| 199 | * t2: cluster id | 
|---|
| 200 | * t3: xicu physical base address in cluster 0 | 
|---|
| 201 | */ | 
|---|
| 202 |  | 
|---|
| 203 | _reset_wait: | 
|---|
| 204 |  | 
|---|
| 205 | sll     t4,     t1,     2       /* t4 <= local_id * 4                 */ | 
|---|
| 206 | addu    t5,     t4,     t3      /* t5 <= &XICU[WTI_REG][local_id]     */ | 
|---|
| 207 |  | 
|---|
| 208 | wait | 
|---|
| 209 |  | 
|---|
| 210 | /* | 
|---|
| 211 | * All other processors, when exiting wait mode, | 
|---|
| 212 | * read from XICU the address to jump. | 
|---|
| 213 | * This address is the boot-loader entry address that has been | 
|---|
| 214 | * written in the mailbox by the IPI sent by processor 0 | 
|---|
| 215 | */ | 
|---|
| 216 |  | 
|---|
| 217 | mtc2    t2,     CP2_PADDR_EXT   /* set PADDR extension                */ | 
|---|
| 218 | lw      k0,     0(t5)           /* k0 <= XICU[WTI_REG][local_id]      */ | 
|---|
| 219 | mtc2    zero,   CP2_PADDR_EXT   /* reset PADDR extension              */ | 
|---|
| 220 |  | 
|---|
| 221 | jr      k0 | 
|---|
| 222 | nop | 
|---|
| 223 |  | 
|---|
| 224 | /* Exception entry point */ | 
|---|
| 225 |  | 
|---|
| 226 | .org 0x0380 | 
|---|
| 227 | _excep: | 
|---|
| 228 | mfc0    a0, CP0_STATUS          /* first arg is status                */ | 
|---|
| 229 | mfc0    a1, CP0_CAUSE           /* second arg is cause                */ | 
|---|
| 230 | mfc0    a2, CP0_EPC             /* third argc is epc                  */ | 
|---|
| 231 | nop | 
|---|
| 232 | j       handle_except | 
|---|
| 233 | nop | 
|---|
| 234 |  | 
|---|
| 235 | .end reset | 
|---|
| 236 |  | 
|---|
| 237 | .set reorder | 
|---|
| 238 |  | 
|---|
| 239 | /* | 
|---|
| 240 | * vim: tabstop=4 : shiftwidth=4 : expandtab | 
|---|
| 241 | */ | 
|---|