^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) #include <linux/pci.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) #include <linux/percpu.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/spinlock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <asm/hpet.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <asm/time.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #define SMBUS_CFG_BASE (loongson_sysconf.ht_control_base + 0x0300a000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #define SMBUS_PCI_REG40 0x40
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #define SMBUS_PCI_REG64 0x64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #define SMBUS_PCI_REGB4 0xb4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #define HPET_MIN_CYCLES 16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #define HPET_MIN_PROG_DELTA (HPET_MIN_CYCLES * 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) static DEFINE_SPINLOCK(hpet_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) DEFINE_PER_CPU(struct clock_event_device, hpet_clockevent_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) static unsigned int smbus_read(int offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) return *(volatile unsigned int *)(SMBUS_CFG_BASE + offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) static void smbus_write(int offset, int data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) *(volatile unsigned int *)(SMBUS_CFG_BASE + offset) = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) static void smbus_enable(int offset, int bit)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) unsigned int cfg = smbus_read(offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) cfg |= bit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) smbus_write(offset, cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) static int hpet_read(int offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) return *(volatile unsigned int *)(HPET_MMIO_ADDR + offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) static void hpet_write(int offset, int data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) *(volatile unsigned int *)(HPET_MMIO_ADDR + offset) = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) static void hpet_start_counter(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) unsigned int cfg = hpet_read(HPET_CFG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) cfg |= HPET_CFG_ENABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) hpet_write(HPET_CFG, cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) static void hpet_stop_counter(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) unsigned int cfg = hpet_read(HPET_CFG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) cfg &= ~HPET_CFG_ENABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) hpet_write(HPET_CFG, cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) static void hpet_reset_counter(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) hpet_write(HPET_COUNTER, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) hpet_write(HPET_COUNTER + 4, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) static void hpet_restart_counter(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) hpet_stop_counter();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) hpet_reset_counter();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) hpet_start_counter();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) static void hpet_enable_legacy_int(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) /* Do nothing on Loongson-3 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) static int hpet_set_state_periodic(struct clock_event_device *evt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) int cfg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) spin_lock(&hpet_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) pr_info("set clock event to periodic mode!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) /* stop counter */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) hpet_stop_counter();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) /* enables the timer0 to generate a periodic interrupt */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) cfg = hpet_read(HPET_T0_CFG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) cfg &= ~HPET_TN_LEVEL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC | HPET_TN_SETVAL |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) HPET_TN_32BIT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) hpet_write(HPET_T0_CFG, cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) /* set the comparator */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) hpet_write(HPET_T0_CMP, HPET_COMPARE_VAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) udelay(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) hpet_write(HPET_T0_CMP, HPET_COMPARE_VAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) /* start counter */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) hpet_start_counter();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) spin_unlock(&hpet_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) static int hpet_set_state_shutdown(struct clock_event_device *evt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) int cfg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) spin_lock(&hpet_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) cfg = hpet_read(HPET_T0_CFG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) cfg &= ~HPET_TN_ENABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) hpet_write(HPET_T0_CFG, cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) spin_unlock(&hpet_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) static int hpet_set_state_oneshot(struct clock_event_device *evt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) int cfg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) spin_lock(&hpet_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) pr_info("set clock event to one shot mode!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) cfg = hpet_read(HPET_T0_CFG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) * set timer0 type
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) * 1 : periodic interrupt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) * 0 : non-periodic(oneshot) interrupt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) cfg &= ~HPET_TN_PERIODIC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) cfg |= HPET_TN_ENABLE | HPET_TN_32BIT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) hpet_write(HPET_T0_CFG, cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) spin_unlock(&hpet_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) static int hpet_tick_resume(struct clock_event_device *evt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) spin_lock(&hpet_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) hpet_enable_legacy_int();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) spin_unlock(&hpet_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) static int hpet_next_event(unsigned long delta,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) struct clock_event_device *evt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) u32 cnt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) s32 res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) cnt = hpet_read(HPET_COUNTER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) cnt += (u32) delta;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) hpet_write(HPET_T0_CMP, cnt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) res = (s32)(cnt - hpet_read(HPET_COUNTER));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) return res < HPET_MIN_CYCLES ? -ETIME : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) static irqreturn_t hpet_irq_handler(int irq, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) int is_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) struct clock_event_device *cd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) unsigned int cpu = smp_processor_id();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) is_irq = hpet_read(HPET_STATUS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) if (is_irq & HPET_T0_IRS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) /* clear the TIMER0 irq status register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) hpet_write(HPET_STATUS, HPET_T0_IRS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) cd = &per_cpu(hpet_clockevent_device, cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) cd->event_handler(cd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) return IRQ_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) * hpet address assignation and irq setting should be done in bios.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) * but pmon don't do this, we just setup here directly.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) * The operation under is normal. unfortunately, hpet_setup process
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) * is before pci initialize.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) * {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) * struct pci_dev *pdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) * pdev = pci_get_device(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) * pci_write_config_word(pdev, SMBUS_PCI_REGB4, HPET_ADDR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) * ...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) * }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) static void hpet_setup(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) /* set hpet base address */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) smbus_write(SMBUS_PCI_REGB4, HPET_ADDR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) /* enable decoding of access to HPET MMIO*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) smbus_enable(SMBUS_PCI_REG40, (1 << 28));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) /* HPET irq enable */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) smbus_enable(SMBUS_PCI_REG64, (1 << 10));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) hpet_enable_legacy_int();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) void __init setup_hpet_timer(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) unsigned long flags = IRQF_NOBALANCING | IRQF_TIMER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) unsigned int cpu = smp_processor_id();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) struct clock_event_device *cd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) hpet_setup();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) cd = &per_cpu(hpet_clockevent_device, cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) cd->name = "hpet";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) cd->rating = 100;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) cd->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) cd->set_state_shutdown = hpet_set_state_shutdown;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) cd->set_state_periodic = hpet_set_state_periodic;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) cd->set_state_oneshot = hpet_set_state_oneshot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) cd->tick_resume = hpet_tick_resume;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) cd->set_next_event = hpet_next_event;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) cd->irq = HPET_T0_IRQ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) cd->cpumask = cpumask_of(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) clockevent_set_clock(cd, HPET_FREQ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) cd->max_delta_ticks = 0x7fffffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) cd->min_delta_ns = clockevent_delta2ns(HPET_MIN_PROG_DELTA, cd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) cd->min_delta_ticks = HPET_MIN_PROG_DELTA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) clockevents_register_device(cd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) if (request_irq(HPET_T0_IRQ, hpet_irq_handler, flags, "hpet", NULL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) pr_err("Failed to request irq %d (hpet)\n", HPET_T0_IRQ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) pr_info("hpet clock event device register\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) static u64 hpet_read_counter(struct clocksource *cs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) return (u64)hpet_read(HPET_COUNTER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) static void hpet_suspend(struct clocksource *cs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) static void hpet_resume(struct clocksource *cs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) hpet_setup();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) hpet_restart_counter();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) static struct clocksource csrc_hpet = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) .name = "hpet",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) /* mips clocksource rating is less than 300, so hpet is better. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) .rating = 300,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) .read = hpet_read_counter,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) .mask = CLOCKSOURCE_MASK(32),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) /* oneshot mode work normal with this flag */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) .flags = CLOCK_SOURCE_IS_CONTINUOUS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) .suspend = hpet_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) .resume = hpet_resume,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) .mult = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) .shift = 10,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) int __init init_hpet_clocksource(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) csrc_hpet.mult = clocksource_hz2mult(HPET_FREQ, csrc_hpet.shift);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) return clocksource_register_hz(&csrc_hpet, HPET_FREQ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) arch_initcall(init_hpet_clocksource);