11/*
2- * Copyright (c) 2018 Intel Corporation
2+ * Copyright (c) 2018-2021 Intel Corporation
33 *
44 * SPDX-License-Identifier: Apache-2.0
55 */
@@ -95,13 +95,15 @@ DEVICE_MMIO_TOPLEVEL_STATIC(hpet_regs, DT_DRV_INST(0));
9595#define INTR_STATUS_REG HPET_REG_ADDR(0x20)
9696
9797/* Main Counter Register */
98- #define MAIN_COUNTER_REG HPET_REG_ADDR(0xf0)
98+ #define MAIN_COUNTER_LOW_REG HPET_REG_ADDR(0xf0)
99+ #define MAIN_COUNTER_HIGH_REG HPET_REG_ADDR(0xf4)
99100
100101/* Timer 0 Configuration and Capabilities register */
101102#define TIMER0_CONF_REG HPET_REG_ADDR(0x100)
102103
103104/* Timer 0 Comparator Register */
104- #define TIMER0_COMPARATOR_REG HPET_REG_ADDR(0x108)
105+ #define TIMER0_COMPARATOR_LOW_REG HPET_REG_ADDR(0x108)
106+ #define TIMER0_COMPARATOR_HIGH_REG HPET_REG_ADDR(0x10c)
105107
106108/**
107109 * @brief Setup memory mappings needed to access HPET registers.
@@ -119,9 +121,17 @@ static inline void hpet_mmio_init(void)
119121 *
120122 * @return Value of Main Counter
121123 */
122- static inline uint32_t hpet_counter_get (void )
124+ static inline uint64_t hpet_counter_get (void )
123125{
124- return sys_read32 (MAIN_COUNTER_REG );
126+ uint32_t high ;
127+ uint32_t low ;
128+
129+ do {
130+ high = sys_read32 (MAIN_COUNTER_HIGH_REG );
131+ low = sys_read32 (MAIN_COUNTER_LOW_REG );
132+ } while (high != sys_read32 (MAIN_COUNTER_HIGH_REG ));
133+
134+ return ((uint64_t )high << 32 ) | low ;
125135}
126136
127137/**
@@ -208,9 +218,14 @@ static inline void hpet_timer_conf_set(uint32_t val)
208218 *
209219 * @param val Value to be written to the register
210220 */
211- static inline void hpet_timer_comparator_set (uint32_t val )
221+ static inline void hpet_timer_comparator_set (uint64_t val )
212222{
213- sys_write32 (val , TIMER0_COMPARATOR_REG );
223+ #if CONFIG_X86_64
224+ sys_write64 (val , TIMER0_COMPARATOR_LOW_REG );
225+ #else
226+ sys_write32 ((uint32_t )val , TIMER0_COMPARATOR_LOW_REG );
227+ sys_write32 ((uint32_t )(val >> 32 ), TIMER0_COMPARATOR_HIGH_REG );
228+ #endif
214229}
215230#endif /* HPET_USE_CUSTOM_REG_ACCESS_FUNCS */
216231
@@ -224,30 +239,26 @@ static inline void hpet_timer_comparator_set(uint32_t val)
224239#define HPET_CMP_MIN_DELAY (1000)
225240#endif
226241
227- #define MAX_TICKS 0x7FFFFFFFUL
228-
229242static __pinned_bss struct k_spinlock lock ;
230- static __pinned_bss unsigned int last_count ;
243+ static __pinned_bss uint64_t last_count ;
231244
232245#ifdef CONFIG_TIMER_READS_ITS_FREQUENCY_AT_RUNTIME
233246static __pinned_bss unsigned int cyc_per_tick ;
234- static __pinned_bss unsigned int max_ticks ;
235247#else
236248#define cyc_per_tick \
237249 (CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC / CONFIG_SYS_CLOCK_TICKS_PER_SEC)
238-
239- #define max_ticks \
240- ((MAX_TICKS - cyc_per_tick) / cyc_per_tick)
241250#endif /* CONFIG_TIMER_READS_ITS_FREQUENCY_AT_RUNTIME */
242251
252+ #define HPET_MAX_TICKS ((int32_t)0x7fffffff)
253+
243254__isr
244255static void hpet_isr (const void * arg )
245256{
246257 ARG_UNUSED (arg );
247258
248259 k_spinlock_key_t key = k_spin_lock (& lock );
249260
250- uint32_t now = hpet_counter_get ();
261+ uint64_t now = hpet_counter_get ();
251262
252263#if ((DT_INST_IRQ (0 , sense ) & IRQ_TYPE_LEVEL ) == IRQ_TYPE_LEVEL )
253264 /*
@@ -265,27 +276,27 @@ static void hpet_isr(const void *arg)
265276 * on the other CPU, despite the HPET being
266277 * theoretically a global device.
267278 */
268- int32_t diff = (int32_t )(now - last_count );
279+ int64_t diff = (int64_t )(now - last_count );
269280
270281 if (last_count && diff < 0 ) {
271282 now = last_count ;
272283 }
273284 }
274- uint32_t dticks = (now - last_count ) / cyc_per_tick ;
285+ uint32_t dticks = (uint32_t )(( now - last_count ) / cyc_per_tick ) ;
275286
276- last_count += dticks * cyc_per_tick ;
287+ last_count += ( uint64_t ) dticks * cyc_per_tick ;
277288
278289 if (!IS_ENABLED (CONFIG_TICKLESS_KERNEL )) {
279- uint32_t next = last_count + cyc_per_tick ;
290+ uint64_t next = last_count + cyc_per_tick ;
280291
281- if ((int32_t )(next - now ) < HPET_CMP_MIN_DELAY ) {
282- next += cyc_per_tick ;
292+ if ((int64_t )(next - now ) < HPET_CMP_MIN_DELAY ) {
293+ next = now + HPET_CMP_MIN_DELAY ;
283294 }
284295 hpet_timer_comparator_set (next );
285296 }
286297
287298 k_spin_unlock (& lock , key );
288- sys_clock_announce (IS_ENABLED ( CONFIG_TICKLESS_KERNEL ) ? dticks : 1 );
299+ sys_clock_announce (dticks );
289300}
290301
291302__pinned_func
@@ -326,12 +337,8 @@ int sys_clock_driver_init(const struct device *dev)
326337 hz = (uint32_t )(HPET_COUNTER_CLK_PERIOD / hpet_counter_clk_period_get ());
327338 z_clock_hw_cycles_per_sec = hz ;
328339 cyc_per_tick = hz / CONFIG_SYS_CLOCK_TICKS_PER_SEC ;
329-
330- max_ticks = (MAX_TICKS - cyc_per_tick ) / cyc_per_tick ;
331340#endif
332341
333- last_count = hpet_counter_get ();
334-
335342 /* Note: we set the legacy routing bit, because otherwise
336343 * nothing in Zephyr disables the PIT which then fires
337344 * interrupts into the same IRQ. But that means we're then
@@ -345,11 +352,16 @@ int sys_clock_driver_init(const struct device *dev)
345352 reg = hpet_timer_conf_get ();
346353 reg &= ~TIMER_CONF_PERIODIC ;
347354 reg &= ~TIMER_CONF_FSB_EN ;
348- reg |= TIMER_CONF_MODE32 ;
355+ reg &= ~ TIMER_CONF_MODE32 ;
349356 reg |= TIMER_CONF_INT_ENABLE ;
350357 hpet_timer_conf_set (reg );
351358
352- hpet_timer_comparator_set (last_count + cyc_per_tick );
359+ last_count = hpet_counter_get ();
360+ if (cyc_per_tick >= HPET_CMP_MIN_DELAY ) {
361+ hpet_timer_comparator_set (last_count + cyc_per_tick );
362+ } else {
363+ hpet_timer_comparator_set (last_count + HPET_CMP_MIN_DELAY );
364+ }
353365
354366 return 0 ;
355367}
@@ -378,15 +390,15 @@ void sys_clock_set_timeout(int32_t ticks, bool idle)
378390 return ;
379391 }
380392
381- ticks = ticks == K_TICKS_FOREVER ? max_ticks : ticks ;
382- ticks = CLAMP (ticks - 1 , 0 , ( int32_t ) max_ticks );
393+ ticks = ticks == K_TICKS_FOREVER ? HPET_MAX_TICKS : ticks ;
394+ ticks = CLAMP (ticks - 1 , 0 , HPET_MAX_TICKS );
383395
384396 k_spinlock_key_t key = k_spin_lock (& lock );
385- uint32_t now = hpet_counter_get (), cyc , adj ;
386- uint32_t max_cyc = max_ticks * cyc_per_tick ;
397+ uint64_t now = hpet_counter_get (), cyc , adj ;
398+ uint64_t max_cyc = ( uint64_t ) HPET_MAX_TICKS * cyc_per_tick ;
387399
388400 /* Round up to next tick boundary. */
389- cyc = ticks * cyc_per_tick ;
401+ cyc = ( uint64_t ) ticks * cyc_per_tick ;
390402 adj = (now - last_count ) + (cyc_per_tick - 1 );
391403 if (cyc <= max_cyc - adj ) {
392404 cyc += adj ;
@@ -396,8 +408,8 @@ void sys_clock_set_timeout(int32_t ticks, bool idle)
396408 cyc = (cyc / cyc_per_tick ) * cyc_per_tick ;
397409 cyc += last_count ;
398410
399- if ((cyc - now ) < HPET_CMP_MIN_DELAY ) {
400- cyc += cyc_per_tick ;
411+ if ((int64_t )( cyc - now ) < HPET_CMP_MIN_DELAY ) {
412+ cyc = now + HPET_CMP_MIN_DELAY ;
401413 }
402414
403415 hpet_timer_comparator_set (cyc );
@@ -413,7 +425,8 @@ uint32_t sys_clock_elapsed(void)
413425 }
414426
415427 k_spinlock_key_t key = k_spin_lock (& lock );
416- uint32_t ret = (hpet_counter_get () - last_count ) / cyc_per_tick ;
428+ uint64_t now = hpet_counter_get ();
429+ uint32_t ret = (uint32_t )((now - last_count ) / cyc_per_tick );
417430
418431 k_spin_unlock (& lock , key );
419432 return ret ;
@@ -422,7 +435,7 @@ uint32_t sys_clock_elapsed(void)
422435__pinned_func
423436uint32_t sys_clock_cycle_get_32 (void )
424437{
425- return hpet_counter_get ();
438+ return ( uint32_t ) hpet_counter_get ();
426439}
427440
428441__pinned_func
0 commit comments