/* 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. */ #define DT_DRV_COMPAT ite_it8xxx2_gctrl #include #include #include #include #include #include "gpio.h" #include "system.h" #include "util.h" LOG_MODULE_REGISTER(cros_system, LOG_LEVEL_ERR); #define GCTRL_IT8XXX2_REG_BASE \ ((struct gctrl_it8xxx2_regs *)DT_INST_REG_ADDR(0)) #define WDT_IT8XXX2_REG_BASE \ ((struct wdt_it8xxx2_regs *)DT_REG_ADDR(DT_NODELABEL(twd0))) static const char *cros_system_it8xxx2_get_chip_vendor(const struct device *dev) { ARG_UNUSED(dev); return "ite"; } static uint32_t system_get_chip_id(void) { struct gctrl_it8xxx2_regs *const gctrl_base = GCTRL_IT8XXX2_REG_BASE; return (gctrl_base->GCTRL_ECHIPID1 << 16) | (gctrl_base->GCTRL_ECHIPID2 << 8) | gctrl_base->GCTRL_ECHIPID3; } static uint8_t system_get_chip_version(void) { struct gctrl_it8xxx2_regs *const gctrl_base = GCTRL_IT8XXX2_REG_BASE; /* bit[3-0], chip version */ return gctrl_base->GCTRL_ECHIPVER & 0x0F; } static const char *cros_system_it8xxx2_get_chip_name(const struct device *dev) { ARG_UNUSED(dev); static char buf[8] = {'i', 't'}; uint32_t chip_id = system_get_chip_id(); int num = 4; for (int n = 2; num >= 0; n++, num--) snprintf(buf+n, (sizeof(buf)-n), "%x", chip_id >> (num * 4) & 0xF); return buf; } static const char *cros_system_it8xxx2_get_chip_revision(const struct device *dev) { ARG_UNUSED(dev); static char buf[3]; uint8_t rev = system_get_chip_version(); snprintf(buf, sizeof(buf), "%1xx", rev+0xa); return buf; } static int cros_system_it8xxx2_get_reset_cause(const struct device *dev) { ARG_UNUSED(dev); struct gctrl_it8xxx2_regs *const gctrl_base = GCTRL_IT8XXX2_REG_BASE; /* system reset flag */ uint32_t system_flags = chip_read_reset_flags(); int chip_reset_cause = 0; uint8_t raw_reset_cause = gctrl_base->GCTRL_RSTS & IT8XXX2_GCTRL_LRS; uint8_t raw_reset_cause2 = gctrl_base->GCTRL_SPCTRL4 & (IT8XXX2_GCTRL_LRSIWR | IT8XXX2_GCTRL_LRSIPWRSWTR | IT8XXX2_GCTRL_LRSIPGWR); /* Clear reset cause. */ gctrl_base->GCTRL_RSTS |= IT8XXX2_GCTRL_LRS; gctrl_base->GCTRL_SPCTRL4 |= (IT8XXX2_GCTRL_LRSIWR | IT8XXX2_GCTRL_LRSIPWRSWTR | IT8XXX2_GCTRL_LRSIPGWR); /* Determine if watchdog reset or power on reset. */ if (raw_reset_cause & IT8XXX2_GCTRL_IWDTR) { system_flags |= EC_RESET_FLAG_WATCHDOG; chip_reset_cause = WATCHDOG_RST; } else if (raw_reset_cause < 2) { system_flags |= EC_RESET_FLAG_POWER_ON; chip_reset_cause = POWERUP; } /* Determine reset-pin reset. */ if (raw_reset_cause2 & IT8XXX2_GCTRL_LRSIWR) { system_flags |= EC_RESET_FLAG_RESET_PIN; chip_reset_cause = VCC1_RST_PIN; } /* watchdog module triggers these reset */ if (system_flags & (EC_RESET_FLAG_HARD | EC_RESET_FLAG_SOFT)) system_flags &= ~EC_RESET_FLAG_WATCHDOG; /* Set the system reset flags. */ system_set_reset_flags(system_flags); return chip_reset_cause; } static int cros_system_it8xxx2_init(const struct device *dev) { struct gctrl_it8xxx2_regs *const gctrl_base = GCTRL_IT8XXX2_REG_BASE; /* System triggers a soft reset by default (command: reboot). */ gctrl_base->GCTRL_ETWDUARTCR &= ~IT8XXX2_GCTRL_ETWD_HW_RST_EN; return 0; } static int cros_system_it8xxx2_soc_reset(const struct device *dev) { struct gctrl_it8xxx2_regs *const gctrl_base = GCTRL_IT8XXX2_REG_BASE; struct wdt_it8xxx2_regs *const wdt_base = WDT_IT8XXX2_REG_BASE; uint32_t chip_reset_flags = chip_read_reset_flags(); /* Disable interrupts to avoid task swaps during reboot. */ interrupt_disable_all(); if (chip_reset_flags & (EC_RESET_FLAG_HARD | EC_RESET_FLAG_HIBERNATE)) gctrl_base->GCTRL_ETWDUARTCR |= IT8XXX2_GCTRL_ETWD_HW_RST_EN; /* * Writing invalid key to watchdog module triggers a soft or hardware * reset. It depends on the setting of bit0 at ETWDUARTCR register. */ wdt_base->ETWCFG |= IT8XXX2_WDT_EWDKEYEN; wdt_base->EWDKEYR = 0x00; /* Spin and wait for reboot */ while (1) ; /* Should never return */ return 0; } static int cros_system_it8xxx2_hibernate(const struct device *dev, uint32_t seconds, uint32_t microseconds) { struct wdt_it8xxx2_regs *const wdt_base = WDT_IT8XXX2_REG_BASE; /* Disable all interrupts. */ interrupt_disable_all(); /* Save and disable interrupts */ if (IS_ENABLED(CONFIG_ITE_IT8XXX2_INTC)) ite_intc_save_and_disable_interrupts(); /* bit5: watchdog is disabled. */ wdt_base->ETWCTRL |= IT8XXX2_WDT_EWDSCEN; /* * Setup GPIOs for hibernate. 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) { /* * Set reset flag in case board_hibernate_late() doesn't * return. */ chip_save_reset_flags(EC_RESET_FLAG_HIBERNATE); board_hibernate_late(); } if (seconds || microseconds) { /* * Convert milliseconds(or at least 1 ms) to 32 Hz * free run timer count for hibernate. */ uint32_t c = (seconds * 1000 + microseconds / 1000 + 1) * 32 / 1000; /* Enable a 32-bit timer and clock source is 32 Hz */ /* Disable external timer x */ IT8XXX2_EXT_CTRLX(FREE_RUN_TIMER) &= ~IT8XXX2_EXT_ETXEN; irq_disable(FREE_RUN_TIMER_IRQ); IT8XXX2_EXT_PSRX(FREE_RUN_TIMER) = EXT_PSR_32; IT8XXX2_EXT_CNTX(FREE_RUN_TIMER) = c & FREE_RUN_TIMER_MAX_CNT; /* Enable and re-start external timer x */ IT8XXX2_EXT_CTRLX(FREE_RUN_TIMER) |= (IT8XXX2_EXT_ETXEN | IT8XXX2_EXT_ETXRST); irq_enable(FREE_RUN_TIMER_IRQ); } 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++) /* Re-enable interrupt for wake-up inputs */ gpio_enable_interrupt(wakeup_pin_list[i]); /* EC sleep mode */ chip_pll_ctrl(CHIP_PLL_SLEEP); /* Chip sleep and wait timer wake it up */ __asm__ volatile ("wfi"); /* Reset EC when wake up from sleep mode (system hibernate) */ system_reset(SYSTEM_RESET_HIBERNATE); return 0; } static const struct cros_system_driver_api cros_system_driver_it8xxx2_api = { .get_reset_cause = cros_system_it8xxx2_get_reset_cause, .soc_reset = cros_system_it8xxx2_soc_reset, .hibernate = cros_system_it8xxx2_hibernate, .chip_vendor = cros_system_it8xxx2_get_chip_vendor, .chip_name = cros_system_it8xxx2_get_chip_name, .chip_revision = cros_system_it8xxx2_get_chip_revision, }; #if CONFIG_CROS_SYSTEM_IT8XXX2_INIT_PRIORITY >= \ CONFIG_PLATFORM_EC_SYSTEM_PRE_INIT_PRIORITY #error "CROS_SYSTEM must initialize before the SYSTEM_PRE initialization" #endif DEVICE_DEFINE(cros_system_it8xxx2_0, "CROS_SYSTEM", cros_system_it8xxx2_init, NULL, NULL, NULL, PRE_KERNEL_1, CONFIG_CROS_SYSTEM_IT8XXX2_INIT_PRIORITY, &cros_system_driver_it8xxx2_api);