I'm trying to trigger a software generated interrupt on core1 from core0
on the Zynq Ultrascale+ Platform. Sadly however no interrupt ever reaches core1
.
I tried multiple approaches also using the xscugic
driver example. But it only worked from core0
to itself (see driver example) never to core1
. This post is my last resort. Can anyone help? What am I missing?
My code currently looks like this:
int ScuGicInit(XScuGic *IntcInstancePtr, u16 DeviceId) {
XScuGic_Config *IntcConfig;
int status;
// Get the configuration for the GIC
IntcConfig = XScuGic_LookupConfig(XPAR_SCUGIC_SINGLE_DEVICE_ID);
if (NULL == IntcConfig) {
return XST_FAILURE;
}
// Initialize the GIC
status = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig,
IntcConfig->CpuBaseAddress);
if (status != XST_SUCCESS) {
return status;
}
// Register the GIC with the exception framework
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT,
(Xil_ExceptionHandler)XScuGic_InterruptHandler,
IntcInstancePtr);
// Enable interrupts in the ARM
Xil_ExceptionEnable();
return XST_SUCCESS;
}
#define INTC_DEVICE_ID XPAR_SCUGIC_0_DEVICE_ID
#define INTC_DEVICE_INT_ID 0x0E
void core1(void){
int Status;
XScuGic IntcInstance;
// Initialize GIC
Status = ScuGicInit(&IntcInstance, XPAR_SCUGIC_SINGLE_DEVICE_ID);
if (Status != XST_SUCCESS) {
// Handle error condition
//return XST_FAILURE;
}
// Connect the SGI handler provided by Core1
Status = XScuGic_Connect(&IntcInstance, INTC_DEVICE_INT_ID,
(Xil_InterruptHandler)DeviceDriverHandler, &IntcInstance);
if (Status != XST_SUCCESS) {
// Handle error condition
//return XST_FAILURE;
}
// Enable the SGI interrupt
XScuGic_Enable(&IntcInstance, INTC_DEVICE_INT_ID);
// Core1 main loop
while (1) {
// Core1's tasks or sleep
}
while (1);
}
int main() {
int Status;
XScuGic IntcInstance;
// Initialize GIC
Status = ScuGicInit(&IntcInstance, XPAR_SCUGIC_SINGLE_DEVICE_ID);
if (Status != XST_SUCCESS) {
// Handle error condition
return XST_FAILURE;
}
set_start_addr();
release_acpus();
sleep(1);
// Core0 main loop
while (1) {
// Trigger an SGI to Core1
// Assuming Core1 has been configured to handle SGI ID 0
XScuGic_SoftwareIntr(&IntcInstance, INTC_DEVICE_INT_ID, XSCUGIC_SPI_CPU1_MASK);
sleep(1);
// Add a delay or triggering condition here as necessary to prevent continuous triggering
}
return XST_SUCCESS;
}
set_start_addr()
and release_acpus()
are verified to work properly. The Main function runs on core0
while the function core1
runs on core1
.
If found the solution. Core 0 initalizes its SCR_EL3 Register like so:
mov w1, #0 //; Initial value of register is unknown
orr w1, w1, #(1 << 11) //; Set ST bit (Secure EL1 can access CNTPS_TVAL_EL1, CNTPS_CTL_EL1 & CNTPS_CVAL_EL1)
orr w1, w1, #(1 << 10) //; Set RW bit (EL1 is AArch64, as this is the Secure world)
orr w1, w1, #(1 << 3) //; Set EA bit (SError routed to EL3)
orr w1, w1, #(1 << 2) //; Set FIQ bit (FIQs routed to EL3)
orr w1, w1, #(1 << 1) //; Set IRQ bit (IRQs routed to EL3)
msr SCR_EL3, x1
Especially the IRQ bit is of interest. Apparently this needed to be set on all CPUs that are running bare metal (EL3) to receive any kind of IRQ. After setting this bit on Core1, Core0 was able to trigger a interrupt.