mirror of
https://github.com/riscv-software-src/opensbi.git
synced 2025-11-22 19:01:33 +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 {
|
struct aplic_data {
|
||||||
/* Private members */
|
/* Private members */
|
||||||
struct sbi_irqchip_device irqchip;
|
struct sbi_irqchip_device irqchip;
|
||||||
|
struct sbi_dlist node;
|
||||||
/* Public members */
|
/* Public members */
|
||||||
unsigned long addr;
|
unsigned long addr;
|
||||||
unsigned long size;
|
unsigned long size;
|
||||||
@@ -48,4 +49,6 @@ struct aplic_data {
|
|||||||
|
|
||||||
int aplic_cold_irqchip_init(struct aplic_data *aplic);
|
int aplic_cold_irqchip_init(struct aplic_data *aplic);
|
||||||
|
|
||||||
|
void aplic_reinit_all(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -115,6 +115,90 @@
|
|||||||
#define APLIC_DISABLE_ITHRESHOLD 1
|
#define APLIC_DISABLE_ITHRESHOLD 1
|
||||||
#define APLIC_ENABLE_ITHRESHOLD 0
|
#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,
|
static void aplic_writel_msicfg(struct aplic_msicfg_data *msicfg,
|
||||||
void *msicfgaddr, void *msicfgaddrH)
|
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 aplic_cold_irqchip_init(struct aplic_data *aplic)
|
||||||
{
|
{
|
||||||
int rc, locked;
|
int rc;
|
||||||
u32 i, j, tmp;
|
|
||||||
struct aplic_delegate_data *deleg;
|
struct aplic_delegate_data *deleg;
|
||||||
u32 first_deleg_irq, last_deleg_irq;
|
u32 first_deleg_irq, last_deleg_irq, i;
|
||||||
|
|
||||||
/* Sanity checks */
|
/* Sanity checks */
|
||||||
if (!aplic ||
|
if (!aplic ||
|
||||||
@@ -184,82 +267,24 @@ int aplic_cold_irqchip_init(struct aplic_data *aplic)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set domain configuration to 0 */
|
/* Init the APLIC registers */
|
||||||
writel(0, (void *)(aplic->addr + APLIC_DOMAINCFG));
|
aplic_init(aplic);
|
||||||
|
|
||||||
/* 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));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add APLIC region to the root domain if:
|
* Add APLIC region to the root domain if:
|
||||||
* 1) It targets M-mode of any HART directly or via MSIs
|
* 1) It targets M-mode of any HART directly or via MSIs
|
||||||
* 2) All interrupts are delegated to some child APLIC
|
* 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 ||
|
if (aplic->targets_mmode ||
|
||||||
((first_deleg_irq < last_deleg_irq) &&
|
((first_deleg_irq < last_deleg_irq) &&
|
||||||
(last_deleg_irq == aplic->num_source) &&
|
(last_deleg_irq == aplic->num_source) &&
|
||||||
@@ -275,5 +300,8 @@ int aplic_cold_irqchip_init(struct aplic_data *aplic)
|
|||||||
/* Register irqchip device */
|
/* Register irqchip device */
|
||||||
sbi_irqchip_add_device(&aplic->irqchip);
|
sbi_irqchip_add_device(&aplic->irqchip);
|
||||||
|
|
||||||
|
/* Attach to the aplic list */
|
||||||
|
sbi_list_add_tail(&aplic->node, &aplic_list);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user