diff options
Diffstat (limited to 'src/soc/cavium/cn81xx/timer.c')
-rw-r--r-- | src/soc/cavium/cn81xx/timer.c | 226 |
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(>i->cc_imp_ctl, 0); + + /* Setup counter to operate at 1MHz */ + const size_t tickrate = 1000000; + write32(>i->cc_cntfid0, tickrate); + write32(>i->ctl_cntfrq, tickrate); + write32(>i->cc_cntrate, ((1ULL << 32) * tickrate) / sclk); + + /* Enable the counter */ + setbits_le32(>i->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)); +} |