summaryrefslogtreecommitdiff
path: root/zephyr/drivers/cros_system/cros_system_npcx.c
diff options
context:
space:
mode:
Diffstat (limited to 'zephyr/drivers/cros_system/cros_system_npcx.c')
-rw-r--r--zephyr/drivers/cros_system/cros_system_npcx.c556
1 files changed, 0 insertions, 556 deletions
diff --git a/zephyr/drivers/cros_system/cros_system_npcx.c b/zephyr/drivers/cros_system/cros_system_npcx.c
deleted file mode 100644
index e3d3bc29b2..0000000000
--- a/zephyr/drivers/cros_system/cros_system_npcx.c
+++ /dev/null
@@ -1,556 +0,0 @@
-/* Copyright 2021 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include <arch/arm/aarch32/cortex_m/cmsis.h>
-#include <drivers/cros_system.h>
-#include <drivers/gpio.h>
-#include <drivers/watchdog.h>
-#include <logging/log.h>
-#include <soc.h>
-#include <soc/nuvoton_npcx/reg_def_cros.h>
-#include <sys/util.h>
-
-#include "gpio.h"
-#include "rom_chip.h"
-#include "soc_gpio.h"
-#include "soc_miwu.h"
-#include "system.h"
-
-LOG_MODULE_REGISTER(cros_system, LOG_LEVEL_ERR);
-
-/* Driver config */
-struct cros_system_npcx_config {
- /* hardware module base address */
- uintptr_t base_scfg;
- uintptr_t base_twd;
- uintptr_t base_mswc;
-};
-
-/* Driver data */
-struct cros_system_npcx_data {
- int reset; /* reset cause */
-};
-
-/* Driver convenience defines */
-#define DRV_CONFIG(dev) ((const struct cros_system_npcx_config *)(dev)->config)
-
-#define HAL_SCFG_INST(dev) (struct scfg_reg *)(DRV_CONFIG(dev)->base_scfg)
-#define HAL_TWD_INST(dev) (struct twd_reg *)(DRV_CONFIG(dev)->base_twd)
-#define HAL_MSWC_INST(dev) (struct mswc_reg *)(DRV_CONFIG(dev)->base_mswc)
-
-#define DRV_DATA(dev) ((struct cros_system_npcx_data *)(dev)->data)
-
-#define SYSTEM_DT_NODE_SOC_ID_CONFIG DT_INST(0, nuvoton_npcx_soc_id)
-
-/* Chip info devicetree data */
-#define NPCX_FAMILY_ID DT_PROP(SYSTEM_DT_NODE_SOC_ID_CONFIG, family_id)
-
-#define NPCX_CHIP_ID DT_PROP(SYSTEM_DT_NODE_SOC_ID_CONFIG, chip_id)
-
-#define NPCX_DEVICE_ID DT_PROP(SYSTEM_DT_NODE_SOC_ID_CONFIG, device_id)
-
-#define NPCX_REVISION_ADDR \
- DT_PROP_BY_IDX(SYSTEM_DT_NODE_SOC_ID_CONFIG, revision_reg, 0)
-#define NPCX_REVISION_LEN \
- DT_PROP_BY_IDX(SYSTEM_DT_NODE_SOC_ID_CONFIG, revision_reg, 1)
-
-/* RAM block size in npcx family (Unit: bytes) */
-#define NPCX_RAM_BLOCK_SIZE (32 * 1024)
-/* RAM block number in npcx7 series */
-
-/* Calculate the number of RAM blocks:
- * total RAM size = code ram + data ram + extra 2K for ROM functions
- * divided by the block size 32k.
- */
-#define DATA_RAM_SIZE DT_REG_SIZE(DT_NODELABEL(sram0))
-#define CODE_RAM_SIZE DT_REG_SIZE(DT_NODELABEL(flash0))
-#define NPCX_RAM_BLOCK_COUNT \
- ((DATA_RAM_SIZE + CODE_RAM_SIZE + KB(2)) / NPCX_RAM_BLOCK_SIZE)
-
-/* Valid bit-depth of RAM block Power-Down control (RAM_PD) registers. Use its
- * mask to power down all unnecessary RAM blocks before hibernating.
- */
-#define NPCX_RAM_PD_DEPTH DT_PROP(DT_NODELABEL(pcc), ram_pd_depth)
-#define NPCX_RAM_BLOCK_PD_MASK (BIT(NPCX_RAM_PD_DEPTH) - 1)
-
-/* Get saved reset flag address in battery-backed ram */
-#define BBRAM_SAVED_RESET_FLAG_ADDR \
- (DT_REG_ADDR(DT_INST(0, nuvoton_npcx_bbram)) + \
- DT_PROP(DT_PATH(named_bbram_regions, saved_reset_flags), offset))
-
-/* Soc specific system local functions */
-static int system_npcx_watchdog_stop(void)
-{
- if (IS_ENABLED(CONFIG_WATCHDOG)) {
- const struct device *wdt_dev = DEVICE_DT_GET(
- DT_NODELABEL(twd0));
- if (!device_is_ready(wdt_dev)) {
- LOG_ERR("Error: device %s is not ready", wdt_dev->name);
- return -ENODEV;
- }
-
- wdt_disable(wdt_dev);
- }
-
- return 0;
-}
-
-static void system_npcx_set_flash_pins_tri_state(const struct device *dev)
-{
- struct scfg_reg *const inst_scfg = HAL_SCFG_INST(dev);
-
- inst_scfg->DEVCNT |= BIT(NPCX_DEVCNT_F_SPI_TRIS);
-}
-
-static void system_npcx_init_watchdog_reset(const struct device *dev)
-{
- struct twd_reg *const inst_twd = HAL_TWD_INST(dev);
-
- /* Enable early touch */
- inst_twd->T0CSR &= ~BIT(NPCX_T0CSR_TESDIS);
- /* watchdog touched by writing 5Ch to WDSDM */
- inst_twd->TWCFG |= BIT(NPCX_TWCFG_WDSDME);
-}
-
-static void system_npcx_turn_off_adc(void)
-{
- struct adc_reg *const inst_adc =
- (struct adc_reg *)(DT_REG_ADDR(DT_INST(0, nuvoton_npcx_adc)));
-
- inst_adc->ADCCNF = 0;
- /* Wait for 1000 us to make sure conversion is completed. */
- k_busy_wait(1000);
-}
-
-static void system_npcx_turn_off_kernel_timer(void)
-{
- static struct itim32_reg *const evt_tmr =
- (struct itim32_reg *)DT_REG_ADDR_BY_NAME(
- DT_INST(0, nuvoton_npcx_itim_timer), evt_itim);
-
- evt_tmr->ITCTS32 &= ~BIT(NPCX_ITCTSXX_ITEN);
-}
-
-static void system_npcx_disable_instant_wakeup(void)
-{
- struct pmc_reg *const inst_pmc = (struct pmc_reg *)(DT_REG_ADDR_BY_NAME(
- DT_INST(0, nuvoton_npcx_pcc), pmc));
-
- inst_pmc->ENIDL_CTL &= ~BIT(NPCX_ENIDL_CTL_LP_WK_CTL);
-}
-
-static void system_npcx_set_wakeup_gpios_before_hibernate(void)
-{
- const uintptr_t miwu_base[] = {
- DT_REG_ADDR(DT_INST(0, nuvoton_npcx_miwu)),
- DT_REG_ADDR(DT_INST(1, nuvoton_npcx_miwu)),
- DT_REG_ADDR(DT_INST(2, nuvoton_npcx_miwu)),
- };
-
- /* Disable all MIWU inputs before entering hibernate */
- for (int table = 0; table < ARRAY_SIZE(miwu_base); table++) {
- for (int group = 0; group < NPCX_MIWU_GROUP_COUNT; group++) {
- /* Disable all wake-ups */
- NPCX_WKEN(miwu_base[table], group) = 0x00;
- /* Clear all pending bits of wake-ups */
- NPCX_WKPCL(miwu_base[table], group) = 0xFF;
- /*
- * Disable all inputs of wake-ups to prevent leakage
- * caused by input floating.
- */
- NPCX_WKINEN(miwu_base[table], group) = 0x00;
- }
- }
-
- static const int wakeup_pin_list[] = {
-#if DT_NODE_EXISTS(SYSTEM_DT_NODE_HIBERNATE_CONFIG)
- UTIL_LISTIFY(SYSTEM_DT_NODE_WAKEUP_PIN_LEN,
- SYSTEM_DT_WAKEUP_GPIO_ENUM_BY_IDX, _)
-#endif
- };
-
- /* Reconfigure wake-up GPIOs */
- for (int i = 0; i < ARRAY_SIZE(wakeup_pin_list); i++) {
- gpio_reset(wakeup_pin_list[i]);
- /* Re-enable interrupt for wake-up inputs */
- gpio_enable_interrupt(wakeup_pin_list[i]);
- }
-}
-
-/*
- * Hibernate function locates in the last 32K ram block in npcx7 series.
- * Do not use global variables or call functions since we have turned off
- * the other ram blocks.
- */
-noreturn void __keep __attribute__((section(".lfw.hiber")))
-system_npcx_hibernate_by_lfw_in_last_ram(const struct device *dev,
- uint32_t pd_ram_mask)
-{
- /* Modules used for hibernating */
- struct twd_reg *const inst_twd = HAL_TWD_INST(dev);
- struct mtc_reg *const inst_mtc = (struct mtc_reg *)(DT_REG_ADDR(
- DT_INST(0, nuvoton_npcx_cros_mtc)));
- struct pmc_reg *const inst_pmc = (struct pmc_reg *)(DT_REG_ADDR_BY_NAME(
- DT_INST(0, nuvoton_npcx_pcc), pmc));
- uint32_t reset_flags;
- volatile uint8_t *saved_reset_flags =
- (volatile uint8_t *)BBRAM_SAVED_RESET_FLAG_ADDR;
-
- /* Turn off all blocks except last one for better power consumption */
- inst_pmc->RAM_PD[0] = (uint8_t)pd_ram_mask;
- inst_pmc->RAM_PD[1] = (uint8_t)(pd_ram_mask >> 8);
-
- /* Set deep idle mode */
- inst_pmc->PMCSR = BIT(NPCX_PMCSR_IDLE) | BIT(NPCX_PMCSR_DHF);
-
- /* Enter system sleep mode */
- __asm__ volatile("wfi");
-
- /*
- * Mark wake-up reason for hibernate. Do not call bbram utilities
- * directly since the other ram blocks are power down.
- */
- if (IS_BIT_SET(inst_mtc->WTC, NPCX_WTC_PTO)) {
- /* Save wake-up reason as RTC alarm. */
- reset_flags = EC_RESET_FLAG_RTC_ALARM;
- } else {
- /* Otherwise, we treat it as GPIOs wake-up */
- reset_flags = EC_RESET_FLAG_WAKE_PIN;
- }
-
- saved_reset_flags[0] |= reset_flags;
- saved_reset_flags[1] |= reset_flags >> 8;
- saved_reset_flags[2] |= reset_flags >> 16;
- saved_reset_flags[3] |= reset_flags >> 24;
-
- /*
- * The trigger of a watchdog event by a "too early service" condition.
- * When the watchdog is written more than once during three watchdog
- * clock cycle.
- */
- inst_twd->WDSDM = 0x5C;
- inst_twd->WDSDM = 0x5C;
-
- /* Spin and wait for reboot; should never return */
- while (1)
- continue;
-}
-
-static inline int system_npcx_get_ram_blk_by_lfw_addr(char *address)
-{
- return NPCX_RAM_BLOCK_COUNT -
- ceiling_fraction((uint32_t)address -
- CONFIG_CROS_EC_PROGRAM_MEMORY_BASE,
- NPCX_RAM_BLOCK_SIZE);
-}
-
-static void system_npcx_hibernate_by_disable_ram(const struct device *dev,
- uint32_t seconds,
- uint32_t microseconds)
-{
- /* Get 32kb ram block order of lfw function */
- extern char __lfw_text_start[], __lfw_text_end[];
- int lfw_block = system_npcx_get_ram_blk_by_lfw_addr(__lfw_text_start);
- uint32_t pd_ram_mask = ~BIT(lfw_block) & NPCX_RAM_BLOCK_PD_MASK;
-
- if (lfw_block != system_npcx_get_ram_blk_by_lfw_addr(__lfw_text_end)) {
- LOG_ERR("LFW cannot cross ram blocks!");
- return;
- }
-
- /*
- * Set status of pins which connect to flash to tri-state in case
- * the leakage current.
- */
- system_npcx_set_flash_pins_tri_state(dev);
-
- /* Initialize watchdog for reset after wake-up from hibernating */
- system_npcx_init_watchdog_reset(dev);
-
- /* Disable ADC and wait for 1000 us to make sure conversion is done */
- if (IS_ENABLED(CONFIG_ADC))
- system_npcx_turn_off_adc();
-
- /* Disable kernel timer */
- system_npcx_turn_off_kernel_timer();
-
- /* Disable instant wake up mode for better power consumption */
- system_npcx_disable_instant_wakeup();
-
- /*
- * Set wake-up input GPIOs and turn off the other sources for better
- * power consumption before entering hibernate mode.
- */
- system_npcx_set_wakeup_gpios_before_hibernate();
-
- /*
- * Give the board a chance to do any late stage hibernation work. This
- * is likely going to configure GPIOs for hibernation. On some boards,
- * it's possible that this may not return at all. On those boards,
- * power to the EC is likely being turn off entirely.
- */
- if (board_hibernate_late) {
- board_hibernate_late();
- }
-
- /* Setup a RTC alarm if needed */
- if (IS_ENABLED(CONFIG_RTC) && (seconds || microseconds)) {
- system_set_rtc_alarm(seconds, microseconds);
- }
-
- /* Clear all pending IRQs in case wake-up immediately after sleeping */
- for (int i = 0; i < CONFIG_NUM_IRQS; i++) {
- NVIC_ClearPendingIRQ(i);
- }
-
- /* Execute hibernate by lfw which locates in last 32K block ram */
- system_npcx_hibernate_by_lfw_in_last_ram(dev, pd_ram_mask);
-}
-
-static const char *cros_system_npcx_get_chip_vendor(const struct device *dev)
-{
- struct mswc_reg *const inst_mswc = HAL_MSWC_INST(dev);
- static char str[11] = "Unknown-XX";
- char *p = str + 8;
- uint8_t fam_id = inst_mswc->SID_CR;
-
-#if DT_NODE_EXISTS(SYSTEM_DT_NODE_SOC_ID_CONFIG)
- if (fam_id == NPCX_FAMILY_ID) {
- return "Nuvoton";
- }
-#endif
-
- hex2char(fam_id >> 4, p++);
- hex2char(fam_id & 0xf, p);
- return str;
-}
-
-static const char *cros_system_npcx_get_chip_name(const struct device *dev)
-{
- struct mswc_reg *const inst_mswc = HAL_MSWC_INST(dev);
- static char str[13] = "Unknown-XXXX";
- char *p = str + 8;
- uint8_t chip_id = inst_mswc->SRID_CR;
- uint8_t device_id = inst_mswc->DEVICE_ID_CR;
-
-#if DT_NODE_EXISTS(SYSTEM_DT_NODE_SOC_ID_CONFIG)
- if (chip_id == NPCX_CHIP_ID && device_id == NPCX_DEVICE_ID) {
- return CONFIG_SOC;
- }
-#endif
-
- hex2char(chip_id >> 4, p++);
- hex2char(chip_id & 0xf, p++);
- hex2char(device_id >> 4, p++);
- hex2char(device_id & 0xf, p);
- return str;
-}
-
-static const char *cros_system_npcx_get_chip_revision(const struct device *dev)
-{
- ARG_UNUSED(dev);
-#if DT_NODE_EXISTS(SYSTEM_DT_NODE_SOC_ID_CONFIG)
- static char rev[NPCX_REVISION_LEN * 2 + 1];
-#else
- static char rev[1];
-#endif
- char *p = rev;
-
-#if DT_NODE_EXISTS(SYSTEM_DT_NODE_SOC_ID_CONFIG)
- /*
- * For NPCX7, the revision number is 1 byte.
- * For NPCX9 and later chips, the revision number is 4 bytes.
- */
- for (int s = NPCX_REVISION_ADDR + NPCX_REVISION_LEN - 1;
- s >= NPCX_REVISION_ADDR; s--) {
- uint8_t r = *((volatile uint8_t *)s);
- hex2char(r >> 4, p++);
- hex2char(r & 0xf, p++);
- }
-#endif
- *p = '\0';
-
- return rev;
-}
-
-static void system_npcx_hibernate_by_psl(const struct device *dev,
- uint32_t seconds,
- uint32_t microseconds)
-{
- ARG_UNUSED(dev);
- /*
- * TODO(b/178230662): RTC wake-up in PSL mode only support in npcx9
- * series. Nuvoton will introduce CLs for it later.
- */
- ARG_UNUSED(seconds);
- ARG_UNUSED(microseconds);
-
- /*
- * Configure PSL input pads from "psl-in-pads" property in device tree
- * file.
- */
- npcx_pinctrl_psl_input_configure();
-
- /*
- * Give the board a chance to do any late stage hibernation work. This
- * is likely going to configure GPIOs for hibernation. On some boards,
- * it's possible that this may not return at all. On those boards,
- * power to the EC is likely being turn off entirely.
- */
- if (board_hibernate_late)
- board_hibernate_late();
-
- /* Turn off VCC1 to enter ultra-low-power mode for hibernating */
- npcx_pinctrl_psl_output_set_inactive();
-}
-
-static int cros_system_npcx_get_reset_cause(const struct device *dev)
-{
- struct cros_system_npcx_data *data = DRV_DATA(dev);
-
- return data->reset;
-}
-
-static int cros_system_npcx_init(const struct device *dev)
-{
- struct scfg_reg *const inst_scfg = HAL_SCFG_INST(dev);
- struct twd_reg *const inst_twd = HAL_TWD_INST(dev);
- struct cros_system_npcx_data *data = DRV_DATA(dev);
-
- /* check reset cause */
- if (IS_BIT_SET(inst_twd->T0CSR, NPCX_T0CSR_WDRST_STS)) {
- data->reset = WATCHDOG_RST;
- inst_twd->T0CSR |= BIT(NPCX_T0CSR_WDRST_STS);
- } else if (IS_BIT_SET(inst_scfg->RSTCTL, NPCX_RSTCTL_DBGRST_STS)) {
- data->reset = DEBUG_RST;
- inst_scfg->RSTCTL |= BIT(NPCX_RSTCTL_DBGRST_STS);
- } else if (IS_BIT_SET(inst_scfg->RSTCTL, NPCX_RSTCTL_VCC1_RST_STS)) {
- data->reset = VCC1_RST_PIN;
- } else {
- data->reset = POWERUP;
- }
-
- return 0;
-}
-
-static int cros_system_npcx_soc_reset(const struct device *dev)
-{
- struct twd_reg *const inst_twd = HAL_TWD_INST(dev);
-
- /* Disable interrupts to avoid task swaps during reboot */
- interrupt_disable_all();
-
- /*
- * NPCX chip doesn't have the specific system reset functionality. Use
- * watchdog reset as a system reset.
- */
-
- /* Stop the watchdog */
- system_npcx_watchdog_stop();
-
- /* Initialize watchdog for reset */
- system_npcx_init_watchdog_reset(dev);
-
- /*
- * The trigger of a watchdog event by a "too early service" condition.
- * When the watchdog is written more than once during three watchdog
- * clock cycle.
- */
- inst_twd->WDSDM = 0x5C;
- inst_twd->WDSDM = 0x5C;
-
- /* Wait for the soc reset. */
- while (1) {
- ;
- }
-
- /* should never return */
- return 0;
-}
-
-static int cros_system_npcx_hibernate(const struct device *dev,
- uint32_t seconds, uint32_t microseconds)
-{
- /* Disable interrupt first */
- interrupt_disable_all();
-
- /* Stop the watchdog */
- system_npcx_watchdog_stop();
-
- /* Enter hibernate mode */
- if (IS_ENABLED(CONFIG_PLATFORM_EC_HIBERNATE_PSL)) {
- system_npcx_hibernate_by_psl(dev, seconds, microseconds);
- } else {
- system_npcx_hibernate_by_disable_ram(dev, seconds,
- microseconds);
- }
-
- return 0;
-}
-
-__maybe_unused static uint64_t
-cros_system_npcx_deep_sleep_ticks(const struct device *dev)
-{
- return npcx_clock_get_sleep_ticks();
-}
-
-static struct cros_system_npcx_data cros_system_npcx_dev_data;
-
-static const struct cros_system_npcx_config cros_system_dev_cfg = {
- .base_scfg = DT_REG_ADDR(DT_INST(0, nuvoton_npcx_scfg)),
- .base_twd = DT_REG_ADDR(DT_INST(0, nuvoton_npcx_watchdog)),
- .base_mswc =
- DT_REG_ADDR_BY_NAME(DT_INST(0, nuvoton_npcx_host_sub), mswc),
-};
-
-static const struct cros_system_driver_api cros_system_driver_npcx_api = {
- .get_reset_cause = cros_system_npcx_get_reset_cause,
- .soc_reset = cros_system_npcx_soc_reset,
- .hibernate = cros_system_npcx_hibernate,
- .chip_vendor = cros_system_npcx_get_chip_vendor,
- .chip_name = cros_system_npcx_get_chip_name,
- .chip_revision = cros_system_npcx_get_chip_revision,
-#ifdef CONFIG_SOC_POWER_MANAGEMENT_TRACE
- .deep_sleep_ticks = cros_system_npcx_deep_sleep_ticks,
-#endif
-};
-
-DEVICE_DEFINE(cros_system_npcx_0, "CROS_SYSTEM", cros_system_npcx_init, NULL,
- &cros_system_npcx_dev_data, &cros_system_dev_cfg, PRE_KERNEL_1,
- CONFIG_CROS_SYSTEM_NPCX_INIT_PRIORITY,
- &cros_system_driver_npcx_api);
-
-#if DT_NODE_EXISTS(DT_NODELABEL(dbg))
-#define HAL_DBG_REG_BASE_ADDR \
- ((struct dbg_reg *)DT_REG_ADDR(DT_INST(0, nuvoton_npcx_cros_dbg)))
-
-#define DBG_NODE DT_NODELABEL(dbg)
-#define DBG_PINCTRL_PH DT_PHANDLE_BY_IDX(DBG_NODE, pinctrl_0, 0)
-#define DBG_ALT_FILED(f) DT_PHA_BY_IDX(DBG_PINCTRL_PH, alts, 0, f)
-
-static int jtag_init(const struct device *dev)
-{
- ARG_UNUSED(dev);
- struct dbg_reg *const dbg_reg_base = HAL_DBG_REG_BASE_ADDR;
- const struct npcx_alt jtag_alts[] = {
- {
- .group = DBG_ALT_FILED(group),
- .bit = DBG_ALT_FILED(bit),
- .inverted = DBG_ALT_FILED(inv)
- }
- };
-
- dbg_reg_base->DBGCTRL = 0x04;
- dbg_reg_base->DBGFRZEN3 &= ~BIT(NPCX_DBGFRZEN3_GLBL_FRZ_DIS);
- if (DT_NODE_HAS_STATUS(DT_NODELABEL(dbg), okay))
- npcx_pinctrl_mux_configure(jtag_alts, 1, 1);
-
- return 0;
-}
-#if CONFIG_KERNEL_INIT_PRIORITY_DEFAULT >= 41
-#error "jtag_init must be called after default kernel init"
-#endif
-SYS_INIT(jtag_init, PRE_KERNEL_1, 41);
-#endif /* DT_NODE_EXISTS(DT_NODELABEL(dbg)) */