From 8e69bf2c5a880540162a34fcb1d6597d9dc6d41f Mon Sep 17 00:00:00 2001 From: Raptor Engineering Development Team Date: Wed, 21 Apr 2021 15:24:35 -0500 Subject: [PATCH] Add initial host power/reset button support --- kestrel/src/kestrel.c | 11 +++++ kestrel/src/kestrel.h | 23 ++++++++++ kestrel/src/zephyr.c | 98 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 132 insertions(+) diff --git a/kestrel/src/kestrel.c b/kestrel/src/kestrel.c index 8804255..c90e96c 100644 --- a/kestrel/src/kestrel.c +++ b/kestrel/src/kestrel.c @@ -117,6 +117,7 @@ uint8_t hiomap_use_direct_access = 0; uint8_t host_background_service_task_active = 0; uint8_t host_console_service_task_active = 0; uint8_t host_console_service_task_requested = 0; +uint8_t host_power_status = HOST_POWER_STATUS_OFFLINE; static int configured_cpu_count = 1; // POST codes @@ -2179,6 +2180,8 @@ static int disable_avsbus_pmbus(const cpu_info_t *cpu_info, int cpu_count) void power_off_chassis(void) { + host_power_status = HOST_POWER_STATUS_POWERING_OFF; + // Disable PMBUS if (disable_avsbus_pmbus(g_cpu_info, configured_cpu_count)) { @@ -2189,6 +2192,8 @@ void power_off_chassis(void) i2c_write_register_byte((uint8_t *)I2CMASTER4_BASE, HOST_PLATFORM_FPGA_I2C_ADDRESS, HOST_PLATFORM_FPGA_I2C_REG_MFR_OVR, 0x00); run_post_shutdown_bmc_peripheral_teardown(); + + host_power_status = HOST_POWER_STATUS_OFFLINE; } static int power_on_chassis(void) @@ -2199,10 +2204,13 @@ static int power_on_chassis(void) int i2c_read_retcode; uint8_t byte; + host_power_status = HOST_POWER_STATUS_POWERING_ON; + // Verify communication with platform control FPGA platform_fpga_identifier[0] = i2c_read_register_byte((uint8_t *)I2CMASTER4_BASE, HOST_PLATFORM_FPGA_I2C_ADDRESS, 0x0c, NULL); if (platform_fpga_identifier[0] == 0xff) { + host_power_status = HOST_POWER_STATUS_OFFLINE; return -1; } platform_fpga_identifier[1] = i2c_read_register_byte((uint8_t *)I2CMASTER4_BASE, HOST_PLATFORM_FPGA_I2C_ADDRESS, 0x0d, NULL); @@ -2211,6 +2219,7 @@ static int power_on_chassis(void) if ((platform_fpga_identifier[0] != 0x52) || (platform_fpga_identifier[1] != 0x43) || (platform_fpga_identifier[2] != 0x53) || (platform_fpga_identifier[3] != 0x20)) { + host_power_status = HOST_POWER_STATUS_OFFLINE; return -1; } KESTREL_LOG("Platform FPGA communication verified"); @@ -2269,6 +2278,8 @@ static int power_on_chassis(void) return -5; } + host_power_status = HOST_POWER_STATUS_RUNNING; + return 0; } diff --git a/kestrel/src/kestrel.h b/kestrel/src/kestrel.h index ca321a8..218763d 100644 --- a/kestrel/src/kestrel.h +++ b/kestrel/src/kestrel.h @@ -11,6 +11,28 @@ #define KESTREL_SERVICE_THREAD_PRIORITY K_PRIO_PREEMPT(CONFIG_NUM_PREEMPT_PRIORITIES - 1) #endif +#if (WITH_ZEPHYR) +#define SW0_NODE DT_ALIAS(sw0) +#if DT_NODE_HAS_STATUS(SW0_NODE, okay) +#define KESTREL_HOST_POWER_BUTTON_GPIO DT_GPIO_LABEL(SW0_NODE, gpios) +#define KESTREL_HOST_POWER_BUTTON_PIN DT_GPIO_PIN(SW0_NODE, gpios) +#else +#error "No power button defined in device tree" +#endif +#define SW1_NODE DT_ALIAS(sw1) +#if DT_NODE_HAS_STATUS(SW1_NODE, okay) +#define KESTREL_HOST_RESET_BUTTON_GPIO DT_GPIO_LABEL(SW1_NODE, gpios) +#define KESTREL_HOST_RESET_BUTTON_PIN DT_GPIO_PIN(SW1_NODE, gpios) +#else +#error "No reset button defined in device tree" +#endif +#endif + +#define HOST_POWER_STATUS_OFFLINE 0 +#define HOST_POWER_STATUS_POWERING_ON 1 +#define HOST_POWER_STATUS_RUNNING 2 +#define HOST_POWER_STATUS_POWERING_OFF 3 + struct firmware_buffer_region { uint8_t *buffer_address; unsigned long long buffer_length; @@ -24,6 +46,7 @@ extern struct firmware_buffer_region main_firmware_buffer; extern uint8_t kestrel_basic_init_complete; extern uint8_t host_background_service_task_active; extern uint8_t host_console_service_task_requested; +extern uint8_t host_power_status; #if (WITH_ZEPHYR) extern k_tid_t kestrel_service_thread_id; diff --git a/kestrel/src/zephyr.c b/kestrel/src/zephyr.c index fe5587d..b90b632 100644 --- a/kestrel/src/zephyr.c +++ b/kestrel/src/zephyr.c @@ -10,12 +10,18 @@ LOG_MODULE_REGISTER(kestrel_init, LOG_LEVEL_DBG); #include #include #include +#include +#include #define WITH_ZEPHYR 1 #include "webservice.h" +#include "flash_filesystem.h" #include "kestrel.h" +static struct gpio_callback host_power_button_callback_data; +static struct gpio_callback host_reset_button_callback_data; + #define KESTREL_INIT_THREAD_PRIORITY K_PRIO_PREEMPT(CONFIG_NUM_PREEMPT_PRIORITIES - 1) static K_THREAD_STACK_DEFINE(kestrel_init_thread_stack, 16384); static struct k_thread kestrel_init_thread_data; @@ -52,6 +58,95 @@ static void kestrel_service_thread(void) } } +void host_power_button_pressed(const struct device *dev, struct gpio_callback *cb, uint32_t pins) +{ + int want_power_on = 0; + int want_power_off = 0; + + LOG_INF("Host power button pressed"); + + // Deactivate interrupts on entering critical section + int key = irq_lock(); + + if (host_power_status == HOST_POWER_STATUS_OFFLINE) { + want_power_on = 1; + } + else { + want_power_off = 1; + } + + // Re-activate interupts on exiting critical section + irq_unlock(key); + + if (want_power_on) { + power_on_host(); + } + else if (want_power_off) { + power_off_chassis(); + } +} + +void host_reset_button_pressed(const struct device *dev, struct gpio_callback *cb, uint32_t pins) +{ + // Deactivate interrupts on entering critical section + int key = irq_lock(); + + // FIXME + // Implement host reset functionality + + // Re-activate interupts on exiting critical section + irq_unlock(key); + + LOG_WRN("[FIXME] Reset button pressed, but not implemented!"); +} + +static int configure_gpios(void) +{ + const struct device *button; + int retcode; + int ret; + + retcode = 0; + + // Set up power button + button = device_get_binding(KESTREL_HOST_POWER_BUTTON_GPIO); + if (button == NULL) { + printk("[ERROR] Unable to locate host power button on node %s\n", KESTREL_HOST_POWER_BUTTON_GPIO); + retcode = -1; + } + else { + ret = gpio_pin_interrupt_configure(button, KESTREL_HOST_POWER_BUTTON_PIN, GPIO_INT_EDGE_TO_ACTIVE); + if (ret != 0) { + printk("[ERROR] failed to configure interrupt on %s pin %d (returned %d)\n", KESTREL_HOST_POWER_BUTTON_GPIO, KESTREL_HOST_POWER_BUTTON_PIN, ret); + retcode = -1; + } + else { + gpio_init_callback(&host_power_button_callback_data, host_power_button_pressed, BIT(KESTREL_HOST_POWER_BUTTON_PIN)); + gpio_add_callback(button, &host_power_button_callback_data); + } + } + + // Set up reset button + button = device_get_binding(KESTREL_HOST_RESET_BUTTON_GPIO); + if (button == NULL) { + printk("[ERROR] Unable to locate host reset button on node %s\n", KESTREL_HOST_RESET_BUTTON_GPIO); + retcode = -1; + } + else { + ret = gpio_pin_interrupt_configure(button, KESTREL_HOST_RESET_BUTTON_PIN, GPIO_INT_EDGE_TO_ACTIVE); + if (ret != 0) { + printk("[ERROR] failed to configure interrupt on %s pin %d (returned %d)\n", KESTREL_HOST_RESET_BUTTON_GPIO, KESTREL_HOST_RESET_BUTTON_PIN, ret); + retcode = -1; + } + else { + gpio_init_callback(&host_reset_button_callback_data, host_reset_button_pressed, BIT(KESTREL_HOST_RESET_BUTTON_PIN)); + gpio_add_callback(button, &host_reset_button_callback_data); + } + } + + return retcode; +} + void main(void) { // Set root command and prompt for all shells @@ -86,5 +181,8 @@ void main(void) NULL, NULL, NULL, KESTREL_SERVICE_THREAD_PRIORITY, 0, K_NO_WAIT); k_thread_name_set(kestrel_service_thread_id, "kestrel_service"); + // Run late setup + configure_gpios(); + LOG_INF("Kestrel system initialization complete\n"); } \ No newline at end of file -- 2.30.2