]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
drivers/arm: Implement acpi_fill_madt
authorPatrick Rudolph <patrick.rudolph@9elements.com>
Wed, 23 Oct 2024 13:20:06 +0000 (15:20 +0200)
committerTom Rini <trini@konsulko.com>
Sun, 27 Oct 2024 23:24:13 +0000 (17:24 -0600)
Fill the MADT table in the GIC driver and armv8 CPU driver to
drop SoC specific code. While the GIC only needs devicetree
data, the CPU driver needs additional information stored in
the cpu_plat struct.

While on it update the only board making use of the existing
drivers and writing ACPI MADT in mainboard code.

TEST: Booted on QEMU sbsa-ref using GICV3 driver model generated MADT.
      Booted on QEMU raspb4 using GICV2 driver model generated MADT.

Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
Cc: Simon Glass <sjg@chromium.org>
arch/arm/lib/gic-v3-its.c
drivers/cpu/Kconfig
drivers/cpu/armv8_cpu.c
drivers/cpu/armv8_cpu.h

index 58f8bf864f13ef79c60488a08762b4f8f3cbdc4c..51cc2397768b81508845be3c7b955ff63e101c43 100644 (file)
@@ -5,9 +5,11 @@
 #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>
@@ -28,12 +30,14 @@ 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,
@@ -51,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;
 }
@@ -160,6 +165,42 @@ int gic_lpi_tables_init(u64 base, u32 num_redist)
        return 0;
 }
 
+#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" },
        {}
@@ -191,4 +232,50 @@ U_BOOT_DRIVER(arm_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)
 };
index 9c0df331d7f32e3f11195293f9df7a10dede2666..4cc3679c009eb0f72907508e762135796e34c9f8 100644 (file)
@@ -29,6 +29,7 @@ config CPU_RISCV
 config CPU_ARMV8
        bool "Enable generic ARMv8 CPU driver"
        depends on CPU && ARM64
+       select IRQ
        help
          Support CPU cores for armv8 architecture.
 
index 19f072be430e4a5e0da2f6aceab01bc33c2620f9..4eedfe5e2c5f49c2e7ed557ebf83ebb0f6798d4b 100644 (file)
@@ -4,10 +4,11 @@
  */
 #include <cpu.h>
 #include <dm.h>
+#include <irq.h>
 #include <acpi/acpigen.h>
 #include <asm/armv8/cpu.h>
-#include <dm/acpi.h>
 #include <asm/io.h>
+#include <dm/acpi.h>
 #include <linux/bitops.h>
 #include <linux/printk.h>
 #include <linux/sizes.h>
@@ -47,8 +48,85 @@ int armv8_cpu_fill_ssdt(const struct udevice *dev, struct acpi_ctx *ctx)
        return 0;
 }
 
+int armv8_cpu_fill_madt(const struct udevice *dev, struct acpi_ctx *ctx)
+{
+       struct acpi_madt_gicc *gicc;
+       struct cpu_plat *cpu_plat;
+       struct udevice *gic;
+       u64 gicc_gicv = 0;
+       u64 gicc_gich = 0;
+       u64 gicc_gicr_base = 0;
+       u64 gicc_phys_base = 0;
+       u32 gicc_perf_gsiv = 0;
+       u64 gicc_mpidr;
+       u32 gicc_vgic_maint_irq = 0;
+       int addr_index;
+       fdt_addr_t addr;
+       int ret;
+       struct irq req_irq;
+
+       cpu_plat = dev_get_parent_plat(dev);
+       if (!cpu_plat)
+               return 0;
+
+       ret = irq_get_interrupt_parent(dev, &gic);
+       if (ret) {
+               log_err("%s: Failed to find interrupt parent for %s\n",
+                       __func__, dev->name);
+               return -ENODEV;
+       }
+
+       addr_index = 1;
+
+       if (device_is_compatible(gic, "arm,gic-v3")) {
+               addr = dev_read_addr_index(gic, addr_index++);
+               if (addr != FDT_ADDR_T_NONE)
+                       gicc_gicr_base = addr;
+       }
+
+       addr = dev_read_addr_index(gic, addr_index++);
+       if (addr != FDT_ADDR_T_NONE)
+               gicc_phys_base = addr;
+
+       addr = dev_read_addr_index(gic, addr_index++);
+       if (addr != FDT_ADDR_T_NONE)
+               gicc_gich = addr;
+
+       addr = dev_read_addr_index(gic, addr_index++);
+       if (addr != FDT_ADDR_T_NONE)
+               gicc_gicv = addr;
+
+       ret = irq_get_by_index(gic, 0, &req_irq);
+       if (!ret)
+               gicc_vgic_maint_irq = req_irq.id;
+
+       gicc_mpidr = dev_read_u64_default(dev, "reg", 0);
+       if (!gicc_mpidr)
+               gicc_mpidr = dev_read_u32_default(dev, "reg", 0);
+
+       /*
+        * gicc_vgic_maint_irq and gicc_gicv are the same for every CPU
+        */
+       gicc = ctx->current;
+       acpi_write_madt_gicc(gicc,
+                            dev_seq(dev),
+                            gicc_perf_gsiv, /* FIXME: needs a PMU driver */
+                            gicc_phys_base,
+                            gicc_gicv,
+                            gicc_gich,
+                            gicc_vgic_maint_irq,
+                            gicc_gicr_base,
+                            gicc_mpidr,
+                            0); /* FIXME: Not defined in DT */
+
+       acpi_inc(ctx, gicc->length);
+
+       return 0;
+}
+
 struct acpi_ops armv8_cpu_acpi_ops = {
        .fill_ssdt      = armv8_cpu_fill_ssdt,
+       .fill_madt      = armv8_cpu_fill_madt,
 };
 #endif
 
index 2c4b0252cf84e50cd4225426d0cd5aa7d7bf4b63..48c705e98de8066ba40e11ff3b7c41aef92812a2 100644 (file)
  */
 int armv8_cpu_fill_ssdt(const struct udevice *dev, struct acpi_ctx *ctx);
 
+/**
+ * armv8_cpu_fill_madt() - Fill the MADT
+ * Parses the FDT and writes the MADT subtables.
+ *
+ * @dev: cpu device to generate ACPI tables for
+ * @ctx: ACPI context pointer
+ * @return:    0 if OK, or a negative error code.
+ */
+int armv8_cpu_fill_madt(const struct udevice *dev, struct acpi_ctx *ctx);
+
 #endif
\ No newline at end of file