~ubuntu-branches/debian/stretch/grub2/stretch

« back to all changes in this revision

Viewing changes to boot/mips/yeeloong/fwstart.S

Tags: upstream-1.98+20100705
ImportĀ upstreamĀ versionĀ 1.98+20100705

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  GRUB  --  GRand Unified Bootloader
 
3
 *  Copyright (C) 2000,2001,2002,2003,2004,2005,2007,2008,2009,2010  Free Software Foundation, Inc.
 
4
 *
 
5
 *  GRUB is free software: you can redistribute it and/or modify
 
6
 *  it under the terms of the GNU General Public License as published by
 
7
 *  the Free Software Foundation, either version 3 of the License, or
 
8
 *  (at your option) any later version.
 
9
 *
 
10
 *  GRUB is distributed in the hope that it will be useful,
 
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 *  GNU General Public License for more details.
 
14
 *
 
15
 *  You should have received a copy of the GNU General Public License
 
16
 *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 
17
 */
 
18
 
 
19
#include <grub/mips/yeeloong/serial.h>
 
20
#include <grub/mips/yeeloong/pci.h>
 
21
#include <grub/mips/loongson.h>
 
22
#include <grub/pci.h>
 
23
#include <grub/serial.h>
 
24
#include <grub/cs5536.h>
 
25
#include <grub/smbus.h>
 
26
 
 
27
        .set noreorder
 
28
        .set noat
 
29
        .set nomacro
 
30
 
 
31
        .global start,_start,__start
 
32
start:
 
33
_start:
 
34
__start:        
 
35
        bal serial_hw_init
 
36
         nop
 
37
        /* Find CS5536 controller.  */
 
38
        /* $t4 chooses device in priority encoding.  */
 
39
        /* Resulting value is kept in GRUB_MACHINE_PCI_CONF_CTRL_REG.
 
40
           This way we don't need to sacrifice a register for it.  */
 
41
        /* We have only one bus (0). Function is 0.  */
 
42
        lui $t0, %hi(GRUB_MACHINE_PCI_CONF_CTRL_REG_ADDR)
 
43
        lui $t1, %hi(GRUB_MACHINE_PCI_CONFSPACE)
 
44
        lui $t3, %hi(GRUB_CS5536_PCIID)
 
45
        addiu $t3, $t3, %lo(GRUB_CS5536_PCIID)
 
46
        ori $t4, $zero, 1
 
47
        lui $a0, %hi(no_cs5536)
 
48
1:
 
49
        andi $t4, $t4, ((1 << GRUB_PCI_NUM_DEVICES) - 1)
 
50
        beql  $t4, $zero, fatal
 
51
         addiu $a0, $a0, %lo(no_cs5536)
 
52
        sw   $t4, %lo(GRUB_MACHINE_PCI_CONF_CTRL_REG_ADDR) ($t0)
 
53
        lw   $t2, (%lo(GRUB_MACHINE_PCI_CONFSPACE) + GRUB_PCI_REG_PCI_ID) ($t1)
 
54
        bnel  $t2, $t3, 1b
 
55
         sll $t4, $t4, 1
 
56
 
 
57
        bal message
 
58
         addiu $a0, $a0, %lo(cs5536_found)
 
59
        bal printhex
 
60
         move $a0, $t4
 
61
 
 
62
        /* Initialise SMBus controller.  */
 
63
        /* Set GPIO LBAR.  */
 
64
        lui $a0, %hi(GRUB_CS5536_MSR_GPIO_BAR)
 
65
        addiu $a0, $a0, %lo(GRUB_CS5536_MSR_GPIO_BAR)
 
66
        ori $a1, $zero, GRUB_CS5536_LBAR_GPIO
 
67
        /* Set mask to 0xf and enabled bit to 1.  */
 
68
        bal wrmsr
 
69
         ori $a2, $zero, ((GRUB_CS5536_LBAR_MASK_MASK \
 
70
                          | GRUB_CS5536_LBAR_ENABLE) >> 32)
 
71
 
 
72
        /* Set SMBUS LBAR.  */
 
73
        lui $a0, %hi(GRUB_CS5536_MSR_SMB_BAR)
 
74
        addiu $a0, $a0, %lo(GRUB_CS5536_MSR_SMB_BAR)
 
75
        ori $a1, $zero, GRUB_CS5536_LBAR_SMBUS
 
76
        /* Set mask to 0xf and enabled bit to 1.  */
 
77
        bal wrmsr
 
78
         ori $a2, $zero, ((GRUB_CS5536_LBAR_MASK_MASK \
 
79
                           | GRUB_CS5536_LBAR_ENABLE) >> 32)
 
80
 
 
81
        lui $a0, %hi(smbus_enabled)
 
82
        bal message
 
83
          addiu $a0, $a0, %lo(smbus_enabled)
 
84
 
 
85
        /* Enable SMBus controller pins.  */
 
86
        lui $t0, %hi(GRUB_MACHINE_PCI_IO_BASE + GRUB_CS5536_LBAR_GPIO)
 
87
        ori $t1, $zero, GRUB_GPIO_SMBUS_PINS
 
88
        sw  $t1, %lo(GRUB_MACHINE_PCI_IO_BASE + GRUB_CS5536_LBAR_GPIO + GRUB_GPIO_REG_OUT_EN) ($t0)
 
89
        sw  $t1, %lo(GRUB_MACHINE_PCI_IO_BASE + GRUB_CS5536_LBAR_GPIO + GRUB_GPIO_REG_OUT_AUX1) ($t0)
 
90
        sw  $t1, %lo(GRUB_MACHINE_PCI_IO_BASE + GRUB_CS5536_LBAR_GPIO + GRUB_GPIO_REG_IN_EN) ($t0)
 
91
        sw  $t1, %lo(GRUB_MACHINE_PCI_IO_BASE + GRUB_CS5536_LBAR_GPIO + GRUB_GPIO_REG_IN_AUX1) ($t0)
 
92
 
 
93
        lui $t0, %hi(GRUB_MACHINE_PCI_IO_BASE + GRUB_CS5536_LBAR_SMBUS)
 
94
 
 
95
        /* Disable SMB.  */
 
96
        sb $zero, %lo(GRUB_MACHINE_PCI_IO_BASE + GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_CTRL2) ($t0)
 
97
 
 
98
        /* Disable interrupts.  */
 
99
        sb $zero, %lo(GRUB_MACHINE_PCI_IO_BASE + GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_CTRL1) ($t0)
 
100
 
 
101
        /* Set as master.  */
 
102
        sb $zero, %lo(GRUB_MACHINE_PCI_IO_BASE + GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_ADDR) ($t0)
 
103
 
 
104
        /* Launch SMBus controller at slowest speed possible.  */
 
105
        ori $t1, $zero, 0xff
 
106
        sb $t1, %lo(GRUB_MACHINE_PCI_IO_BASE + GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_CTRL3) ($t0)
 
107
        sb $t1, %lo(GRUB_MACHINE_PCI_IO_BASE + GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_CTRL2) ($t0)
 
108
 
 
109
        /* Yeeloong has only one memory slot.  */
 
110
        /* Output first byte on serial for debugging.  */
 
111
        ori $a1, $zero, GRUB_SMB_RAM_START_ADDR
 
112
        bal read_spd
 
113
         move $a0, $zero
 
114
        bal printhex
 
115
         move $a0, $v0
 
116
 
 
117
        bal read_spd
 
118
         ori $a0, $zero, GRUB_SMBUS_SPD_MEMORY_TYPE_ADDR
 
119
        ori $t0, $zero, GRUB_SMBUS_SPD_MEMORY_TYPE_DDR2
 
120
        lui $a0, %hi(unimplemented_memory_type)
 
121
        bne $t0, $v0, fatal
 
122
         addiu $a0, $a0, %hi(unimplemented_memory_type)
 
123
 
 
124
        /* And here is our goal: DDR2 controller initialisation.  */
 
125
        lui     $t0, %hi(GRUB_CPU_LOONGSON_CORECFG)
 
126
        ld      $t1, %lo(GRUB_CPU_LOONGSON_CORECFG) ($t0)
 
127
        /* Use addiu for sign-extension.  */
 
128
        addiu   $t2, $zero, ~(GRUB_CPU_LOONGSON_CORECFG_DISABLE_DDR2_SPACE|GRUB_CPU_LOONGSON_CORECFG_BUFFER_CPU)
 
129
        and     $t1, $t1, $t2
 
130
        sd      $t1, %lo (GRUB_CPU_LOONGSON_CORECFG) ($t0)
 
131
 
 
132
        b continue
 
133
 
 
134
        . = start + GRUB_CPU_LOONGSON_FLASH_TLB_REFILL - GRUB_CPU_LOONGSON_FLASH_START
 
135
tlb_refill:     
 
136
        mfc0 $s1, GRUB_CPU_LOONGSON_COP0_EPC
 
137
        mfc0 $s2, GRUB_CPU_LOONGSON_COP0_BADVADDR
 
138
        move $s3, $ra
 
139
        lui $a0, %hi(epc)
 
140
        bal message
 
141
         addiu $a0, $a0, %lo(epc)
 
142
 
 
143
        bal printhex
 
144
         move $a0, $s1
 
145
 
 
146
        lui $a0, %hi(badvaddr)
 
147
        bal message
 
148
         addiu $a0, $a0, %lo(badvaddr)
 
149
 
 
150
        bal printhex
 
151
         move $a0, $s2
 
152
 
 
153
        lui $a0, %hi(return_msg)
 
154
        bal message
 
155
         addiu $a0, $a0, %lo(return_msg)
 
156
 
 
157
        bal printhex
 
158
         move $a0, $s3
 
159
        
 
160
        lui $a0, %hi(newline)
 
161
        bal message
 
162
         addiu $a0, $a0, %lo(newline)
 
163
 
 
164
        lui $a0, %hi(unhandled_tlb_refill)
 
165
        b fatal
 
166
         addiu $a0, $a0, %lo(unhandled_tlb_refill)
 
167
 
 
168
        . = start + GRUB_CPU_LOONGSON_FLASH_CACHE_ERROR - GRUB_CPU_LOONGSON_FLASH_START
 
169
cache_error:
 
170
        lui $a0, %hi(unhandled_cache_error)
 
171
        b fatal
 
172
         addiu $a0, $a0, %lo(unhandled_cache_error)
 
173
 
 
174
        . = start + GRUB_CPU_LOONGSON_FLASH_OTHER_EXCEPTION - GRUB_CPU_LOONGSON_FLASH_START
 
175
other_exception:
 
176
        mfc0 $s0, GRUB_CPU_LOONGSON_COP0_CAUSE
 
177
        mfc0 $s1, GRUB_CPU_LOONGSON_COP0_EPC
 
178
        mfc0 $s2, GRUB_CPU_LOONGSON_COP0_BADVADDR
 
179
        lui $a0, %hi(cause)
 
180
        bal message
 
181
         addiu $a0, $a0, %lo(cause)
 
182
 
 
183
        bal printhex
 
184
         move $a0, $s0
 
185
 
 
186
        lui $a0, %hi(epc)
 
187
        bal message
 
188
         addiu $a0, $a0, %lo(epc)
 
189
 
 
190
        bal printhex
 
191
         move $a0, $s1
 
192
 
 
193
        lui $a0, %hi(badvaddr)
 
194
        bal message
 
195
         addiu $a0, $a0, %lo(badvaddr)
 
196
 
 
197
        bal printhex
 
198
         move $a0, $s2
 
199
        
 
200
        lui $a0, %hi(newline)
 
201
        bal message
 
202
         addiu $a0, $a0, %lo(newline)
 
203
        
 
204
        lui $a0, %hi(unhandled_exception)
 
205
        b fatal
 
206
         addiu $a0, $a0, %lo(unhandled_exception)
 
207
 
 
208
        /* Same as similarly named C function but in asm since
 
209
           we need it early.  */
 
210
        /* In: none. Out: none. Clobbered: $t0, $t1, $a0.  */
 
211
serial_hw_init:
 
212
        lui $t0, %hi (GRUB_MACHINE_SERIAL_PORT)
 
213
 
 
214
        /* Turn off the interrupt.  */
 
215
        sb $zero, (%lo (GRUB_MACHINE_SERIAL_PORT) + UART_IER)($t0)
 
216
 
 
217
        /* Set DLAB.  */
 
218
        ori $t1, $zero, UART_DLAB
 
219
        sb  $t1, (%lo (GRUB_MACHINE_SERIAL_PORT) + UART_LCR)($t0)
 
220
 
 
221
        /* Set the baud rate 115200.  */
 
222
        ori $t1, $zero, GRUB_MACHINE_SERIAL_DIVISOR_115200
 
223
        sb $t1, (%lo (GRUB_MACHINE_SERIAL_PORT) + UART_DLL)($t0) 
 
224
        sb $zero, (%lo (GRUB_MACHINE_SERIAL_PORT) + UART_DLH)($t0) 
 
225
 
 
226
        /* Set the line status.  */
 
227
        ori $t1, $zero, (UART_NO_PARITY | UART_8BITS_WORD | UART_1_STOP_BIT)
 
228
        sb  $t1, (%lo (GRUB_MACHINE_SERIAL_PORT) + UART_LCR)($t0)
 
229
 
 
230
        /* Enable the FIFO.  */
 
231
        ori $t1, $zero, UART_ENABLE_FIFO_TRIGGER1
 
232
        sb $t1, (%lo (GRUB_MACHINE_SERIAL_PORT) + UART_FCR)($t0)
 
233
 
 
234
        /* Turn on DTR and RTS.  */
 
235
        ori $t1, $zero, UART_ENABLE_DTRRTS
 
236
        sb  $t1, (%lo (GRUB_MACHINE_SERIAL_PORT) + UART_MCR)($t0)
 
237
 
 
238
        /* Let message return to original caller.  */
 
239
        lui  $a0, %hi(notification_string)
 
240
        addiu $a0, $a0, %lo(notification_string)
 
241
 
 
242
        /* Print message on serial console.  */
 
243
        /* In: $a0 = asciiz message. Out: none. Clobbered: $t0, $t1, $a0.  */
 
244
message:
 
245
        lui $t0, %hi (GRUB_MACHINE_SERIAL_PORT)
 
246
1:
 
247
        lb $t1, (%lo (GRUB_MACHINE_SERIAL_PORT) + UART_LSR)($t0)
 
248
        andi $t1, $t1, UART_EMPTY_TRANSMITTER
 
249
        beq $t1, $zero, 1b
 
250
         nop
 
251
        lb  $t1, 0($a0)
 
252
        sb  $t1, (%lo (GRUB_MACHINE_SERIAL_PORT) + UART_TX)($t0)
 
253
        bne $t1, $zero, 1b
 
254
         addiu $a0, $a0, 1
 
255
        jr  $ra
 
256
         nop
 
257
        
 
258
        /* Print 32-bit hexadecimal on serial.
 
259
           In:  $a0. Out: None. Clobbered: $a0, $t0, $t1, $t2
 
260
        */
 
261
printhex:
 
262
        lui $t0, %hi  (GRUB_MACHINE_SERIAL_PORT)
 
263
        ori $t2, $zero, 8
 
264
1:
 
265
        lb $t1, (%lo (GRUB_MACHINE_SERIAL_PORT) + UART_LSR)($t0)
 
266
        andi $t1, $t1, UART_EMPTY_TRANSMITTER
 
267
        beq $t1, $zero, 1b
 
268
         nop
 
269
        srl  $t1, $a0, 28
 
270
        addiu $t1, $t1, -10
 
271
        blt  $t1, $zero, 2f
 
272
         sll  $a0, $a0, 4
 
273
        addiu $t1, $t1, 'A'-10-'0' 
 
274
2:      addiu $t1, $t1, '0'+10
 
275
        sb  $t1, (%lo (GRUB_MACHINE_SERIAL_PORT) + UART_TX)($t0)
 
276
        addiu $t2, $t2, -1
 
277
        bne $t2, $zero, 1b
 
278
         nop
 
279
        jr  $ra
 
280
         nop
 
281
 
 
282
fatal:
 
283
        bal message
 
284
         nop
 
285
self:
 
286
        b self
 
287
         nop
 
288
        
 
289
        /* Write CS5536 MSR.
 
290
           In:   $a0 address, $a1 lower word, $a2 upper word.
 
291
           Out:  None
 
292
           Clobbered:    $t0
 
293
        */
 
294
wrmsr:
 
295
        lui $t0, %hi(GRUB_MACHINE_PCI_CONFSPACE)
 
296
        sw  $a0, (%lo(GRUB_MACHINE_PCI_CONFSPACE) + GRUB_CS5536_MSR_MAILBOX_ADDR) ($t0)
 
297
        sw  $a1, (%lo(GRUB_MACHINE_PCI_CONFSPACE) + GRUB_CS5536_MSR_MAILBOX_DATA0) ($t0)
 
298
        jr $ra
 
299
         sw  $a2, (%lo(GRUB_MACHINE_PCI_CONFSPACE) + GRUB_CS5536_MSR_MAILBOX_DATA1) ($t0)
 
300
 
 
301
        /* Wait for SMBus data or empty transmitter.  */
 
302
        /* In: $a0 = exception handler. Out: none. Clobbered: $t0, $t1  */
 
303
smbus_wait:
 
304
1:      
 
305
        lui $t0, %hi(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_STATUS + GRUB_MACHINE_PCI_IO_BASE)
 
306
        lb $t0, %lo(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_STATUS + GRUB_MACHINE_PCI_IO_BASE) ($t0)
 
307
        andi $t1, $t0, GRUB_CS5536_SMB_REG_STATUS_SDAST
 
308
        bne $t1, $zero, return
 
309
         nop
 
310
        andi $t1, $t0, (GRUB_CS5536_SMB_REG_STATUS_BER | GRUB_CS5536_SMB_REG_STATUS_NACK)
 
311
        beq $t1, $zero, 1b
 
312
         nop
 
313
        jr $a0
 
314
         nop
 
315
return:
 
316
        jr $ra
 
317
         nop
 
318
        
 
319
        /* Read SPD byte. In: $a0 byte, $a1 device. Out: $v0 read byte (0x100 on failure).
 
320
           Clobbered: $t0, $t1, $t2, $t3, $a0. */
 
321
read_spd:
 
322
        move $t2, $a0
 
323
        move $t3, $ra
 
324
        lui $a0, %hi(read_spd_fail)
 
325
        addiu $a0, $a0, %hi(read_spd_fail)
 
326
 
 
327
        /* Send START.  */
 
328
        lui $t0, %hi(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_CTRL1 + GRUB_MACHINE_PCI_IO_BASE)
 
329
        lb $t1, %lo(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_CTRL1 + GRUB_MACHINE_PCI_IO_BASE) ($t0)
 
330
        ori $t1, $t1, GRUB_CS5536_SMB_REG_CTRL1_START
 
331
        bal smbus_wait
 
332
         sb $t1, %lo(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_CTRL1 + GRUB_MACHINE_PCI_IO_BASE) ($t0)
 
333
        
 
334
        /* Send device address.  */
 
335
        lui $t0, %hi(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_DATA + GRUB_MACHINE_PCI_IO_BASE)
 
336
        sll $t1, $a1, 1
 
337
        bal smbus_wait
 
338
         sb $t1, %lo(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_DATA + GRUB_MACHINE_PCI_IO_BASE) ($t0)
 
339
 
 
340
        /* Send ACK.  */
 
341
        lui $t0, %hi(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_CTRL1 + GRUB_MACHINE_PCI_IO_BASE)
 
342
        lb $t1, %lo(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_CTRL1 + GRUB_MACHINE_PCI_IO_BASE) ($t0)
 
343
        ori $t1, $t1, GRUB_CS5536_SMB_REG_CTRL1_ACK
 
344
        sb $t1, %lo(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_CTRL1 + GRUB_MACHINE_PCI_IO_BASE) ($t0)
 
345
 
 
346
        /* Send byte address.  */
 
347
        lui $t0, %hi(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_DATA + GRUB_MACHINE_PCI_IO_BASE)
 
348
        bal smbus_wait
 
349
         sb $t2, %lo(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_DATA + GRUB_MACHINE_PCI_IO_BASE) ($t0)
 
350
 
 
351
        /* Send START.  */
 
352
        lui $t0, %hi(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_CTRL1 + GRUB_MACHINE_PCI_IO_BASE)
 
353
        lb $t1, %lo(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_CTRL1 + GRUB_MACHINE_PCI_IO_BASE) ($t0)
 
354
        ori $t1, $t1, GRUB_CS5536_SMB_REG_CTRL1_START
 
355
        bal smbus_wait
 
356
         sb $t1, %lo(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_CTRL1 + GRUB_MACHINE_PCI_IO_BASE) ($t0)
 
357
 
 
358
        /* Send device address.  */
 
359
        lui $t0, %hi(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_DATA + GRUB_MACHINE_PCI_IO_BASE)
 
360
        sll $t1, $a1, 1
 
361
        ori $t1, $t1, 1
 
362
        bal smbus_wait
 
363
         sb $t1, %lo(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_DATA + GRUB_MACHINE_PCI_IO_BASE) ($t0)
 
364
 
 
365
        /* Send STOP.  */
 
366
        lui $t0, %hi(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_CTRL1 + GRUB_MACHINE_PCI_IO_BASE)
 
367
        lb $t1, %lo(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_CTRL1 + GRUB_MACHINE_PCI_IO_BASE) ($t0)
 
368
        ori $t1, $t1, GRUB_CS5536_SMB_REG_CTRL1_STOP
 
369
        bal smbus_wait
 
370
         sb $t1, %lo(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_CTRL1 + GRUB_MACHINE_PCI_IO_BASE) ($t0)
 
371
 
 
372
        lui $t0, %hi(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_DATA + GRUB_MACHINE_PCI_IO_BASE)
 
373
        lb $v0, %lo(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_DATA + GRUB_MACHINE_PCI_IO_BASE) ($t0)
 
374
        jr $t3
 
375
         andi $v0, $v0, 0xff
 
376
read_spd_fail:
 
377
        jr $t3
 
378
         ori $v0, $v0, 0x100
 
379
 
 
380
notification_string:    .asciz "GRUB "
 
381
no_cs5536:      .asciz "No CS5536 found.\n\r"
 
382
cs5536_found:   .asciz "CS5536 at "
 
383
sm_failed: .asciz "SM transaction failed.\n\r"
 
384
unhandled_tlb_refill:   .asciz "Unhandled TLB refill.\n\r"
 
385
unhandled_cache_error:  .asciz "Unhandled cache error.\n\r"
 
386
unhandled_exception:    .asciz "Unhandled exception.\n\r"
 
387
smbus_enabled:  .asciz "SMBus controller enabled.\n\r"
 
388
unimplemented_memory_type:      .asciz "non-DDR2 memory isn't supported.\n\r"
 
389
no_cas_latency:         .asciz "Couldn't determine CAS latency.\n\r"
 
390
cause:   .asciz "Cause: "
 
391
epc:    .asciz "\n\rEPC: "
 
392
badvaddr:       .asciz "\n\rBadVaddr: "
 
393
newline:        .asciz "\n\r"
 
394
return_msg:       .asciz "\n\rReturn address: "
 
395
caches_enabled: .asciz "Caches enabled\n\r"
 
396
 
 
397
        .p2align 3
 
398
 
 
399
regdump:
 
400
        .quad 0x0100010000000101 /* 0 */
 
401
        .quad 0x0100010100000000 /* 2 */
 
402
        .quad 0x0101000001000000 /* 3 */
 
403
        .quad 0x0100020200010101 /* 4 */
 
404
        .quad 0x0a04030603050203 /* 6 */
 
405
        .quad 0x0f0e040000010a0b /* 7 */
 
406
        .quad 0x0000010200000102 /* 8 */
 
407
        .quad 0x0000060c00000000 /* 9 */
 
408
        .quad 0x2323233f3f1f0200 /* a */
 
409
        .quad 0x5f7f232323232323 /* b */
 
410
        .quad 0x002a3c0615000000 /* c */
 
411
        .quad 0x002a002a002a002a /* d */
 
412
        .quad 0x002a002a002a002a /* e */
 
413
        .quad 0x00b40020006d0004 /* f */
 
414
        .quad 0x070007ff00000087 /* 10 */
 
415
        .quad 0x000000000016101f /* 11 */
 
416
        .quad 0x001c000000000000 /* 12 */
 
417
        .quad 0x28e1000200c8006b /* 13 */
 
418
        .quad 0x0000204200c8002f /* 14 */
 
419
        .quad 0x0000000000030d40 /* 15 */
 
420
        .quad 0 /* 16 */
 
421
        .quad 0 /* 17 */
 
422
        .quad 0 /* 18 */
 
423
        .quad 0 /* 19 */
 
424
        .quad 0 /* 1a */
 
425
        .quad 0 /* 1b */
 
426
        .quad 0 /* 1c */
 
427
 
 
428
        .p2align
 
429
 
 
430
write_dumpreg:  
 
431
        ld $t2, 0($t6)
 
432
        sd $t2, 0($t4)
 
433
        addiu $t4, $t4, GRUB_CPU_LOONGSON_DDR2_REG_STEP
 
434
        jr $ra
 
435
         addiu $t6, $t6, GRUB_CPU_LOONGSON_DDR2_REG_SIZE
 
436
 
 
437
continue:
 
438
        lui $t4, %hi(GRUB_CPU_LOONGSON_DDR2_BASE)
 
439
        addiu $t4, $t4, %lo(GRUB_CPU_LOONGSON_DDR2_BASE)
 
440
        lui $t6, %hi(regdump)
 
441
 
 
442
        /* 0 */
 
443
        bal write_dumpreg
 
444
         addiu $t6, $t6, %lo(regdump)
 
445
 
 
446
        /* 1 */
 
447
        ori $a1, $a1, GRUB_SMB_RAM_START_ADDR
 
448
        move $t8, $zero
 
449
        lui  $t5, 0x0001
 
450
        bal read_spd
 
451
         ori $a0, $zero, GRUB_SMBUS_SPD_MEMORY_NUM_BANKS_ADDR
 
452
        ori $t7, $zero, 8
 
453
        bne $v0, $t7, 1f
 
454
         ori $t5, $t5, 0x0001
 
455
        ori $t8, $t8, GRUB_CPU_LOONGSON_DDR2_REG1_HI_8BANKS
 
456
1:
 
457
        dsll $t8, $t8, 32
 
458
        or $t5, $t5, $t8
 
459
        sd  $t5, 0 ($t4)
 
460
        addiu $t4, $t4, GRUB_CPU_LOONGSON_DDR2_REG_STEP
 
461
 
 
462
        /* 2 */
 
463
        bal write_dumpreg
 
464
         nop
 
465
 
 
466
        /* 3 */
 
467
        bal write_dumpreg
 
468
         nop
 
469
 
 
470
        /* 4 */
 
471
        bal write_dumpreg
 
472
         nop
 
473
 
 
474
        /* 5 */
 
475
        /* FIXME: figure termination resistance.  */
 
476
        ori $t5, $zero, 0x2
 
477
        bal read_spd
 
478
         ori $a0, $zero, GRUB_SMBUS_SPD_MEMORY_NUM_ROWS_ADDR
 
479
        /* $v0 = 15 - $v0.  */
 
480
        xori $v0, $v0, 0xf
 
481
        andi $v0, $v0, 0x7
 
482
        sll $v0, $v0, 8
 
483
        or $t5, $t5, $v0
 
484
 
 
485
        /* Find the fastest supported CAS latency.  */
 
486
        bal read_spd
 
487
         ori $a0, $zero, GRUB_SMBUS_SPD_MEMORY_CAS_LATENCY_ADDR
 
488
        ori $t0, $zero, GRUB_SMBUS_SPD_MEMORY_CAS_LATENCY_MIN_VALUE
 
489
        ori $t1, $zero, (1 << GRUB_SMBUS_SPD_MEMORY_CAS_LATENCY_MIN_VALUE)
 
490
2:      
 
491
        and $t2, $t1, $v0
 
492
        bne $t2, $zero, 1f
 
493
         ori $t3, $zero, 8
 
494
        lui $a0, %hi(no_cas_latency)
 
495
        beq $t0, $t3, fatal
 
496
         addiu $a0, $a0, %lo(no_cas_latency)
 
497
        addiu $t0, $t0, 1
 
498
        b 2b
 
499
         sll $t1, $t1, 1
 
500
1:
 
501
        sll $t0, $t0, 16
 
502
        or $t5, $t5, $t0
 
503
        
 
504
        bal read_spd
 
505
         ori $a0, $zero, GRUB_SMBUS_SPD_MEMORY_NUM_COLUMNS_ADDR
 
506
        /* $v0 = 15 - ($v0 + 1) = 14 - $v0.  */
 
507
        addiu $v0, $v0, 1
 
508
        xori $v0, $v0, 0xf
 
509
        andi $v0, $v0, 0x7
 
510
        sll $v0, 24
 
511
        or $t5, $t5, $v0
 
512
        sd  $t5, 0 ($t4)
 
513
 
 
514
        addiu $t4, $t4, GRUB_CPU_LOONGSON_DDR2_REG_STEP
 
515
        
 
516
        ori $t7, $zero, 0x16
 
517
 
 
518
1:      
 
519
        ld $t2, 0($t6)
 
520
        sd $t2, 0($t4)
 
521
        addiu $t4, $t4, GRUB_CPU_LOONGSON_DDR2_REG_STEP
 
522
        addiu $t7, $t7, -1
 
523
        bne $t7, $zero, 1b
 
524
         addiu $t6, $t6, GRUB_CPU_LOONGSON_DDR2_REG_SIZE
 
525
        
 
526
        lui $t4, %hi(GRUB_CPU_LOONGSON_DDR2_BASE)
 
527
        ld  $t5, (%lo(GRUB_CPU_LOONGSON_DDR2_BASE) + 0x30) ($t4)
 
528
        ori $t0, $zero, 1
 
529
        dsll $t0, $t0, 40
 
530
        or $t5, $t5, $t0
 
531
        sd  $t5, (%lo(GRUB_CPU_LOONGSON_DDR2_BASE) + 0x30) ($t4)
 
532
 
 
533
        /* Desactivate DDR2 registers.  */
 
534
        lui     $t0, %hi (GRUB_CPU_LOONGSON_CORECFG)
 
535
        ld      $t1, %lo (GRUB_CPU_LOONGSON_CORECFG) ($t0)
 
536
        ori     $t1, $t1, GRUB_CPU_LOONGSON_CORECFG_DISABLE_DDR2_SPACE
 
537
        sd      $t1, %lo (GRUB_CPU_LOONGSON_CORECFG) ($t0)
 
538
 
 
539
        /* Enable cache.  */
 
540
        mfc0    $t0, GRUB_CPU_LOONGSON_COP0_CACHE_CONFIG
 
541
        addiu   $t1, $zero, ~GRUB_CPU_LOONGSON_CACHE_TYPE_MASK
 
542
        and     $t0, $t1, $t1
 
543
        /* Set line size to 32 bytes and disabled cache.  */
 
544
        ori     $t0, $t0, (GRUB_CPU_LOONGSON_COP0_CACHE_CONFIG_ILINESIZE \
 
545
                           | GRUB_CPU_LOONGSON_COP0_CACHE_CONFIG_DLINESIZE \
 
546
                           | GRUB_CPU_LOONGSON_CACHE_ACCELERATED)
 
547
        mtc0    $t0, GRUB_CPU_LOONGSON_COP0_CACHE_CONFIG
 
548
 
 
549
        /* Invalidate all I-cache entries.  */
 
550
        srl $t1, $t0, GRUB_CPU_LOONGSON_COP0_CACHE_ISIZE_SHIFT
 
551
        andi $t1, $t1, GRUB_CPU_LOONGSON_COP0_CACHE_SIZE_MASK
 
552
        ori $t2, $zero, (1 << (GRUB_CPU_LOONGSON_COP0_CACHE_SIZE_OFFSET \
 
553
                               - GRUB_CPU_LOONGSON_CACHE_LINE_SIZE_LOG_BIG \
 
554
                               - GRUB_CPU_LOONGSON_I_CACHE_LOG_WAYS))
 
555
        sll $t1, $t2, $t1
 
556
        lui $t2, 0x8000
 
557
 
 
558
1:      
 
559
        cache GRUB_CPU_LOONGSON_COP0_I_INDEX_INVALIDATE, 0($t2)
 
560
        addiu $t1, $t1, -1
 
561
        bne $t1, $zero, 1b
 
562
         addiu $t2, $t2, (1 << GRUB_CPU_LOONGSON_COP0_I_INDEX_BIT_OFFSET)
 
563
 
 
564
        /* Invalidate all D-cache entries.  */
 
565
        srl $t1, $t0, GRUB_CPU_LOONGSON_COP0_CACHE_DSIZE_SHIFT
 
566
        andi $t1, $t1, GRUB_CPU_LOONGSON_COP0_CACHE_SIZE_MASK
 
567
        ori $t2, $zero, (1 << (GRUB_CPU_LOONGSON_COP0_CACHE_SIZE_OFFSET \
 
568
                               - GRUB_CPU_LOONGSON_CACHE_LINE_SIZE_LOG_BIG \
 
569
                               - GRUB_CPU_LOONGSON_D_CACHE_LOG_WAYS))
 
570
        sll $t1, $t2, $t1
 
571
        lui $t2, 0x8000
 
572
        mtc0 $zero, GRUB_CPU_LOONGSON_COP0_CACHE_TAGLO
 
573
        mtc0 $zero, GRUB_CPU_LOONGSON_COP0_CACHE_TAGHI
 
574
1:
 
575
        /* All four ways.  */
 
576
        cache GRUB_CPU_LOONGSON_COP0_D_INDEX_TAG_STORE, 0($t2)
 
577
        cache GRUB_CPU_LOONGSON_COP0_D_INDEX_TAG_STORE, 1($t2)
 
578
        cache GRUB_CPU_LOONGSON_COP0_D_INDEX_TAG_STORE, 2($t2)
 
579
        cache GRUB_CPU_LOONGSON_COP0_D_INDEX_TAG_STORE, 3($t2)
 
580
        addiu $t1, $t1, -1
 
581
        bne $t1, $zero, 1b
 
582
         addiu $t2, $t2, (1 << GRUB_CPU_LOONGSON_COP0_D_INDEX_BIT_OFFSET)
 
583
 
 
584
        /* Invalidate all S-cache entries.  */
 
585
        ori $t1, $zero, (1 << (GRUB_CPU_LOONGSON_SECONDARY_CACHE_LOG_SIZE \
 
586
                               - GRUB_CPU_LOONGSON_CACHE_LINE_SIZE_LOG_BIG \
 
587
                               - GRUB_CPU_LOONGSON_S_CACHE_LOG_WAYS))
 
588
        lui $t2, 0x8000
 
589
        mtc0 $zero, GRUB_CPU_LOONGSON_COP0_CACHE_TAGLO
 
590
        mtc0 $zero, GRUB_CPU_LOONGSON_COP0_CACHE_TAGHI
 
591
1:
 
592
        /* All four ways.  */
 
593
        cache GRUB_CPU_LOONGSON_COP0_S_INDEX_TAG_STORE, 0($t2)
 
594
        cache GRUB_CPU_LOONGSON_COP0_S_INDEX_TAG_STORE, 1($t2)
 
595
        cache GRUB_CPU_LOONGSON_COP0_S_INDEX_TAG_STORE, 2($t2)
 
596
        cache GRUB_CPU_LOONGSON_COP0_S_INDEX_TAG_STORE, 3($t2)
 
597
        addiu $t1, $t1, -1
 
598
        bne $t1, $zero, 1b
 
599
         addiu $t2, $t2, (1 << GRUB_CPU_LOONGSON_COP0_D_INDEX_BIT_OFFSET)
 
600
        
 
601
        /* Finally enable cache.  */
 
602
        mfc0    $t0, GRUB_CPU_LOONGSON_COP0_CACHE_CONFIG
 
603
        addiu   $t1, $zero, ~GRUB_CPU_LOONGSON_CACHE_TYPE_MASK
 
604
        and     $t0, $t1, $t1
 
605
        ori     $t0, $t0, GRUB_CPU_LOONGSON_CACHE_CACHED
 
606
        mtc0    $t0, GRUB_CPU_LOONGSON_COP0_CACHE_CONFIG
 
607
 
 
608
        lui $a0, %hi(caches_enabled)
 
609
        bal message
 
610
          addiu $a0, $a0, %lo(caches_enabled)
 
611
 
 
612
        /* Set ROM delay cycles to 1.  */
 
613
        lui $t0, %hi(GRUB_CPU_LOONGSON_LIOCFG)
 
614
        lw  $t1, %lo(GRUB_CPU_LOONGSON_LIOCFG) ($t0)
 
615
        addiu $t2, $zero, ~(GRUB_CPU_LOONGSON_ROM_DELAY_MASK \
 
616
                            << GRUB_CPU_LOONGSON_ROM_DELAY_OFFSET)
 
617
        and $t1, $t1, $t2
 
618
        ori $t1, $t1, (1 << GRUB_CPU_LOONGSON_ROM_DELAY_OFFSET)
 
619
        sw  $t1, %lo(GRUB_CPU_LOONGSON_LIOCFG) ($t0)
 
620
        
 
621
        addiu $a0, $zero, -1
 
622
        addiu $a1, $zero, -1
 
623
 
 
624
        /* Take advantage of cache.  */
 
625
        lui $t0, %hi(cached_continue - 0x20000000)
 
626
        addiu $t0, $t0, %lo(cached_continue - 0x20000000)
 
627
        jr $t0
 
628
         addiu $a2, $zero, -1
 
629
 
 
630
cached_continue:
 
 
b'\\ No newline at end of file'