/* * Copyright (c) 2012-2014 Wind River Systems, Inc. * Copyright (c) 2020 Arm Limited * Copyright (c) 2021-2023 Nordic Semiconductor ASA * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include "target.h" #include "bootutil/bootutil_log.h" #if defined(CONFIG_BOOT_SERIAL_PIN_RESET) || defined(CONFIG_BOOT_FIRMWARE_LOADER_PIN_RESET) #include #endif #if defined(CONFIG_BOOT_SERIAL_BOOT_MODE) || defined(CONFIG_BOOT_FIRMWARE_LOADER_BOOT_MODE) #include #endif /* Validate serial recovery configuration */ #ifdef CONFIG_MCUBOOT_SERIAL #if !defined(CONFIG_BOOT_SERIAL_ENTRANCE_GPIO) && \ !defined(CONFIG_BOOT_SERIAL_WAIT_FOR_DFU) && \ !defined(CONFIG_BOOT_SERIAL_BOOT_MODE) && \ !defined(CONFIG_BOOT_SERIAL_NO_APPLICATION) && \ !defined(CONFIG_BOOT_SERIAL_PIN_RESET) #error "Serial recovery selected without an entrance mode set" #endif #endif /* Validate firmware loader configuration */ #ifdef CONFIG_BOOT_FIRMWARE_LOADER #if !defined(CONFIG_BOOT_FIRMWARE_LOADER_ENTRANCE_GPIO) && \ !defined(CONFIG_BOOT_FIRMWARE_LOADER_BOOT_MODE) && \ !defined(CONFIG_BOOT_FIRMWARE_LOADER_NO_APPLICATION) && \ !defined(CONFIG_BOOT_FIRMWARE_LOADER_PIN_RESET) #error "Firmware loader selected without an entrance mode set" #endif #endif #ifdef CONFIG_MCUBOOT_INDICATION_LED /* * The led0 devicetree alias is optional. If present, we'll use it * to turn on the LED whenever the button is pressed. */ #if DT_NODE_EXISTS(DT_ALIAS(mcuboot_led0)) #define LED0_NODE DT_ALIAS(mcuboot_led0) #elif DT_NODE_EXISTS(DT_ALIAS(bootloader_led0)) #warning "bootloader-led0 alias is deprecated; use mcuboot-led0 instead" #define LED0_NODE DT_ALIAS(bootloader_led0) #endif #if DT_NODE_HAS_STATUS(LED0_NODE, okay) && DT_NODE_HAS_PROP(LED0_NODE, gpios) static const struct gpio_dt_spec led0 = GPIO_DT_SPEC_GET(LED0_NODE, gpios); #else /* A build error here means your board isn't set up to drive an LED. */ #error "Unsupported board: led0 devicetree alias is not defined" #endif BOOT_LOG_MODULE_DECLARE(mcuboot); void io_led_init(void) { if (!device_is_ready(led0.port)) { BOOT_LOG_ERR("Didn't find LED device referred by the LED0_NODE\n"); return; } gpio_pin_configure_dt(&led0, GPIO_OUTPUT); gpio_pin_set_dt(&led0, 0); } void io_led_set(int value) { gpio_pin_set_dt(&led0, value); } #endif /* CONFIG_MCUBOOT_INDICATION_LED */ #if defined(CONFIG_BOOT_SERIAL_ENTRANCE_GPIO) || defined(CONFIG_BOOT_USB_DFU_GPIO) || \ defined(CONFIG_BOOT_FIRMWARE_LOADER_ENTRANCE_GPIO) #if defined(CONFIG_MCUBOOT_SERIAL) #define BUTTON_0_DETECT_DELAY CONFIG_BOOT_SERIAL_DETECT_DELAY #elif defined(CONFIG_BOOT_FIRMWARE_LOADER) #define BUTTON_0_DETECT_DELAY CONFIG_BOOT_FIRMWARE_LOADER_DETECT_DELAY #else #define BUTTON_0_DETECT_DELAY CONFIG_BOOT_USB_DFU_DETECT_DELAY #endif #define BUTTON_0_NODE DT_ALIAS(mcuboot_button0) #if DT_NODE_EXISTS(BUTTON_0_NODE) && DT_NODE_HAS_PROP(BUTTON_0_NODE, gpios) static const struct gpio_dt_spec button0 = GPIO_DT_SPEC_GET(BUTTON_0_NODE, gpios); #else #error "Serial recovery/USB DFU button must be declared in device tree as 'mcuboot_button0'" #endif bool io_detect_pin(void) { int rc; int pin_active; if (!device_is_ready(button0.port)) { __ASSERT(false, "GPIO device is not ready.\n"); return false; } rc = gpio_pin_configure_dt(&button0, GPIO_INPUT); __ASSERT(rc == 0, "Failed to initialize boot detect pin.\n"); rc = gpio_pin_get_dt(&button0); pin_active = rc; __ASSERT(rc >= 0, "Failed to read boot detect pin.\n"); if (pin_active) { if (BUTTON_0_DETECT_DELAY > 0) { #ifdef CONFIG_MULTITHREADING k_sleep(K_MSEC(50)); #else k_busy_wait(50000); #endif /* Get the uptime for debounce purposes. */ int64_t timestamp = k_uptime_get(); for(;;) { rc = gpio_pin_get_dt(&button0); pin_active = rc; __ASSERT(rc >= 0, "Failed to read boot detect pin.\n"); /* Get delta from when this started */ uint32_t delta = k_uptime_get() - timestamp; /* If not pressed OR if pressed > debounce period, stop. */ if (delta >= BUTTON_0_DETECT_DELAY || !pin_active) { break; } /* Delay 1 ms */ #ifdef CONFIG_MULTITHREADING k_sleep(K_MSEC(1)); #else k_busy_wait(1000); #endif } } } return (bool)pin_active; } #endif #if defined(CONFIG_BOOT_SERIAL_PIN_RESET) || defined(CONFIG_BOOT_FIRMWARE_LOADER_PIN_RESET) bool io_detect_pin_reset(void) { uint32_t reset_cause; int rc; rc = hwinfo_get_reset_cause(&reset_cause); if (rc == 0 && reset_cause == RESET_PIN) { (void)hwinfo_clear_reset_cause(); return true; } return false; } #endif #if defined(CONFIG_BOOT_SERIAL_BOOT_MODE) || defined(CONFIG_BOOT_FIRMWARE_LOADER_BOOT_MODE) bool io_detect_boot_mode(void) { int32_t boot_mode; boot_mode = bootmode_check(BOOT_MODE_TYPE_BOOTLOADER); if (boot_mode == 1) { /* Boot mode to stay in bootloader, clear status and enter serial * recovery mode */ bootmode_clear(); return true; } return false; } #endif