From bae5247e17f33f8f068877b9ed373bdc2c693a2a Mon Sep 17 00:00:00 2001 From: Daniel Berlin Date: Thu, 30 Nov 2023 13:19:19 -0500 Subject: [PATCH] Support new version of AIC used by M3 Small changes, mostly some offsts are now available in the DT, and a mask change. Signed-off-by: Daniel Berlin --- src/aic.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/aic_regs.h | 8 +++++ 2 files changed, 99 insertions(+) diff --git a/src/aic.c b/src/aic.c index 6974aac49..d82d72118 100644 --- a/src/aic.c +++ b/src/aic.c @@ -33,8 +33,92 @@ static struct aic aic2 = { }, }; +static struct aic aic3 = { + .version = 3, + .regs = + { + .config = AIC2_IRQ_CFG, + }, +}; + struct aic *aic; +static int aic3_init(int node) +{ + int ret = ADT_GETPROP(adt, node, "aic-iack-offset", &aic->regs.event); + if (ret < 0) { + printf("AIC: failed to get property aic-iack-offset\n"); + return ret; + } + + int cap0_offset; + + ret = ADT_GETPROP(adt, node, "cap0-offset", &cap0_offset); + if (ret < 0) { + printf("AIC: failed to get property cap0-offset\n"); + } + u32 info1 = read32(aic->base + cap0_offset); + aic->nr_die = FIELD_GET(AIC3_INFO1_LAST_DIE, info1) + 1; + aic->nr_irq = FIELD_GET(AIC3_INFO1_NR_IRQ, info1); + + int maxnumirq_offset; + ret = ADT_GETPROP(adt, node, "maxnumirq-offset", &maxnumirq_offset); + if (ret < 0) { + printf("AIC: failed to get property maxnumirq-offset\n"); + } + + u32 info3 = read32(aic->base + maxnumirq_offset); + aic->max_die = FIELD_GET(AIC3_INFO3_MAX_DIE, info3); + aic->max_irq = FIELD_GET(AIC3_INFO3_MAX_IRQ, info3); + + if (aic->nr_die > AIC_MAX_DIES) { + printf("AIC: more dies than supported: %u\n", aic->max_die); + return -1; + } + + if (aic->max_irq > AIC_MAX_HW_NUM) { + printf("AIC: more IRQs than supported: %u\n", aic->max_irq); + return -1; + } + + const u64 start_off = aic->regs.config; + u64 off = start_off + sizeof(u32) * aic->max_irq; /* IRQ_CFG */ + + aic->regs.sw_set = off; + off += sizeof(u32) * (aic->max_irq >> 5); /* SW_SET */ + aic->regs.sw_clr = off; + off += sizeof(u32) * (aic->max_irq >> 5); /* SW_CLR */ + aic->regs.mask_set = off; + off += sizeof(u32) * (aic->max_irq >> 5); /* MASK_SET */ + aic->regs.mask_clr = off; + off += sizeof(u32) * (aic->max_irq >> 5); /* MASK_CLR */ + off += sizeof(u32) * (aic->max_irq >> 5); /* HW_STATE */ + + aic->die_stride = off - start_off; + aic->regs.reg_size = aic->regs.event + 4; + + printf("AIC: AIC3 with %u/%u dies, %u/%u IRQs, reg_size:%05lx die_stride:%05x\n", aic->nr_die, + aic->max_die, aic->nr_irq, aic->max_irq, aic->regs.reg_size, aic->die_stride); + + u32 ext_intr_config_len; + const u8 *ext_intr_config = adt_getprop(adt, node, "aic-ext-intr-cfg", &ext_intr_config_len); + + if (ext_intr_config) { + printf("AIC: Configuring %d external interrupts\n", ext_intr_config_len / 3); + for (u32 i = 0; i < ext_intr_config_len; i += 3) { + u8 die = ext_intr_config[i + 1] >> 4; + u16 irq = ext_intr_config[i] | ((ext_intr_config[i + 1] & 0xf) << 8); + u8 target = ext_intr_config[i + 2]; + assert(die < aic->nr_die); + assert(irq < aic->nr_irq); + mask32(aic->base + aic->regs.config + die * aic->die_stride + 4 * irq, + AIC3_IRQ_CFG_TARGET, FIELD_PREP(AIC3_IRQ_CFG_TARGET, target)); + } + } + + return 0; +} + static int aic2_init(int node) { int ret = ADT_GETPROP(adt, node, "aic-iack-offset", &aic->regs.event); @@ -113,6 +197,8 @@ void aic_init(void) aic = &aic1; } else if (adt_is_compatible(adt, node, "aic,2")) { aic = &aic2; + } else if (adt_is_compatible(adt, node, "aic,3")) { + aic = &aic3; } else { printf("AIC: Error: Unsupported version\n"); return; @@ -132,6 +218,11 @@ void aic_init(void) int ret = aic2_init(node); if (ret < 0) aic = NULL; + } else if (aic->version == 3) { + printf("AIC: Version 3 @ 0x%lx\n", aic->base); + int ret = aic3_init(node); + if (ret < 0) + aic = NULL; } } diff --git a/src/aic_regs.h b/src/aic_regs.h index 8cc360b7d..852e86702 100644 --- a/src/aic_regs.h +++ b/src/aic_regs.h @@ -35,6 +35,14 @@ #define AIC2_INFO3_MAX_IRQ GENMASK(15, 0) #define AIC2_INFO3_MAX_DIE GENMASK(27, 24) +#define AIC3_IRQ_CFG_TARGET GENMASK(3, 0) + +#define AIC3_INFO1_NR_IRQ GENMASK(15, 0) +#define AIC3_INFO1_LAST_DIE GENMASK(27, 24) + +#define AIC3_INFO3_MAX_IRQ GENMASK(15, 0) +#define AIC3_INFO3_MAX_DIE GENMASK(31, 24) + #define AIC_EVENT_DIE GENMASK(31, 24) #define AIC_EVENT_TYPE GENMASK(23, 16) #define AIC_EVENT_NUM GENMASK(15, 0)