1/* interrupts-asm.S -- interrupt handling for OpenRISC 1000.
2 *
3 * Copyright (c) 2011, 2012, 2014 Authors
4 *
5 * Contributor Julius Baxter <juliusbaxter@gmail.com>
6 * Contributor Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
7 * Contributor Stefan Wallentowitz <stefan.wallentowitz@tum.de>
8 *
9 * The authors hereby grant permission to use, copy, modify, distribute,
10 * and license this software and its documentation for any purpose, provided
11 * that existing copyright notices are retained in all copies and that this
12 * notice is included verbatim in any distributions. No written agreement,
13 * license, or royalty fee is required for any of the authorized uses.
14 * Modifications to this software may be copyrighted by their authors
15 * and need not follow the licensing terms described here, provided that
16 * the new terms are clearly indicated on the first page of each file where
17 * they apply.
18 */
19
20/* -------------------------------------------------------------------------- */
21/*!Generic interrupt handler function for or1k
22                                                                              */
23/* -------------------------------------------------------------------------- */
24
25#include "include/or1k-asm.h"
26#include "include/or1k-sprs.h"
27
28	.extern _or1k_interrupt_handler_table
29	.extern _or1k_interrupt_handler_data_ptr_table
30
31/* -------------------------------------------------------------------------- */
32/*!Function to call appropriate interrupt handler
33                                                                              */
34/* -------------------------------------------------------------------------- */
35
36	.section .text
37	.global	_or1k_interrupt_handler
38	.type	_or1k_interrupt_handler,@function
39
40_or1k_interrupt_handler:
41	/* Make room on stack, save link address register */
42	l.addi	r1,r1,-4
43	l.sw	0(r1),r9
44
45	/* Read PICSR */
46	l.mfspr	r20,r0,OR1K_SPR_PIC_PICSR_ADDR
47
48	/* Load handler table base address */
49	// Needs to be callee-saved register
50	l.movhi r16,hi(_or1k_interrupt_handler_table)
51	l.ori	r16,r16,lo(_or1k_interrupt_handler_table)
52	/* Load data pointer table base address */
53	// Needs to be callee-saved register
54	l.movhi r18,hi(_or1k_interrupt_handler_data_ptr_table)
55	l.ori	r18,r18,lo(_or1k_interrupt_handler_data_ptr_table)
56#ifdef __OR1K_MULTICORE__
57	/* Read the addresses of the arrays of cores */
58	/* r7 = (*or1k_interrupt_handler_table)  */
59	l.lwz	r16,0(r16)
60	/* r12 = (*or1k_interrupt_handler_data_ptr_table)  */
61	l.lwz	r18,0(r18)
62	/* Generate offset in arrays */
63	/* r14 = coreid */
64	l.mfspr	r14,r0,OR1K_SPR_SYS_COREID_ADDR
65	/* r14 = coreid*32*4 = off */
66	l.slli	r14,r14,7
67	/* r7 = (*or1k_exception_handler_table)[coreid] */
68	l.add	r16,r16,r14
69	/* r12 = (*or1k_exception_handler_table)[coreid] */
70	l.add	r18,r18,r14
71#endif
72
73.L0:
74	/* Find first set bit in PICSR */
75	l.ff1	r4,r20
76	/* Any bits set? */
77	l.sfne	r4,r0
78	/* If none, finish */
79	OR1K_DELAYED_NOP(OR1K_INST(l.bnf .L2))
80	/* What is IRQ function table offset? */
81	l.addi	r22,r4,-1
82	l.slli	r6,r22,2
83	/* Add this to table bases */
84	l.add	r14,r6,r16
85	l.add	r13,r6,r18
86
87	/* Fetch handler function address */
88	l.lwz	r14,0(r14)
89
90	/* Double check it's valid, compare against INTERRUPT_HANDLER_NOT_SET */
91	l.sfne	r14,r0
92	/* Skip if no handler: TODO: Indicate interrupt fired but no handler*/
93	OR1K_DELAYED_NOP(OR1K_INST(l.bnf .L1))
94
95	/* Call handler, load data pointer */
96	OR1K_DELAYED(
97		OR1K_INST(l.lwz  r3,0(r13)),
98		OR1K_INST(l.jalr r14)
99	)
100
101.L1:
102	/* Clear bit from PICSR, return to start of checking loop */
103	l.ori	r6,r0,1
104	l.sll	r6,r6,r22
105	OR1K_DELAYED(
106		OR1K_INST(l.xor r20,r20,r6),
107		OR1K_INST(l.j   .L0)
108	)
109
110.L2:
111	/* Finish up - write PICSR back, restore r9*/
112	l.lwz	r9,0(r1)
113	l.mtspr	r0,r20,OR1K_SPR_PIC_PICSR_ADDR
114	OR1K_DELAYED(
115		OR1K_INST(l.addi r1,r1,4),
116		OR1K_INST(l.jr   r9)
117	)
118
119/* -------------------------------------------------------------------------- */
120/*!Function to enable an interrupt handler in the PICMR
121                                                                              */
122/* -------------------------------------------------------------------------- */
123	.global	or1k_interrupt_enable
124	.type	or1k_interrupt_enable,@function
125
126	/* r3 should have IRQ line for peripheral */
127or1k_interrupt_enable:
128	l.addi 	r1,r1,-4
129	l.sw	0(r1),r4
130	l.ori	r4,r0,0x1
131	l.sll	r4,r4,r3
132	l.mfspr	r3,r0,OR1K_SPR_PIC_PICMR_ADDR
133	l.or	r3,r3,r4
134	l.mtspr	r0,r3,OR1K_SPR_PIC_PICMR_ADDR
135	l.lwz	r4,0(r1)
136	OR1K_DELAYED(
137		OR1K_INST(l.addi	r1,r1,4),
138		OR1K_INST(l.jr	r9)
139	)
140
141/* -------------------------------------------------------------------------- */
142/*!Function to disable an interrupt handler in the PICMR
143                                                                              */
144/* -------------------------------------------------------------------------- */
145	.global	or1k_interrupt_disable
146	.type	or1k_interrupt_disable,@function
147
148	/* r3 should have IRQ line for peripheral */
149or1k_interrupt_disable:
150	l.addi 	r1,r1,-4
151	l.sw	0(r1),r4
152	l.ori	r4,r0,0x1
153	l.sll	r4,r4,r3
154	l.xori	r4,r4,0xffff
155	l.mfspr	r3,r0,OR1K_SPR_PIC_PICMR_ADDR
156	l.and	r3,r3,r4
157	l.mtspr	r0,r3,OR1K_SPR_PIC_PICMR_ADDR
158	l.lwz	r4,0(r1)
159	OR1K_DELAYED(
160		OR1K_INST(l.addi r1,r1,4),
161		OR1K_INST(l.jr   r9)
162	)
163