Skip to content

Commit a56c425

Browse files
kwd-doodlingcfriedt
authored andcommitted
timer: hpet: make it support EHL/PSE CPU
Add config macro to set interrupt as level triggered for ARM CPUs Merge all timer configures into one place, then no need to overwrite hpet_timer_conf_get/set() functions in SoC layer Make hpet_timer_comparator_set() as the only register access function to implemented in the SoC layer Signed-off-by: Dong Wang <[email protected]>
1 parent eeb15aa commit a56c425

File tree

2 files changed

+44
-45
lines changed

2 files changed

+44
-45
lines changed

drivers/timer/Kconfig

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,6 @@ config APIC_TIMER_IRQ_PRIORITY
8080

8181
config HPET_TIMER
8282
bool "HPET timer"
83-
depends on X86
8483
select IOAPIC if X86
8584
select LOAPIC if X86
8685
imply TIMER_READS_ITS_FREQUENCY_AT_RUNTIME

drivers/timer/hpet.c

Lines changed: 44 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -60,26 +60,6 @@
6060
#define TIMER_CONF_FSB_EN BIT(14) /* FSB interrupt delivery */
6161
/* enable */
6262

63-
/*
64-
* The following MMIO initialization and register access functions
65-
* should work on generic x86 hardware. If the targeted SoC requires
66-
* special handling of HPET registers, these functions will need to be
67-
* implemented in the SoC layer by first defining the macro
68-
* HPET_USE_CUSTOM_REG_ACCESS_FUNCS in soc.h to signal such intent.
69-
*
70-
* This is a list of functions which must be implemented in the SoC
71-
* layer:
72-
* void hpet_mmio_init(void)
73-
* uint32_t hpet_counter_get(void)
74-
* uint32_t hpet_counter_clk_period_get(void)
75-
* uint32_t hpet_gconf_get(void)
76-
* void hpet_gconf_set(uint32_t val)
77-
* void hpet_int_sts_set(uint32_t val)
78-
* uint32_t hpet_timer_conf_get(void)
79-
* void hpet_timer_conf_set(uint32_t val)
80-
* void hpet_timer_comparator_set(uint32_t val)
81-
*/
82-
#ifndef HPET_USE_CUSTOM_REG_ACCESS_FUNCS
8363
DEVICE_MMIO_TOPLEVEL_STATIC(hpet_regs, DT_DRV_INST(0));
8464

8565
#define HPET_REG_ADDR(off) \
@@ -105,17 +85,6 @@ DEVICE_MMIO_TOPLEVEL_STATIC(hpet_regs, DT_DRV_INST(0));
10585
#define TIMER0_COMPARATOR_LOW_REG HPET_REG_ADDR(0x108)
10686
#define TIMER0_COMPARATOR_HIGH_REG HPET_REG_ADDR(0x10c)
10787

108-
/**
109-
* @brief Setup memory mappings needed to access HPET registers.
110-
*
111-
* This is called in sys_clock_driver_init() to setup any memory
112-
* mappings needed to access HPET registers.
113-
*/
114-
static inline void hpet_mmio_init(void)
115-
{
116-
DEVICE_MMIO_TOPLEVEL_MAP(hpet_regs, K_MEM_CACHE_NONE);
117-
}
118-
11988
/**
12089
* @brief Return the value of the main counter.
12190
*
@@ -210,6 +179,19 @@ static inline void hpet_timer_conf_set(uint32_t val)
210179
sys_write32(val, TIMER0_CONF_REG);
211180
}
212181

182+
/*
183+
* The following register access functions should work on generic x86
184+
* hardware. If the targeted SoC requires special handling of HPET
185+
* registers, these functions will need to be implemented in the SoC
186+
* layer by first defining the macro HPET_USE_CUSTOM_REG_ACCESS_FUNCS
187+
* in soc.h to signal such intent.
188+
*
189+
* This is a list of functions which must be implemented in the SoC
190+
* layer:
191+
* void hpet_timer_comparator_set(uint32_t val)
192+
*/
193+
#ifndef HPET_USE_CUSTOM_REG_ACCESS_FUNCS
194+
213195
/**
214196
* @brief Write to the Timer Comparator Value Register
215197
*
@@ -239,6 +221,21 @@ static inline void hpet_timer_comparator_set(uint64_t val)
239221
#define HPET_CMP_MIN_DELAY (1000)
240222
#endif
241223

224+
/*
225+
* HPET_INT_LEVEL_TRIGGER is used to set HPET interrupt as level trigger
226+
* for ARM CPU with NVIC like EHL PSE, whose DTS interrupt setting
227+
* has no "sense" cell.
228+
*/
229+
#if (DT_INST_IRQ_HAS_CELL(0, sense))
230+
#ifdef HPET_INT_LEVEL_TRIGGER
231+
__WARN("HPET_INT_LEVEL_TRIGGER has no effect, DTS setting is used instead")
232+
#undef HPET_INT_LEVEL_TRIGGER
233+
#endif
234+
#if ((DT_INST_IRQ(0, sense) & IRQ_TYPE_LEVEL) == IRQ_TYPE_LEVEL)
235+
#define HPET_INT_LEVEL_TRIGGER
236+
#endif
237+
#endif /* (DT_INST_IRQ_HAS_CELL(0, sense)) */
238+
242239
static __pinned_bss struct k_spinlock lock;
243240
static __pinned_bss uint64_t last_count;
244241

@@ -260,7 +257,7 @@ static void hpet_isr(const void *arg)
260257

261258
uint64_t now = hpet_counter_get();
262259

263-
#if ((DT_INST_IRQ(0, sense) & IRQ_TYPE_LEVEL) == IRQ_TYPE_LEVEL)
260+
#ifdef HPET_INT_LEVEL_TRIGGER
264261
/*
265262
* Clear interrupt only if level trigger is selected.
266263
* When edge trigger is selected, spec says only 0 can
@@ -300,18 +297,22 @@ static void hpet_isr(const void *arg)
300297
}
301298

302299
__pinned_func
303-
static void set_timer0_irq(unsigned int irq)
300+
static void config_timer0(unsigned int irq)
304301
{
305302
uint32_t val = hpet_timer_conf_get();
306303

307304
/* 5-bit IRQ field starting at bit 9 */
308305
val = (val & ~(0x1f << 9)) | ((irq & 0x1f) << 9);
309306

310-
#if ((DT_INST_IRQ(0, sense) & IRQ_TYPE_LEVEL) == IRQ_TYPE_LEVEL)
311-
/* Level trigger */
307+
#ifdef HPET_INT_LEVEL_TRIGGER
308+
/* Set level trigger if selected */
312309
val |= TIMER_CONF_INT_LEVEL;
313310
#endif
314311

312+
val &= ~((uint32_t)(TIMER_CONF_MODE32 | TIMER_CONF_PERIODIC |
313+
TIMER_CONF_FSB_EN));
314+
val |= TIMER_CONF_INT_ENABLE;
315+
315316
hpet_timer_conf_set(val);
316317
}
317318

@@ -325,12 +326,18 @@ int sys_clock_driver_init(const struct device *dev)
325326
ARG_UNUSED(hz);
326327
ARG_UNUSED(z_clock_hw_cycles_per_sec);
327328

328-
hpet_mmio_init();
329+
DEVICE_MMIO_TOPLEVEL_MAP(hpet_regs, K_MEM_CACHE_NONE);
329330

331+
#if DT_INST_IRQ_HAS_CELL(0, sense)
330332
IRQ_CONNECT(DT_INST_IRQN(0),
331333
DT_INST_IRQ(0, priority),
332334
hpet_isr, 0, DT_INST_IRQ(0, sense));
333-
set_timer0_irq(DT_INST_IRQN(0));
335+
#else
336+
IRQ_CONNECT(DT_INST_IRQN(0),
337+
DT_INST_IRQ(0, priority),
338+
hpet_isr, 0, 0);
339+
#endif
340+
config_timer0(DT_INST_IRQN(0));
334341
irq_enable(DT_INST_IRQN(0));
335342

336343
#ifdef CONFIG_TIMER_READS_ITS_FREQUENCY_AT_RUNTIME
@@ -349,13 +356,6 @@ int sys_clock_driver_init(const struct device *dev)
349356
reg |= GCONF_LR | GCONF_ENABLE;
350357
hpet_gconf_set(reg);
351358

352-
reg = hpet_timer_conf_get();
353-
reg &= ~TIMER_CONF_PERIODIC;
354-
reg &= ~TIMER_CONF_FSB_EN;
355-
reg &= ~TIMER_CONF_MODE32;
356-
reg |= TIMER_CONF_INT_ENABLE;
357-
hpet_timer_conf_set(reg);
358-
359359
last_count = hpet_counter_get();
360360
if (cyc_per_tick >= HPET_CMP_MIN_DELAY) {
361361
hpet_timer_comparator_set(last_count + cyc_per_tick);

0 commit comments

Comments
 (0)