Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Aarch64 powerdown: add support for GPIO power key #2076

Merged
merged 1 commit into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions platform/virt/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ SRCS-kernel.elf= \
$(SRCDIR)/aarch64/crt0.S \
$(SRCDIR)/aarch64/elf64.c \
$(SRCDIR)/aarch64/gic.c \
$(SRCDIR)/aarch64/gpio.c \
$(SRCDIR)/aarch64/hyperv.c \
$(SRCDIR)/aarch64/interrupt.c \
$(SRCDIR)/aarch64/kernel_machine.c \
Expand Down
1 change: 1 addition & 0 deletions platform/virt/kernel_platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@

#define VIRT_PCIE_IRQ_BASE 3
#define VIRT_PCIE_IRQ_NUM 4
#define VIRT_GPIO_IRQ 7
#define VIRT_MMIO_IRQ_BASE 16
#define VIRT_MMIO_IRQ_NUM 32

Expand Down
29 changes: 29 additions & 0 deletions platform/virt/service.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#include <management.h>
#include <virtio/virtio.h>
#include <devicetree.h>
#include <gic.h>
#include <gpio.h>
#include <hyperv_platform.h>
#include "serial.h"

Expand All @@ -32,6 +34,8 @@
#define init_dump(p, len)
#endif

static RO_AFTER_INIT u8 gpio_key_power = -1;

BSS_RO_AFTER_INIT struct uefi_boot_params boot_params;

u64 machine_random_seed(void)
Expand Down Expand Up @@ -396,6 +400,12 @@ void __attribute__((noreturn)) start(u64 x0, u64 x1)
while (1);
}

closure_func_basic(thunk, void, gpio_key_handler)
{
kernel_powerdown();
gpio_irq_clear(U64_FROM_BIT(gpio_key_power));
}

static void platform_dtb_parse(kernel_heaps kh, vector cpu_ids)
{
struct fdt fdt;
Expand Down Expand Up @@ -441,6 +451,18 @@ static void platform_dtb_parse(kernel_heaps kh, vector cpu_ids)
}
}
}
} else if (!runtime_strcmp(name, ss("gpio-keys"))) {
fdt_foreach_node(&fdt, node) {
if (!runtime_strcmp(fdt_node_name(&fdt, node), ss("poweroff"))) {
dt_prop gpio_prop = fdt_get_prop(&fdt, ss("gpios"));
if ((gpio_prop != INVALID_ADDRESS) &&
(dt_prop_cell_count(gpio_prop) >= 2))
/* cell #0: phandle of GPIO controller
* cell #1: GPIO number
*/
gpio_key_power = dt_prop_get_cell(gpio_prop, 1);
}
}
}
}
}
Expand Down Expand Up @@ -491,6 +513,13 @@ void detect_hypervisor(kernel_heaps kh)

void detect_devices(kernel_heaps kh, storage_attach sa)
{
if (gpio_key_power != (typeof(gpio_key_power))-1) {
thunk handler = closure_func(heap_locked(kh), thunk, gpio_key_handler);
assert(handler != INVALID_ADDRESS);
irq_register_handler(GIC_SPI_INTS_START + VIRT_GPIO_IRQ, handler, ss("gpio-keys"),
irange(0, 0));
gpio_irq_enable(U64_FROM_BIT(gpio_key_power));
}
init_acpi(kh);
if (hyperv_detected()) {
boolean hv_storvsc_attached = false;
Expand Down
17 changes: 17 additions & 0 deletions src/aarch64/gpio.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#include <kernel.h>
#include <gpio.h>

#define PL061_GPIOIEV 0x40c
#define PL061_GPIOIE 0x410
#define PL061_GPIOIC 0x41c

void gpio_irq_enable(u64 mask)
{
mmio_write_32(mmio_base_addr(GPIO) + PL061_GPIOIEV, mask);
mmio_write_32(mmio_base_addr(GPIO) + PL061_GPIOIE, mask);
}

void gpio_irq_clear(u64 mask)
{
mmio_write_32(mmio_base_addr(GPIO) + PL061_GPIOIC, mask);
}
2 changes: 2 additions & 0 deletions src/aarch64/gpio.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
void gpio_irq_enable(u64 mask);
void gpio_irq_clear(u64 mask);
33 changes: 33 additions & 0 deletions src/devicetree/devicetree.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,17 @@ static struct prop_value_map {
{ ss_static_init("cpu"), DT_VALUE_PHANDLE },
};

unsigned int dt_prop_cell_count(dt_prop prop)
{
return dt_u32(prop->data_length) / sizeof(u32);
}

u32 dt_prop_get_cell(dt_prop prop, unsigned int index)
{
void *ptr = prop->data + index * sizeof(u32);
return dt_u32(*((u32 *)ptr));
}

sstring dtb_string(void *dtb, u64 off)
{
dt_header fdt = dtb;
Expand Down Expand Up @@ -665,3 +676,25 @@ boolean fdt_get_reg(fdt fdt, u32 acells, u32 scells, dt_reg_iterator *iter)
fdt->ptr = ptr;
return found;
}

/* Consumes all the properties of the current node (i.e. only children of the current node can be
* parsed after this function is called). */
dt_prop fdt_get_prop(fdt fdt, sstring name)
{
void *ptr = fdt->ptr;
void *end = fdt->end;
dt_prop prop = INVALID_ADDRESS;
while (ptr < end) {
u32 token = dt_u32(*(u32 *)ptr);
if (token != FDT_PROP)
break;
ptr += sizeof(token);
dt_prop p = ptr;
u32 prop_len = dt_u32(p->data_length);
ptr += sizeof(*p) + pad(prop_len, 4);
if (!runtime_strcmp(fdt_prop_name(fdt, p), name))
prop = p;
}
fdt->ptr = ptr;
return prop;
}
4 changes: 4 additions & 0 deletions src/devicetree/devicetree.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ typedef struct dt_value {

closure_type(dt_node_handler, boolean, dt_node n, sstring name);

unsigned int dt_prop_cell_count(dt_prop prop);
u32 dt_prop_get_cell(dt_prop prop, unsigned int index);

typedef struct fdt {
void *ptr, *end;
char *strings_start, *strings_end;
Expand Down Expand Up @@ -72,6 +75,7 @@ dt_node fdt_next_node(fdt fdt);
sstring fdt_node_name(fdt fdt, dt_node node);
void fdt_get_cells(fdt fdt, u32 *acells, u32 *scells);
boolean fdt_get_reg(fdt fdt, u32 acells, u32 scells, dt_reg_iterator *iter);
dt_prop fdt_get_prop(fdt fdt, sstring name);

#define fdt_foreach_node(fdt, node) \
for (dt_node node = fdt_get_node(fdt); node; node = fdt_next_node(fdt))