mirror of
https://github.com/riscv-software-src/opensbi.git
synced 2025-11-23 11:14:20 +00:00
lib: utils/irqchip: Add APLIC restore function
Since the APLIC may enter a reset state upon system wake-up from a platform low power state, adding a restore function to reinitialize the APLIC. Reviewed-by: Yong-Xuan Wang <yongxuan.wang@sifive.com> Reviewed-by: Cyan Yang <cyan.yang@sifive.com> Reviewed-by: Anup Patel <anup@brainfault.org> Signed-off-by: Nick Hu <nick.hu@sifive.com> Link: https://lore.kernel.org/r/20251020-cache-upstream-v7-7-69a132447d8a@sifive.com Signed-off-by: Anup Patel <anup@brainfault.org>
This commit is contained in:
@@ -33,6 +33,7 @@ struct aplic_delegate_data {
|
||||
struct aplic_data {
|
||||
/* Private members */
|
||||
struct sbi_irqchip_device irqchip;
|
||||
struct sbi_dlist node;
|
||||
/* Public members */
|
||||
unsigned long addr;
|
||||
unsigned long size;
|
||||
@@ -48,4 +49,6 @@ struct aplic_data {
|
||||
|
||||
int aplic_cold_irqchip_init(struct aplic_data *aplic);
|
||||
|
||||
void aplic_reinit_all(void);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -115,6 +115,90 @@
|
||||
#define APLIC_DISABLE_ITHRESHOLD 1
|
||||
#define APLIC_ENABLE_ITHRESHOLD 0
|
||||
|
||||
static SBI_LIST_HEAD(aplic_list);
|
||||
static void aplic_writel_msicfg(struct aplic_msicfg_data *msicfg,
|
||||
void *msicfgaddr, void *msicfgaddrH);
|
||||
|
||||
static void aplic_init(struct aplic_data *aplic)
|
||||
{
|
||||
struct aplic_delegate_data *deleg;
|
||||
u32 i, j, tmp;
|
||||
int locked;
|
||||
|
||||
/* Set domain configuration to 0 */
|
||||
writel(0, (void *)(aplic->addr + APLIC_DOMAINCFG));
|
||||
|
||||
/* Disable all interrupts */
|
||||
for (i = 0; i <= aplic->num_source; i += 32)
|
||||
writel(-1U, (void *)(aplic->addr + APLIC_CLRIE_BASE +
|
||||
(i / 32) * sizeof(u32)));
|
||||
|
||||
/* Set interrupt type and priority for all interrupts */
|
||||
for (i = 1; i <= aplic->num_source; i++) {
|
||||
/* Set IRQ source configuration to 0 */
|
||||
writel(0, (void *)(aplic->addr + APLIC_SOURCECFG_BASE +
|
||||
(i - 1) * sizeof(u32)));
|
||||
/* Set IRQ target hart index and priority to 1 */
|
||||
writel(APLIC_DEFAULT_PRIORITY, (void *)(aplic->addr +
|
||||
APLIC_TARGET_BASE +
|
||||
(i - 1) * sizeof(u32)));
|
||||
}
|
||||
|
||||
/* Configure IRQ delegation */
|
||||
for (i = 0; i < APLIC_MAX_DELEGATE; i++) {
|
||||
deleg = &aplic->delegate[i];
|
||||
if (!deleg->first_irq || !deleg->last_irq)
|
||||
continue;
|
||||
if (aplic->num_source < deleg->first_irq ||
|
||||
aplic->num_source < deleg->last_irq)
|
||||
continue;
|
||||
if (deleg->child_index > APLIC_SOURCECFG_CHILDIDX_MASK)
|
||||
continue;
|
||||
if (deleg->first_irq > deleg->last_irq) {
|
||||
tmp = deleg->first_irq;
|
||||
deleg->first_irq = deleg->last_irq;
|
||||
deleg->last_irq = tmp;
|
||||
}
|
||||
for (j = deleg->first_irq; j <= deleg->last_irq; j++)
|
||||
writel(APLIC_SOURCECFG_D | deleg->child_index,
|
||||
(void *)(aplic->addr + APLIC_SOURCECFG_BASE +
|
||||
(j - 1) * sizeof(u32)));
|
||||
}
|
||||
|
||||
/* Default initialization of IDC structures */
|
||||
for (i = 0; i < aplic->num_idc; i++) {
|
||||
writel(0, (void *)(aplic->addr + APLIC_IDC_BASE +
|
||||
i * APLIC_IDC_SIZE + APLIC_IDC_IDELIVERY));
|
||||
writel(0, (void *)(aplic->addr + APLIC_IDC_BASE +
|
||||
i * APLIC_IDC_SIZE + APLIC_IDC_IFORCE));
|
||||
writel(APLIC_DISABLE_ITHRESHOLD, (void *)(aplic->addr +
|
||||
APLIC_IDC_BASE +
|
||||
(i * APLIC_IDC_SIZE) +
|
||||
APLIC_IDC_ITHRESHOLD));
|
||||
}
|
||||
|
||||
/* MSI configuration */
|
||||
locked = readl((void *)(aplic->addr + APLIC_MMSICFGADDRH)) & APLIC_xMSICFGADDRH_L;
|
||||
if (aplic->targets_mmode && aplic->has_msicfg_mmode && !locked) {
|
||||
aplic_writel_msicfg(&aplic->msicfg_mmode,
|
||||
(void *)(aplic->addr + APLIC_MMSICFGADDR),
|
||||
(void *)(aplic->addr + APLIC_MMSICFGADDRH));
|
||||
}
|
||||
if (aplic->targets_mmode && aplic->has_msicfg_smode && !locked) {
|
||||
aplic_writel_msicfg(&aplic->msicfg_smode,
|
||||
(void *)(aplic->addr + APLIC_SMSICFGADDR),
|
||||
(void *)(aplic->addr + APLIC_SMSICFGADDRH));
|
||||
}
|
||||
}
|
||||
|
||||
void aplic_reinit_all(void)
|
||||
{
|
||||
struct aplic_data *aplic;
|
||||
|
||||
sbi_list_for_each_entry(aplic, &aplic_list, node)
|
||||
aplic_init(aplic);
|
||||
}
|
||||
|
||||
static void aplic_writel_msicfg(struct aplic_msicfg_data *msicfg,
|
||||
void *msicfgaddr, void *msicfgaddrH)
|
||||
{
|
||||
@@ -163,10 +247,9 @@ static int aplic_check_msicfg(struct aplic_msicfg_data *msicfg)
|
||||
|
||||
int aplic_cold_irqchip_init(struct aplic_data *aplic)
|
||||
{
|
||||
int rc, locked;
|
||||
u32 i, j, tmp;
|
||||
int rc;
|
||||
struct aplic_delegate_data *deleg;
|
||||
u32 first_deleg_irq, last_deleg_irq;
|
||||
u32 first_deleg_irq, last_deleg_irq, i;
|
||||
|
||||
/* Sanity checks */
|
||||
if (!aplic ||
|
||||
@@ -184,82 +267,24 @@ int aplic_cold_irqchip_init(struct aplic_data *aplic)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Set domain configuration to 0 */
|
||||
writel(0, (void *)(aplic->addr + APLIC_DOMAINCFG));
|
||||
|
||||
/* Disable all interrupts */
|
||||
for (i = 0; i <= aplic->num_source; i += 32)
|
||||
writel(-1U, (void *)(aplic->addr + APLIC_CLRIE_BASE +
|
||||
(i / 32) * sizeof(u32)));
|
||||
|
||||
/* Set interrupt type and priority for all interrupts */
|
||||
for (i = 1; i <= aplic->num_source; i++) {
|
||||
/* Set IRQ source configuration to 0 */
|
||||
writel(0, (void *)(aplic->addr + APLIC_SOURCECFG_BASE +
|
||||
(i - 1) * sizeof(u32)));
|
||||
/* Set IRQ target hart index and priority to 1 */
|
||||
writel(APLIC_DEFAULT_PRIORITY, (void *)(aplic->addr +
|
||||
APLIC_TARGET_BASE +
|
||||
(i - 1) * sizeof(u32)));
|
||||
}
|
||||
|
||||
/* Configure IRQ delegation */
|
||||
first_deleg_irq = -1U;
|
||||
last_deleg_irq = 0;
|
||||
for (i = 0; i < APLIC_MAX_DELEGATE; i++) {
|
||||
deleg = &aplic->delegate[i];
|
||||
if (!deleg->first_irq || !deleg->last_irq)
|
||||
continue;
|
||||
if (aplic->num_source < deleg->first_irq ||
|
||||
aplic->num_source < deleg->last_irq)
|
||||
continue;
|
||||
if (APLIC_SOURCECFG_CHILDIDX_MASK < deleg->child_index)
|
||||
continue;
|
||||
if (deleg->first_irq > deleg->last_irq) {
|
||||
tmp = deleg->first_irq;
|
||||
deleg->first_irq = deleg->last_irq;
|
||||
deleg->last_irq = tmp;
|
||||
}
|
||||
if (deleg->first_irq < first_deleg_irq)
|
||||
first_deleg_irq = deleg->first_irq;
|
||||
if (last_deleg_irq < deleg->last_irq)
|
||||
last_deleg_irq = deleg->last_irq;
|
||||
for (j = deleg->first_irq; j <= deleg->last_irq; j++)
|
||||
writel(APLIC_SOURCECFG_D | deleg->child_index,
|
||||
(void *)(aplic->addr + APLIC_SOURCECFG_BASE +
|
||||
(j - 1) * sizeof(u32)));
|
||||
}
|
||||
|
||||
/* Default initialization of IDC structures */
|
||||
for (i = 0; i < aplic->num_idc; i++) {
|
||||
writel(0, (void *)(aplic->addr + APLIC_IDC_BASE +
|
||||
i * APLIC_IDC_SIZE + APLIC_IDC_IDELIVERY));
|
||||
writel(0, (void *)(aplic->addr + APLIC_IDC_BASE +
|
||||
i * APLIC_IDC_SIZE + APLIC_IDC_IFORCE));
|
||||
writel(APLIC_DISABLE_ITHRESHOLD, (void *)(aplic->addr +
|
||||
APLIC_IDC_BASE +
|
||||
(i * APLIC_IDC_SIZE) +
|
||||
APLIC_IDC_ITHRESHOLD));
|
||||
}
|
||||
|
||||
/* MSI configuration */
|
||||
locked = readl((void *)(aplic->addr + APLIC_MMSICFGADDRH)) & APLIC_xMSICFGADDRH_L;
|
||||
if (aplic->targets_mmode && aplic->has_msicfg_mmode && !locked) {
|
||||
aplic_writel_msicfg(&aplic->msicfg_mmode,
|
||||
(void *)(aplic->addr + APLIC_MMSICFGADDR),
|
||||
(void *)(aplic->addr + APLIC_MMSICFGADDRH));
|
||||
}
|
||||
if (aplic->targets_mmode && aplic->has_msicfg_smode && !locked) {
|
||||
aplic_writel_msicfg(&aplic->msicfg_smode,
|
||||
(void *)(aplic->addr + APLIC_SMSICFGADDR),
|
||||
(void *)(aplic->addr + APLIC_SMSICFGADDRH));
|
||||
}
|
||||
/* Init the APLIC registers */
|
||||
aplic_init(aplic);
|
||||
|
||||
/*
|
||||
* Add APLIC region to the root domain if:
|
||||
* 1) It targets M-mode of any HART directly or via MSIs
|
||||
* 2) All interrupts are delegated to some child APLIC
|
||||
*/
|
||||
first_deleg_irq = -1U;
|
||||
last_deleg_irq = 0;
|
||||
for (i = 0; i < APLIC_MAX_DELEGATE; i++) {
|
||||
deleg = &aplic->delegate[i];
|
||||
if (deleg->first_irq < first_deleg_irq)
|
||||
first_deleg_irq = deleg->first_irq;
|
||||
if (last_deleg_irq < deleg->last_irq)
|
||||
last_deleg_irq = deleg->last_irq;
|
||||
}
|
||||
|
||||
if (aplic->targets_mmode ||
|
||||
((first_deleg_irq < last_deleg_irq) &&
|
||||
(last_deleg_irq == aplic->num_source) &&
|
||||
@@ -275,5 +300,8 @@ int aplic_cold_irqchip_init(struct aplic_data *aplic)
|
||||
/* Register irqchip device */
|
||||
sbi_irqchip_add_device(&aplic->irqchip);
|
||||
|
||||
/* Attach to the aplic list */
|
||||
sbi_list_add_tail(&aplic->node, &aplic_list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user