From 8cbd569f74d8929387730e45b0d6e993b1365c02 Mon Sep 17 00:00:00 2001 From: David Hendricks Date: Fri, 1 Dec 2017 20:49:48 -0800 Subject: cavium: Add CN81xx SoC and eval board support This adds Cavium CN81xx SoC and SFF EVB files. Code is based off of Cavium's Octeon-TX SDK: https://github.com/Cavium-Open-Source-Distributions/OCTEON-TX-SDK BDK coreboot differences: bootblock: - Get rid of BDK header - Add Kconfig for link address - Move CAR setup code into assembly - Move unaligned memory access enable into assembly - Implement custom bootblock entry function - Add CLIB and CSIB blobs romstage: - Use minimal DRAM init only devicetree: - Convert FTD to static C file containing key value pairs Tested on CN81xx: - Boots to payload - Tested with GNU/Linux 4.16.3 - All hardware is usable (after applying additional commits) Implemented in future commits: - Vboot integration - MMU suuport - L2 Cache handling - ATF from external repo - Devicetree patching - Extended DRAM testing - UART init Not working: - Booting a payload - Booting upstream ATF TODO: - Configuration straps Change-Id: I47b4412d29203b45aee49bfa026c1d86ef7ce688 Signed-off-by: David Hendricks Signed-off-by: Patrick Rudolph Reviewed-on: https://review.coreboot.org/23037 Tested-by: build bot (Jenkins) Reviewed-by: David Hendricks --- src/soc/cavium/cn81xx/timer.c | 226 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 226 insertions(+) create mode 100644 src/soc/cavium/cn81xx/timer.c (limited to 'src/soc/cavium/cn81xx/timer.c') 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 +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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)); +} -- cgit v1.2.3