diff --git a/src/aic.c b/src/aic.c index 6974aac49..d02274e5a 100644 --- a/src/aic.c +++ b/src/aic.c @@ -29,13 +29,26 @@ static struct aic aic2 = { .version = 2, .regs = { - .config = AIC2_IRQ_CFG, + .config = AIC23_IRQ_CFG, }, + .cap0_offset = AIC2_CAP0, + .maxnumirq_offset = AIC2_MAXNUMIRQ, +}; + +static struct aic aic3 = { + .version = 3, + .regs = + { + .config = AIC23_IRQ_CFG, + }, + /* These are dynamic on AIC3, and filled in from the DT */ + .cap0_offset = -1, + .maxnumirq_offset = -1, }; struct aic *aic; -static int aic2_init(int node) +static int aic23_init(int version, int node) { int ret = ADT_GETPROP(adt, node, "aic-iack-offset", &aic->regs.event); if (ret < 0) { @@ -43,13 +56,28 @@ static int aic2_init(int node) return ret; } - u32 info1 = read32(aic->base + AIC2_INFO1); - aic->nr_die = FIELD_GET(AIC2_INFO1_LAST_DIE, info1) + 1; - aic->nr_irq = FIELD_GET(AIC2_INFO1_NR_IRQ, info1); + int32_t cap0_offset = aic->cap0_offset; + if (cap0_offset == -1) { + ret = ADT_GETPROP(adt, node, "cap0-offset", &cap0_offset); + if (ret < 0) { + printf("AIC: failed to get property cap0-offset\n"); + } + } + u32 cap0 = read32(aic->base + cap0_offset); + aic->nr_die = FIELD_GET(AIC23_CAP0_LAST_DIE, cap0) + 1; + aic->nr_irq = FIELD_GET(AIC23_CAP0_NR_IRQ, cap0); + + int32_t maxnumirq_offset = aic->maxnumirq_offset; + if (maxnumirq_offset == -1) { + 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 + AIC2_INFO3); - aic->max_die = FIELD_GET(AIC2_INFO3_MAX_DIE, info3); - aic->max_irq = FIELD_GET(AIC2_INFO3_MAX_IRQ, info3); + u32 info3 = read32(aic->base + maxnumirq_offset); + aic->max_die = FIELD_GET(AIC23_MAXNUMIRQ_MAX_DIE, info3); + aic->max_irq = FIELD_GET(AIC23_MAXNUMIRQ_MAX_IRQ, info3); if (aic->nr_die > AIC_MAX_DIES) { printf("AIC: more dies than supported: %u\n", aic->max_die); @@ -77,8 +105,9 @@ static int aic2_init(int node) aic->die_stride = off - start_off; aic->regs.reg_size = aic->regs.event + 4; - printf("AIC: AIC2 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); + printf("AIC: AIC%d with %u/%u dies, %u/%u IRQs, reg_size:%05lx die_stride:%05x\n", version, + 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); @@ -92,7 +121,7 @@ static int aic2_init(int node) assert(die < aic->nr_die); assert(irq < aic->nr_irq); mask32(aic->base + aic->regs.config + die * aic->die_stride + 4 * irq, - AIC2_IRQ_CFG_TARGET, FIELD_PREP(AIC2_IRQ_CFG_TARGET, target)); + AIC23_IRQ_CFG_TARGET, FIELD_PREP(AIC23_IRQ_CFG_TARGET, target)); } } @@ -113,6 +142,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; @@ -129,7 +160,12 @@ void aic_init(void) aic->max_irq = AIC1_MAX_IRQ; } else if (aic->version == 2) { printf("AIC: Version 2 @ 0x%lx\n", aic->base); - int ret = aic2_init(node); + int ret = aic23_init(2, node); + if (ret < 0) + aic = NULL; + } else if (aic->version == 3) { + printf("AIC: Version 3 @ 0x%lx\n", aic->base); + int ret = aic23_init(3, node); if (ret < 0) aic = NULL; } diff --git a/src/aic.h b/src/aic.h index 1f401b1c3..39b067809 100644 --- a/src/aic.h +++ b/src/aic.h @@ -28,6 +28,8 @@ struct aic { uint32_t max_die; uint32_t die_stride; + int32_t cap0_offset; + int32_t maxnumirq_offset; struct aic_regs regs; }; diff --git a/src/aic_regs.h b/src/aic_regs.h index 8cc360b7d..0cdd5ee1d 100644 --- a/src/aic_regs.h +++ b/src/aic_regs.h @@ -19,21 +19,28 @@ #define AIC_CPU_IPI_MASK_SET(cpu) (0x5024 + ((cpu) << 7)) #define AIC_CPU_IPI_MASK_CLR(cpu) (0x5028 + ((cpu) << 7)) -#define AIC2_INFO1 0x0004 -#define AIC2_INFO2 0x0008 -#define AIC2_INFO3 0x000c -#define AIC2_LATENCY 0x0204 -#define AIC2_IRQ_CFG 0x2000 +#define AIC2_CAP0 0x0004 +#define AIC2_INFO2 0x0008 +#define AIC2_MAXNUMIRQ 0x000c +#define AIC2_LATENCY 0x0204 -#define AIC2_IRQ_CFG_TARGET GENMASK(3, 0) +#define AIC23_IRQ_CFG 0x2000 +#define AIC23_IRQ_CFG_TARGET GENMASK(3, 0) -#define AIC_INFO_NR_HW GENMASK(15, 0) +#define AIC23_CAP0_NR_IRQ GENMASK(15, 0) +#define AIC23_CAP0_LAST_DIE GENMASK(27, 24) + +#define AIC23_MAXNUMIRQ_MAX_IRQ GENMASK(15, 0) +/* + * This might actually be 8 bits on the M3. + * So far nothing has more than 8 dies anyway + */ +#define AIC23_MAXNUMIRQ_MAX_DIE GENMASK(27, 24) -#define AIC2_INFO1_NR_IRQ GENMASK(15, 0) -#define AIC2_INFO1_LAST_DIE GENMASK(27, 24) +#define AIC_INFO_NR_HW GENMASK(15, 0) -#define AIC2_INFO3_MAX_IRQ GENMASK(15, 0) -#define AIC2_INFO3_MAX_DIE GENMASK(27, 24) +#define AIC1_MAX_IRQ 0x400 +#define AIC_MAX_HW_NUM (0x80 * 32) // max_irq of the M1 Max #define AIC_EVENT_DIE GENMASK(31, 24) #define AIC_EVENT_TYPE GENMASK(23, 16) @@ -48,6 +55,3 @@ #define AIC_IPI_OTHER BIT(0) #define AIC_IPI_SELF BIT(31) - -#define AIC1_MAX_IRQ 0x400 -#define AIC_MAX_HW_NUM (0x80 * 32) // max_irq of the M1 Max diff --git a/src/kboot.c b/src/kboot.c index a0656dc74..7c944a9c9 100644 --- a/src/kboot.c +++ b/src/kboot.c @@ -417,6 +417,8 @@ static int dt_set_cpus(void) int aic = fdt_node_offset_by_compatible(dt, -1, "apple,aic"); if (aic == -FDT_ERR_NOTFOUND) aic = fdt_node_offset_by_compatible(dt, -1, "apple,aic2"); + if (aic == -FDT_ERR_NOTFOUND) + aic = fdt_node_offset_by_compatible(dt, -1, "apple,aic3"); if (aic < 0) bail_cleanup("FDT: Failed to find AIC node\n"); @@ -2141,6 +2143,8 @@ static int dt_transfer_virtios(void) int aic = fdt_node_offset_by_compatible(dt, -1, "apple,aic"); if (aic == -FDT_ERR_NOTFOUND) aic = fdt_node_offset_by_compatible(dt, -1, "apple,aic2"); + if (aic == -FDT_ERR_NOTFOUND) + aic = fdt_node_offset_by_compatible(dt, -1, "apple,aic3"); if (aic < 0) bail("FDT: failed to find AIC node\n");