summaryrefslogtreecommitdiff
path: root/board/raspberrypi/rpi/rpi.c
diff options
context:
space:
mode:
authorSimon Glass <sjg@chromium.org>2024-10-23 15:20:12 +0200
committerTom Rini <trini@konsulko.com>2024-10-27 17:24:13 -0600
commit2f3b679298903c6ce5169953dfe7e08ffeadc3b9 (patch)
tree39d9584bc04df93b53e268ce9df107f16c8e61d9 /board/raspberrypi/rpi/rpi.c
parent797b01cc0dfbf756c70c1e7b5557b6e6ccf9f6fb (diff)
board: raspberrypi: Add ASL files from tianocore
Add the necessary DSDT files copied from tianocore to boot the RPi4. In addition generate a board specific SSDT to dynamically enable/disable ACPI devices based on FDT. This is required to support the various variants and boot options. It also allows to test the code on QEMU 9.0 without modifications, since it doesn't emulate PCIe yet. Signed-off-by: Simon Glass <sjg@chromium.org> Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com> Reviewed-by: Simon Glass <sjg@chromium.org> Cc: Simon Glass <sjg@chromium.org> Cc: Matthias Brugger <mbrugger@suse.com> Cc: Peter Robinson <pbrobinson@gmail.com>
Diffstat (limited to 'board/raspberrypi/rpi/rpi.c')
-rw-r--r--board/raspberrypi/rpi/rpi.c183
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