diff options
Diffstat (limited to 'arch/arm/lib/gic-v3-its.c')
-rw-r--r-- | arch/arm/lib/gic-v3-its.c | 121 |
1 files changed, 116 insertions, 5 deletions
diff --git a/arch/arm/lib/gic-v3-its.c b/arch/arm/lib/gic-v3-its.c index 2cc0a32f9d4..51cc2397768 100644 --- a/arch/arm/lib/gic-v3-its.c +++ b/arch/arm/lib/gic-v3-its.c @@ -4,9 +4,13 @@ */ #include <cpu_func.h> #include <dm.h> +#include <irq.h> +#include <asm/acpi_table.h> #include <asm/gic.h> #include <asm/gic-v3.h> #include <asm/io.h> +#include <dm/acpi.h> +#include <dt-bindings/interrupt-controller/arm-gic.h> #include <linux/bitops.h> #include <linux/printk.h> #include <linux/sizes.h> @@ -26,19 +30,21 @@ static u32 lpi_id_bits; struct gic_v3_its_priv { ulong gicd_base; ulong gicr_base; + ulong gicr_length; }; static int gic_v3_its_get_gic_addr(struct gic_v3_its_priv *priv) { struct udevice *dev; fdt_addr_t addr; + fdt_size_t size; int ret; ret = uclass_get_device_by_driver(UCLASS_IRQ, - DM_DRIVER_GET(arm_gic_v3_its), &dev); + DM_DRIVER_GET(arm_gic_v3), &dev); if (ret) { pr_err("%s: failed to get %s irq device\n", __func__, - DM_DRIVER_GET(arm_gic_v3_its)->name); + DM_DRIVER_GET(arm_gic_v3)->name); return ret; } @@ -49,12 +55,13 @@ static int gic_v3_its_get_gic_addr(struct gic_v3_its_priv *priv) } priv->gicd_base = addr; - addr = dev_read_addr_index(dev, 1); + addr = dev_read_addr_size_index(dev, 1, &size); if (addr == FDT_ADDR_T_NONE) { pr_err("%s: failed to get GICR address\n", __func__); return -EINVAL; } priv->gicr_base = addr; + priv->gicr_length = size; return 0; } @@ -158,13 +165,117 @@ int gic_lpi_tables_init(u64 base, u32 num_redist) return 0; } -static const struct udevice_id gic_v3_its_ids[] = { +#ifdef CONFIG_ACPIGEN +/** + * acpi_gicv3_fill_madt() - Fill out the body of the MADT + * + * Write GICD and GICR tables based on collected devicetree data. + * + * @dev: Device to write ACPI tables for + * @ctx: ACPI context to write MADT sub-tables to + * Return: 0 if OK + */ +static int acpi_gicv3_fill_madt(const struct udevice *dev, struct acpi_ctx *ctx) +{ + struct acpi_madt_gicd *gicd; + struct acpi_madt_gicr *gicr; + + struct gic_v3_its_priv priv; + + if (gic_v3_its_get_gic_addr(&priv)) + return -EINVAL; + + gicd = ctx->current; + acpi_write_madt_gicd(gicd, dev_seq(dev), priv.gicd_base, 3); + acpi_inc(ctx, gicd->length); + + gicr = ctx->current; + acpi_write_madt_gicr(gicr, priv.gicr_base, priv.gicr_length); + acpi_inc(ctx, gicr->length); + + return 0; +} + +struct acpi_ops gic_v3_acpi_ops = { + .fill_madt = acpi_gicv3_fill_madt, +}; +#endif + +static const struct udevice_id gic_v3_ids[] = { { .compatible = "arm,gic-v3" }, {} }; -U_BOOT_DRIVER(arm_gic_v3_its) = { +static int arm_gic_v3_of_xlate(struct irq *irq, struct ofnode_phandle_args *args) +{ + if (args->args_count < 3) { + log_debug("Invalid args_count: %d\n", args->args_count); + return -EINVAL; + } + + if (args->args[0] == GIC_SPI) + irq->id = args->args[1] + 32; + else + irq->id = args->args[1] + 16; + + irq->flags = args->args[2]; + + return 0; +} + +static const struct irq_ops arm_gic_v3_ops = { + .of_xlate = arm_gic_v3_of_xlate, +}; + +U_BOOT_DRIVER(arm_gic_v3) = { .name = "gic-v3", .id = UCLASS_IRQ, + .of_match = gic_v3_ids, + .ops = &arm_gic_v3_ops, + ACPI_OPS_PTR(&gic_v3_acpi_ops) +}; + +#ifdef CONFIG_ACPIGEN +/** + * acpi_gic_its_fill_madt() - Fill out the body of the MADT + * + * Write ITS tables based on collected devicetree data. + * + * @dev: Device to write ACPI tables for + * @ctx: ACPI context to write MADT sub-tables to + * Return: 0 if OK + */ +static int acpi_gic_its_fill_madt(const struct udevice *dev, struct acpi_ctx *ctx) +{ + struct acpi_madt_its *its; + fdt_addr_t addr; + + addr = dev_read_addr_index(dev, 0); + if (addr == FDT_ADDR_T_NONE) { + pr_err("%s: failed to get GIC ITS address\n", __func__); + return -EINVAL; + } + + its = ctx->current; + acpi_write_madt_its(its, dev_seq(dev), addr); + acpi_inc(ctx, its->length); + + return 0; +} + +struct acpi_ops gic_v3_its_acpi_ops = { + .fill_madt = acpi_gic_its_fill_madt, +}; +#endif + +static const struct udevice_id gic_v3_its_ids[] = { + { .compatible = "arm,gic-v3-its" }, + {} +}; + +U_BOOT_DRIVER(arm_gic_v3_its) = { + .name = "gic-v3-its", + .id = UCLASS_IRQ, .of_match = gic_v3_its_ids, + ACPI_OPS_PTR(&gic_v3_its_acpi_ops) }; |