1/******************************************************************************
2 * Copyright (c) 2004, 2008 IBM Corporation
3 * All rights reserved.
4 * This program and the accompanying materials
5 * are made available under the terms of the BSD License
6 * which accompanies this distribution, and is available at
7 * http://www.opensource.org/licenses/bsd-license.php
8 *
9 * Contributors:
10 *     IBM Corporation - initial implementation
11 *****************************************************************************/
12
13# SLOF for JS20/JS21 -- ROM boot code.
14# Initial entry point, copy code from flash to cache, memory setup.
15# Also sets up serial console and optimizes some settings.
16
17#include "termctrl.h"
18#include <product.h>
19#include <xvect.h>
20#include <cpu.h>
21#include <macros.h>
22#include <southbridge.h>
23
24	.text
25	.globl __start
26__start:
27	/* put rombase in sprg1 ***********************/
28
29	bl	postHeader
30	.long 0xDEADBEE0
31	.long 0x0       /* size */
32	.long 0x0       /* crc  */
33	.long relTag - __start
34postHeader:
35	mflr	r3
36	li	r4, 0x7fff
37	not	r4, r4
38	and	r3, r3, r4
39	mtsprg	1, r3      /* romfs base */
40	bl	_start
41
42	.org 0x150 - 0x100
43__startSlave:
44	bl setup_cpu
45	bl set_ci_bit
46#	b slaveWithNumber
47	b slave
48
49	.org 0x180 - 0x100
50__startMaster:
51	li 3,0
52	mtsprg	1, r3      /* romfs base */
53	bl setup_cpu
54	bl set_ci_bit
55	b master
56
57
58	/* FIXME: Also need 0280, 0380, 0f20, etc. */
59
60	.irp i, 0x0100,0x0180,0x0200,0x0280,0x0300,0x0380,0x0400,0x0500,0x0600,0x0700, \
61		0x0800,0x0900,0x0a00,0x0b00,0x0c00,0x0d00,0x0e00,0x0f00, \
62		0x1000,0x1100,0x1200,0x1300,0x1400,0x1500,0x1600,0x1700, \
63		0x1800,0x1900,0x1a00,0x1b00,0x1c00,0x1d00,0x1e00,0x1f00, \
64		0x2000,0x2100,0x2200,0x2300,0x2400,0x2500,0x2600,0x2700, \
65		0x2800,0x2900,0x2a00,0x2b00,0x2c00,0x2d00,0x2e00
66	. = \i
67
68	/* enable this if you get exceptions before the console works    */
69	/* this will allow using the hardware debugger to see where      */
70	/* it traps, and with what register values etc.                  */
71	// b	$
72
73	mtsprg	0, r0
74	mfctr	r0
75	mtsprg  2,r0
76	mflr	r0
77// 10
78	mtsprg  3,r0
79	ld	r0, (\i + 0x160)(0)
80	mtctr	r0
81	li	r0, \i + 0x100
82// 20
83	bctr
84
85	. = \i + 0x60
86
87	.quad intHandler2C
88
89	.endr
90
91
92	. = XVECT_M_HANDLER - 0x100
93	.quad 0x00
94	. = XVECT_S_HANDLER - 0x100
95
96	.quad 0
97
98
99
100	.org 0x4000 - 0x100
101_start:
102	# optimize HID register settings
103	bl setup_cpu
104	bl set_ci_bit
105
106	# read semaphore, run as slave if not the first to do so
107	li 3,0 ; oris 3,3,0xf800 ; lwz 3,0x60(3) ; andi. 3,3,1 ; beq slave
108master:
109	# setup flash, serial
110	bl setup_sio
111
112	# early greet
113	li	r3, 10
114	bl	putc
115	li 3,13 ; bl putc ; li 3,10 ; bl putc ; li 3,'S' ; bl putc
116
117
118	#do we run from ram ?
119	mfsprg	r3, 1	/* rombase */
120	cmpdi	r3,0	/* rombase is 0 when running from RAM */
121
122	bne copy_to_cache
123
124	# wait a bit, start scripts are slow...  need to get all cores running!
125	lis 3,0x4000 ; mtctr 3 ; bdnz $
126
127	# copy 4MB from 0 to temp memory
128   lis 4,0x8 ; mtctr 4 ; lis 4,0x200  ; li 3,0 ; addi 4,4,-8 ; addi 3,3,-8
1290:	ldu 5,8(3) ; stdu 5,8(4) ; bdnz 0b
130
131	lis 4,0x200
132	mtsprg	1, r4
133
134	lis 4,0x1
135	lis 3,0x20 ; addi 3,3,0x200-8 ;
136	FLUSH_CACHE(r3, r4)
137
138	lis 4,0x200
139	addi 4,4,copy_to_cache@l
140	mtctr 4
141	bctr
142
143# make all data accesses cache-inhibited
144set_ci_bit:
145	SETCI(r0)
146	blr
147
148# make all data accesses cacheable
149clr_ci_bit:
150	CLRCI(r0)
151	blr
152
153# write a character to the serial port
154putc:
155# always write to serial1
1560:	lbz 0,5(13) ; andi. 0,0,0x20 ; beq 0b ; stb 3,0(13) ; eieio
157
158# read ID register: only if it is a PC87427 (JS21) also use serial2
159	li 4,0 ; oris 4,4,0xf400
160	li 5,0x20 ; stb 5,0x2e(4) ; lbz 5,0x2f(4); cmpdi 5,0xf2 ; bne 1f
161
162	addi 4,4,0x2f8
1630:	lbz 0,5(4) ; andi. 0,0,0x20 ; beq 0b ; stb 3,0(4) ; eieio
164
1651:	blr
166
167# transfer from running from flash to running from cache
168return_cacheable:
169	# find and set address to start running from cache, set msr value
170	mflr 3 ; rldicl 3,3,0,44
171jump_cacheable:
172	mtsrr0 3 ;
173	mfmsr 3 ; ori 3,3,0x1000 ; mtsrr1 3 # enable MCE, as well
174
175	# set cacheable insn fetches, jump to cache
176	mfspr 3,HID1 ; rldicl 3,3,32,0 ; oris 3,3,0x0020 ; rldicl 3,3,32,0
177	sync ; mtspr HID1,3 ; mtspr HID1,3 ; rfid ; b .
178
179
180
181
182copy_to_cache:
183	# zero the whole cache
184	# also, invalidate the insn cache, to clear parity errors
185	# 128kB @ 0MB (boot code and vectors from 0x0 up to 0x20000)
186	li 4,0x400 ; mtctr 4 ; li 5,0x0 ; bl clr_ci_bit
1870:	dcbz 0,5 ; sync ; icbi 0,5 ; sync ; isync ; addi 5,5,0x80 ; bdnz 0b
188
189	# 0x2000 to 0x100000/0x80000 (smaller on 970/970FX)
190	li 4,0x1C00 ; mfpvr 0 ; srdi 0,0,16 ; cmpdi 0,0x0044 ; bge 0f ; li 4,0xC00
1910:
192	mtctr 4 ; li 5,0x2000
1930:	dcbz 0,5 ; sync ; isync ; addi 5,5,0x80 ; bdnz 0b ; bl set_ci_bit
194
195	# find base address
196	bcl 20,31,$+4 ; mflr 31 ; rldicr 31,31,0,43
197
198	# copy 1kB from 0x4000
199	li 4,0x80 ; mtctr 4 ;
200	li	5,0x3ff8
201	addi 3,31,0x3ff8
2020:	ldu 4,8(3) ; bl clr_ci_bit ; stdu 4,8(5) ; bl set_ci_bit ; bdnz 0b
203	# now start executing from cache -- insn cache is huge speed boost
204
205	bl return_cacheable
206
207	li 3,'L' ; bl putc
208
209	# copy 128kB of flash to cache
210	li 4,0x800 ; mtctr 4 ; li 5,0x200-64 ; addi 3,31,0x200-64 ;
2110:	ldu 16,64(3) ; ld 17,8(3) ; ld 18,16(3) ; ld 19,24(3)
212	ld 20,32(3) ; ld 21,40(3) ; ld 22,48(3) ; ld 23,56(3)
213	bl clr_ci_bit
214	stdu 16,64(5) ; std 17,8(5) ; std 18,16(5) ; std 19,24(5)
215	std 20,32(5) ; std 21,40(5) ; std 22,48(5) ; std 23,56(5)
216	icbi 0,5 ; bl set_ci_bit ; bdnz 0b ; isync
217
218
219	li 3,'O' ; bl putc
220
221	lis 4,0x20
222	mfsprg	r3,1
223	cmpd r3,r4
224	beq 1f
225
226	// at 0xf8000000 we decide if it is u3 or u4
227	li 4,0 ; oris 4,4,0xf800 ; lwz 3,0(4) ; srdi 3,3,4 ; cmpdi 3,3 ; bne 0f
228	bl setup_mem_u3
229	bl setup_mem_size
230	b 1f
2310:
232
2331:
234	li 3,'F' ; bl putc
235
236	# setup nvram logging only when not running from RAM
237	mfsprg	r3, 1	/* rombase */
238	cmpdi	r3, 0	/* rombase is 0 when running from RAM */
239	beq	0f
240
241	// at 0xf8000000 we decide if it is u3 or u4
242	li	r4, 0
243	oris	r4, r4, 0xf800
244	lwz	r3, 0(r4)
245	srdi	r3, r3, 4
246	cmpdi	r3, 3	/* 3 means js20; no nvram logging on js20 */
247	beq	0f
248
249	bl	io_log_init
2500:
251
252	#bl print_mem
253
254	# data is cacheable by default from now on
255	bl clr_ci_bit
256
257
258	/* give live sign *****************************/
259	bl	0f
260	.ascii	TERM_CTRL_RESET
261	.ascii	TERM_CTRL_CRSOFF
262	.ascii  " **********************************************************************"
263	.ascii	"\r\n"
264	.ascii	TERM_CTRL_BRIGHT
265	.ascii	PRODUCT_NAME
266	.ascii  " Starting\r\n"
267	.ascii  TERM_CTRL_RESET
268	.ascii  " Build Date = ", __DATE__, " ", __TIME__
269	.ascii	"\r\n"
270	.ascii  " FW Version = " , RELEASE
271	.ascii	"\r\n\0"
272	.align	2
2730:	mflr	r3
274	bl	io_print
275
276	# go!
277	li	r3,__startC@l
278	mtctr	r3
279	mfsprg	r10, 1
280	bctrl
281
282relTag:
283	.ascii  RELEASE
284	.ascii	"\0"
285	.align	2
286
287slave:
288
289	# get cpu number
290	li 3,0 ; oris 3,3,0xf800 ; lwz 28,0x50(3)
291
292slaveWithNumber:
293	# create our slave loop address
294	sldi 3,28,24 ; oris 3,3,0x3000
295
296	# invalidate the insn cache, to clear parity errors
297	# clear the L2 cache as well, to get ECC right
298	li 4,0x2000 ; mfpvr 0 ; srdi 0,0,16 ; cmpdi 0,0x0044 ; bge 0f ; li 4,0x1000
2990:	mtctr 4 ; mr 5,3 ; bl clr_ci_bit
300
3010:	dcbz 0,5 ; sync ; icbi 0,5 ; sync ; isync ; addi 5,5,0x80 ; bdnz 0b
302
303
304	# write a "b $" insn in there
305	lis 4,0x4800 ; stw 4,0(3)
306/*
307	mr 5,3
308
309	# jump there
310	bl set_ci_bit
311	li 13,0 ; oris 13,13,0xf400
312	# device address
313	addi 13,13,0x2f8
314	li 3,'O' ; add 3,3,28 ; bl putc
315	bl clr_ci_bit
316	mr 3,5
317*/
318	b jump_cacheable
319
320
321
322
323# allow the flash chip to be accessed faster
324# initialize the 16550-compatible uart on serial port 1 of the sio
325setup_sio:
326
327	# i/o base address
328	li 3,0 ; oris 3,3,0xf400
329
330	# i/o base address
331	li 3,0 ; oris 3,3,0xf400
332
333	# put x-bus in turbo mode
334	li 4,0xf1 ; stb 4,0x400(3) ; eieio
335
336
337	# select sio serial1
338	li 4,7 ; stb 4,0x2e(3) ; eieio ; li 4,3 ; stb 4,0x2f(3) ; eieio
339
340	# set base address to 3f8
341	li 4,0x60 ; stb 4,0x2e(3) ; eieio ; li 4,3 ; stb 4,0x2f(3) ; eieio
342
343	# enable device
344	li 4,0x30 ; stb 4,0x2e(3) ; eieio ; li 4,1 ; stb 4,0x2f(3) ; eieio
345
346	# read ID register: only if it is a PC87427, enable serial2
347	li 4,0x20 ; stb 4,0x2e(3) ; eieio ; lbz 4,0x2f(3) ; cmpdi 4,0xf2 ; bne 0f
348
349	# select sio serial2
350	li 4,7 ; stb 4,0x2e(3) ; eieio ; li 4,2 ; stb 4,0x2f(3) ; eieio
351
352	# set base address to 2f8
353	li 4,0x60 ; stb 4,0x2e(3) ; eieio ; li 4,2 ; stb 4,0x2f(3) ; eieio
354
355	# enable device
356	li 4,0x30 ; stb 4,0x2e(3) ; eieio ; li 4,1 ; stb 4,0x2f(3) ; eieio
357
358	# uart @0x2f8
359	addi 3,3,0x2f8
360
361	# disable interrupts, fifo off
362	li 4,0 ; stb 4,1(3) ; eieio ; stb 4,2(3) ; eieio
363
364	# set serial speed
365	li 4,0x80 ; stb 4,3(3) ; eieio
366	li 4,115200/19200 ; stb 4,0(3) ; eieio ; li 4,0 ; stb 4,1(3) ; eieio
367
368	# set 8-N-1, set RTS and DTR
369	li 4,3 ; stb 4,3(3) ; eieio ; stb 4,4(3) ; eieio
370
371	eieio
372
373	addi 3,3,-0x2f8
374
375	# uart @0x3f8
3760:	addi 3,3,0x3f8
377
378	# disable interrupts, fifo off
379	li 4,0 ; stb 4,1(3) ; eieio ; stb 4,2(3) ; eieio
380
381	# set serial speed
382	li 4,0x80 ; stb 4,3(3) ; eieio
383	li 4,115200/19200 ; stb 4,0(3) ; eieio ; li 4,0 ; stb 4,1(3) ; eieio
384
385	# set 8-N-1, set RTS and DTR
386	li 4,3 ; stb 4,3(3) ; eieio ; stb 4,4(3) ; eieio
387
388	eieio
389
390	# save UART base for putc routine
3910:	mr 13,3
392
393	blr
394
395
396
397
398# set the HID registers of the 970 for optimally executing from flash
399setup_cpu:
400
401	/* clear all the HV cruft */
402	li	r0, 0
403	sync
404	mtspr	HID4, r0
405	isync
406
407	/* enable dpm, disable attn insn, enable external mce
408	 * first, try external time base; if clock doesn't run, switch to
409	 * internal */
410	li	r0, 1			/* do the setup for external timebase */
411	rldicl	r0, r0, 44, 0		/* bit 19 has to be set */
412	oris	r0, r0, 0x8000		/* Enable external machine check */
413					/* interrupts (preferred state */
414					/* equals `1'). */
415	sync
416	mtspr	HID0, r0
417	isync
418
419	mftb	r3			/* read the timebase */
420	li	r1, 0x4000		/* wait long enough for the external */
421	mtctr	r1			/* timebase (14MHz) to tick a bit */
422	bdnz	$			/* 0x4000 seems to be enough (for now) */
423	mftb	r4			/* read the timebase a second time */
424	cmpld	r3, r4			/* see if it changed */
425	bne	0f
426	/* timebase did not change, do the setup for internal */
427	rldicl	r0, r0, 19, 1
428	rldicl	r0, r0, 45, 0
429	sync
430	mtspr	HID0, r0
431	isync
432
4330:
434	/* enable insn prefetch, speculative table walks */
435	mfspr	r0, HID1
436	rldicl	r0, r0, 20, 0
437	ori	r0, r0, 0x1002
438	mfsprg	r3, 1			/* read rombase */
439	cmpdi	r3, 0			/* check if running from ram */
440	bne	0f
441	/* running from ram */
442	/* Enable instruction fetch cacheability control */
443	ori	r0, r0, 0x200
4440:
445	rldicl	r0, r0, 44, 0
446	sync
447	mtspr	HID1, r0
448	isync
449
450	/* enable cache parity */
451	mfspr	r0, HID4
452	oris	r0, r0, 0xfff0
453	xoris	r0, r0, 0xfff0
454	sync
455	mtspr	HID4, r0
456	isync
457
458	/* exception offset at 0 */
459	li	r3, 0
460	mtspr	HIOR, r3
461
462	blr
463
464C_ENTRY(proceedInterrupt)
465
466	ld      r3,exception_stack_frame@got(r2)
467	ld	r1,0(r3)
468
469	.irp i, 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, \
470	        17, 18, 19, 20, 21, 22, 23, 24, 25, 26, \
471		27, 28, 29, 30, 31
472	ld	r\i, 0x30+\i*8 (r1)
473	.endr
474
475	ld	r14,0x138(r1);
476	mtsrr0	r14
477
478	ld	r14,0x140(r1);
479	mtsrr1	r14
480
481	ld	r14,0x148(r1);
482	mtcr	r14
483
484
485	ld 0,XVECT_M_HANDLER(0)
486	mtctr 0
487
488	ld	r0,0x30(r1); # restore vector number
489	ld	r1,0x38(r1);
490
491	bctr
492
493intHandler2C:
494	mtctr	r1 # save old stack pointer
495	lis	r1,0x4
496	stdu	r1, -0x160(r1)
497	.irp i, 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, \
498	        17, 18, 19, 20, 21, 22, 23, 24, 25, 26, \
499		27, 28, 29, 30, 31
500	std	r\i, 0x30+\i*8 (r1)
501	.endr
502
503	std	r0,0x30(r1);  # save vector number
504
505	mfctr	r14
506	std	r14,0x38(r1); # save old r1
507
508	mfsrr0	r14
509	std	r14,0x138(r1);
510
511	mfsrr1	r14
512	std	r14,0x140(r1);
513
514	mfcr	r14
515	std	r14,0x148(r1);
516
517	mfxer	r14
518	std	r14,0x150(r1);
519
520	bl toc_init
521
522	ld      r3,exception_stack_frame@got(r2)
523	std     r1,0(r3)
524
525
526	mr 	r3,r0
527	bl .c_interrupt
528
529	ld	r14,0x138(r1);
530	mtsrr0	r14
531
532	ld	r14,0x140(r1);
533	mtsrr1	r14
534
535	ld	r14,0x148(r1);
536	mtcr	r14
537
538	ld	r14,0x150(r1);
539	mtxer	r14
540
541
542	.irp i, 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, \
543	        17, 18, 19, 20, 21, 22, 23, 24, 25, 26, \
544		27, 28, 29, 30, 31
545	ld	r\i, 0x30+\i*8 (r1)
546	.endr
547
548	ld	r1,0x38(r1);
549
550	mfsprg	r0,2
551	mtctr	r0
552	mfsprg	r0,3
553	mtlr	r0
554	mfsprg	r0,0
555	rfid
556
557/* Set exception handler for given exception vector.
558	r3:	exception vector offset
559	r4:	exception handler
560*/
561	.globl .set_exception
562.set_exception:
563	.globl set_exception
564set_exception:
565    ld r4,0x0(r4)
566	.globl .set_exception_asm
567.set_exception_asm:
568	.globl set_exception_asm
569set_exception_asm:
570	std	r4, 0x60(r3)	# fixme diff 1f - 0b
571	blr
572
573
574setup_mem_u3:
575	li 4,0x2000 ; oris 4,4,0xf800
576
577	# MemTimingParam -- CAS lat 2.5 / 4 (read-to-read / read-to-write)
578	lis 3,0x49e1 ; ori 3,3,0xa000 ; stw 3,0x50(4)
579
580	# MRSRegCntl -- CAS lat 2.5
581	li 3,0x6a ; stw 3,0xf0(4)
582
583	# MemBusConfig -- 128 bit bus
584	lis 3,0x8500 ; stw 3,0x190(4)
585
586	# CKDelAdj -- clock delay 75
587	lis 3,0x12c3 ; ori 3,3,0x30cc ; stw 3,0x520(4)
588
589	# IOModeCntl -- no termination on differential and 3-state drivers
590	lis 3,0x0350 ; stw 3,0x530(4)
591
592	li 3,18 ; mtctr 3 ; addi 5,4,0x5f0
5930:	# DQSDelAdj -- read delay offset -10
594	lis 3,0x3d8f ; ori 3,3,0x6000 ; stwu 3,0x10(5)
595
596	# DQSDataDelAdj -- write delay offset -32, write data delay offset +15
597	lis 3,0x380e ; ori 3,3,0x003c ; stwu 3,0x10(5)
598	bdnz 0b
599
600	# MemProgCntl -- set all
601	lis 3,0xc000 ; stw 3,0xe0(4)
602
603	eieio
604
605	blr
606
607
608# read dimm SPDs, program memory size and type
609setup_mem_size:
610	mflr 14
611
612	li 15,0 ; oris 15,15,0xf800 ; li 17,0
613	li 3,0xa0 ; li 4,3 ; li 5,3 ; bl i2c_read
614	mr 16,4 ; cmpdi 3,0 ; beq 0f ; li 16,0
6150:	li 3,0xa2 ; li 4,3 ; li 5,3 ; bl i2c_read
616	cmpd 16,4 ; bne 0f ; cmpdi 3,0 ; beq 1f
6170:	li 16,0x1e00
6181:	#li 3,0xd ; bl print_byte ; li 3,0xa ; bl print_byte
619	#mr 3,16 ; bl print_hex
620
621	#li 3,0x20 ; bl print_byte
622	sldi 3,16,7 ; add 3,3,16 ; rlwinm 3,3,10,0,6 ; subis 3,3,0x3c00
623	stw 3,0x21c0(15) ; andi. 0,16,2 ; beq 0f ; stw 3,0x21e0(15)
6240:	#bl print_hex
625	sldi 3,16,8 ; add 3,3,16 ; rldicl 3,3,48,56 ; li 0,8 ; slw 3,0,3
626		# slw, not sld, so that empty/bad banks translate into size 0
627	stw 17,0x21d0(15) ; bl add17173 ; stw 17,0x21f0(15)
628	andi. 0,16,2 ; beq 0f ; bl add17173
6290:	#bl print_hex
630
631	li 3,0xa4 ; li 4,3 ; li 5,3 ; bl i2c_read
632	mr 16,4 ; cmpdi 3,0 ; beq 0f ; li 16,0
6330:	li 3,0xa6 ; li 4,3 ; li 5,3 ; bl i2c_read
634	cmpd 16,4 ; bne 0f ; cmpdi 3,0 ; beq 1f
6350:	li 16,0x1e00
6361:	#li 3,0xd ; bl print_byte ; li 3,0xa ; bl print_byte
637	#mr 3,16 ; bl print_hex
638
639	#li 3,0x20 ; bl print_byte
640	sldi 3,16,7 ; add 3,3,16 ; rlwinm 3,3,10,0,6 ; subis 3,3,0x3c00
641	stw 3,0x2200(15) ; andi. 0,16,2 ; beq 0f ; stw 3,0x2220(15)
6420:	#bl print_hex
643	sldi 3,16,8 ; add 3,3,16 ; rldicl 3,3,48,56 ; li 0,8 ; slw 3,0,3
644	stw 17,0x2210(15) ; bl add17173 ; stw 17,0x2230(15)
645	andi. 0,16,2 ; beq 0f ; bl add17173
6460:	#bl print_hex
647	#mr 3,17 ; bl print_hex
648	stw 17,0x2250(15) ; stw 17,0x2270(15)
649	stw 17,0x2290(15) ; stw 17,0x22b0(15)
650
651	mtlr 14
652	blr
653
654
655
656
657# print GPR3 as 8-digit hex.  uses GPR18,19
658print_hex:
659	mflr 18 ; mr 19,3 ; li 3,8 ; mtctr 3
6601:	rlwinm 3,19,4,28,31 ; sldi 19,19,4
661	cmpdi 3,0xa ; blt 0f ; addi 3,3,0x27
6620:	addi 3,3,0x30 ; bl putc
663	bdnz 1b ; mtlr 18 ; blr
664
665
666# i2c stuff uses GPR20..GPR24
667
668# terminate any i2c transaction, at any point during that transaction
669i2c_stop:
6700:	lwz 3,0x30(20) ; stw 3,0x30(20) ; andi. 3,3,4 ; beq 0b
671	mr 3,21 ; mr 4,22 ; mtlr 24 ; eieio ; blr
672
673# do a combined-mode read
674# in: GPR3 = addr, GPR4 = subaddr, GPR5 = len
675# out: GPR3 = error, GPR4 = result (right-aligned, msb)
676i2c_read:
677	mflr 24
678	li 20,0x1000 ; oris 20,20,0xf800	# uni-n i2c base
679	mr 21,3 ; mr 22,4 ; mr 23,5		# save params
680	li 4,0xc ; stw 4,0(20)			# set mode (combined)
681	ori 4,21,1 ; stw 4,0x50(20)		# set addr, read
682	stw 22,0x60(20)				# set subaddr
683	li 4,2 ; stw 4,0x10(20) ; eieio		# start address phase
684	li 21,1					# error
685	li 22,0					# result accumulator
6860:	lwz 3,0x30(20) ; andi. 3,3,2 ; beq 0b	# wait until sent
687	lwz 3,0x20(20) ; andi. 3,3,2 ; beq i2c_stop # check result
688	li 4,1 ; cmpdi 23,1 ; bne 0f ; li 4,0
6890:	stw 4,0x10(20)				# AAK for next byte (or not)
690	li 4,2 ; stw 4,0x30(20) ; eieio		# ack address phase
691i2c_read_loop:
692	lwz 3,0x30(20) ; andi. 3,3,1 ; beq 1f	# if byte recv'd:
693	subi 23,23,1 ; sldi 22,22,8		# shift byte accum
694	lwz 3,0x70(20) ; rlwimi 22,3,0,24,31	# get byte
695	cmpdi 23,0 ; bne 0f ; li 21,0 ; b i2c_stop # all done
6960:	li 4,1 ; cmpdi 23,1 ; bne 0f ; li 4,0
6970:      stw 4,0x10(20)				# AAK for next byte (or not)
698	li 4,1 ; stw 4,0x30(20) ; eieio		# ack data phase
6991:	lwz 3,0x30(20) ; andi. 3,3,4 ; beq i2c_read_loop
700	li 4,0 ; stw 4,0x10(20) ; eieio ; b i2c_stop # stop bit received
701
702add17173: # add GPR3 into GPR17; if passing 2GB (0x10000000), add another 2GB.
703	lis 0,0x1000 ; cmpld 17,0 ; add 17,17,3 ; bgtlr
704	cmpld 17,0 ; blelr ; add 17,17,0 ; blr
705
706io_log_init:
707	LOAD64(r3, SB_NVRAM_adr)
708	b checkinitLog
709