1#include <arminc.h>
2#include <hndsoc.h>
3#include <sbchipc.h>
4
5#ifndef __arm__
6#error __arm__ is NOT defined
7#endif
8
9/* Routine begin/end macro */
10#if defined(__thumb__)
11#define FUNC(x) THUMBLEAF(x)
12#else
13#define FUNC(x) LEAF(x)
14#endif  /* __thumb__ */
15
16#ifdef BCMDBG
17#define TRACE(x) \
18	ldr	r9,=(x); \
19	ldr     r10,=SI_ENUM_BASE; \
20	str	r9,[r10,#0x64]
21
22#define TRACE1(x) \
23	mov	r9,x; \
24	ldr     r10,=SI_ENUM_BASE; \
25	str	r9,[r10,#0x68]
26
27#define TRACE2(x) \
28	mov	r9,x; \
29	ldr     r10,=SI_ENUM_BASE; \
30	str	r9,[r10,#0x64]
31#else
32#define TRACE(x)
33#define TRACE1(x)
34#define TRACE2(x)
35#endif
36
37	.text
38
39FUNC(pcie_phy_init)
40	mov	r6,lr
41	/*
42	 *    Sys Init code -- read OTP, program the H/W blocks
43	 *    At completion, take a jump to __hw_init_done
44	 */
45__sys_init:
46
47	ldr	r0,=SI_ENUM_BASE		/* r0:	core regs SI base address */
48	ldr	r4,[r0,#CC_CAPABILITIES]	/* r4:	capabitilies */
49	and	r4,r4,#CC_CAP_OTPSIZE
50	cmp	r4,#0
51	beq	__hw_init_done
52	ldr	r1,[r0,#CC_CLKDIV]
53	mov	r2,#~CLKD_OTP
54	and	r2,r2,r1
55	mov	r1,#(0xe << CLKD_OTP_SHIFT)
56	orr	r2,r2,r1
57	str	r2,[r0,#CC_CLKDIV]		/* Update OtpClk in clkdiv with 14 */
58	ldr	r1,=200				/* Wait for 200 cycles for stable OTP clock */
59spinn:	sub	r1,r1,#0x1
60	cmp	r1,#0x0
61	bne	spinn
62	lsr	r2,r4,#CC_CAP_OTPSIZE_SHIFT	/* Get OTP size */
63	adrl	r1,otp_sizes
64	lsl	r2,r2,#0x2
65	ldr	r3,[r1,r2]			/* Get the OTP size from otp_sizes table (in bytes) */
66
67	cmp	r3,#0x0				/* skip zero size */
68	beq	__hw_init_done
69	ldr	r1,[r0,#CC_OTPST]
70	and	r1,r1,#OTPS_READY
71	cmp	r1,#0x0				/* 0: OTP is not ready for whatever reason */
72	beq	__hw_init_done
73	add	r2,r3,r0			/* Seek to the end of OTP region */
74	/* Scan entire OTP from END -> BEGIN to find first
75	 * matching hwinit entry */
76	sub	r2,r2,#2
771:
78	add	r4,r2,#CC_SROM_OTP
79	ldrh	r1,[r4]
80	lsl	r1,r1,#0x10
81	sub	r2,r2,#2
82	add	r4,r2,#CC_SROM_OTP
83	ldrh	r3,[r4]
84	orr	r1,r1,r3
85	ldr	r4,=0xeaeaeaea			/* SID */
86	cmp	r1,r4
87	beq	1f
88	cmp	r0,r2
89	blt	1b
90	/* no hwinit data from OTP */
91	b	__hw_init_done
921:
93	add	r0,r2,#CC_SROM_OTP
94	add	r0,r0,#4
95	mov	r1,#0x800	/* for the first delay */
96
97__init_next_cmd:
98
99	/*
100	 *    delay for N cycles
101	 *    read OTP : 32b entry comprise {16b loop count, 8b delay, 8b cmd}
102	 *    execute OPT cmd.
103	 *    Do_Next if any.
104	 */
105
106	bl	__init_dly	/* inter-command delay */
107
108	ldrh	r1,[r0],#2	/* {delay, Cmd} */
109	and	r2,r1,#0x0f	/* extract Cmd */
110	cmp	r2,#0x1		/* EID (end of init data) */
111	beq	__hw_init_done	/* jump to __hw_init_done on End of Init Data */
112	ldrh	r3,[r0],#2	/* Loop Count */
113
114	cmp	r2,#0		/* NOP */
115	beq	__init_next_cmd
116
117	/* load two 32b datum */
118	bl	__init_load64
119	mov	r7,r10		/* prepare indirect addr */
120	mov	r8,r12		/* prepare indirect data */
121
122	/*
123	 * handle various cases
124	 */
125	cmp	r2,#4
126	beq	__init_wr_dir
127	cmp	r2,#5
128	beq	__init_wr_indir
129	cmp	r2,#6
130	beq	__init_wr_indir_incaddr
131	cmp	r2,#7
132	beq	__init_wr_indir_incaddr
133	cmp	r2,#8
134	beq	__init_wr_dir_incaddr_data
135	cmp	r2,#9
136	beq	__init_wr_indir_incaddr_data
137	cmp	r2,#10
138	beq	__init_wr_dir_incaddr_incdata
139	cmp	r2,#11
140	beq	__init_wr_indir_incaddr_incdata
141
142	/* write direct (cmd=0x02) is a special case of
143	 * write direct multiple (cmd=0x04), under loop count=1
144
145	 * write indirect (cmd=0x03) is a special case of
146	 * write indirect multiple (cmd=0x05), under loop count=1
147	 */
148
149	/* write direct multiple (cmd=0x04) */
150__init_wr_dir:
151	str	r12,[r10]		/* Mem[addr] = data */
152	subs	r3,r3,#1		/* loop cnt = loop cnt -1 */
153	beq	__init_next_cmd		/* loop cnt = 0 */
154	bl	__init_load64		/* load next pair of addr, data */
155	bl	__init_dly		/* inter-op delay */
156	b	__init_wr_dir
157
158	/* write indirect multiple (cmd=0x05) */
159__init_wr_indir:
160	bl	__init_load64		/* load next pair of addr, data */
161	str	r10,[r7]		/* mem[indirect addr] = addr */
162	str	r12,[r8]		/* mem[indirect data] = data */
163	subs	r3,r3,#1		/* loop cnt = loop cnt -1 */
164	beq	__init_next_cmd		/* loop cnt = 0 */
165	bl	__init_dly		/* inter-op delay */
166	b	__init_wr_indir
167
168	/* cmd=0x06 */
169	/* write direct, (post) auto-inc address */
170__init_wr_dir_incaddr:
171	str	r12,[r10],#4		/* Mem[addr++] = data, auto-inc addr */
172	subs	r3,r3,#1		/* loop cnt = loop cnt -1 */
173	beq	__init_next_cmd		/* loop cnt = 0 */
174	bl	__init_load32		/* load next data */
175	bl	__init_dly		/* inter-op delay */
176	b	__init_wr_indir_incaddr
177
178	/* cmd=0x07 */
179	/* write indirect, (post) auto-inc address */
180__init_wr_indir_incaddr:
181	bl	__init_load64		/* load first addr & data */
182__next_d_0:
183	str	r10,[r7]		/* Mem[addr] = addr */
184	str	r12,[r8]		/* Mem[data] = data */
185	subs	r3,r3,#1		/* loop cnt = loop cnt -1 */
186	beq	__init_next_cmd		/* loop cnt = 0 */
187	add	r10,r10,#4		/* inc addr by 4 bytes */
188	bl	__init_load32		/* load next data */
189	bl	__init_dly		/* inter-op delay */
190	b	__next_d_0
191
192	/* cmd=0x08 */
193	/* write direct multiple, repeatedly the same data to (post) auto-inc address */
194__init_wr_dir_incaddr_data:
195	str	r12,[r10],#4		/* Mem[addr] = data, auto_inc addr */
196	subs	r3,r3,#1		/* loop cnt = loop cnt -1 */
197	beq	__init_next_cmd		/* loop cnt = 0 */
198	bl	__init_dly		/* inter-op delay */
199	b	__init_wr_dir_incaddr_data
200
201	/* cmd=0x09 */
202	/* write inirect multiple, repeatedly the same data to (post) auto-inc address */
203__init_wr_indir_incaddr_data:
204	bl	__init_load64		/* load first addr & data */
205__next_d_1:
206	str	r10,[r7]		/* Mem[addr] = addr */
207	str	r12,[r8]		/* Mem[data] = data */
208	subs	r3,r3,#1		/* loop cnt = loop cnt -1 */
209	beq	__init_next_cmd		/* loop cnt = 0 */
210	add	r10,r10,#4		/* inc addr by 4 bytes */
211	bl	__init_dly		/* inter-op delay */
212	b	__next_d_1
213
214	/* cmd=0x0a */
215	/* write direct multiple, (post) auto-inc addr and data */
216__init_wr_dir_incaddr_incdata:
217	str	r12,[r10],#4		/* Mem[addr] = data, inc addr */
218	subs	r3,r3,#1		/* loop cnt = loop cnt -1 */
219	beq	__init_next_cmd		/* loop cnt = 0 */
220	add	r12,r12,#1		/* inc data by 1 */
221	bl	__init_dly		/* inter-op delay */
222	b	__init_wr_dir_incaddr_incdata
223
224	/* cmd=0x0b */
225	/* write indirect multiple, (post) auto-inc addr and data */
226__init_wr_indir_incaddr_incdata:
227	bl	__init_load64		/* load first addr & data */
228__next_d_2:
229	str	r10,[r7]		/* Mem[addr] = addr */
230	str	r12,[r8]		/* Mem[data] = data */
231	subs	r3,r3,#1		/* loop cnt = loop cnt -1 */
232	beq	__init_next_cmd		/* loop cnt = 0 */
233	add	r10,r10,#4		/* inc addr by 4 bytes */
234	add	r12,r12,#1		/* inc data by 1 */
235	bl	__init_dly		/* inter-op delay */
236	b	__next_d_2
237
238	/*
239	 * Define two Utilities to save the code space.
240	 *
241	 * load one or two 32b datum from current OTP position
242	 * r10 = {r10, r9}
243	 * r12 = {r12, r11}
244	 */
245__init_load64:
246	ldrh	r10,[r0],#2
247	ldrh	r9,[r0],#2
248	orr	r10,r9,r10,lsl #16
249__init_load32:
250	ldrh	r12,[r0],#2
251	ldrh	r11,[r0],#2
252	orr	r12,r11,r12,lsl #16
253	bx	lr			 /* return */
254
255	/* impose some inter-op and inter-cmd delay
256	 * delay count is passed thru reg. r1
257	 */
258__init_dly:
259	asr	r9,r1,#11	/* r1/8 cycles, effectively (r1&0x0000ff00) >> 3 */
260	cmp	r9,#0
261	beq	__no_dly
262__dly_loop:
263	subs	r9,r9,#1	/* loop here */
264	bne	__dly_loop
265__no_dly:
266	bx	lr		/* return */
267
268	/*
269	 * Hardware init. is done
270	 */
271
272__hw_init_done:
273	/* Continuing boot */
274	mov	lr,r6
275	mov	pc,lr
276
277/* OTP sizes in bytes */
278otp_sizes:
279	.word	0
280	.word	256	/* 2048 bits: 32X64 */
281	.word	512	/* 4096 bits: 2*32X64 */
282	.word	1024	/* 8192 bits: 4*32X64 */
283	.word	512	/* 4096 bits: 64X64 */
284	.word	768	/* 6144 bits: 5 32X64 */
285	.word	0	/* 512 bits: dont care */
286	.word	128	/* 1024 bits: 8X64 */
287
288END(pcie_phy_init)
289