rt-thread-official/libcpu/risc-v/virt64/plic.c

135 lines
3.6 KiB
C
Raw Normal View History

2021-05-21 17:03:30 +08:00
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-05-20 bigmagic first version
*/
#include <rthw.h>
2021-09-11 11:07:51 +08:00
#include <rtthread.h>
#include <stdint.h>
2021-05-21 17:03:30 +08:00
#include "plic.h"
#include <riscv_io.h>
#include "encoding.h"
#include <riscv.h>
#include <string.h>
#include <stdlib.h>
2021-05-21 17:03:30 +08:00
/*
2021-05-21 18:39:41 +08:00
* Each PLIC interrupt source can be assigned a priority by writing
2021-05-21 17:03:30 +08:00
* to its 32-bit memory-mapped priority register.
2021-05-21 18:39:41 +08:00
* The QEMU-virt (the same as FU540-C000) supports 7 levels of priority.
* A priority value of 0 is reserved to mean "never interrupt" and
* effectively disables the interrupt.
* Priority 1 is the lowest active priority, and priority 7 is the highest.
* Ties between global interrupts of the same priority are broken by
* the Interrupt ID; interrupts with the lowest ID have the highest
2021-05-21 17:03:30 +08:00
* effective priority.
*/
void plic_set_priority(int irq, int priority)
{
*(uint32_t*)PLIC_PRIORITY(irq) = priority;
}
/*
2021-05-21 18:39:41 +08:00
* Each global interrupt can be enabled by setting the corresponding
2021-05-21 17:03:30 +08:00
* bit in the enables registers.
*/
void plic_irq_enable(int irq)
{
int hart = __raw_hartid();
2021-05-21 17:03:30 +08:00
*(uint32_t*)PLIC_ENABLE(hart) = ((*(uint32_t*)PLIC_ENABLE(hart)) | (1 << irq));
#ifdef RISCV_S_MODE
set_csr(sie, read_csr(sie) | MIP_SEIP);
#else
set_csr(mie, read_csr(mie) | MIP_MEIP);
#endif
}
void plic_irq_disable(int irq)
{
int hart = __raw_hartid();
2021-05-21 17:03:30 +08:00
*(uint32_t*)PLIC_ENABLE(hart) = (((*(uint32_t*)PLIC_ENABLE(hart)) & (~(1 << irq))));
}
2021-05-21 18:39:41 +08:00
/*
2021-05-21 17:03:30 +08:00
* PLIC will mask all interrupts of a priority less than or equal to threshold.
* Maximum threshold is 7.
* For example, a threshold value of zero permits all interrupts with
* non-zero priority, whereas a value of 7 masks all interrupts.
* Notice, the threshold is global for PLIC, not for each interrupt source.
*/
void plic_set_threshold(int threshold)
{
int hart = __raw_hartid();
2021-05-21 17:03:30 +08:00
*(uint32_t*)PLIC_THRESHOLD(hart) = threshold;
}
2021-05-21 18:39:41 +08:00
/*
2021-05-21 17:03:30 +08:00
* DESCRIPTION:
* Query the PLIC what interrupt we should serve.
* Perform an interrupt claim by reading the claim register, which
2021-05-21 18:39:41 +08:00
* returns the ID of the highest-priority pending interrupt or zero if there
* is no pending interrupt.
2021-05-21 17:03:30 +08:00
* A successful claim also atomically clears the corresponding pending bit
* on the interrupt source.
* RETURN VALUE:
2021-05-21 18:39:41 +08:00
* the ID of the highest-priority pending interrupt or zero if there
2021-05-21 17:03:30 +08:00
* is no pending interrupt.
*/
int plic_claim(void)
{
int hart = __raw_hartid();
2021-05-21 17:03:30 +08:00
int irq = *(uint32_t*)PLIC_CLAIM(hart);
return irq;
}
2021-05-21 18:39:41 +08:00
/*
2021-05-21 17:03:30 +08:00
* DESCRIPTION:
2021-05-21 18:39:41 +08:00
* Writing the interrupt ID it received from the claim (irq) to the
* complete register would signal the PLIC we've served this IRQ.
* The PLIC does not check whether the completion ID is the same as the
* last claim ID for that target. If the completion ID does not match an
2021-05-21 17:03:30 +08:00
* interrupt source that is currently enabled for the target, the completion
* is silently ignored.
* RETURN VALUE: none
*/
void plic_complete(int irq)
{
int hart = __raw_hartid();
2021-05-21 17:03:30 +08:00
*(uint32_t*)PLIC_COMPLETE(hart) = irq;
}
void plic_set_ie(rt_uint32_t word_index, rt_uint32_t val)
{
volatile void *plic_ie = (void *)(rt_size_t)(PLIC_BASE_ADDR + PLIC_ENABLE_BASE + word_index * 4);
writel(val, plic_ie);
}
void plic_init()
{
int i;
plic_set_threshold(0);
for(i = 0;i < 128;i++)
{
plic_set_priority(i,7);
}
plic_set_ie(0,0xffffffff);
plic_set_ie(1,0xffffffff);
plic_set_ie(2,0xffffffff);
plic_set_ie(3,0xffffffff);
rt_uint64_t addr;
for(addr = 0xC001000;addr <= 0xC1F1F80;addr += 4)
{
*((rt_uint32_t *)addr) = 0xffffffff;
}
}