summaryrefslogtreecommitdiff
path: root/chip/mchp/system.c
diff options
context:
space:
mode:
authorScott Worley <scott.worley@microchip.corp-partner.google.com>2017-12-20 17:08:09 -0500
committerchrome-bot <chrome-bot@chromium.org>2017-12-28 12:35:07 -0800
commit4e9588ddcffb9315b0a74ac62121efb76b7b2202 (patch)
treed1ce8cea735b68c5e43f7631af2e90026006df58 /chip/mchp/system.c
parentc334f648bd644f5e72e841458fdac6796efa1ceb (diff)
downloadchrome-ec-4e9588ddcffb9315b0a74ac62121efb76b7b2202.tar.gz
ec_chip_mchp: Add MCHP chip folder
BRANCH=none BUG= TEST=Review only. Committing small pieces until all code passes review. Change-Id: I9d16f95314a7c97b11c4fe61602c6db2621e6024 Signed-off-by: Scott Worley <scott.worley@microchip.corp-partner.google.com>
Diffstat (limited to 'chip/mchp/system.c')
-rw-r--r--chip/mchp/system.c490
1 files changed, 490 insertions, 0 deletions
diff --git a/chip/mchp/system.c b/chip/mchp/system.c
new file mode 100644
index 0000000000..24aafdbf1e
--- /dev/null
+++ b/chip/mchp/system.c
@@ -0,0 +1,490 @@
+/* Copyright 2017 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.
+ */
+
+/* System module for Chrome EC : MCHP hardware specific implementation */
+
+#include "clock.h"
+#include "common.h"
+#include "console.h"
+#include "cpu.h"
+#include "gpio.h"
+#include "host_command.h"
+#include "registers.h"
+#include "shared_mem.h"
+#include "system.h"
+#include "hooks.h"
+#include "task.h"
+#include "timer.h"
+#include "util.h"
+#include "spi.h"
+#include "lpc_chip.h"
+#include "tfdp_chip.h"
+
+
+#define CPUTS(outstr) cputs(CC_LPC, outstr)
+#define CPRINTS(format, args...) cprints(CC_LPC, format, ## args)
+
+
+/* Indices for hibernate data registers (RAM backed by VBAT) */
+enum hibdata_index {
+ HIBDATA_INDEX_SCRATCHPAD = 0, /* General-purpose scratchpad */
+ HIBDATA_INDEX_SAVED_RESET_FLAGS, /* Saved reset flags */
+ HIBDATA_INDEX_PD0, /* USB-PD0 saved port state */
+ HIBDATA_INDEX_PD1, /* USB-PD1 saved port state */
+};
+
+static void check_reset_cause(void)
+{
+ uint32_t status = MCHP_VBAT_STS;
+ uint32_t flags = 0;
+ uint32_t rst_sts = MCHP_PCR_PWR_RST_STS &
+ (MCHP_PWR_RST_STS_VTR |
+ MCHP_PWR_RST_STS_VBAT);
+
+ trace12(0, MEC, 0,
+ "check_reset_cause: VBAT_PFR = 0x%08X PCR PWRST = 0x%08X",
+ status, rst_sts);
+
+ /* Clear the reset causes now that we've read them */
+ MCHP_VBAT_STS |= status;
+ MCHP_PCR_PWR_RST_STS |= rst_sts;
+
+
+ trace0(0, MEC, 0, "check_reset_cause: after clear");
+ trace11(0, MEC, 0, " VBAT_PFR = 0x%08X", MCHP_VBAT_STS);
+ trace11(0, MEC, 0, " PCR PWRST = 0x%08X", MCHP_PCR_PWR_RST_STS);
+
+ /*
+ * BIT[6] determine VTR reset
+ */
+ if (rst_sts & MCHP_PWR_RST_STS_VTR)
+ flags |= RESET_FLAG_RESET_PIN;
+
+
+ flags |= MCHP_VBAT_RAM(HIBDATA_INDEX_SAVED_RESET_FLAGS);
+ MCHP_VBAT_RAM(HIBDATA_INDEX_SAVED_RESET_FLAGS) = 0;
+
+ if ((status & MCHP_VBAT_STS_WDT) && !(flags & (RESET_FLAG_SOFT |
+ RESET_FLAG_HARD |
+ RESET_FLAG_HIBERNATE)))
+ flags |= RESET_FLAG_WATCHDOG;
+
+ trace11(0, MEC, 0, "check_reset_cause: EC reset flags = 0x%08x", flags);
+
+ system_set_reset_flags(flags);
+}
+
+int system_is_reboot_warm(void)
+{
+ uint32_t reset_flags;
+ /*
+ * Check reset cause here,
+ * gpio_pre_init is executed faster than system_pre_init
+ */
+ check_reset_cause();
+ reset_flags = system_get_reset_flags();
+
+ if ((reset_flags & RESET_FLAG_RESET_PIN) ||
+ (reset_flags & RESET_FLAG_POWER_ON) ||
+ (reset_flags & RESET_FLAG_WATCHDOG) ||
+ (reset_flags & RESET_FLAG_HARD) ||
+ (reset_flags & RESET_FLAG_SOFT))
+ return 0;
+ else
+ return 1;
+}
+
+/*
+ * Sleep unused blocks to reduce power.
+ * Drivers/modules will unsleep their blocks.
+ * Keep sleep enables cleared for required blocks:
+ * ECIA, PMC, CPU, ECS and optionally JTAG.
+ * SLEEP_ALL feature will set these upon sleep entry.
+ * Based on CONFIG_CHIPSET_DEBUG enable or disable JTAG.
+ * JTAG mode (4-pin or 2-pin SWD + 1-pin SWV) was set
+ * by Boot-ROM. We can override Boot-ROM JTAG mode
+ * using
+ * CONFIG_MCHP_JTAG_MODE
+ */
+static void chip_periph_sleep_control(void)
+{
+ uint32_t d;
+
+ d = MCHP_PCR_SLP_EN0_SLEEP;
+#ifdef CONFIG_CHIPSET_DEBUG
+ d &= ~(MCHP_PCR_SLP_EN0_JTAG);
+#ifdef CONFIG_MCHP_JTAG_MODE
+ MCHP_EC_JTAG_EN = CONFIG_MCHP_JTAG_MODE;
+#else
+ MCHP_EC_JTAG_EN |= 0x01;
+#endif
+#else
+ MCHP_EC_JTAG_EN &= ~0x01;
+#endif
+ MCHP_PCR_SLP_EN0 = d;
+ MCHP_PCR_SLP_EN1 = MCHP_PCR_SLP_EN1_UNUSED_BLOCKS;
+ MCHP_PCR_SLP_EN2 = MCHP_PCR_SLP_EN2_SLEEP;
+ MCHP_PCR_SLP_EN3 = MCHP_PCR_SLP_EN3_SLEEP;
+ MCHP_PCR_SLP_EN4 = MCHP_PCR_SLP_EN4_SLEEP;
+}
+
+#ifdef CONFIG_CHIP_PRE_INIT
+void chip_pre_init(void)
+{
+ chip_periph_sleep_control();
+}
+#endif
+
+void system_pre_init(void)
+{
+#ifdef CONFIG_MCHP_TFDP
+ uint8_t imgtype;
+#endif
+
+ /*
+ * Make sure AHB Error capture is enabled.
+ * Signals bus fault to Cortex-M4 core if an address presented
+ * to AHB is not claimed by any HW block.
+ */
+ MCHP_EC_AHB_ERR = 0; /* write any value to clear */
+ MCHP_EC_AHB_ERR_EN = 0; /* enable capture of address on error */
+
+#ifdef CONFIG_ESPI
+ MCHP_EC_GPIO_BANK_PWR |= MCHP_EC_GPIO_BANK_PWR_VTR3_18;
+#endif
+
+#ifndef CONFIG_CHIP_PRE_INIT
+ chip_periph_sleep_control();
+#endif
+
+ /* Enable direct NVIC */
+ MCHP_EC_INT_CTRL |= 1;
+
+ /* Disable ARM TRACE debug port */
+ MCHP_EC_TRACE_EN &= ~1;
+
+ /*
+ * Enable aggregated only interrupt GIRQ's
+ * Make sure direct mode interrupt sources aggregated outputs
+ * are not enabled.
+ * Aggregated only GIRQ's 8,9,10,11,12,22,24,25,26
+ * Direct GIRQ's = 13,14,15,16,17,18,19,21,23
+ * These bits only need to be touched again on RESET_SYS.
+ * NOTE: GIRQ22 wake for AHB peripherals not processor.
+ */
+ MCHP_INT_BLK_DIS = 0xfffffffful;
+ MCHP_INT_BLK_EN = (0x1Ful << 8) + (0x07ul << 24);
+
+ spi_enable(CONFIG_SPI_FLASH_PORT, 1);
+
+#ifdef CONFIG_MCHP_TFDP
+ /*
+ * MCHP Enable TFDP for fast debug messages
+ * If not defined then traceN() and TRACEN() macros are empty
+ */
+ tfdp_power(1);
+ tfdp_enable(1, 1);
+ imgtype = MCHP_VBAT_RAM(MCHP_IMAGETYPE_IDX);
+ CPRINTS("system_pre_init. Image type = 0x%02x", imgtype);
+ trace1(0, MEC, 0, "System pre-init. Image type = 0x%02x", imgtype);
+
+ /* Debug: dump some signals */
+ imgtype = gpio_get_level(GPIO_PCH_RSMRST_L);
+ trace1(0, MEC, 0, "PCH_RSMRST_L = %d", imgtype);
+
+ imgtype = gpio_get_level(GPIO_RSMRST_L_PGOOD);
+ trace1(0, MEC, 0, "RSMRST_L_PGOOD = %d", imgtype);
+ imgtype = gpio_get_level(GPIO_POWER_BUTTON_L);
+ trace1(0, MEC, 0, "POWER_BUTTON_L = %d", imgtype);
+ imgtype = gpio_get_level(GPIO_PMIC_DPWROK);
+ trace1(0, MEC, 0, "PMIC_DPWROK = %d", imgtype);
+ imgtype = gpio_get_level(GPIO_ALL_SYS_PWRGD);
+ trace1(0, MEC, 0, "ALL_SYS_PWRGD = %d", imgtype);
+ imgtype = gpio_get_level(GPIO_AC_PRESENT);
+ trace1(0, MEC, 0, "AC_PRESENT = %d", imgtype);
+ imgtype = gpio_get_level(GPIO_PCH_SLP_SUS_L);
+ trace1(0, MEC, 0, "PCH_SLP_SUS_L = %d", imgtype);
+ imgtype = gpio_get_level(GPIO_PMIC_INT_L);
+ trace1(0, MEC, 0, "PCH_PMIC_INT_L = %d", imgtype);
+#endif
+}
+
+void chip_save_reset_flags(int flags)
+{
+ MCHP_VBAT_RAM(HIBDATA_INDEX_SAVED_RESET_FLAGS) = flags;
+}
+
+void __attribute__((noreturn)) _system_reset(int flags,
+ int wake_from_hibernate)
+{
+ uint32_t save_flags = 0;
+
+ /* Disable interrupts to avoid task swaps during reboot */
+ interrupt_disable();
+
+ trace12(0, MEC, 0,
+ "_system_reset: flags=0x%08X wake_from_hibernate=%d",
+ flags, wake_from_hibernate);
+
+ /* Save current reset reasons if necessary */
+ if (flags & SYSTEM_RESET_PRESERVE_FLAGS)
+ save_flags = system_get_reset_flags() | RESET_FLAG_PRESERVED;
+
+ if (flags & SYSTEM_RESET_LEAVE_AP_OFF)
+ save_flags |= RESET_FLAG_AP_OFF;
+
+ if (wake_from_hibernate)
+ save_flags |= RESET_FLAG_HIBERNATE;
+ else if (flags & SYSTEM_RESET_HARD)
+ save_flags |= RESET_FLAG_HARD;
+ else
+ save_flags |= RESET_FLAG_SOFT;
+
+ chip_save_reset_flags(save_flags);
+
+ trace11(0, MEC, 0, "_system_reset: save_flags=0x%08X", save_flags);
+
+ /*
+ * Trigger chip reset
+ */
+#ifndef CONFIG_CHIPSET_DEBUG
+ MCHP_PCR_SYS_RST |= MCHP_PCR_SYS_SOFT_RESET;
+#endif
+ /* Spin and wait for reboot; should never return */
+ while (1)
+ ;
+}
+
+void system_reset(int flags)
+{
+ _system_reset(flags, 0);
+}
+
+const char *system_get_chip_vendor(void)
+{
+ return "mchp";
+}
+
+/*
+ * MEC1701H Chip ID = 0x2D
+ * Rev = 0x82
+ */
+const char *system_get_chip_name(void)
+{
+ switch (MCHP_CHIP_DEV_ID) {
+ case 0x2D:
+ return "mec1701";
+ default:
+ return "unknown";
+ }
+}
+
+static char to_hex(int x)
+{
+ if (x >= 0 && x <= 9)
+ return '0' + x;
+ return 'a' + x - 10;
+}
+
+const char *system_get_chip_revision(void)
+{
+ static char buf[3];
+ uint8_t rev = MCHP_CHIP_DEV_REV;
+
+ buf[0] = to_hex(rev / 16);
+ buf[1] = to_hex(rev & 0xf);
+ buf[2] = '\0';
+ return buf;
+}
+
+static int bbram_idx_lookup(enum system_bbram_idx idx)
+{
+ switch (idx) {
+#ifdef CONFIG_USB_PD_DUAL_ROLE
+ case SYSTEM_BBRAM_IDX_PD0:
+ return HIBDATA_INDEX_PD0;
+ case SYSTEM_BBRAM_IDX_PD1:
+ return HIBDATA_INDEX_PD1;
+#endif
+ default:
+ return 1;
+ }
+}
+
+int system_get_bbram(enum system_bbram_idx idx, uint8_t *value)
+{
+ int hibdata = bbram_idx_lookup(idx);
+
+ if (hibdata < 0)
+ return EC_ERROR_UNIMPLEMENTED;
+
+ *value = MCHP_VBAT_RAM(hibdata);
+ return EC_SUCCESS;
+}
+
+int system_set_bbram(enum system_bbram_idx idx, uint8_t value)
+{
+ int hibdata = bbram_idx_lookup(idx);
+
+ if (hibdata < 0)
+ return EC_ERROR_UNIMPLEMENTED;
+
+ MCHP_VBAT_RAM(hibdata) = value;
+ return EC_SUCCESS;
+}
+
+int system_set_scratchpad(uint32_t value)
+{
+ MCHP_VBAT_RAM(HIBDATA_INDEX_SCRATCHPAD) = value;
+ return EC_SUCCESS;
+}
+
+uint32_t system_get_scratchpad(void)
+{
+ return MCHP_VBAT_RAM(HIBDATA_INDEX_SCRATCHPAD);
+}
+
+void system_hibernate(uint32_t seconds, uint32_t microseconds)
+{
+ int i;
+
+#ifdef CONFIG_HOSTCMD_PD
+ /* Inform the PD MCU that we are going to hibernate. */
+ host_command_pd_request_hibernate();
+ /* Wait to ensure exchange with PD before hibernating. */
+ msleep(100);
+#endif
+
+ cflush();
+
+ if (board_hibernate)
+ board_hibernate();
+
+ /* Disable interrupts */
+ interrupt_disable();
+ for (i = 0; i <= 92; ++i) {
+ task_disable_irq(i);
+ task_clear_pending_irq(i);
+ }
+
+ for (i = 8; i <= 26; ++i)
+ MCHP_INT_DISABLE(i) = 0xffffffff;
+
+ MCHP_INT_BLK_DIS |= 0xffff00;
+
+ /* Disable UART */
+ MCHP_UART_ACT(0) &= ~0x1;
+ MCHP_LPC_ACT &= ~0x1;
+
+ /* Disable JTAG */
+ MCHP_EC_JTAG_EN &= ~1;
+
+ /* Disable 32KHz clock */
+ MCHP_VBAT_CE &= ~0x2;
+
+ /* Stop watchdog */
+ MCHP_WDG_CTL &= ~1;
+
+ /* Stop timers */
+ MCHP_TMR32_CTL(0) &= ~1;
+ MCHP_TMR32_CTL(1) &= ~1;
+ MCHP_TMR16_CTL(0) &= ~1;
+
+ /* Power down ADC */
+ /*
+ * If ADC is in middle of acquisition it will continue until finished
+ */
+ MCHP_ADC_CTRL &= ~1;
+
+ /* Disable blocks */
+ MCHP_PCR_SLOW_CLK_CTL &= ~(MCHP_PCR_SLOW_CLK_CTL_MASK);
+
+ /*
+ * Set sleep state
+ * arm sleep state to trigger on next WFI
+ */
+ CPU_SCB_SYSCTRL |= 0x4;
+ MCHP_PCR_SYS_SLP_CTL = MCHP_PCR_SYS_SLP_HEAVY;
+ MCHP_PCR_SYS_SLP_CTL = MCHP_PCR_SYS_SLP_ALL;
+
+ /* Setup GPIOs for hibernate */
+ if (board_hibernate_late)
+ board_hibernate_late();
+
+ if (hibernate_wake_pins_used > 0) {
+ for (i = 0; i < hibernate_wake_pins_used; ++i) {
+ const enum gpio_signal pin = hibernate_wake_pins[i];
+
+ gpio_reset(pin);
+ gpio_enable_interrupt(pin);
+ }
+
+ interrupt_enable();
+ task_enable_irq(MCHP_IRQ_GIRQ8);
+ task_enable_irq(MCHP_IRQ_GIRQ9);
+ task_enable_irq(MCHP_IRQ_GIRQ10);
+ task_enable_irq(MCHP_IRQ_GIRQ11);
+ task_enable_irq(MCHP_IRQ_GIRQ12);
+ }
+
+ if (seconds || microseconds) {
+ /*
+ * Not needed when using direct mode interrupts.
+ * MCHP_INT_BLK_EN |= 1 << MCHP_HTIMER_GIRQ;
+ */
+ MCHP_INT_ENABLE(MCHP_HTIMER_GIRQ) =
+ MCHP_HTIMER_GIRQ_BIT(0);
+ interrupt_enable();
+ task_enable_irq(MCHP_IRQ_HTIMER0);
+ if (seconds > 2) {
+ ASSERT(seconds <= 0xffff / 8);
+ MCHP_HTIMER_CONTROL(0) = 1;
+ MCHP_HTIMER_PRELOAD(0) =
+ (seconds * 8 + microseconds / 125000);
+ } else {
+ MCHP_HTIMER_CONTROL(0) = 0;
+ MCHP_HTIMER_PRELOAD(0) =
+ (seconds * 1000000 + microseconds) * 2 / 71;
+ }
+ }
+
+ asm("wfi");
+
+ /* Use 48MHz clock to speed through wake-up */
+ MCHP_PCR_PROC_CLK_CTL = 1;
+
+ /* Reboot */
+ _system_reset(0, 1);
+
+ /* We should never get here. */
+ while (1)
+ ;
+}
+
+void htimer_interrupt(void)
+{
+ /* Time to wake up */
+}
+DECLARE_IRQ(MCHP_IRQ_HTIMER0, htimer_interrupt, 1);
+
+enum system_image_copy_t system_get_shrspi_image_copy(void)
+{
+ return MCHP_VBAT_RAM(MCHP_IMAGETYPE_IDX);
+}
+
+uint32_t system_get_lfw_address(void)
+{
+ uint32_t * const lfw_vector =
+ (uint32_t * const)CONFIG_PROGRAM_MEMORY_BASE;
+
+ return *(lfw_vector + 1);
+}
+
+void system_set_image_copy(enum system_image_copy_t copy)
+{
+ MCHP_VBAT_RAM(MCHP_IMAGETYPE_IDX) = (copy == SYSTEM_IMAGE_RW) ?
+ SYSTEM_IMAGE_RW : SYSTEM_IMAGE_RO;
+}
+