Angel Pons | 5f249e6 | 2020-04-04 18:51:01 +0200 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
Angel Pons | 5f249e6 | 2020-04-04 18:51:01 +0200 | [diff] [blame] | 2 | |
David Hendricks | 8cbd569 | 2017-12-01 20:49:48 -0800 | [diff] [blame] | 3 | /* |
David Hendricks | 8cbd569 | 2017-12-01 20:49:48 -0800 | [diff] [blame] | 4 | * Derived from Cavium's BSD-3 Clause OCTEONTX-SDK-6.2.0. |
| 5 | */ |
| 6 | |
Elyes HAOUAS | bf0970e | 2019-03-21 11:10:03 +0100 | [diff] [blame] | 7 | #include <delay.h> |
Kyösti Mälkki | 13f6650 | 2019-03-03 08:01:05 +0200 | [diff] [blame] | 8 | #include <device/mmio.h> |
Julius Werner | 73be9dd | 2018-08-07 14:02:55 -0700 | [diff] [blame] | 9 | #include <arch/lib_helpers.h> |
David Hendricks | 8cbd569 | 2017-12-01 20:49:48 -0800 | [diff] [blame] | 10 | #include <console/console.h> |
David Hendricks | 8cbd569 | 2017-12-01 20:49:48 -0800 | [diff] [blame] | 11 | #include <soc/clock.h> |
| 12 | #include <soc/timer.h> |
| 13 | #include <stdint.h> |
| 14 | #include <timer.h> |
| 15 | #include <soc/addressmap.h> |
| 16 | #include <assert.h> |
| 17 | |
| 18 | /* Global System Timers Unit (GTI) registers */ |
| 19 | struct cn81xx_timer { |
| 20 | u32 cc_cntcr; |
| 21 | u32 cc_cntsr; |
| 22 | u64 cc_cntcv; |
| 23 | u8 rsvd[0x10]; |
| 24 | u32 cc_cntfid0; |
| 25 | u32 cc_cntfid1; |
| 26 | u8 rsvd2[0x98]; |
| 27 | u32 cc_cntrate; |
| 28 | u32 cc_cntracc; |
| 29 | u64 cc_cntadd; |
| 30 | u64 cc_cntmb; |
| 31 | u64 cc_cntmbts; |
| 32 | u64 cc_cntmb_int; |
| 33 | u64 cc_cntmb_int_set; |
| 34 | u64 cc_cntmb_int_ena_clr; |
| 35 | u64 cc_cntmb_int_ena_set; |
| 36 | u64 cc_imp_ctl; |
| 37 | u8 skip[0x1fef8]; |
| 38 | u32 ctl_cntfrq; |
| 39 | u32 ctl_cntnsar; |
| 40 | u32 ctl_cnttidr; |
| 41 | u8 rsvd3[0x34]; |
| 42 | u32 ctl_cntacr0; |
| 43 | u8 skip2[0x1ffb8]; |
| 44 | u64 cwd_wdog[48]; /* Offset 0x40000 */ |
| 45 | u8 skip3[0xfe80]; |
| 46 | u64 cwd_poke[48]; /* Offset 0x50000 */ |
| 47 | }; |
| 48 | |
| 49 | check_member(cn81xx_timer, cc_imp_ctl, 0x100); |
| 50 | check_member(cn81xx_timer, ctl_cntacr0, 0x20040); |
| 51 | check_member(cn81xx_timer, cwd_wdog[0], 0x40000); |
| 52 | check_member(cn81xx_timer, cwd_poke[0], 0x50000); |
| 53 | |
David Hendricks | 8cbd569 | 2017-12-01 20:49:48 -0800 | [diff] [blame] | 54 | #define GTI_CC_CNTCR_EN (1 << 0) |
| 55 | #define GTI_CC_CNTCR_HDBG (1 << 1) |
| 56 | #define GTI_CC_CNTCR_FCREQ (1 << 8) |
| 57 | |
| 58 | #define GTI_CC_CNTSR_DBGH (1 << 1) |
| 59 | #define GTI_CC_CNTSR_FCACK (1 << 8) |
| 60 | |
| 61 | #define GTI_CWD_WDOG_MODE_SHIFT 0 |
| 62 | #define GTI_CWD_WDOG_MODE_MASK 0x3 |
| 63 | #define GTI_CWD_WDOG_STATE_SHIFT 2 |
| 64 | #define GTI_CWD_WDOG_STATE_MASK 0x3 |
| 65 | #define GTI_CWD_WDOG_LEN_SHIFT 4 |
| 66 | #define GTI_CWD_WDOG_LEN_MASK 0xffff |
| 67 | #define GTI_CWD_WDOG_CNT_SHIFT 20 |
| 68 | #define GTI_CWD_WDOG_CNT_MASK 0xffffff |
| 69 | #define GTI_CWD_WDOC_DSTOP (1 << 44) |
| 70 | #define GTI_CWD_WDOC_GSTOP (1 << 45) |
| 71 | |
| 72 | static uint64_t timer_raw_value(void) |
| 73 | { |
| 74 | struct cn81xx_timer *timer = (void *)GTI_PF_BAR0; |
| 75 | |
| 76 | return read64(&timer->cc_cntcv); |
| 77 | } |
| 78 | |
| 79 | /** |
| 80 | * Get GTI counter value. |
| 81 | * @param mt Structure to fill |
| 82 | */ |
| 83 | void timer_monotonic_get(struct mono_time *mt) |
| 84 | { |
| 85 | mono_time_set_usecs(mt, timer_raw_value()); |
| 86 | } |
| 87 | |
Patrick Rudolph | ae15fec | 2018-03-29 11:41:01 +0200 | [diff] [blame] | 88 | /* Setup counter to operate at 1MHz */ |
| 89 | static const size_t tickrate = 1000000; |
| 90 | |
David Hendricks | 8cbd569 | 2017-12-01 20:49:48 -0800 | [diff] [blame] | 91 | /** |
| 92 | * Init Global System Timers Unit (GTI). |
| 93 | * Configure timer to run at 1MHz tick-rate. |
| 94 | */ |
| 95 | void init_timer(void) |
| 96 | { |
| 97 | struct cn81xx_timer *gti = (struct cn81xx_timer *)GTI_PF_BAR0; |
| 98 | |
| 99 | /* Check if the counter was already setup */ |
| 100 | if (gti->cc_cntcr & GTI_CC_CNTCR_EN) |
| 101 | return; |
| 102 | |
| 103 | u64 sclk = thunderx_get_io_clock(); |
| 104 | |
| 105 | /* Use coprocessor clock source */ |
| 106 | write32(>i->cc_imp_ctl, 0); |
| 107 | |
David Hendricks | 8cbd569 | 2017-12-01 20:49:48 -0800 | [diff] [blame] | 108 | write32(>i->cc_cntfid0, tickrate); |
| 109 | write32(>i->ctl_cntfrq, tickrate); |
| 110 | write32(>i->cc_cntrate, ((1ULL << 32) * tickrate) / sclk); |
| 111 | |
| 112 | /* Enable the counter */ |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 113 | setbits32(>i->cc_cntcr, GTI_CC_CNTCR_EN); |
David Hendricks | 8cbd569 | 2017-12-01 20:49:48 -0800 | [diff] [blame] | 114 | |
| 115 | //u32 u = (CNTPS_CTL_EL1_IMASK | CNTPS_CTL_EL1_EN); |
| 116 | //BDK_MSR(CNTPS_CTL_EL1, u); |
| 117 | } |
| 118 | |
Patrick Rudolph | ae15fec | 2018-03-29 11:41:01 +0200 | [diff] [blame] | 119 | void soc_timer_init(void) |
| 120 | { |
Julius Werner | 73be9dd | 2018-08-07 14:02:55 -0700 | [diff] [blame] | 121 | raw_write_cntfrq_el0(tickrate); |
Patrick Rudolph | ae15fec | 2018-03-29 11:41:01 +0200 | [diff] [blame] | 122 | } |
| 123 | |
David Hendricks | 8cbd569 | 2017-12-01 20:49:48 -0800 | [diff] [blame] | 124 | /** |
| 125 | * Setup the watchdog to expire in timeout_ms milliseconds. When the watchdog |
| 126 | * expires, the chip three things happen: |
| 127 | * 1) Expire 1: interrupt that is ignored by the BDK |
| 128 | * 2) Expire 2: DEL3T interrupt, which is disabled and ignored |
| 129 | * 3) Expire 3: Soft reset of the chip |
| 130 | * |
| 131 | * Since we want a soft reset, we actually program the watchdog to expire at |
| 132 | * the timeout / 3. |
| 133 | * |
| 134 | * @param index Index of watchdog to configure |
| 135 | * @param timeout_ms Timeout in milliseconds. |
| 136 | */ |
| 137 | void watchdog_set(const size_t index, unsigned int timeout_ms) |
| 138 | { |
| 139 | uint64_t sclk = thunderx_get_io_clock(); |
| 140 | uint64_t timeout_sclk = sclk * timeout_ms / 1000; |
| 141 | struct cn81xx_timer *timer = (struct cn81xx_timer *)GTI_PF_BAR0; |
| 142 | |
| 143 | assert(index < ARRAY_SIZE(timer->cwd_wdog)); |
| 144 | if (index >= ARRAY_SIZE(timer->cwd_wdog)) |
| 145 | return; |
| 146 | |
| 147 | /* |
| 148 | * Per comment above, we want the watchdog to expire at 3x the rate |
| 149 | * specified |
| 150 | */ |
| 151 | timeout_sclk /= 3; |
| 152 | /* Watchdog counts in 1024 cycle steps */ |
| 153 | uint64_t timeout_wdog = timeout_sclk >> 10; |
| 154 | /* We can only specify the upper 16 bits of a 24 bit value. Round up */ |
| 155 | timeout_wdog = (timeout_wdog + 0xff) >> 8; |
| 156 | /* If the timeout overflows the hardware limit, set max */ |
| 157 | if (timeout_wdog >= 0x10000) |
| 158 | timeout_wdog = 0xffff; |
| 159 | |
| 160 | printk(BIOS_DEBUG, "Watchdog: Set to expire %llu SCLK cycles\n", |
| 161 | timeout_wdog << 18); |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 162 | clrsetbits64(&timer->cwd_wdog[index], |
| 163 | (GTI_CWD_WDOG_LEN_MASK << GTI_CWD_WDOG_LEN_SHIFT) | |
| 164 | (GTI_CWD_WDOG_MODE_MASK << GTI_CWD_WDOG_MODE_SHIFT), |
| 165 | (timeout_wdog << GTI_CWD_WDOG_LEN_SHIFT) | |
| 166 | (3 << GTI_CWD_WDOG_MODE_SHIFT)); |
David Hendricks | 8cbd569 | 2017-12-01 20:49:48 -0800 | [diff] [blame] | 167 | } |
| 168 | |
| 169 | /** |
| 170 | * Signal the watchdog that we are still running. |
| 171 | * |
| 172 | * @param index Index of watchdog to configure. |
| 173 | */ |
| 174 | void watchdog_poke(const size_t index) |
| 175 | { |
| 176 | struct cn81xx_timer *timer = (struct cn81xx_timer *)GTI_PF_BAR0; |
| 177 | |
| 178 | assert(index < ARRAY_SIZE(timer->cwd_poke)); |
| 179 | if (index >= ARRAY_SIZE(timer->cwd_poke)) |
| 180 | return; |
| 181 | |
| 182 | write64(&timer->cwd_poke[0], 0); |
| 183 | } |
| 184 | |
| 185 | /** |
| 186 | * Disable the hardware watchdog |
| 187 | * |
| 188 | * @param index Index of watchdog to configure. |
| 189 | */ |
| 190 | void watchdog_disable(const size_t index) |
| 191 | { |
| 192 | struct cn81xx_timer *timer = (struct cn81xx_timer *)GTI_PF_BAR0; |
| 193 | |
| 194 | assert(index < ARRAY_SIZE(timer->cwd_wdog)); |
| 195 | if (index >= ARRAY_SIZE(timer->cwd_wdog)) |
| 196 | return; |
| 197 | |
| 198 | write64(&timer->cwd_wdog[index], 0); |
| 199 | printk(BIOS_DEBUG, "Watchdog: Disabled\n"); |
| 200 | } |
| 201 | |
| 202 | /** |
| 203 | * Return true if the watchdog is configured and running |
| 204 | * |
| 205 | * @param index Index of watchdog to configure. |
| 206 | * |
| 207 | * @return Non-zero if watchdog is running. |
| 208 | */ |
| 209 | int watchdog_is_running(const size_t index) |
| 210 | { |
| 211 | struct cn81xx_timer *timer = (struct cn81xx_timer *)GTI_PF_BAR0; |
| 212 | |
| 213 | assert(index < ARRAY_SIZE(timer->cwd_wdog)); |
| 214 | if (index >= ARRAY_SIZE(timer->cwd_wdog)) |
| 215 | return 0; |
| 216 | |
| 217 | uint64_t val = read64(&timer->cwd_wdog[index]); |
| 218 | |
| 219 | return !!(val & (GTI_CWD_WDOG_MODE_MASK << GTI_CWD_WDOG_MODE_SHIFT)); |
| 220 | } |