summaryrefslogtreecommitdiff
path: root/zephyr/drivers/cros_system/cros_system_stm32.c
diff options
context:
space:
mode:
Diffstat (limited to 'zephyr/drivers/cros_system/cros_system_stm32.c')
-rw-r--r--zephyr/drivers/cros_system/cros_system_stm32.c150
1 files changed, 150 insertions, 0 deletions
diff --git a/zephyr/drivers/cros_system/cros_system_stm32.c b/zephyr/drivers/cros_system/cros_system_stm32.c
new file mode 100644
index 0000000000..bc42909666
--- /dev/null
+++ b/zephyr/drivers/cros_system/cros_system_stm32.c
@@ -0,0 +1,150 @@
+/* Copyright 2023 The ChromiumOS Authors
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#define DT_DRV_COMPAT st_stm32_rcc
+
+#include "drivers/cros_system.h"
+#include "system.h"
+
+#include <zephyr/device.h>
+#include <zephyr/drivers/hwinfo.h>
+#include <zephyr/drivers/watchdog.h>
+#include <zephyr/sys/reboot.h>
+
+/* Driver data */
+struct cros_system_stm32_data {
+ int reset; /* reset cause */
+};
+
+#define DRV_DATA(dev) ((struct cros_system_stm32_data *)(dev)->data)
+
+static const struct device *const watchdog =
+ DEVICE_DT_GET(DT_CHOSEN(cros_ec_watchdog));
+
+static const char *cros_system_stm32_get_chip_vendor(const struct device *dev)
+{
+ ARG_UNUSED(dev);
+
+ return "st";
+}
+
+static const char *cros_system_stm32_get_chip_name(const struct device *dev)
+{
+ ARG_UNUSED(dev);
+
+ return CONFIG_SOC;
+}
+
+static const char *cros_system_stm32_get_chip_revision(const struct device *dev)
+{
+ ARG_UNUSED(dev);
+
+ return "";
+}
+
+static int cros_system_stm32_get_reset_cause(const struct device *dev)
+{
+ struct cros_system_stm32_data *data = DRV_DATA(dev);
+
+ return data->reset;
+}
+
+static int cros_system_stm32_soc_reset(const struct device *dev)
+{
+ ARG_UNUSED(dev);
+
+ uint32_t chip_reset_flags = chip_read_reset_flags();
+
+ /*
+ * We are going to reboot MCU here, so we need to disable caches here.
+ * SCB_DisableDCache also flushes data cache lines.
+ */
+#ifdef CONFIG_DCACHE
+ SCB_DisableDCache();
+#endif
+
+#ifdef CONFIG_ICACHE
+ SCB_DisableICache();
+#endif
+
+ if (chip_reset_flags & EC_RESET_FLAG_HARD) {
+ /*
+ * Set minimal watchdog timeout - 1 millisecond.
+ * STM32 IWDG can be set for lower value, but we are limited by
+ * Zephyr API.
+ */
+ struct wdt_timeout_cfg minimal_timeout = { .window.max = 1 };
+
+ /* Setup watchdog */
+ wdt_install_timeout(watchdog, &minimal_timeout);
+
+ /* Apply the changes (the driver will reload watchdog) */
+ wdt_setup(watchdog, 0);
+
+ /* Spin and wait for reboot */
+ while (1)
+ ;
+ } else {
+ /* Reset implementation for ARM ignores the reset type */
+ sys_reboot(0);
+ }
+
+ /* Should never return */
+ return 0;
+}
+
+static uint64_t cros_system_stm32_deep_sleep_ticks(const struct device *dev)
+{
+ /* Deep sleep is not supported for now */
+ return 0;
+}
+
+static int cros_system_stm32_init(const struct device *dev)
+{
+ struct cros_system_stm32_data *data = DRV_DATA(dev);
+ uint32_t reset_cause;
+
+ data->reset = UNKNOWN_RST;
+ hwinfo_get_reset_cause(&reset_cause);
+
+ /* Clear the hardware reset cause. */
+ hwinfo_clear_reset_cause();
+
+ if (reset_cause & RESET_WATCHDOG) {
+ data->reset = WATCHDOG_RST;
+ } else if (reset_cause & RESET_SOFTWARE) {
+ /* Use DEBUG_RST because it maps to EC_RESET_FLAG_SOFT. */
+ data->reset = DEBUG_RST;
+ } else if (reset_cause & RESET_POR) {
+ data->reset = POWERUP;
+ } else if (reset_cause & RESET_PIN) {
+ data->reset = VCC1_RST_PIN;
+ }
+
+ return 0;
+}
+
+static struct cros_system_stm32_data cros_system_stm32_dev_data;
+
+static const struct cros_system_driver_api cros_system_driver_stm32_api = {
+ .get_reset_cause = cros_system_stm32_get_reset_cause,
+ .soc_reset = cros_system_stm32_soc_reset,
+ .chip_vendor = cros_system_stm32_get_chip_vendor,
+ .chip_name = cros_system_stm32_get_chip_name,
+ .chip_revision = cros_system_stm32_get_chip_revision,
+#ifdef CONFIG_PM
+ .deep_sleep_ticks = cros_system_stm32_deep_sleep_ticks,
+#endif
+};
+
+DEVICE_DEFINE(cros_system_stm32_0, "CROS_SYSTEM", cros_system_stm32_init, NULL,
+ &cros_system_stm32_dev_data, NULL, PRE_KERNEL_1,
+ CONFIG_CROS_SYSTEM_STM32_INIT_PRIORITY,
+ &cros_system_driver_stm32_api);
+
+#if CONFIG_CROS_SYSTEM_STM32_INIT_PRIORITY >= \
+ CONFIG_PLATFORM_EC_SYSTEM_PRE_INIT_PRIORITY
+#error "CROS_SYSTEM must initialize before the SYSTEM_PRE initialization"
+#endif