Mainline:Broadcom Kona/Timers
The Kona platform has three timers:
- HUB/AON
- Slave/Peripheral
- (BCM23550 only) Core
The driver for the timers is split up into three files:
arch/arm/plat-kona/kona_timer.c
arch/arm/plat-kona/timer.c
arch/arm/plat-kona/localtimer.c
- setup for the local tick timer (local, I assume, means "CPU-local" - meaning each channel belongs to a different CPU core)
All timers use the same driver.
Timer operation
Each timer device manages 4 channels. Each channel has its own separate IRQ.
The timer operates in oneshot mode, meaning that it can be programmed to generate a clock event once (as opposed to PERIODIC mode which generates periodical events). See https://elixir.bootlin.com/linux/v6.10.6/source/include/linux/clockchips.h#L22. Downstream has some code to emulate periodic timers.
Due to hardware limitations, there is a delay of 5 clock cycles when writing values to the timers. Downstream claims that this is only true for HUB timer, but applies the mitigation to all timers. (https://github.com/knuxdroid/android_kernel_samsung_baffinlite/blob/cm-12.1/arch/arm/plat-kona/localtimer.c#L176-L179)
Timer rate
The Hub/AON timer uses the TIMERS
clock, which can be set to either 32KHz or 1MHz. (Downstream also claims it can use 19.5MHz, but the clock doesn't have the setting for it; if it did, it would have the selector value of 2. I assume either kona_timer.c or clock driver is mistaken.)
Getting the counter value
In 64-bit mode: Read the value of KONA_GPTIMER_STCLO_OFFSET
(0x04
) to get the low 32 bits, and KONA_GPTIMER_STCHI_OFFSET
(0x08
) to get the high 32 bits, then combine to get the full value.
In 32-bit mode: Read the value of KONA_GPTIMER_STCLO_OFFSET
(0x04
).
It's worth noting that despite the timer being capable of counting to 64 bits, the downstream driver overrides this for the hub timer. The reasoning is that the match values used for each channel are 32-bit. (Slave/Peripheral does not use channels? TODO) (https://github.com/knuxdroid/android_kernel_samsung_baffinlite/blob/cm-12.1/arch/arm/plat-kona/timer.c#L137-L142)
Switching to 32-bit mode is done by writing to the CHIPREG register. For Rhea, Hawaii and Java, this is done as such: (https://github.com/knuxdroid/android_kernel_samsung_baffinlite/blob/cm-12.1/arch/arm/plat-kona/kona_timer.c#L322-L326)
/* Configure KONA Timer count in 32 bit mode */
writel(0x0, KONA_CHIPREG_VA + CHIPREG_HUB_TIMER_WIDTH_OFFSET);
For Capri, this is done as such: (https://github.com/ghsr/android_kernel_samsung_i9152/blob/android-7.1/arch/arm/plat-kona/kona_timer.c#L268-L271)
/* Use 32bit mode timer */
reg = readl(KONA_CHIPREG_VA + CHIPREG_ARM_PERI_CONTROL_OFFSET);
reg &= ~(CHIPREG_ARM_PERI_CONTROL_SLV_TIMER_64BITMODE_MASK |
CHIPREG_ARM_PERI_CONTROL_HUB_TIMER_64BITMODE_MASK);
writel(reg, KONA_CHIPREG_VA + CHIPREG_ARM_PERI_CONTROL_OFFSET);
Note that on Capri, it seems to set both the Hub and the Slave/Peripheral timer to 32-bit mode, whereas on Rhea/Hawaii/Java only Hub timer is configured (Slave/Peripheral timer has a separate width offset at CHIPREG_SLAVE_TIMER_WIDTH_OFFSET
).
Starting the counter
To set the value and start counting:
- Set the value of
KONA_GPTIMER_STCM{n}
to the 32-bit value to match for ({n}
is the number of the channel) - Wait for the value to sync by watching the
STCM{n}_SYNC
value inKONA_GPTIMER_STCS
- In STCS, all in one write:
- Clear the timer match field (bits 3..0)
- Write the timer match bit for the selected channel (bits 3..0)
- Write the compare enable bit for the selected channel (bits 7..4)
Local tick timer
The local tick timer refers to the timer the channels of which are used as CPU-local timers. In downstream, it's set up in arch/arm/plat-kona/localtimer.c
.
Timer regs
KONA_GPTIMER_STCS (0x00
)
Settings register. Contains controls for the timer's state.
Name | Bit | Description |
---|---|---|
Reserved | 31:16 | Reserved |
STCM{0,3}_SYNC
|
15:12 | Sync bit for STCM{0,3} value being set (bit 12 is STCM0, bit 13 is STCM1, bit 14 is STCM2, bit 15 is STCM3). |
STCS_COMPARE_ENABLE_SYNC
|
11:8 | Sync bit for COMPARE_ENABLE. Same layout as the above. |
STCS_COMPARE_ENABLE
|
7:4 | Enable compare (match) on the specified channel(s). When this bit is set for a channel, the value of the STCM{0,3} register will be used for a match. - 0b0001 - enable compare for channel 0- 0b0010 - enable compare for channel 1- 0b0100 - enable compare for channel 2- 0b1000 - enable compare for channel 3
|
STCS_TIMER_MATCH
|
3:0 | Represents the state of the timer interrupt for each channel; 0 means the interrupt is enabled, 1 means the interrupt is cleared.To clean the interrupt, clean the entire field and set the bit corresponding to the channel to clear the interrupt for to 1 . Leaving the other bits set to 0 while setting will keep the interrupt state intact (TODO - if not, then this means only one interrupt can be serviced at a time?)
|
KONA_GPTIMER_STCLO (0x04
)
Contains the lower 32 bits of the counter value.
Name | Bit | Description |
---|---|---|
STCLO
|
31:0 | Lower 32 bits of the counter value. In 32-bit mode, this is the only register used for the counter value. |
KONA_GPTIMER_STCHI (0x08
)
Contains the upper 32 bits of the counter value.
Name | Bit | Description |
---|---|---|
STCHI
|
31:0 | Upper 32 bits of the counter value. Only used in 64-bit mode. |
KONA_GPTIMER_STCM{0,3} (0x0c
, 0x10
, 0x14
, 0x18
)
Match registers for channels 0-3.
Name | Bit | Description |
---|---|---|
STCM{0,3}
|
31:0 | 32-bit time value for timer match. When the lower bits of the counter match this value, the interrupt for the channel is raised and the bit corresponding to the triggered timer number is set in STCS_TIMER_MATCH. |
Timer initialization in downstream
- Starts in
hawaii_timer_init
in hawaii.c (https://github.com/knuxdroid/android_kernel_samsung_baffinlite/blob/cm-12.1/arch/arm/mach-hawaii/hawaii.c#L176-L208) - This sets up a GP timer setup struct and calls
gp_timer_init
, which is placed inarch/arm/plat-kona/timer.c
(https://github.com/knuxdroid/android_kernel_samsung_baffinlite/blob/cm-12.1/arch/arm/plat-kona/timer.c#L262C1-L305C2)- Calls
timers_init
, which 1. sets up clock rates, 2. callskona_timer_config
on the GP timer from the struct;- Sets a callback function,
gptimer_interrupt_cb
to call on timer interrupt.
- Sets a callback function,
- Calls
Downstream driver: https://github.com/knuxdroid/android_kernel_samsung_baffinlite/blob/cm-12.1/arch/arm/plat-kona/kona_timer.c