Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 
0003 #include <linux/interrupt.h>
0004 #include <linux/ioport.h>
0005 #include <linux/clocksource.h>
0006 #include <linux/clockchips.h>
0007 #include <linux/module.h>
0008 #include <linux/slab.h>
0009 #include <linux/goldfish.h>
0010 #include <clocksource/timer-goldfish.h>
0011 
0012 struct goldfish_timer {
0013     struct clocksource cs;
0014     struct clock_event_device ced;
0015     struct resource res;
0016     void __iomem *base;
0017 };
0018 
0019 static struct goldfish_timer *ced_to_gf(struct clock_event_device *ced)
0020 {
0021     return container_of(ced, struct goldfish_timer, ced);
0022 }
0023 
0024 static struct goldfish_timer *cs_to_gf(struct clocksource *cs)
0025 {
0026     return container_of(cs, struct goldfish_timer, cs);
0027 }
0028 
0029 static u64 goldfish_timer_read(struct clocksource *cs)
0030 {
0031     struct goldfish_timer *timerdrv = cs_to_gf(cs);
0032     void __iomem *base = timerdrv->base;
0033     u32 time_low, time_high;
0034     u64 ticks;
0035 
0036     /*
0037      * time_low: get low bits of current time and update time_high
0038      * time_high: get high bits of time at last time_low read
0039      */
0040     time_low = gf_ioread32(base + TIMER_TIME_LOW);
0041     time_high = gf_ioread32(base + TIMER_TIME_HIGH);
0042 
0043     ticks = ((u64)time_high << 32) | time_low;
0044 
0045     return ticks;
0046 }
0047 
0048 static int goldfish_timer_set_oneshot(struct clock_event_device *evt)
0049 {
0050     struct goldfish_timer *timerdrv = ced_to_gf(evt);
0051     void __iomem *base = timerdrv->base;
0052 
0053     gf_iowrite32(0, base + TIMER_ALARM_HIGH);
0054     gf_iowrite32(0, base + TIMER_ALARM_LOW);
0055     gf_iowrite32(1, base + TIMER_IRQ_ENABLED);
0056 
0057     return 0;
0058 }
0059 
0060 static int goldfish_timer_shutdown(struct clock_event_device *evt)
0061 {
0062     struct goldfish_timer *timerdrv = ced_to_gf(evt);
0063     void __iomem *base = timerdrv->base;
0064 
0065     gf_iowrite32(0, base + TIMER_IRQ_ENABLED);
0066 
0067     return 0;
0068 }
0069 
0070 static int goldfish_timer_next_event(unsigned long delta,
0071                      struct clock_event_device *evt)
0072 {
0073     struct goldfish_timer *timerdrv = ced_to_gf(evt);
0074     void __iomem *base = timerdrv->base;
0075     u64 now;
0076 
0077     now = goldfish_timer_read(&timerdrv->cs);
0078 
0079     now += delta;
0080 
0081     gf_iowrite32(upper_32_bits(now), base + TIMER_ALARM_HIGH);
0082     gf_iowrite32(lower_32_bits(now), base + TIMER_ALARM_LOW);
0083 
0084     return 0;
0085 }
0086 
0087 static irqreturn_t goldfish_timer_irq(int irq, void *dev_id)
0088 {
0089     struct goldfish_timer *timerdrv = dev_id;
0090     struct clock_event_device *evt = &timerdrv->ced;
0091     void __iomem *base = timerdrv->base;
0092 
0093     gf_iowrite32(1, base + TIMER_CLEAR_INTERRUPT);
0094 
0095     evt->event_handler(evt);
0096 
0097     return IRQ_HANDLED;
0098 }
0099 
0100 int __init goldfish_timer_init(int irq, void __iomem *base)
0101 {
0102     struct goldfish_timer *timerdrv;
0103     int ret;
0104 
0105     timerdrv = kzalloc(sizeof(*timerdrv), GFP_KERNEL);
0106     if (!timerdrv)
0107         return -ENOMEM;
0108 
0109     timerdrv->base = base;
0110 
0111     timerdrv->ced = (struct clock_event_device){
0112         .name           = "goldfish_timer",
0113         .features       = CLOCK_EVT_FEAT_ONESHOT,
0114         .set_state_shutdown = goldfish_timer_shutdown,
0115         .set_state_oneshot      = goldfish_timer_set_oneshot,
0116         .set_next_event     = goldfish_timer_next_event,
0117     };
0118 
0119     timerdrv->res = (struct resource){
0120         .name  = "goldfish_timer",
0121         .start = (unsigned long)base,
0122         .end   = (unsigned long)base + 0xfff,
0123     };
0124 
0125     ret = request_resource(&iomem_resource, &timerdrv->res);
0126     if (ret) {
0127         pr_err("Cannot allocate '%s' resource\n", timerdrv->res.name);
0128         return ret;
0129     }
0130 
0131     timerdrv->cs = (struct clocksource){
0132         .name       = "goldfish_timer",
0133         .rating     = 400,
0134         .read       = goldfish_timer_read,
0135         .mask       = CLOCKSOURCE_MASK(64),
0136         .flags      = 0,
0137         .max_idle_ns    = LONG_MAX,
0138     };
0139 
0140     clocksource_register_hz(&timerdrv->cs, NSEC_PER_SEC);
0141 
0142     ret = request_irq(irq, goldfish_timer_irq, IRQF_TIMER,
0143               "goldfish_timer", timerdrv);
0144     if (ret) {
0145         pr_err("Couldn't register goldfish-timer interrupt\n");
0146         return ret;
0147     }
0148 
0149     clockevents_config_and_register(&timerdrv->ced, NSEC_PER_SEC,
0150                     1, 0xffffffff);
0151 
0152     return 0;
0153 }