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