1/* Copyright 2005 Oleg I. Vdovikin (oleg@cs.msu.su)	*/
2/* cache manipulation adapted from Broadcom code 	*/
3/* idea taken from original bunzip2 decompressor code	*/
4/* Copyright 2004 Manuel Novoa III (mjn3@codepoet.org)	*/
5/* Licensed under the linux kernel's version of the GPL.*/
6
7#include <asm/asm.h>
8#include <asm/regdef.h>
9
10#define KSEG0		0x80000000
11
12#define C0_CONFIG	$16
13#define C0_TAGLO	$28
14#define C0_TAGHI	$29
15
16#define	CONF1_DA_SHIFT	7			/* D$ associativity */
17#define CONF1_DA_MASK	0x00000380
18#define CONF1_DA_BASE	1
19#define CONF1_DL_SHIFT	10			/* D$ line size */
20#define CONF1_DL_MASK	0x00001c00
21#define CONF1_DL_BASE	2
22#define CONF1_DS_SHIFT	13			/* D$ sets/way */
23#define CONF1_DS_MASK	0x0000e000
24#define CONF1_DS_BASE	64
25#define CONF1_IA_SHIFT	16			/* I$ associativity */
26#define CONF1_IA_MASK	0x00070000
27#define CONF1_IA_BASE	1
28#define CONF1_IL_SHIFT	19			/* I$ line size */
29#define CONF1_IL_MASK	0x00380000
30#define CONF1_IL_BASE	2
31#define CONF1_IS_SHIFT	22			/* Instruction cache sets/way */
32#define CONF1_IS_MASK	0x01c00000
33#define CONF1_IS_BASE	64
34
35#define CONF_AR         (7 << 10)
36
37#define Index_Invalidate_I	0x00
38#define Index_Writeback_Inv_D   0x01
39
40	.text
41	LEAF(startup)
42	.set noreorder
43	addi	sp, -48
44	sw	a0, 16(sp)
45	sw	a1, 20(sp)
46	sw	a2, 24(sp)
47	sw	a3, 28(sp)
48
49	/* Copy decompressor code to the right place */
50	li	t2, BZ_TEXT_START
51	add	a0, t2, 0
52	la      a1, code_start
53	la	a2, code_stop
54$L1:
55	lw	t0, 0(a1)
56	sw	t0, 0(a0)
57	add	a1, 4
58	add	a0, 4
59	blt	a1, a2, $L1
60	nop
61
62	/* At this point we need to invalidate dcache and */
63	/* icache before jumping to new code */
64
651:	/* Get cache sizes */
66	.set	mips32
67	mfc0	s0,C0_CONFIG,1
68	.set	mips0
69
70	li	s1,CONF1_DL_MASK
71	and	s1,s0
72	beq	s1,zero,nodc
73	nop
74
75	srl	s1,CONF1_DL_SHIFT
76	li	t0,CONF1_DL_BASE
77	sll	s1,t0,s1		/* s1 has D$ cache line size */
78
79	li	s2,CONF1_DA_MASK
80	and	s2,s0
81	srl	s2,CONF1_DA_SHIFT
82	addiu	s2,CONF1_DA_BASE	/* s2 now has D$ associativity */
83
84	li	t0,CONF1_DS_MASK
85	and	t0,s0
86	srl	t0,CONF1_DS_SHIFT
87	li	s3,CONF1_DS_BASE
88	sll	s3,s3,t0		/* s3 has D$ sets per way */
89
90	multu	s2,s3			/* sets/way * associativity */
91	mflo	t0			/* total cache lines */
92
93	multu	s1,t0			/* D$ linesize * lines */
94	mflo	s2			/* s2 is now D$ size in bytes */
95
96	/* Figure if it is a mips32r2 CPU which we take as an indication that
97	 * there is no BRCM CP0 register and the D$ tags are in select 2
98	 */
99	mfc0	s6,C0_CONFIG
100	andi	s6,CONF_AR			# s6 != 0 if mips32r2
101	/* Initilize the D$: */
102	beqz	s6,1f
103	nop
104	.set	mips32
105	mtc0	zero,C0_TAGLO,2			# For mips32r2 the D$ Tags are in select 2
106	mtc0	zero,C0_TAGHI,2
107	.set	mips0
108	b	2f
109	nop
110
1111:
112	mtc0	zero,C0_TAGLO
113	mtc0	zero,C0_TAGHI
114
1152:
116	li	t0,KSEG0		/* Just an address for the first $ line */
117	addu	t1,t0,s2		/*  + size of cache == end */
118
119	.set	mips3
1203:	cache	Index_Writeback_Inv_D,0(t0)
121	.set	mips0
122	bne	t0,t1,3b
123	addu	t0,s1
124
125nodc:
126	/* Now we get to do it all again for the I$ */
127
128	move	s3,zero			/* just in case there is no icache */
129	move	s4,zero
130
131	li	t0,CONF1_IL_MASK
132	and	t0,s0
133	beq	t0,zero,noic
134	nop
135
136	srl	t0,CONF1_IL_SHIFT
137	li	s3,CONF1_IL_BASE
138	sll	s3,t0			/* s3 has I$ cache line size */
139
140	li	t0,CONF1_IA_MASK
141	and	t0,s0
142	srl	t0,CONF1_IA_SHIFT
143	addiu	s4,t0,CONF1_IA_BASE	/* s4 now has I$ associativity */
144
145	li	t0,CONF1_IS_MASK
146	and	t0,s0
147	srl	t0,CONF1_IS_SHIFT
148	li	s5,CONF1_IS_BASE
149	sll	s5,t0			/* s5 has I$ sets per way */
150
151	multu	s4,s5			/* sets/way * associativity */
152	mflo	t0			/* s4 is now total cache lines */
153
154	multu	s3,t0			/* I$ linesize * lines */
155	mflo	s4			/* s4 is cache size in bytes */
156
157	/* Initilize the I$: */
158	mtc0	zero,C0_TAGLO
159	mtc0	zero,C0_TAGHI
160
161	li	t0,KSEG0		/* Just an address for the first $ line */
162	addu	t1,t0,s4		/*  + size of cache == end */
163
164	.set	mips3
1651:	cache	Index_Invalidate_I,0(t0)
166	.set	mips0
167	bne	t0,t1,1b
168	addu	t0,s3
169
170noic:
171	move	a0,s3			/* icache line size */
172	move	a1,s4			/* icache size */
173	move	a2,s1			/* dcache line size */
174	jal	t2
175	move	a3,s2			/* dcache size */
176
177	.set reorder
178	END(startup)
179