timer-goldfish.c (3659B)
1// SPDX-License-Identifier: GPL-2.0 2 3#include <linux/interrupt.h> 4#include <linux/ioport.h> 5#include <linux/clocksource.h> 6#include <linux/clockchips.h> 7#include <linux/module.h> 8#include <linux/slab.h> 9#include <linux/goldfish.h> 10#include <clocksource/timer-goldfish.h> 11 12struct goldfish_timer { 13 struct clocksource cs; 14 struct clock_event_device ced; 15 struct resource res; 16 void __iomem *base; 17}; 18 19static struct goldfish_timer *ced_to_gf(struct clock_event_device *ced) 20{ 21 return container_of(ced, struct goldfish_timer, ced); 22} 23 24static struct goldfish_timer *cs_to_gf(struct clocksource *cs) 25{ 26 return container_of(cs, struct goldfish_timer, cs); 27} 28 29static u64 goldfish_timer_read(struct clocksource *cs) 30{ 31 struct goldfish_timer *timerdrv = cs_to_gf(cs); 32 void __iomem *base = timerdrv->base; 33 u32 time_low, time_high; 34 u64 ticks; 35 36 /* 37 * time_low: get low bits of current time and update time_high 38 * time_high: get high bits of time at last time_low read 39 */ 40 time_low = gf_ioread32(base + TIMER_TIME_LOW); 41 time_high = gf_ioread32(base + TIMER_TIME_HIGH); 42 43 ticks = ((u64)time_high << 32) | time_low; 44 45 return ticks; 46} 47 48static int goldfish_timer_set_oneshot(struct clock_event_device *evt) 49{ 50 struct goldfish_timer *timerdrv = ced_to_gf(evt); 51 void __iomem *base = timerdrv->base; 52 53 gf_iowrite32(0, base + TIMER_ALARM_HIGH); 54 gf_iowrite32(0, base + TIMER_ALARM_LOW); 55 gf_iowrite32(1, base + TIMER_IRQ_ENABLED); 56 57 return 0; 58} 59 60static int goldfish_timer_shutdown(struct clock_event_device *evt) 61{ 62 struct goldfish_timer *timerdrv = ced_to_gf(evt); 63 void __iomem *base = timerdrv->base; 64 65 gf_iowrite32(0, base + TIMER_IRQ_ENABLED); 66 67 return 0; 68} 69 70static int goldfish_timer_next_event(unsigned long delta, 71 struct clock_event_device *evt) 72{ 73 struct goldfish_timer *timerdrv = ced_to_gf(evt); 74 void __iomem *base = timerdrv->base; 75 u64 now; 76 77 now = goldfish_timer_read(&timerdrv->cs); 78 79 now += delta; 80 81 gf_iowrite32(upper_32_bits(now), base + TIMER_ALARM_HIGH); 82 gf_iowrite32(lower_32_bits(now), base + TIMER_ALARM_LOW); 83 84 return 0; 85} 86 87static irqreturn_t goldfish_timer_irq(int irq, void *dev_id) 88{ 89 struct goldfish_timer *timerdrv = dev_id; 90 struct clock_event_device *evt = &timerdrv->ced; 91 void __iomem *base = timerdrv->base; 92 93 gf_iowrite32(1, base + TIMER_CLEAR_INTERRUPT); 94 95 evt->event_handler(evt); 96 97 return IRQ_HANDLED; 98} 99 100int __init goldfish_timer_init(int irq, void __iomem *base) 101{ 102 struct goldfish_timer *timerdrv; 103 int ret; 104 105 timerdrv = kzalloc(sizeof(*timerdrv), GFP_KERNEL); 106 if (!timerdrv) 107 return -ENOMEM; 108 109 timerdrv->base = base; 110 111 timerdrv->ced = (struct clock_event_device){ 112 .name = "goldfish_timer", 113 .features = CLOCK_EVT_FEAT_ONESHOT, 114 .set_state_shutdown = goldfish_timer_shutdown, 115 .set_state_oneshot = goldfish_timer_set_oneshot, 116 .set_next_event = goldfish_timer_next_event, 117 }; 118 119 timerdrv->res = (struct resource){ 120 .name = "goldfish_timer", 121 .start = (unsigned long)base, 122 .end = (unsigned long)base + 0xfff, 123 }; 124 125 ret = request_resource(&iomem_resource, &timerdrv->res); 126 if (ret) { 127 pr_err("Cannot allocate '%s' resource\n", timerdrv->res.name); 128 return ret; 129 } 130 131 timerdrv->cs = (struct clocksource){ 132 .name = "goldfish_timer", 133 .rating = 400, 134 .read = goldfish_timer_read, 135 .mask = CLOCKSOURCE_MASK(64), 136 .flags = 0, 137 .max_idle_ns = LONG_MAX, 138 }; 139 140 clocksource_register_hz(&timerdrv->cs, NSEC_PER_SEC); 141 142 ret = request_irq(irq, goldfish_timer_irq, IRQF_TIMER, 143 "goldfish_timer", timerdrv); 144 if (ret) { 145 pr_err("Couldn't register goldfish-timer interrupt\n"); 146 return ret; 147 } 148 149 clockevents_config_and_register(&timerdrv->ced, NSEC_PER_SEC, 150 1, 0xffffffff); 151 152 return 0; 153}