diff options
author | Tom Rini <trini@konsulko.com> | 2024-10-27 17:14:22 -0600 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2024-10-27 18:44:13 -0600 |
commit | 2800aecce08b47b169d8e9824dd23b1297b2cedc (patch) | |
tree | 2f8b61eaee1520b6fd5bd6cedb111aa3ee13f2f7 /board/raspberrypi/rpi/rpi.c | |
parent | 568407fab5336c00cf0265e9de6c507078988504 (diff) | |
parent | 25081abf081880930365ff2bc6afc6c0273ca4bf (diff) |
Merge patch series "Implement ACPI on aarch64"
Patrick Rudolph <patrick.rudolph@9elements.com> says:
Based on the existing work done by Simon Glass this series adds
support for booting aarch64 devices using ACPI only.
As first target QEMU SBSA support is added, which relies on ACPI
only to boot an OS. As secondary target the Raspberry Pi4 was used,
which is broadly available and allows easy testing of the proposed
solution.
The series is split into ACPI cleanups and code movements, adding
Arm specific ACPI tables and finally SoC and mainboard related
changes to boot a Linux on the QEMU SBSA and RPi4. Currently only the
mandatory ACPI tables are supported, allowing to boot into Linux
without errors.
The QEMU SBSA support is feature complete and provides the same
functionality as the EDK2 implementation.
The changes were tested on real hardware as well on QEMU v9.0:
qemu-system-aarch64 -machine sbsa-ref -nographic -cpu cortex-a57 \
-pflash secure-world.rom \
-pflash unsecure-world.rom
qemu-system-aarch64 -machine raspi4b -kernel u-boot.bin -cpu cortex-a72 \
-smp 4 -m 2G -drive file=raspbian.img,format=raw,index=0 \
-dtb bcm2711-rpi-4-b.dtb -nographic
Tested against FWTS V24.03.00.
Known issues:
- The QEMU rpi4 support is currently limited as it doesn't emulate PCI,
USB or ethernet devices!
- The SMP bringup doesn't work on RPi4, but works in QEMU (Possibly
cache related).
- PCI on RPI4 isn't working on real hardware since the pcie_brcmstb
Linux kernel module doesn't support ACPI yet.
Link: https://lore.kernel.org/r/20241023132116.970117-1-patrick.rudolph@9elements.com
Diffstat (limited to 'board/raspberrypi/rpi/rpi.c')
-rw-r--r-- | board/raspberrypi/rpi/rpi.c | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/board/raspberrypi/rpi/rpi.c b/board/raspberrypi/rpi/rpi.c index ab5ea85cf9f..9122f33d88d 100644 --- a/board/raspberrypi/rpi/rpi.c +++ b/board/raspberrypi/rpi/rpi.c @@ -23,6 +23,11 @@ #endif #include <watchdog.h> #include <dm/pinctrl.h> +#include <dm/ofnode.h> +#include <acpi/acpi_table.h> +#include <acpi/acpigen.h> +#include <dm/lists.h> +#include <tables_csum.h> DECLARE_GLOBAL_DATA_PTR; @@ -583,3 +588,181 @@ int ft_board_setup(void *blob, struct bd_info *bd) return 0; } + +#if CONFIG_IS_ENABLED(GENERATE_ACPI_TABLE) +static bool is_rpi4(void) +{ + return of_machine_is_compatible("brcm,bcm2711") || + of_machine_is_compatible("brcm,bcm2712"); +} + +static bool is_rpi3(void) +{ + return of_machine_is_compatible("brcm,bcm2837"); +} + +static int acpi_rpi_board_fill_ssdt(struct acpi_ctx *ctx) +{ + int node, ret, uart_in_use, mini_clock_rate; + bool enabled; + struct udevice *dev; + struct { + const char *fdt_compatible; + const char *acpi_scope; + bool on_rpi4; + bool on_rpi3; + u32 mmio_address; + } map[] = { + {"brcm,bcm2711-pcie", "\\_SB.PCI0", true, false}, + {"brcm,bcm2711-emmc2", "\\_SB.GDV1.SDC3", true, false}, + {"brcm,bcm2835-pwm", "\\_SB.GDV0.PWM0", true, true}, + {"brcm,bcm2711-genet-v5", "\\_SB.ETH0", true, false}, + {"brcm,bcm2711-thermal", "\\_SB.EC00", true, true}, + {"brcm,bcm2835-sdhci", "\\_SB.SDC1", true, true}, + {"brcm,bcm2835-sdhost", "\\_SB.SDC2", false, true}, + {"brcm,bcm2835-mbox", "\\_SB.GDV0.RPIQ", true, true}, + {"brcm,bcm2835-i2c", "\\_SB.GDV0.I2C1", true, true, 0xfe205000}, + {"brcm,bcm2835-i2c", "\\_SB.GDV0.I2C2", true, true, 0xfe804000}, + {"brcm,bcm2835-spi", "\\_SB.GDV0.SPI0", true, true}, + {"brcm,bcm2835-aux-spi", "\\_SB.GDV0.SPI1", true, true, 0xfe215080}, + {"arm,pl011", "\\_SB.URT0", true, true}, + {"brcm,bcm2835-aux-uart", "\\_SB.URTM", true, true}, + { /* Sentinel */ } + }; + + /* Device enable */ + for (int i = 0; map[i].fdt_compatible; i++) { + if ((is_rpi4() && !map[i].on_rpi4) || + (is_rpi3() && !map[i].on_rpi3)) { + enabled = false; + } else { + node = fdt_node_offset_by_compatible(gd->fdt_blob, -1, + map[i].fdt_compatible); + while (node != -FDT_ERR_NOTFOUND && map[i].mmio_address) { + struct fdt_resource r; + + ret = fdt_get_resource(gd->fdt_blob, node, "reg", 0, &r); + if (ret) { + node = -FDT_ERR_NOTFOUND; + break; + } + + if (r.start == map[i].mmio_address) + break; + + node = fdt_node_offset_by_compatible(gd->fdt_blob, node, + map[i].fdt_compatible); + } + + enabled = (node > 0) ? fdtdec_get_is_enabled(gd->fdt_blob, node) : 0; + } + acpigen_write_scope(ctx, map[i].acpi_scope); + acpigen_write_name_integer(ctx, "_STA", enabled ? 0xf : 0); + acpigen_pop_len(ctx); + } + + /* GPIO quirks */ + node = fdt_node_offset_by_compatible(gd->fdt_blob, -1, "brcm,bcm2835-gpio"); + if (node <= 0) + node = fdt_node_offset_by_compatible(gd->fdt_blob, -1, "brcm,bcm2711-gpio"); + + acpigen_write_scope(ctx, "\\_SB.GDV0.GPI0"); + enabled = (node > 0) ? fdtdec_get_is_enabled(gd->fdt_blob, node) : 0; + acpigen_write_name_integer(ctx, "_STA", enabled ? 0xf : 0); + acpigen_pop_len(ctx); + + if (is_rpi4()) { + /* eMMC quirks */ + node = fdt_node_offset_by_compatible(gd->fdt_blob, -1, "brcm,bcm2711-emmc2"); + if (node) { + phys_addr_t cpu; + dma_addr_t bus; + u64 size; + + ret = fdt_get_dma_range(gd->fdt_blob, node, &cpu, &bus, &size); + + acpigen_write_scope(ctx, "\\_SB.GDV1"); + acpigen_write_method_serialized(ctx, "_DMA", 0); + acpigen_emit_byte(ctx, RETURN_OP); + + if (!ret && bus != cpu) /* Translated DMA range */ + acpigen_emit_namestring(ctx, "\\_SB.GDV1.DMTR"); + else if (!ret && bus == cpu) /* Non translated DMA */ + acpigen_emit_namestring(ctx, "\\_SB.GDV1.DMNT"); + else /* Silicon revisions older than C0: Translated DMA range */ + acpigen_emit_namestring(ctx, "\\_SB.GDV1.DMTR"); + acpigen_pop_len(ctx); + } + } + + /* Serial */ + uart_in_use = ~0; + mini_clock_rate = 0x1000000; + + ret = uclass_get_device_by_driver(UCLASS_SERIAL, + DM_DRIVER_GET(bcm283x_pl011_uart), + &dev); + if (!ret) + uart_in_use = 0; + + ret = uclass_get_device_by_driver(UCLASS_SERIAL, + DM_DRIVER_GET(serial_bcm283x_mu), + &dev); + if (!ret) { + if (uart_in_use == 0) + log_err("Invalid config: PL011 and MiniUART are both enabled."); + else + uart_in_use = 1; + + mini_clock_rate = dev_read_u32_default(dev, "clock", 0x1000000); + } + if (uart_in_use > 1) + log_err("No working serial: PL011 and MiniUART are both disabled."); + + acpigen_write_scope(ctx, "\\_SB.BTH0"); + acpigen_write_name_integer(ctx, "URIU", uart_in_use); + acpigen_pop_len(ctx); + + acpigen_write_scope(ctx, "\\_SB.URTM"); + acpigen_write_name_integer(ctx, "MUCR", mini_clock_rate); + acpigen_pop_len(ctx); + + return 0; +} + +static int rpi_acpi_write_ssdt(struct acpi_ctx *ctx, const struct acpi_writer *entry) +{ + struct acpi_table_header *ssdt; + int ret; + + ssdt = ctx->current; + memset(ssdt, '\0', sizeof(struct acpi_table_header)); + + acpi_fill_header(ssdt, "SSDT"); + ssdt->revision = acpi_get_table_revision(ACPITAB_SSDT); + ssdt->creator_revision = 1; + ssdt->length = sizeof(struct acpi_table_header); + + acpi_inc(ctx, sizeof(struct acpi_table_header)); + + ret = acpi_rpi_board_fill_ssdt(ctx); + if (ret) { + ctx->current = ssdt; + return log_msg_ret("fill", ret); + } + + /* (Re)calculate length and checksum */ + ssdt->length = ctx->current - (void *)ssdt; + ssdt->checksum = table_compute_checksum((void *)ssdt, ssdt->length); + log_debug("SSDT at %p, length %x\n", ssdt, ssdt->length); + + /* Drop the table if it is empty */ + if (ssdt->length == sizeof(struct acpi_table_header)) + return log_msg_ret("fill", -ENOENT); + acpi_add_table(ctx, ssdt); + + return 0; +} + +ACPI_WRITER(5ssdt, "SSDT", rpi_acpi_write_ssdt, 0); +#endif |