Commit 288ddd47 authored by Jeffrey Lee's avatar Jeffrey Lee Committed by ROOL

Add GIC interrupt controller support for BCM2838.

* Requires 'enable_gic=1' in config.txt (or Pi4 dtb to be present?)
* IRQs are managed via the GIC, FIQs via the BCM2838 FIQ controller
* Implemented in s.IntVC6 to avoid making s.Interrupts too
confusing.
* Previous VC6 interrupt support removed from s.Interrupts
* From the OS's perspective, interrupt numbers mostly remain
unchanged. However iDev_QA7 interrupts are unavailable, and some of
the BCM2838 interrupts have been overlaid ontop of them.
* Device drivers must take care to issue HAL_IRQClear, as that is
a new requirement for this HAL
parent 045a679d
......@@ -17,7 +17,7 @@
COMPONENT = BCM2835 HAL
TARGET = BCM2835
OBJS = Top CLib CMOS Debug Interrupts SDIO Timers UART USB Video DMA Messaging GPIO VCHIQ IIC RTC SPI Touch KbdScan DBell
OBJS = Top CLib CMOS Debug Interrupts SDIO Timers UART USB Video DMA Messaging GPIO VCHIQ IIC RTC SPI Touch KbdScan DBell IntVC6
HDRS =
CMHGFILE =
......
......@@ -553,25 +553,31 @@ ExtIRQ_MASK_CLEAR1 * &0C ; write: clear mask for extended interrupts
; Raspberry Pi interrupt sources.
; There are 5 groups of interrupt sources:
; * 64 GPU interrupts. On BCM2835-7, these are mapped to bits in the "1" and "2"
; registers, but some are also mapped into the upper 24 bits of the "base"
; interrupt registers. We don't use the upper bits of the "base" registers
; because masking is only possible in the "1" and "2" registers, because
; IRQ_FIQCTL also (and only) accepts sources in that order, and because it
; keeps the timers with the lowest priority, which is desirable because we run
; our counter from them. BCM2838 has the same interrupt controller block, but
; it is normally disabled in favour of the GICv2, which features additional
; important interrupt sources. Add 64 to the GPU interrupt number to find the
; equivalent GIC interrupt number.
; * 8 ARM interrupts. On BCM2835-7, these are mapped into the bottom 8 bits of
; the "base" interrupt registers. Add 32 to the ARM interrupt number to find
; the equivalent GIC interrupt number.
; * 64 GPU interrupts.
; * On BCM2835-7, these are mapped to bits in the "1" and "2" registers, but
; some are also mapped into the upper 24 bits of the "base" interrupt
; registers. We don't use the upper bits of the "base" registers because
; masking is only possible in the "1" and "2" registers, because IRQ_FIQCTL
; also (and only) accepts sources in that order, and because it keeps the
; timers with the lowest priority, which is desirable because we run our
; counter from them.
; * BCM2838 has the same interrupt controller block, but it is normally
; disabled in favour of the GICv2, which features additional important
; interrupt sources. With the GIC, the GPU interrupts are mapped to SPIs
; 64 to 127.
; * 8 ARM interrupts.
; * On BCM2835-7, these are mapped into the bottom 8 bits of the "base"
; interrupt registers.
; * On the BCM2838 GIC, they're mapped to SPIs 32-39.
; * 32 core-specific interrupts managed by the QA7 block in BCM2836-8.
; * These are at least partially mapped to GIC SPIs 0-31, in a non-trivial
; manner.
; * 64 GPU extended peripheral interrupts in BCM2838. These are routed through
; GPU interrupt 58 when bypassing the GIC, otherwise add 128 to find the
; equivalent GIC interrupt number.
; * Other GIC interrupts on BCM2838 in the ranges 0-31, 40-63, 192-255. It is
; not clear if these can be accessed in GIC bypass mode.
; GPU interrupt 58 when bypassing the GIC, otherwise they're mapped to SPIs
; 128-191.
; * The GIC also has some extra BCM2838-specific interrupts mapped to SPIs
; 40-63 (and potentially some other locations). It's unclear whether these
; are accessible when the GIC is bypassed.
; devices in register 1 - start at 0
iDev_GPU_Timer0 * 0 ; not on list in datasheet
......@@ -655,6 +661,7 @@ iDev_ARM_GPU0Hlt * 64+4
iDev_ARM_GPU1Hlt * 64+5
iDev_ARM_IllegAcs1 * 64+6
iDev_ARM_IllegAcs0 * 64+7
; Following iDev_ARM interrupts aren't valid when using the GIC (GIC reuses some for different purposes)
iDev_ARM_MiscGPU1 * 64+8 ; OR of GPU IRQs 0-31 excluding those listed below
iDev_ARM_MiscGPU2 * 64+9 ; OR of GPU IRQs 32-63 excluding those listed below
iDev_ARM_VCJPEG * 64+10 ; copy of GPU IRQ 7
......@@ -694,8 +701,10 @@ iDev_QA7_LocalTimer # 4 ; Can only be assigned to one core (as either IRQ or
iDev_QA7_Max # 0
; GPU extended peripheral interrupt sources
iDev_Ext_Base # 0
; GPU extended peripheral interrupt sources - overlaid on QA7 interrupts to
; avoid wasting lots of number space (extended interrupts are only used when
; the GIC is used, which also mostly rules out QA7 interrupts)
iDev_Ext_Base * 64+32
iDev_Ext_Vec * iDev_Ext_Base+0
iDev_Ext_BVNB0 * iDev_Ext_Base+1
iDev_Ext_BVNF0 * iDev_Ext_Base+2
......@@ -728,6 +737,7 @@ iDev_Ext_V3D * iDev_Ext_Base+28
iDev_Ext_Genet_A * iDev_Ext_Base+29 ; used by Linux
iDev_Ext_Genet_B * iDev_Ext_Base+30 ; used by Linux
iDev_Ext_BVNM1 * iDev_Ext_Base+31
; Note: 32+ aren't accessible via the GIC (boot stub doesn't assign them to the correct group)
iDev_Ext_HDMI_SEC * iDev_Ext_Base+32
iDev_Ext_CPU * iDev_Ext_Base+33
iDev_Ext_AIO * iDev_Ext_Base+34
......@@ -750,14 +760,29 @@ iDev_Ext_USB0_PP_Changed_0 * iDev_Ext_Base+50
iDev_Ext_Max * iDev_Ext_Base+51
; Remaining GIC interrupt sources
; For now, these are the literal interrupt numbers and haven't had any offsets applied
; TODO: figure out how to combine them into the unified iDev numberspace
iDev_GIC_PMU0 * 16
iDev_GIC_PMU1 * 17
iDev_GIC_PMU2 * 18
iDev_GIC_PMU3 * 19
iDev_GIC_VCUSB * 40 ; additional interrupt for DWC
iDev_GIC_Base * iDev_Ext_Base+64
iDev_GIC_QA7_Core0_MBox0 * iDev_GIC_Base+0 ; Mailboxes from the QA7 block
iDev_GIC_QA7_Core0_MBox1 * iDev_GIC_Base+1 ;
iDev_GIC_QA7_Core0_MBox2 * iDev_GIC_Base+2 ; Note that we don't attempt to
iDev_GIC_QA7_Core0_MBox3 * iDev_GIC_Base+3 ; map these device numbers to
iDev_GIC_QA7_Core1_MBox0 * iDev_GIC_Base+4 ; their iDev_QA7 equivalents - it
iDev_GIC_QA7_Core1_MBox1 * iDev_GIC_Base+5 ; would add a bit too much
iDev_GIC_QA7_Core1_MBox2 * iDev_GIC_Base+6 ; complexity to the interrupt
iDev_GIC_QA7_Core1_MBox3 * iDev_GIC_Base+7 ; handling. Instead we just have
iDev_GIC_QA7_Core2_MBox0 * iDev_GIC_Base+8 ; the HAL report the different
iDev_GIC_QA7_Core2_MBox1 * iDev_GIC_Base+9 ; device numbers to the OS.
iDev_GIC_QA7_Core2_MBox2 * iDev_GIC_Base+10
iDev_GIC_QA7_Core2_MBox3 * iDev_GIC_Base+11
iDev_GIC_QA7_Core3_MBox0 * iDev_GIC_Base+12
iDev_GIC_QA7_Core3_MBox1 * iDev_GIC_Base+13
iDev_GIC_QA7_Core3_MBox2 * iDev_GIC_Base+14
iDev_GIC_QA7_Core3_MBox3 * iDev_GIC_Base+15
iDev_GIC_PMU0 * iDev_GIC_Base+16
iDev_GIC_PMU1 * iDev_GIC_Base+17
iDev_GIC_PMU2 * iDev_GIC_Base+18
iDev_GIC_PMU3 * iDev_GIC_Base+19
iDev_GIC_VCUSB * iDev_ARM_MiscGPU1 ; GIC SPI 40, additional interrupt for DWC
;IIC0 (BSC0, i.e. Broadcom Serial Controller 0)
......
......@@ -91,7 +91,8 @@ IntBase # 4
PeriBase2 # 4
IRQ_Base_Address # 4
FIQ_Base_Address # 4
ExtIRQ_Base_Address # 4
GICD_Base_Address # 4
GICC_Base_Address # 4
ARM_Counter_IO_Address # 4
ARM_Timer_IO_Address # 4
SDIO_Address # 4
......@@ -121,6 +122,8 @@ Timer SETA Timer + 1
FB_CacheMode # 4
GIC_LastSGI # 4*4 ; Last SGI interrupt that was received by each core, for HAL_IRQClear
; info interrogated from the VC side
ARM_Base # 4
ARM_End # 4
......
......@@ -115,7 +115,11 @@ DBell_Sleep
DBell_GetIRQ
; In: a2 = core number
ADD a1, a2, #iDev_QA7_MBox0
; Return GIC or non-GIC device numbers, as appropriate
CPUDetect ip
ADDLS a1, a2, #iDev_QA7_MBox0
MOVHI a1, a2, LSL #2
ADDHI a1, a1, #iDev_GIC_QA7_Core0_MBox0
MOV pc, lr
DBell_ClearIRQ
......
;
; Copyright (c) 2019, RISC OS Open Ltd
; All rights reserved.
;
; Redistribution and use in source and binary forms, with or without
; modification, are permitted provided that the following conditions are met:
; * Redistributions of source code must retain the above copyright
; notice, this list of conditions and the following disclaimer.
; * Redistributions in binary form must reproduce the above copyright
; notice, this list of conditions and the following disclaimer in the
; documentation and/or other materials provided with the distribution.
; * Neither the name of RISC OS Open Ltd nor the names of its contributors
; may be used to endorse or promote products derived from this software
; without specific prior written permission.
;
; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
; ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
; LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
; SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
; CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
; ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
; POSSIBILITY OF SUCH DAMAGE.
;
; Interrupt handling - BCM2711 / 2838
; Note that contrary to the Cortex-A72 TRM, the BCM2838 has opted to go with
; a GICv2 rather than the expected GICv3.
EXPORT InterruptVC6_Init
EXPORT VC6_HAL_IRQEnable
EXPORT VC6_HAL_IRQDisable
EXPORT VC6_HAL_IRQClear
EXPORT VC6_HAL_IRQSource
EXPORT VC6_HAL_IRQStatus
EXPORT VC6_HAL_FIQEnable
EXPORT VC6_HAL_FIQDisable
EXPORT VC6_HAL_FIQDisableAll
EXPORT VC6_HAL_FIQClear
EXPORT VC6_HAL_FIQSource
EXPORT VC6_HAL_FIQStatus
EXPORT VC6_HAL_IRQMax
EXPORT VC6_HAL_IRQProperties
EXPORT VC6_HAL_IRQSetCores
EXPORT VC6_HAL_IRQGetCores
GET Hdr:ListOpts
GET Hdr:Macros
GET Hdr:System
GET Hdr:Proc
GET Hdr:HALEntries
GET hdr.BCM2835
GET hdr.StaticWS
GBLL GICDebug
GICDebug SETL {FALSE} :LAND: HALDebug
[ HALDebug
IMPORT HAL_DebugTX
IMPORT HAL_DebugHexTX4
IMPORT HAL_DebugTXStrInline
]
AREA |ARM$$code|, CODE, READONLY, PIC
; Mapping of OS device numbers to GIC interrupts, and vice-versa:
; - GIC SPI 0-31 are for QA7 interrupts (but with non-trivial mapping to iDev_QA7)
; - GIC SPI 32-63 map to iDev_ARM (first 8 only? rest are dupes of other GPU interrupts)
; - GIC SPI 64-127 map to iDev_GPU
; - GIC SPI 128-191 map to iDev_Ext
; - SPI literally means SPI, i.e. add an extra 32 to get the real GIC interrupt number
; This means that the bottom five bits of each IRQ can be a 1:1 mapping, and
; the top bits can be remapped via a table lookup.
OStoGIC
ASSERT iDev_GPU_Timer0 = 0
DCB 3 ; iDev_GPU
ASSERT iDev_GPU_HostPort = 32
DCB 4 ; iDev_GPU+32
ASSERT iDev_ARM_Timer = 64
DCB 2 ; iDev_ARM
ASSERT iDev_Ext_Base = 96
DCB 5 ; iDev_Ext
ASSERT iDev_Ext_HDMI_SEC = 128
DCB 6 ; iDev_Ext+32
ASSERT iDev_GIC_Base = 160
DCB 1 ; iDev_GIC
PPI_BASE * (. - OStoGIC)*32
DCB 0 ; PPI core 0
DCB 0 ; PPI core 1
DCB 0 ; PPI core 2
DCB 0 ; PPI core 3
MAX_IRQ * (. - OStoGIC)*32
ALIGN
GICtoOS
DCB 6 ; PPIs (also 7, 8, 9)
DCB 5 ; iDev_GIC
DCB 2 ; iDev_ARM
DCB 0 ; iDev_GPU
DCB 1 ; iDev_GPU+32
DCB 3 ; iDev_Ext
DCB 4 ; iDev_Ext+32
ALIGN
MACRO
OStoGICNumber $irq, $temp
ADR $temp, OStoGIC
LDRB $temp, [$temp, $irq, LSR #5]
BFI $irq, $temp, #5, #8
MEND
MACRO
OStoGICBitno $regno, $bitno, $irq
ASSERT $regno <> $irq
ADR $regno, OStoGIC
LDRB $regno, [$regno, $irq, LSR #5]
AND $bitno, $irq, #31
MEND
; Map GIC IRQ number to OS GIC number
; Also returns CPU core number in $core, if it's a private interrupt
MACRO
GICtoOSNumber $irq, $core
ADR $core, GICtoOS
CMP $irq, #32
LDRB $core, [$core, $irq, LSR #5]
BFI $irq, $core, #5, #8
; Remap private interrupts
MRCLO p15, 0, $core, c0, c0, 5
ANDLO $core, $core, #3
ADDLO $irq, $irq, $core, LSL #5
MEND
; Things the boot stubs do for us:
; https://github.com/raspberrypi/tools/blob/master/armstubs/armstub7.S
;
; * Set GICD_CTLR to 3 for secondary cores (group 0 + 1 enabled). For the primary core it's not initialised.
; * Assign the first 192 interrupts to group 1 (i.e. private interrupts plus first 160 SPIs)
; * Set GICC_CTLR to &1e7: GIC bypasses disabled, AckCtl=1 (but irrelevant since it'll only apply to secure mode), group 0+1 enabled
; * Set GICC_PMR to &ff (= any priority level will pass)
; * Drops out of secure mode into non-secure SVC
;
; The upshot of the above is that we can only use the GIC for IRQs (not FIQs),
; and the extended GPU IRQs in the range >= iDev_Ext_Base+32 are inaccessible.
; However we do have control over the FIQ bypass, so by leaving that enabled we
; can access FIQs via the new BCM2838 FIQ controller.
;
; TODO - Do we still need BCM2835-style memory barriers?
MAX_FIQ * iDev_ARM_MiscGPU1
InterruptVC6_Init ROUT
Entry "v1-v3"
LDR a1, PeriBase
ADD a1, a1, #FIQ_Base
STR a1, FIQ_Base_Address
LDR a1, IntBase
ADD v1, a1, #GICD_Base
STR v1, GICD_Base_Address
ADD v2, a1, #GICC_Base
STR v2, GICC_Base_Address
; Disable distributor while we fiddle with it
MOV a1, #0
STR a1, [v1, #GICD_CTLR]
; How many IRQ lines does the GIC support?
LDR v3, [v1, #GICD_TYPER]
AND v3, v3, #&1F
ADD v3, v3, #1 ; num_interrupts/32
; Disable all interrupts
MOV a1, #-1
ADD a2, v1, #GICD_ICENABLER
MOV a3, v3
10
STR a1, [a2], #4
SUBS a3, a3, #1
BNE %BT10
; Set priority & CPU target
LDR a1, =&80808080 ; Mid priority
LDR a2, =&01010101 ; CPU 0
ADD a3, v1, #GICD_IPRIORITYR
MOV a4, v3, LSL #3
20
STR a2, [a3, #GICD_ITARGETSR-GICD_IPRIORITYR]
STR a1, [a3], #4
SUBS a4, a4, #1
BGT %BT20
; Route QA7 mailbox interrupts to the expected cores (SMP module currently doesn't configure routing itself)
MOV a2, a2, LSL #1
STR a2, [v1, #GICD_ITARGETSR+36]
MOV a2, a2, LSL #1
STR a2, [v1, #GICD_ITARGETSR+40]
MOV a2, a2, LSL #1
STR a2, [v1, #GICD_ITARGETSR+44]
; Configure all interrupts as level-triggered
MOV a1, #0
ADD a2, v1, #GICD_ICFGR
MOV a3, v3, LSL #1
SUB a3, a3, #1
30
STR a1, [a2, #4]! ; Pre-increment (ICFGR0 is read-only)
SUBS a3, a3, #1
BGT %BT30
; We can now re-enable the controller
MOV a1, #1
STR a1, [v1, #GICD_CTLR]
; Configure CPU interface
MOV a1, #&FF
STR a1, [v2, #GICC_PMR] ; Highest PMR value = any priority interrupt will pass the test
MOV a1, #3
STR a1, [v2, #GICC_BPR] ; gggg.ssss binary point? not used ATM
; Enable CPU interface
; - IRQBypDisGrp1 is ignored since some of the secure mode settings take priority over this bit
; - FIQBypDisGrp1 is left at zero so that the bypass is enabled, allowing us to get FIQs from the BCM2838 FIQ controller
MOV a1, #1
STR a1, [v2, #GICC_CTLR]
EXIT
;
; IRQ handling
;
VC6_HAL_IRQEnable ROUT
CMP a1, #MAX_IRQ
BHS ExitZero
[ GICDebug
Push "lr"
BL HAL_DebugTXStrInline
DCB "eOG ",0
ALIGN
BL HAL_DebugHexTX4
Pull "lr"
]
LDR a4, GICD_Base_Address
OStoGICBitno a2, a3, a1
[ GICDebug
Push "a1-a4,ip,lr"
ORR a1, a3, a2, LSL #5
BL HAL_DebugHexTX4
MOV a1, #10
BL HAL_DebugTX
Pull "a1-a4,ip,lr"
]
MOV ip, #1
ADD a4, a4, #GICD_ISENABLER
MOV a3, ip, LSL a3
LDR a1, [a4, a2, LSL #2] ; Get old state
STR a3, [a4, a2, LSL #2] ; Enable
AND a1, a1, a3
MOV pc, lr
VC6_HAL_IRQDisable ROUT
CMP a1, #MAX_IRQ
BHS ExitZero
LDR a4, GICD_Base_Address
OStoGICBitno a2, a3, a1
MOV ip, #1
ADD a4, a4, #GICD_ICENABLER
MOV a3, ip, LSL a3
LDR ip, [a4, a2, LSL #2]! ; Get old state
STR a3, [a4] ; Set new state
LDR a4, [a4, #GICD_ISACTIVER-GICD_ICENABLER]
TST a4, a3 ; Was it active?
BEQ %FT90
ORRS a4, a2, a3, LSR #16 ; SGI?
BFINE a1, a2, #5, #8 ; Construct GIC interrupt number
BNE %FT80
; Look up the last SGI that was received for this core, it should correspond to the one we need to clear
; TODO - Potential interrupt hole regarding this?
MRC p15, 0, a2, c0, c0, 5
ADR a1, GIC_LastSGI
AND a2, a2, #3
LDR a1, [a1, a2, LSL #2]
80
LDR a2, GICC_Base_Address
STR a1, [a2, #GICC_EOIR]
90
AND a1, ip, a3
DSB SY
MOV pc, lr
VC6_HAL_IRQClear ROUT
LDR a4, GICC_Base_Address
OStoGICNumber a1, ip
CMP a1, #16 ; SGI?
BHS %FT10
; Look up the last SGI that was received for this core, it should correspond to the one we need to clear
MRC p15, 0, ip, c0, c0, 5
ADR a1, GIC_LastSGI
AND ip, ip, #3
LDR a1, [a1, ip, LSL #2]
10
STR a1, [a4, #GICC_EOIR]
DSB SY
MOV pc, lr
VC6_HAL_IRQSource ROUT
LDR a4, GICC_Base_Address
LDR a2, [a4, #GICC_IAR]
[ GICDebug
Push "lr"
BL HAL_DebugTXStrInline
DCB "sGO ",0
ALIGN
MOV a1, a2
BL HAL_DebugHexTX4
Pull "lr"
]
UBFX a1, a2, #0, #10
CMP a1, #&3FC ; Spurious interrupt?
MOVHS a1, #-1
MOVHS pc, lr
; Remap to OS
GICtoOSNumber a1, ip
; If it's an SGI, make a note of the IAR value so HAL_IRQClear can clear it correctly
TST a2, #&3F0
ADREQ a4, GIC_LastSGI
STREQ a2, [a4, ip, LSL #2]
[ GICDebug
Push "a1,lr"
BL HAL_DebugHexTX4
MOV a1, #10
BL HAL_DebugTX
Pull "a1,lr"
]
MOV pc, lr
VC6_HAL_IRQStatus ROUT
CMP a1, #MAX_IRQ
BHS ExitZero
LDR a4, GICD_Base_Address
OStoGICBitno a2, a3, a1
MOV ip, #1
ADD a4, a4, #GICD_ISPENDR
LDR a1, [a4, a2, LSL #2]
AND a1, ip, a1, LSR a3
MOV pc, lr
;
; FIQ handling
;
; This implementation only provides access to the interrupts exposed by the
; BCM2828 FIQ controller, i.e. iDev_GPU and iDev_ARM. Technically we also have
; access to the interrupts from the QA7 controller (BCM2838 FIQ controller is
; the QA7 "GPU" FIQ?), but the QA7 interrupts aren't very exciting, so for now
; just ignore them.
VC6_HAL_FIQEnable ROUT
CMP a1, #MAX_FIQ
BHS ExitZero
DoMemBarrier ip
LDR ip, FIQ_Base_Address
ADD ip, ip, #FIQ_EN1
MOV a2, #1
AND a3, a1, #&1F ; get bit in register
MOV a2, a2, LSL a3 ; bitmask
MOV a3, a1, LSR #5 ; shift to get relevant register
LDR a4, [ip, a3, LSL #2] ; get old enable mask
STR a2, [ip, a3, LSL #2] ; enable our bit
AND a1, a2, a4 ; test our bit in old mask
DoMemBarrier ip
MOV pc, lr
VC6_HAL_FIQDisable ROUT
CMP a1, #MAX_FIQ
BHS ExitZero
DoMemBarrier ip
LDR ip, FIQ_Base_Address
ADD ip, ip, #FIQ_DIS1
MOV a2, #1
AND a3, a1, #&1F ; get bit in register
MOV a2, a2, LSL a3 ; bitmask
MOV a3, a1, LSR #5 ; shift to get relevant register
LDR a4, [ip, a3, LSL #2] ; get old enable mask
STR a2, [ip, a3, LSL #2] ; disable our bit
AND a1, a2, a4 ; test our bit in old mask
DoMemBarrier ip
MOV pc, lr
VC6_HAL_FIQDisableAll ROUT
MOV a1, #-1
LDR ip, FIQ_Base_Address
DoMemBarrier a2
STR a1, [ip, #FIQ_DIS1]
STR a1, [ip, #FIQ_DIS2]
STR a1, [ip, #FIQ_DISB]
DoMemBarrier a2
MOV pc, lr
VC6_HAL_FIQClear ROUT
MOV pc, lr
VC6_HAL_FIQSource ROUT
DoMemBarrier ip
LDR a2, FIQ_Base_Address
LDRB a1, [a2, #FIQ_PENDB] ; note, LDRB so we ignore bits 8-31
CLZ a1, a1
RSBS a1, a1, #31
ADDPL a1, a1, #iDev_ARM_Timer ; 64
BPL %FT90
LDR a1, [a2, #FIQ_PEND2]
CLZ a1, a1
RSBS a1, a1, #31
ADDPL a1, a1, #iDev_GPU_HostPort ; 32
BPL %FT90
LDR a1, [a2, #FIQ_PEND1]
CLZ a1, a1
RSB a1, a1, #31
90
DoMemBarrier ip
MOV pc, lr
VC6_HAL_FIQStatus ROUT
CMP a1, #MAX_FIQ
BHS ExitZero
DoMemBarrier ip
LDR ip, FIQ_Base_Address
ASSERT FIQ_PEND1 = 0
MOV a2, #1
AND a3, a1, #&1F ; get bit in register
MOV a2, a2, LSL a3 ; bitmask
MOV a3, a1, LSR #5 ; shift to get relevant register
LDR a4, [ip, a3, LSL #2] ; get pending mask
AND a1, a2, a4 ; test our bit
DoMemBarrier ip
MOV pc, lr
;
; Misc
;
VC6_HAL_IRQMax ROUT
MOV a1, #MAX_IRQ
MOV pc, lr
; In: a1 = device number
; Out: a1 = IRQ mask
; a2 = FIQ mask
; bits 0-15 of each register give cores that the interrupt can be
; assigned to
; bit 30 = private flag
; bit 31 = interrupt can be routed to multiple cores at once
VC6_HAL_IRQProperties ROUT
CMP a1, #MAX_IRQ
MOV a2, #0
MOVHS a1, #0
MOVHS pc, lr
SUBS a1, a1, #PPI_BASE
BGE %FT90
; SPI
CMP a1, #MAX_FIQ-PPI_BASE
MOVLT a2, #1 ; Fixed FIQ routing to core 0
MOV a1, #&F + HALIRQProperty_Multicore
MOV pc, lr
90
; PPI
MOV a1, a1, LSR #5
MOV a3, #1
MOV a1, a3, LSL a1
ORR a1, a1, #HALIRQProperty_Private
MOV pc, lr
; In: a1 = device number
; a2 = desired core mask
; Out: a1 = actual core mask
VC6_HAL_IRQSetCores ROUT
CMP a1, #MAX_IRQ
BHS ExitZero
SUBS a2, a1, #PPI_BASE
BGE %FT80
; SPI
LDR a4, GICD_Base_Address
OStoGICNumber a1, ip
ADD a4, a4, a1
AND a1, a2, #&F
STRB a1, [a4, #GICD_ITARGETSR]
MOV pc, lr
VC6_HAL_IRQGetCores ; read-only version of IRQSetCores
CMP a1, #MAX_IRQ
BHS ExitZero
SUBS a2, a1, #PPI_BASE
BGE %FT80
; SPI
LDR a4, GICD_Base_Address
OStoGICNumber a1, ip
ADD a4, a4, #GICD_ITARGETSR
LDRB a1, [a4, a1]
MOV pc, lr
80
; PPI
MOV a2, a2, LSR #5
MOV a1, #1
MOV a1, a1, LSL a2