1/* fw-m0sub.S
2 *
3 * Copyright 2015 Brian Swetland <swetland@frotz.net>
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18.syntax unified
19
20m0_vectors:
21	.word 0x18003FF0
22	.word m0_reset + 1
23	.word m0_fault + 1
24	.word m0_fault + 1
25	.word m0_fault + 1
26	.word m0_fault + 1
27	.word m0_fault + 1
28	.word m0_fault + 1
29	.word m0_fault + 1
30	.word m0_fault + 1
31	.word m0_fault + 1
32	.word m0_fault + 1
33	.word m0_fault + 1
34	.word m0_fault + 1
35	.word m0_fault + 1
36	.word m0_fault + 1
37// external IRQs
38	.word m0_fault + 1
39	.word m0_irq + 1
40
41m0_fault:
42	ldr r0, =0x18000000
43	ldr r1, =0xeeee0000
44	mrs r2, xpsr
45	movs r3, #0xFF
46	ands r2, r2, r3
47	orrs r1, r1, r2
48	str r1, [r0]
49	b .
50
51.ltorg
52
53#define REPORT_DELAY	0
54
55#define COMM_BASE	0x18004000
56
57#define	COMM_CMD	0
58#define COMM_ARG0	4
59#define COMM_ARG1	8
60#define COMM_RESP	12
61#define COMM_RETRY	16
62
63
64#define M4_TXEV		0x40043130 // write 0 to clear
65
66#define SGPIO_BASE	(0x40101210)
67#define OFF_IN		0
68#define OFF_OUT		4
69#define OFF_OEN		8
70#define SGPIO_IN	(0x40101210)
71#define SGPIO_OUT	(0x40101214)
72#define SGPIO_OEN	(0x40101218)
73
74#define CLK_BIT		11
75#define DIO_BIT		14
76#define TEN_BIT		15
77#define CLK_MSK		(1 << CLK_BIT)
78#define DIO_MSK		(1 << DIO_BIT)
79#define TEN_MSK		(1 << TEN_BIT)
80
81#define CLK1_OUT	(CLK_MSK | TEN_MSK)
82#define CLK0_OUT	(TEN_MSK)
83#define CLK1_IN		(CLK_MSK)
84#define CLK0_IN		(0)
85
86#define OEN_IN		((1 << CLK_BIT) | (1 << TEN_BIT))
87#define OEN_OUT		((1 << CLK_BIT) | (1 << DIO_BIT) | (1 << TEN_BIT))
88
89#define NOP4	nop ; nop ; nop ; nop
90#define NOP8	NOP4 ; NOP4
91#define NOP16	NOP8 ; NOP8
92
93//#define DELAY	nop ; nop
94//#define DELAY NOP8
95
96// r11 CLK1_OUT     const
97// r10 CLK0_OUT     const
98// r9  delay        subroutine
99// r8  comm_base    addr
100// r7  SGPIO_BASE   addr
101// r6  DIO_MSK      const
102// r5  CLK1_IN      const
103// r4  CLK0_IN      const
104// r3  outbits      data
105
106snooze_1m:
107	nop ; nop ; nop ; nop
108	nop ; nop ; nop ; nop
109	nop ; nop ; nop ; nop
110	nop ; nop ; nop ; nop
111	nop ; nop ; nop ; nop
112	nop ; nop ; nop ; nop
113	nop ; nop ; nop ; nop
114	nop ; nop ; nop ; nop
115	nop ; nop ; nop ; nop
116snooze_2m:
117	nop ; nop ; nop ; nop
118	nop ; nop ; nop ; nop
119	nop ; nop ; nop ; nop
120	nop ; nop ; nop ; nop
121snooze_3m:
122	nop ; nop ; nop ; nop
123	nop ; nop ; nop ; nop
124snooze_4m:
125	nop ; nop ; nop ; nop
126	nop ; nop ; nop ; nop
127snooze_6m:
128	nop ; nop ; nop ; nop
129snooze_8m:
130	bx lr
131
132// delay    0 nops  16MHz
133// delay    2 nops  12MHz
134// delay    4 nops   9.6MHz
135#define DELAY blx r9
136
137// 12 cycles + DELAY x 2
138.macro ONE_BIT_OUT
139	lsls r2, r3, #DIO_BIT	// shift bit 1 to posn
140	ands r2, r2, r6		// isolate bit 1
141	movs r1, r2		// save bit 1
142	add r2, r2, r10		// combine with CLK1
143	DELAY
144	str r2, [r7, #OFF_OUT]	// commit negative edge
145	lsrs r3, r3, #1		// advance to next bit
146	add r1, r1, r11		// combine with CLK1
147	nop
148	nop
149	DELAY
150	str r1, [r7, #OFF_OUT]	// commit positive edge
151.endm
152
153.macro ONE_BIT_IN
154	ands r0, r0, r6		// isolate input bit
155	lsls r0, r0, #(31-DIO_BIT) // move to posn 31
156	lsrs r3, r3, #1		// make room
157	orrs r3, r3, r0		// add bit
158	DELAY
159	str r4, [r7, #OFF_OUT]	// commit negative edge
160	ldr r0, [r7, #OFF_IN]	// sample input
161	nop
162	nop
163	DELAY
164	str r5, [r7, #OFF_OUT]	// commit positive edge
165.endm
166
167// used for the final parity and turn bits on input so this
168// actually only reads one bit
169read_2:
170	push {lr}
171	nop
172	nop
173	nop
174	nop
175	DELAY
176	str r4, [r7, #OFF_OUT]
177	ldr r0, [r7, #OFF_IN]
178	nop
179	nop
180	DELAY
181	str r5, [r7, #OFF_OUT]
182	ands r0, r0, r6		// isolate bit
183	lsrs r0, r0, #DIO_BIT	// shift to bit0
184	nop
185	nop
186	DELAY
187	str r4, [r7, #OFF_OUT]
188	nop
189	nop
190	nop
191	nop
192	DELAY
193	str r5, [r7, #OFF_OUT]
194	pop {pc}
195
196// w0: <15> <parity:1> <cmd:16>
197// w1: <data:32>
198
199
200write_16:
201	push {lr}
202	b _write_16
203write_32:
204	push {lr}
205	ONE_BIT_OUT
206	ONE_BIT_OUT
207	ONE_BIT_OUT
208	ONE_BIT_OUT
209	ONE_BIT_OUT
210	ONE_BIT_OUT
211	ONE_BIT_OUT
212	ONE_BIT_OUT
213	ONE_BIT_OUT
214	ONE_BIT_OUT
215	ONE_BIT_OUT
216	ONE_BIT_OUT
217	ONE_BIT_OUT
218	ONE_BIT_OUT
219	ONE_BIT_OUT
220	ONE_BIT_OUT
221_write_16:
222	ONE_BIT_OUT
223	ONE_BIT_OUT
224	ONE_BIT_OUT
225	ONE_BIT_OUT
226	ONE_BIT_OUT
227	ONE_BIT_OUT
228	ONE_BIT_OUT
229	ONE_BIT_OUT
230	ONE_BIT_OUT
231	ONE_BIT_OUT
232	ONE_BIT_OUT
233	ONE_BIT_OUT
234	ONE_BIT_OUT
235	ONE_BIT_OUT
236	ONE_BIT_OUT
237	ONE_BIT_OUT
238	pop {pc}
239write_1:
240	push {lr}
241	ONE_BIT_OUT
242	pop {pc}
243
244read_4:
245	push {lr}
246	b _read_4
247read_5:
248	push {lr}
249	b _read_5
250read_32:
251	push {lr}
252	ONE_BIT_IN
253	ONE_BIT_IN
254	ONE_BIT_IN
255	ONE_BIT_IN
256	ONE_BIT_IN
257	ONE_BIT_IN
258	ONE_BIT_IN
259	ONE_BIT_IN
260	ONE_BIT_IN
261	ONE_BIT_IN
262	ONE_BIT_IN
263	ONE_BIT_IN
264	ONE_BIT_IN
265	ONE_BIT_IN
266	ONE_BIT_IN
267	ONE_BIT_IN
268	ONE_BIT_IN
269	ONE_BIT_IN
270	ONE_BIT_IN
271	ONE_BIT_IN
272	ONE_BIT_IN
273	ONE_BIT_IN
274	ONE_BIT_IN
275	ONE_BIT_IN
276	ONE_BIT_IN
277	ONE_BIT_IN
278	ONE_BIT_IN
279_read_5:
280	ONE_BIT_IN
281_read_4:
282	ONE_BIT_IN
283	ONE_BIT_IN
284	ONE_BIT_IN
285	ONE_BIT_IN
286	ands r0, r0, r6		// isolate input bit
287	lsls r0, r0, #(31-DIO_BIT) // move to posn 31
288	lsrs r3, r3, #1		// make room
289	orrs r3, r3, r0		// add bit
290	pop {pc}
291
292init:
293	ldr r0, =CLK1_OUT
294	mov r11, r0
295	ldr r0, =CLK0_OUT
296	mov r10, r0
297	ldr r0, =(snooze_4m + 1)
298	ldr r0, =(snooze_1m + 1)
299	mov r9, r0
300	ldr r0, =COMM_BASE
301	mov r8, r0
302	ldr r7, =SGPIO_BASE
303	ldr r6, =DIO_MSK
304	ldr r5, =CLK1_IN
305	ldr r4, =CLK0_IN
306	bx lr
307
308#define MAX_RETRY	8192
309
310err_fail:
311	movs r0, #3
312	mov r3, r8
313	str r0, [r3, #COMM_RESP];
314	pop {pc}
315
316err_timeout:
317	movs r0, #2
318	mov r3, r8
319	str r0, [r3, #COMM_RESP];
320	pop {pc}
321
322cmd_read_txn:
323	push {lr}
324
325	ldr r0, =MAX_RETRY
326	//movs r0, #MAX_RETRY
327	mov r12, r0
328
329rd_retry:
330	ldr r3, [r3, #COMM_ARG0]
331	bl write_16
332
333	ldr r3, =OEN_IN
334	str r3, [r7, #OFF_OEN]
335	bl read_4
336
337	lsrs r3, r3, #29
338	cmp r3, #1		// OK
339	beq rd_okay
340
341	ldr r1, =OEN_OUT
342	str r1, [r7, #OFF_OEN]
343
344	cmp r3, #2		// WAIT
345	bne err_fail
346
347	mov r0, r12
348	subs r0, r0, #1
349	mov r12, r0
350	beq err_timeout
351	mov r3, r8
352	b rd_retry
353
354rd_okay:
355	bl read_32
356	bl read_2
357	ldr r1, =OEN_OUT
358	str r1, [r7, #OFF_OEN]
359	mov r1, r11
360	orrs r1, r1, r6
361	str r1, [r7, #OFF_OUT]
362
363	mov r1, r8		// get COMM_BASE
364	str r3, [r1, #COMM_ARG0]
365	str r0, [r1, #COMM_ARG1]
366	movs r0, #0
367	str r0, [r1, #COMM_RESP]
368#if REPORT_DELAY
369	mov r0, r12
370	str r0, [r1, #COMM_RETRY]
371#endif
372	pop {pc}
373
374
375cmd_write_txn:
376	push {lr}
377
378	ldr r0, =MAX_RETRY
379	mov r12, r0
380
381wr_retry:
382	ldr r3, [r3, #COMM_ARG0]
383	bl write_16
384	push {r3}		// stash parity bit
385
386	ldr r3, =OEN_IN
387	str r3, [r7, #OFF_OEN]
388	bl read_4
389
390	lsrs r3, r3, #29
391	cmp r3, #1		// OK
392	beq wr_okay
393
394	pop {r0}		// discard saved parity bit
395
396	ldr r1, =OEN_OUT
397	str r1, [r7, #OFF_OEN]
398
399	cmp r3, #2		// WAIT
400	bne err_fail
401
402	mov r0, r12
403	subs r0, r0, #1
404	mov r12, r0
405	beq err_timeout
406
407	mov r3, r8
408	b wr_retry
409
410wr_okay:
411	ldr r3, =OEN_OUT
412	str r3, [r7, #OFF_OEN]
413	bl write_1
414
415	mov r3, r8
416	ldr r3, [r3, #COMM_ARG1]
417	bl write_32
418
419	pop {r3}		// recover parity bit
420	bl write_1
421
422	mov r3, r8		// get COMM_BASE
423	movs r0, #0
424	str r0, [r3, #COMM_RESP]
425#if REPORT_DELAY
426	mov r0, r12
427	str r0, [r3, #COMM_RETRY]
428#endif
429	pop {pc}
430
431// write without caring about the response
432cmd_write_blind:
433	push {lr}
434
435	ldr r3, [r3, #COMM_ARG0]
436	bl write_16
437	push {r3}		// stash parity bit
438
439	ldr r3, =OEN_IN		// ignore Trn/Rsp/Trn
440	str r3, [r7, #OFF_OEN]
441	bl read_5
442
443	ldr r3, =OEN_OUT
444	str r3, [r7, #OFF_OEN]
445
446	mov r3, r8
447	ldr r3, [r3, #COMM_ARG1]
448	bl write_32
449
450	pop {r3}		// recover parity bit
451	bl write_1
452
453	mov r3, r8		// get COMM_BASE
454	movs r0, #0
455	str r0, [r3, #COMM_RESP]
456#if REPORT_DELAY
457	mov r0, =MAX_RETRY
458	str r0, [r3, #COMM_RETRY]
459#endif
460	pop {pc}
461
462
463cmd_jtag_to_swd:
464	push {lr}
465	ldr r3, =0xffffffff
466	bl write_32
467	ldr r3, =0xffffffff
468	bl write_32
469	ldr r3, =0b1110011110011110
470	bl write_16
471
472	mov r3, r8
473	movs r0, #0
474	str r0, [r3, #COMM_RESP]
475	pop {pc}
476
477cmd_swd_to_dormant:
478	push {lr}
479	ldr r3, =0xffffffff
480	bl write_32
481	ldr r3, =0xffffffff
482	bl write_32
483	ldr r3, =0xE3BC
484	bl write_16
485
486	mov r3, r8
487	movs r0, #0
488	str r0, [r3, #COMM_RESP]
489	pop {pc}
490
491cmd_dormant_to_swd:
492	push {lr}
493	// at least 8 HI
494	ldr r3, =0xffff
495	bl write_16
496	// activation sequence (128bit)
497	ldr r3, =0x6209F392
498	bl write_32
499	ldr r3, =0x86852D95
500	bl write_32
501	ldr r3, =0xE3DDAFE9
502	bl write_32
503	ldr r3, =0x19BC0EA2
504	bl write_32
505	// 4 LO, selection sequence, 4 HI
506	ldr r3, =0xF1A0
507	bl write_16
508
509	mov r3, r8
510	movs r0, #0
511	str r0, [r3, #COMM_RESP]
512	pop {pc}
513
514cmd_reset:
515	push {lr}
516	// 50+ HI (60 here), 2+ LO (4 here)
517	ldr r3, =0xffffffff
518	bl write_32
519	ldr r3, =0x0fffffff
520	bl write_32
521
522	mov r3, r8
523	movs r0, #0
524	str r0, [r3, #COMM_RESP]
525	pop {pc}
526
527
528m0_irq:
529	push {lr}
530
531	// clear event from m4
532	ldr r0, =M4_TXEV
533	movs r1, #0
534	str r1, [r0]
535
536	mov r3, r8		// get COMM_BASE
537	ldr r0, [r3, #COMM_CMD]
538	cmp r0, #9
539	bls good_cmd
540	movs r0, #0
541good_cmd:
542	lsls r0, r0, #2
543	adr r1, cmd_table
544	ldr r2, [r1, r0]
545	blx r2
546
547	pop {pc}
548
549.align 4
550cmd_table:
551	.word cmd_invalid + 1
552	.word cmd_nop + 1
553	.word cmd_read_txn + 1
554	.word cmd_write_txn + 1
555	.word cmd_reset + 1
556	.word cmd_setclock + 1
557	.word cmd_write_blind + 1
558	.word cmd_jtag_to_swd + 1
559	.word cmd_dormant_to_swd + 1
560	.word cmd_swd_to_dormant + 1
561
562cmd_invalid:
563	movs r0, #9
564	str r0, [r3, #COMM_RESP]
565	bx lr
566
567cmd_nop:
568	movs r0, #0
569	str r0, [r3, #COMM_RESP]
570	bx lr
571
572cmd_setclock:
573	ldr r0, [r3, #COMM_ARG0]
574	cmp r0, #8
575	bls good_clock
576	movs r0, #0
577good_clock:
578	lsls r2, r0, #2
579	adr r1, snooze_table
580	ldr r1, [r1, r2]
581	mov r9, r1
582
583	// return actual clock used
584	str r0, [r3, #COMM_RESP]
585	bx lr
586
587.align 4
588snooze_table:
589	.word snooze_1m + 1
590	.word snooze_1m + 1
591	.word snooze_2m + 1
592	.word snooze_3m + 1
593	.word snooze_4m + 1
594	.word snooze_4m + 1
595	.word snooze_6m + 1
596	.word snooze_6m + 1
597	.word snooze_8m + 1
598
599m0_reset:
600	ldr r0, =0x18000000
601	ldr r1, =0xaaaa0000
602	str r1, [r0]
603
604	bl init
605
606	// enable IRQ1 (Event From M4)
607	ldr r0, =0xE000E100
608	movs r1, #2
609	str r1, [r0]
610
611m0_idle:
612	wfi
613	b m0_idle
614