aboutsummaryrefslogtreecommitdiff
path: root/src/soc/cavium/cn81xx/timer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/soc/cavium/cn81xx/timer.c')
-rw-r--r--src/soc/cavium/cn81xx/timer.c226
1 files changed, 226 insertions, 0 deletions
diff --git a/src/soc/cavium/cn81xx/timer.c b/src/soc/cavium/cn81xx/timer.c
new file mode 100644
index 0000000000..0321a49ad9
--- /dev/null
+++ b/src/soc/cavium/cn81xx/timer.c
@@ -0,0 +1,226 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2018 Facebook, Inc.
+ * Copyright 2003-2017 Cavium Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Derived from Cavium's BSD-3 Clause OCTEONTX-SDK-6.2.0.
+ */
+
+#include <arch/io.h>
+#include <console/console.h>
+#include <inttypes.h>
+#include <soc/clock.h>
+#include <soc/timer.h>
+#include <stdint.h>
+#include <timer.h>
+#include <soc/addressmap.h>
+#include <assert.h>
+
+/* Global System Timers Unit (GTI) registers */
+struct cn81xx_timer {
+ u32 cc_cntcr;
+ u32 cc_cntsr;
+ u64 cc_cntcv;
+ u8 rsvd[0x10];
+ u32 cc_cntfid0;
+ u32 cc_cntfid1;
+ u8 rsvd2[0x98];
+ u32 cc_cntrate;
+ u32 cc_cntracc;
+ u64 cc_cntadd;
+ u64 cc_cntmb;
+ u64 cc_cntmbts;
+ u64 cc_cntmb_int;
+ u64 cc_cntmb_int_set;
+ u64 cc_cntmb_int_ena_clr;
+ u64 cc_cntmb_int_ena_set;
+ u64 cc_imp_ctl;
+ u8 skip[0x1fef8];
+ u32 ctl_cntfrq;
+ u32 ctl_cntnsar;
+ u32 ctl_cnttidr;
+ u8 rsvd3[0x34];
+ u32 ctl_cntacr0;
+ u8 skip2[0x1ffb8];
+ u64 cwd_wdog[48]; /* Offset 0x40000 */
+ u8 skip3[0xfe80];
+ u64 cwd_poke[48]; /* Offset 0x50000 */
+};
+
+check_member(cn81xx_timer, cc_imp_ctl, 0x100);
+check_member(cn81xx_timer, ctl_cntacr0, 0x20040);
+check_member(cn81xx_timer, cwd_wdog[0], 0x40000);
+check_member(cn81xx_timer, cwd_poke[0], 0x50000);
+
+
+#define GTI_CC_CNTCR_EN (1 << 0)
+#define GTI_CC_CNTCR_HDBG (1 << 1)
+#define GTI_CC_CNTCR_FCREQ (1 << 8)
+
+#define GTI_CC_CNTSR_DBGH (1 << 1)
+#define GTI_CC_CNTSR_FCACK (1 << 8)
+
+#define GTI_CWD_WDOG_MODE_SHIFT 0
+#define GTI_CWD_WDOG_MODE_MASK 0x3
+#define GTI_CWD_WDOG_STATE_SHIFT 2
+#define GTI_CWD_WDOG_STATE_MASK 0x3
+#define GTI_CWD_WDOG_LEN_SHIFT 4
+#define GTI_CWD_WDOG_LEN_MASK 0xffff
+#define GTI_CWD_WDOG_CNT_SHIFT 20
+#define GTI_CWD_WDOG_CNT_MASK 0xffffff
+#define GTI_CWD_WDOC_DSTOP (1 << 44)
+#define GTI_CWD_WDOC_GSTOP (1 << 45)
+
+static uint64_t timer_raw_value(void)
+{
+ struct cn81xx_timer *timer = (void *)GTI_PF_BAR0;
+
+ return read64(&timer->cc_cntcv);
+}
+
+/**
+ * Get GTI counter value.
+ * @param mt Structure to fill
+ */
+void timer_monotonic_get(struct mono_time *mt)
+{
+ mono_time_set_usecs(mt, timer_raw_value());
+}
+
+/**
+ * Init Global System Timers Unit (GTI).
+ * Configure timer to run at 1MHz tick-rate.
+ */
+void init_timer(void)
+{
+ struct cn81xx_timer *gti = (struct cn81xx_timer *)GTI_PF_BAR0;
+
+ /* Check if the counter was already setup */
+ if (gti->cc_cntcr & GTI_CC_CNTCR_EN)
+ return;
+
+ u64 sclk = thunderx_get_io_clock();
+
+ /* Use coprocessor clock source */
+ write32(&gti->cc_imp_ctl, 0);
+
+ /* Setup counter to operate at 1MHz */
+ const size_t tickrate = 1000000;
+ write32(&gti->cc_cntfid0, tickrate);
+ write32(&gti->ctl_cntfrq, tickrate);
+ write32(&gti->cc_cntrate, ((1ULL << 32) * tickrate) / sclk);
+
+ /* Enable the counter */
+ setbits_le32(&gti->cc_cntcr, GTI_CC_CNTCR_EN);
+
+ //u32 u = (CNTPS_CTL_EL1_IMASK | CNTPS_CTL_EL1_EN);
+ //BDK_MSR(CNTPS_CTL_EL1, u);
+}
+
+/**
+ * Setup the watchdog to expire in timeout_ms milliseconds. When the watchdog
+ * expires, the chip three things happen:
+ * 1) Expire 1: interrupt that is ignored by the BDK
+ * 2) Expire 2: DEL3T interrupt, which is disabled and ignored
+ * 3) Expire 3: Soft reset of the chip
+ *
+ * Since we want a soft reset, we actually program the watchdog to expire at
+ * the timeout / 3.
+ *
+ * @param index Index of watchdog to configure
+ * @param timeout_ms Timeout in milliseconds.
+ */
+void watchdog_set(const size_t index, unsigned int timeout_ms)
+{
+ uint64_t sclk = thunderx_get_io_clock();
+ uint64_t timeout_sclk = sclk * timeout_ms / 1000;
+ struct cn81xx_timer *timer = (struct cn81xx_timer *)GTI_PF_BAR0;
+
+ assert(index < ARRAY_SIZE(timer->cwd_wdog));
+ if (index >= ARRAY_SIZE(timer->cwd_wdog))
+ return;
+
+ /*
+ * Per comment above, we want the watchdog to expire at 3x the rate
+ * specified
+ */
+ timeout_sclk /= 3;
+ /* Watchdog counts in 1024 cycle steps */
+ uint64_t timeout_wdog = timeout_sclk >> 10;
+ /* We can only specify the upper 16 bits of a 24 bit value. Round up */
+ timeout_wdog = (timeout_wdog + 0xff) >> 8;
+ /* If the timeout overflows the hardware limit, set max */
+ if (timeout_wdog >= 0x10000)
+ timeout_wdog = 0xffff;
+
+ printk(BIOS_DEBUG, "Watchdog: Set to expire %llu SCLK cycles\n",
+ timeout_wdog << 18);
+ clrsetbits_le64(&timer->cwd_wdog[index],
+ (GTI_CWD_WDOG_LEN_MASK << GTI_CWD_WDOG_LEN_SHIFT) |
+ (GTI_CWD_WDOG_MODE_MASK << GTI_CWD_WDOG_MODE_SHIFT),
+ (timeout_wdog << GTI_CWD_WDOG_LEN_SHIFT) |
+ (3 << GTI_CWD_WDOG_MODE_SHIFT));
+}
+
+/**
+ * Signal the watchdog that we are still running.
+ *
+ * @param index Index of watchdog to configure.
+ */
+void watchdog_poke(const size_t index)
+{
+ struct cn81xx_timer *timer = (struct cn81xx_timer *)GTI_PF_BAR0;
+
+ assert(index < ARRAY_SIZE(timer->cwd_poke));
+ if (index >= ARRAY_SIZE(timer->cwd_poke))
+ return;
+
+ write64(&timer->cwd_poke[0], 0);
+}
+
+/**
+ * Disable the hardware watchdog
+ *
+ * @param index Index of watchdog to configure.
+ */
+void watchdog_disable(const size_t index)
+{
+ struct cn81xx_timer *timer = (struct cn81xx_timer *)GTI_PF_BAR0;
+
+ assert(index < ARRAY_SIZE(timer->cwd_wdog));
+ if (index >= ARRAY_SIZE(timer->cwd_wdog))
+ return;
+
+ write64(&timer->cwd_wdog[index], 0);
+ printk(BIOS_DEBUG, "Watchdog: Disabled\n");
+}
+
+/**
+ * Return true if the watchdog is configured and running
+ *
+ * @param index Index of watchdog to configure.
+ *
+ * @return Non-zero if watchdog is running.
+ */
+int watchdog_is_running(const size_t index)
+{
+ struct cn81xx_timer *timer = (struct cn81xx_timer *)GTI_PF_BAR0;
+
+ assert(index < ARRAY_SIZE(timer->cwd_wdog));
+ if (index >= ARRAY_SIZE(timer->cwd_wdog))
+ return 0;
+
+ uint64_t val = read64(&timer->cwd_wdog[index]);
+
+ return !!(val & (GTI_CWD_WDOG_MODE_MASK << GTI_CWD_WDOG_MODE_SHIFT));
+}