Commit 07348d58 authored by Ben Avison's avatar Ben Avison Committed by ROOL

Extended IRQ support, and FIQ support

Both still use GIC bypass mode. Assuming for now that extended GPU peripherals
can't support FIQ without GIC (it seems as though they either all use IRQ or
all use FIQ, and RISC OS isn't set up for there being multiple FIQ sources
active at once).
parent 004817c4
......@@ -535,9 +535,21 @@ FIQ_ENB * &18 ; read: enabled basic interrupts; write: bi
FIQ_DIS1 * &20 ; read: enabled interrupts 1; write: bits to BIC from enabled interrupts 1
FIQ_DIS2 * &24 ; read: enabled interrupts 2; write: bits to BIC from enabled interrupts 2
FIQ_DISB * &28 ; read: enabled basic interrupts; write: bits to BIC from enabled basic interrupts
;
; Extended interrupt demultiplexing (BCM2838 only)
;
ExtIRQ_Base * &0000F300
ExtIRQ_STATUS0 * &00 ; read: pending extended interrupts 0-31
ExtIRQ_STATUS1 * &04 ; read: pending extended interrupts 32-51
ExtIRQ_MASK_STATUS0 * &08 ; read: masked extended interrupts 0-31
ExtIRQ_MASK_STATUS1 * &0C ; read: masked extended interrupts 32-51
ExtIRQ_MASK_SET0 * &08 ; write: set mask for extended interrupts 0-31
ExtIRQ_MASK_SET1 * &0C ; write: set mask for extended interrupts 32-51
ExtIRQ_MASK_CLEAR0 * &08 ; write: clear mask for extended interrupts 0-31
ExtIRQ_MASK_CLEAR1 * &0C ; write: clear mask for extended interrupts 32-51
; Raspberry Pi interrupt sources.
; There are 4 groups of 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
......@@ -552,7 +564,11 @@ FIQ_DISB * &28 ; read: enabled basic interrupts; write: bi
; the "base" interrupt registers. Add 32 to the ARM interrupt number to find
; the equivalent GIC interrupt number.
; * 32 core-specific interrupts managed by the QA7 block in BCM2836-8.
; * (At least) four other banks of 32 GPU interrupts in the GIC in BCM2838.
; * 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.
; devices in register 1 - start at 0
iDev_GPU_Timer0 * 0 ; not on list in datasheet
......@@ -622,6 +638,7 @@ iDev_GPU_PCM * 55
iDev_GPU_SDIO * 56 ; not on list in datasheet; only controller on BCM235-7; backward-compatible controller on BCM2838
iDev_GPU_Uart * 57 ; UART0 on BCM2835-7; shared UART0, UART2-5 on BCM2838
iDev_GPU_SlimBus * 58 ; not on list in datasheet
iDev_GPU_Extended * 58 ; extended peripheral interrupts all routed through here on BCM2838 when not using GIC
iDev_GPU_Vec * 59 ; not on list in datasheet
iDev_GPU_CPG * 60 ; not on list in datasheet
iDev_GPU_RNG * 61 ; not on list in datasheet
......@@ -674,7 +691,62 @@ iDev_QA7_LocalTimer # 4 ; Can only be assigned to one core (as either IRQ or
iDev_QA7_Max # 0
; GIC interrupt sources
; GPU extended peripheral interrupt sources
iDev_Ext_Base # 0
iDev_Ext_Vec * iDev_Ext_Base+0
iDev_Ext_BVNB0 * iDev_Ext_Base+1
iDev_Ext_BVNF0 * iDev_Ext_Base+2
iDev_Ext_BVNF1 * iDev_Ext_Base+3
iDev_Ext_BVNF5 * iDev_Ext_Base+4
iDev_Ext_BVNF9 * iDev_Ext_Base+5
iDev_Ext_BVNF16 * iDev_Ext_Base+6
iDev_Ext_BVNM0 * iDev_Ext_Base+7
iDev_Ext_BVNB1 * iDev_Ext_Base+8
iDev_Ext_AVS * iDev_Ext_Base+9 ; used (for thermal) by Linux
iDev_Ext_HDMI0_TX * iDev_Ext_Base+10
iDev_Ext_HDMI1_TX * iDev_Ext_Base+11
iDev_Ext_HDMI_AON_TX * iDev_Ext_Base+12
iDev_Ext_HDMI_BSC_TX * iDev_Ext_Base+13
iDev_Ext_PCIe_Err_Attn * iDev_Ext_Base+14
iDev_Ext_PCIe_IntA * iDev_Ext_Base+15 ; used by Linux
iDev_Ext_PCIe_IntB * iDev_Ext_Base+16 ; used by Linux
iDev_Ext_PCIe_IntC * iDev_Ext_Base+17 ; used by Linux
iDev_Ext_PCIe_IntD * iDev_Ext_Base+18 ; used by Linux
iDev_Ext_PCIe_IntR * iDev_Ext_Base+19
iDev_Ext_PCIe_MSI * iDev_Ext_Base+20 ; used by Linux
iDev_Ext_PCIe_NMI * iDev_Ext_Base+21
iDev_Ext_HVD0 * iDev_Ext_Base+22
iDev_Ext_MEMC0 * iDev_Ext_Base+23
iDev_Ext_SATA_AHCI * iDev_Ext_Base+24
iDev_Ext_SATA_GRB * iDev_Ext_Base+25
iDev_Ext_Sys * iDev_Ext_Base+26
iDev_Ext_Upg_Main * iDev_Ext_Base+27
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
iDev_Ext_HDMI_SEC * iDev_Ext_Base+32
iDev_Ext_CPU * iDev_Ext_Base+33
iDev_Ext_AIO * iDev_Ext_Base+34
iDev_Ext_DTE_Int0 * iDev_Ext_Base+35
iDev_Ext_DTE_Int1 * iDev_Ext_Base+36
iDev_Ext_DTE_Int2 * iDev_Ext_Base+37
iDev_Ext_Upg_Tmr * iDev_Ext_Base+38
iDev_Ext_GFX * iDev_Ext_Base+39
iDev_Ext_CPU_Therm_Hi * iDev_Ext_Base+40
iDev_Ext_XPT_RAV * iDev_Ext_Base+41
iDev_Ext_XPT_MCPB * iDev_Ext_Base+42
iDev_Ext_XPT_FE * iDev_Ext_Base+43
iDev_Ext_XPT_PCR * iDev_Ext_Base+44
iDev_Ext_XPT_CPU_Status * iDev_Ext_Base+45
iDev_Ext_XPT_SCPU_Status * iDev_Ext_Base+46
iDev_Ext_XPT_SCPU_RAV * iDev_Ext_Base+47
iDev_Ext_USB0_XHCI_0 * iDev_Ext_Base+48 ; used by Linux
iDev_Ext_USB0_USBD * iDev_Ext_Base+49
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
......@@ -683,15 +755,6 @@ iDev_GIC_PMU1 * 17
iDev_GIC_PMU2 * 18
iDev_GIC_PMU3 * 19
iDev_GIC_VCUSB * 40 ; additional interrupt for DWC
iDev_GIC_Thermal * 137
iDev_GIC_PCIe0 * 143
iDev_GIC_PCIe1 * 144
iDev_GIC_PCIe2 * 145
iDev_GIC_PCIe3 * 146
iDev_GIC_PCIe4 * 148
iDev_GIC_Genet0 * 157
iDev_GIC_Genet1 * 158
iDev_GIC_XHCI * 176
;IIC0 (BSC0, i.e. Broadcom Serial Controller 0)
......
......@@ -90,6 +90,8 @@ PeriBase # 4
IntBase # 4
PeriBase2 # 4
IRQ_Base_Address # 4
FIQ_Base_Address # 4
ExtIRQ_Base_Address # 4
ARM_Counter_IO_Address # 4
ARM_Timer_IO_Address # 4
UARTOldModemStatus # 4
......
......@@ -87,13 +87,40 @@ Interrupt_Init
LDR a1, PeriBase
ADD a1, a1, #IRQ_Base
STR a1, IRQ_Base_Address
ADD a1, a1, #FIQ_Base - IRQ_Base
STR a1, FIQ_Base_Address
ADD a1, a1, #ExtIRQ_Base - FIQ_Base
STR a1, ExtIRQ_Base_Address
MOV pc, lr
VC6_HAL_IRQEnable
QA7_HAL_IRQEnable ROUT
VC6_HAL_IRQEnable ROUT
CMP a1, #iDev_Ext_Max
BHS ExitZero
SUBS a2, a1, #iDev_Ext_Base
BLT HAL_IRQEnable_QA7_or_GPU
DoMemBarrier ip
LDR a1, ExtIRQ_Base_Address
MOV a3, #1
AND a4, a2, #&1F ; get bit in register
MOV a2, a2, LSR #5 ; shift to get relevant register
ADD ip, a1, #ExtIRQ_MASK_STATUS0
ADD a1, a1, #ExtIRQ_MASK_SET0
MOV a3, a3, LSL a4 ; bitmask
LDR a4, IRQ_Base_Address
LDR ip, [ip, a2, LSL #2] ; get old enable mask
STR a3, [a1, a2, LSL #2] ; enable our bit
MOV a1, #1 :SHL: (iDev_GPU_Extended - 32)
STR a1, [a4, #IRQ_EN2] ; enable extended interrupts
AND a1, ip, a3 ; test our bit in our mask
DoMemBarrier ip
MOV pc, lr
QA7_HAL_IRQEnable
CMP a1, #iDev_QA7_Max
BHS ExitZero
HAL_IRQEnable_QA7_or_GPU
SUBS a2, a1, #iDev_QA7_Base
BLT HAL_IRQEnable_GPU
MOV a4, #1 ; Signal this is an IRQ enable event
......@@ -245,11 +272,32 @@ ExitZero
MOV pc, lr
VC6_HAL_IRQDisable ROUT
CMP a1, #iDev_QA7_Max
CMP a1, #iDev_Ext_Max
BHS ExitZero
SUBS a2, a1, #iDev_Ext_Base
BLT %FT10
DoMemBarrier ip
LDR a1, ExtIRQ_Base_Address
MOV a3, #1
AND a4, a2, #&1F ; get bit in register
MOV a2, a2, LSR #5 ; shift to get relevant register
ADD ip, a1, #ExtIRQ_MASK_STATUS0
ADD a1, a1, #ExtIRQ_MASK_CLEAR0
MOV a3, a3, LSL a4 ; bitmask
LDR ip, [ip, a2, LSL #2] ; get old enable mask
STR a3, [a1, a2, LSL #2] ; enable our bit
AND a1, ip, a3 ; test our bit in our mask
; Note we don't disable IRQ 58 in the GPU here, since other extended
; interrupts may still be required
DoMemBarrier ip
MOV pc, lr
10
SUBS a2, a1, #iDev_QA7_Base
MOVGE a4, #0 ; Signal this is an IRQ disable event
BGE ToggleIRQ
CMP a1, #iDev_GPU_Extended
BEQ ExitZero ; don't allow shared extended interrupt bit to be masked
DoMemBarrier ip
LDR ip, IRQ_Base_Address
ADD ip, ip, #IRQ_DIS1_BCM2838
......@@ -314,8 +362,20 @@ VC6_HAL_IRQSource
BPL %FT90
TST a2, #QA7_GPU_IRQ_bit
BEQ %FT90 ; No GPU interrupt, so must be spurious? (a1 already -1)
; Read GPU interrupt source using BCM2838 register mappings
; Read GPU extended interrupt sources
DoMemBarrier ip
LDR a2, ExtIRQ_Base_Address
LDR a1, [a2, #ExtIRQ_STATUS1]
CLZ a1, a1
RSBS a1, a1, #31
ADDPL a1, a1, #iDev_Ext_Base + 32
BPL %FT90
LDR a1, [a2, #ExtIRQ_STATUS0]
CLZ a1, a1
RSBS a1, a1, #31
ADDPL a1, a1, #iDev_Ext_Base + 0
BPL %FT90
; Read GPU interrupt source using BCM2838 register mappings
LDR a2, IRQ_Base_Address
LDRB a1, [a2, #IRQ_PENDB_BCM2838] ; note, LDRB so we ignore bits 8-31
CLZ a1, a1
......@@ -323,6 +383,13 @@ VC6_HAL_IRQSource
ADDPL a1, a1, #iDev_ARM_Timer ; 64
BPL %FT90
LDR a1, [a2, #IRQ_PEND2_BCM2838]
; It's possible that a new extended IRQ became pending since we checked
; above. Ensure that in such a case, the earlier IRQ isn't reported as
; iDev_GPU_Extended. The CPU interrupt line will still be asserted when
; we finish handling whatever lower-priority interrupt initially caused
; us to be entered, but interrupt dispatch will simply be re-entered and
; we'll identify the correct extended IRQ at that time.
BIC a1, a1, #1 :SHL: (iDev_GPU_Extended - 32)
CLZ a1, a1
RSBS a1, a1, #31
ADDPL a1, a1, #iDev_GPU_HostPort ; 32
......@@ -373,8 +440,23 @@ ARM11_HAL_IRQSource
MOV pc, lr
VC6_HAL_IRQStatus ROUT
CMP a1, #iDev_QA7_Max
CMP a1, #iDev_Ext_Max
BHS ExitZero
SUBS a2, a1, #iDev_Ext_Base
BLT %FT10
DoMemBarrier ip
LDR a1, ExtIRQ_Base_Address
MOV a3, #1
AND a4, a2, #&1F ; get bit in register
MOV a2, a2, LSR #5 ; shift to get relevant register
ADD ip, a1, #ExtIRQ_MASK_STATUS0
MOV a3, a3, LSL a4 ; bitmask
LDR ip, [ip, a2, LSL #2] ; get old enable mask
AND a1, ip, a3 ; test our bit in our mask
DoMemBarrier ip
MOV pc, lr
10
SUBS a3, a1, #iDev_QA7_Base
BGE %FT40
; GPU pending registers now go in device order, so can't reuse ARM11 code
......@@ -433,8 +515,25 @@ FIQEnable * 1<<7
FIQSourceMask * &7F
VC6_HAL_FIQEnable ROUT
; TODO
MOV pc,lr
CMP a1, #iDev_QA7_Max
BHS ExitZero
SUBS a2, a1, #iDev_QA7_Base
BLT %FT20
MOV a4, #3 ; Signal this is a FIQ enable event
B ToggleIRQ
20
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
QA7_HAL_FIQEnable ROUT
CMP a1, #iDev_QA7_Max
......@@ -462,7 +561,24 @@ HAL_FIQEnable_GPU
MOV pc, lr
VC6_HAL_FIQDisable ROUT
; TODO
CMP a1, #iDev_QA7_Max
BHS ExitZero
SUBS a2, a1, #iDev_QA7_Base
BLT %FT20
MOV a4, #2 ; Signal this is a FIQ disable event
B ToggleIRQ
20
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
QA7_HAL_FIQDisable ROUT
......@@ -491,11 +607,9 @@ HAL_FIQDisable_GPU
DoMemBarrier ip
MOV pc, lr
VC6_HAL_FIQDisableAll ROUT
; TODO
MOV pc, lr
QA7_HAL_FIQDisableAll ROUT
MACRO
QA7_FIQDisableAll
LDR a1, IntBase
MRC p15, 0, a3, c0, c0, 5 ; Read MPIDR
AND a3, a3, #3 ; Extract core number
......@@ -531,9 +645,25 @@ QA7_HAL_FIQDisableAll ROUT
UBFX a1, a1, #2, #2
CMP a1, a3
MOVNE pc, lr ; We're not the owner, so leave them alone
MEND
VC6_HAL_FIQDisableAll ROUT
QA7_FIQDisableAll
; We are the GPU FIQ owner, so fall through to GPU FIQ disable code
; (n.b. race condition here if another core tries to claim the GPU FIQs)
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
QA7_HAL_FIQDisableAll ROUT
QA7_FIQDisableAll
; We are the GPU FIQ owner, so fall through to GPU FIQ disable code
; (n.b. race condition here if another core tries to claim the GPU FIQs)
ARM11_HAL_FIQDisableAll
DoMemBarrier ip
LDR ip, IRQ_Base_Address
......@@ -547,12 +677,9 @@ ARM11_HAL_FIQDisableAll
DoMemBarrier ip
MOV pc, lr
VC6_HAL_FIQSource
; TODO
MOV a1, #0
MOV pc, lr
QA7_HAL_FIQSource
MACRO
QA7_FIQSource
DoMemBarrier ip
LDR a2, IntBase
MRC p15, 0, a1, c0, c0, 5 ; Read MPIDR
......@@ -566,9 +693,35 @@ QA7_HAL_FIQSource
CLZ a1, a1
RSBS a1, a1, #31
ADDPL a1, a3, a1, LSL #2
BPL %FT90
BPL %F90
TST a2, #QA7_GPU_IRQ_bit
BEQ %FT90 ; No GPU interrupt, so must be spurious? (a1 already -1)
BEQ %F90 ; No GPU interrupt, so must be spurious? (a1 already -1)
MEND
VC6_HAL_FIQSource
QA7_FIQSource
; Fall through to read GPU interrupt source
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
QA7_HAL_FIQSource
QA7_FIQSource
; Fall through to read GPU interrupt source
ARM11_HAL_FIQSource
; There can only be one, the configured FIQ device
......@@ -580,16 +733,32 @@ ARM11_HAL_FIQSource
DoMemBarrier ip
MOV pc, lr
VC6_HAL_FIQStatus ROUT
; TODO
MOV a1, #0
RSBS a2, a1, #iDev_QA7_Max-1
CMPHS a1, #iDev_QA7_Base
BHS %FT20
CMP a1, #iDev_ARM_MiscGPU1
BHS ExitZero
; Here we're enquiring about a GPU FIQ
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
QA7_HAL_FIQStatus ROUT
QA7_HAL_FIQStatus
CMP a1, #iDev_QA7_Max
BHS ExitZero
SUBS a3, a1, #iDev_QA7_Base ; For GPU interrupts just skip straight to reading the pending registers (shouldn't really matter whether we own the GPU FIQ or not)
BLT %FT50
20
DoMemBarrier ip
LDR a2, IntBase
AND a1, a3, #3 ; Extract core number
......@@ -622,11 +791,14 @@ ARM11_HAL_IRQMax
MOV a1, #iDev_ARM11_Max
MOV pc, lr
VC6_HAL_IRQMax
QA7_HAL_IRQMax
MOV a1, #iDev_QA7_Max
MOV pc, lr
VC6_HAL_IRQMax
MOV a1, #iDev_Ext_Max
MOV pc, lr
; In: a1 = device number
; Out: a1 = IRQ mask
; a2 = FIQ mask
......@@ -635,12 +807,25 @@ QA7_HAL_IRQMax
; bit 30 = private flag
; bit 31 = interrupt can be routed to multiple cores at once
VC6_HAL_IRQProperties
CMP a1, #iDev_Ext_Max
MOVHS a1, #0
MOVHS a2, #0
MOVHS pc, lr
; Extended interrupts probably can't be used for FIQ
; Without using GIC, they have to be routed to the same core as all
; other GPU interrupts
CMP a1, #iDev_Ext_Base
BLO %FT10
MOV a1, #1
MOV a2, #0
MOV pc, lr
QA7_HAL_IRQProperties
CMP a1, #iDev_QA7_Max
MOVHS a1, #0
MOVHS a2, #0
MOVHS pc, lr
SUBS a2, a1, #iDev_ARM11_Max
10 SUBS a2, a1, #iDev_ARM11_Max
BLO ARM11_HAL_IRQProperties
; For now, just pretend that all the QA7 interrupts are core-specific
; In reality some of them can be switched (e.g. local timer)
......@@ -665,11 +850,16 @@ ARM11_HAL_IRQProperties
; Out: a1 = actual core mask
VC6_HAL_IRQSetCores
VC6_HAL_IRQGetCores
CMP a1, #iDev_Ext_Max
BHS ExitZero
B %FT10
QA7_HAL_IRQSetCores
QA7_HAL_IRQGetCores ; read-only version of IRQSetCores
CMP a1, #iDev_QA7_Max
BHS ExitZero
SUBS a2, a1, #iDev_ARM11_Max
10 RSBS a2, a1, #iDev_QA7_Max-1
SUBHSS a2, a1, #iDev_QA7_Base
MOV a1, #1
ANDHS a2, a2, #3
MOVHS a1, a1, LSL a2
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment