Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * J-Core SoC PIT/clocksource driver
0004  *
0005  * Copyright (C) 2015-2016 Smart Energy Instruments, Inc.
0006  */
0007 
0008 #include <linux/kernel.h>
0009 #include <linux/slab.h>
0010 #include <linux/interrupt.h>
0011 #include <linux/clockchips.h>
0012 #include <linux/clocksource.h>
0013 #include <linux/sched_clock.h>
0014 #include <linux/cpu.h>
0015 #include <linux/cpuhotplug.h>
0016 #include <linux/of_address.h>
0017 #include <linux/of_irq.h>
0018 
0019 #define PIT_IRQ_SHIFT       12
0020 #define PIT_PRIO_SHIFT      20
0021 #define PIT_ENABLE_SHIFT    26
0022 #define PIT_PRIO_MASK       0xf
0023 
0024 #define REG_PITEN       0x00
0025 #define REG_THROT       0x10
0026 #define REG_COUNT       0x14
0027 #define REG_BUSPD       0x18
0028 #define REG_SECHI       0x20
0029 #define REG_SECLO       0x24
0030 #define REG_NSEC        0x28
0031 
0032 struct jcore_pit {
0033     struct clock_event_device   ced;
0034     void __iomem            *base;
0035     unsigned long           periodic_delta;
0036     u32             enable_val;
0037 };
0038 
0039 static void __iomem *jcore_pit_base;
0040 static struct jcore_pit __percpu *jcore_pit_percpu;
0041 
0042 static notrace u64 jcore_sched_clock_read(void)
0043 {
0044     u32 seclo, nsec, seclo0;
0045     __iomem void *base = jcore_pit_base;
0046 
0047     seclo = readl(base + REG_SECLO);
0048     do {
0049         seclo0 = seclo;
0050         nsec  = readl(base + REG_NSEC);
0051         seclo = readl(base + REG_SECLO);
0052     } while (seclo0 != seclo);
0053 
0054     return seclo * NSEC_PER_SEC + nsec;
0055 }
0056 
0057 static u64 jcore_clocksource_read(struct clocksource *cs)
0058 {
0059     return jcore_sched_clock_read();
0060 }
0061 
0062 static int jcore_pit_disable(struct jcore_pit *pit)
0063 {
0064     writel(0, pit->base + REG_PITEN);
0065     return 0;
0066 }
0067 
0068 static int jcore_pit_set(unsigned long delta, struct jcore_pit *pit)
0069 {
0070     jcore_pit_disable(pit);
0071     writel(delta, pit->base + REG_THROT);
0072     writel(pit->enable_val, pit->base + REG_PITEN);
0073     return 0;
0074 }
0075 
0076 static int jcore_pit_set_state_shutdown(struct clock_event_device *ced)
0077 {
0078     struct jcore_pit *pit = container_of(ced, struct jcore_pit, ced);
0079 
0080     return jcore_pit_disable(pit);
0081 }
0082 
0083 static int jcore_pit_set_state_oneshot(struct clock_event_device *ced)
0084 {
0085     struct jcore_pit *pit = container_of(ced, struct jcore_pit, ced);
0086 
0087     return jcore_pit_disable(pit);
0088 }
0089 
0090 static int jcore_pit_set_state_periodic(struct clock_event_device *ced)
0091 {
0092     struct jcore_pit *pit = container_of(ced, struct jcore_pit, ced);
0093 
0094     return jcore_pit_set(pit->periodic_delta, pit);
0095 }
0096 
0097 static int jcore_pit_set_next_event(unsigned long delta,
0098                     struct clock_event_device *ced)
0099 {
0100     struct jcore_pit *pit = container_of(ced, struct jcore_pit, ced);
0101 
0102     return jcore_pit_set(delta, pit);
0103 }
0104 
0105 static int jcore_pit_local_init(unsigned cpu)
0106 {
0107     struct jcore_pit *pit = this_cpu_ptr(jcore_pit_percpu);
0108     unsigned buspd, freq;
0109 
0110     pr_info("Local J-Core PIT init on cpu %u\n", cpu);
0111 
0112     buspd = readl(pit->base + REG_BUSPD);
0113     freq = DIV_ROUND_CLOSEST(NSEC_PER_SEC, buspd);
0114     pit->periodic_delta = DIV_ROUND_CLOSEST(NSEC_PER_SEC, HZ * buspd);
0115 
0116     clockevents_config_and_register(&pit->ced, freq, 1, ULONG_MAX);
0117 
0118     return 0;
0119 }
0120 
0121 static irqreturn_t jcore_timer_interrupt(int irq, void *dev_id)
0122 {
0123     struct jcore_pit *pit = this_cpu_ptr(dev_id);
0124 
0125     if (clockevent_state_oneshot(&pit->ced))
0126         jcore_pit_disable(pit);
0127 
0128     pit->ced.event_handler(&pit->ced);
0129 
0130     return IRQ_HANDLED;
0131 }
0132 
0133 static int __init jcore_pit_init(struct device_node *node)
0134 {
0135     int err;
0136     unsigned pit_irq, cpu;
0137     unsigned long hwirq;
0138     u32 irqprio, enable_val;
0139 
0140     jcore_pit_base = of_iomap(node, 0);
0141     if (!jcore_pit_base) {
0142         pr_err("Error: Cannot map base address for J-Core PIT\n");
0143         return -ENXIO;
0144     }
0145 
0146     pit_irq = irq_of_parse_and_map(node, 0);
0147     if (!pit_irq) {
0148         pr_err("Error: J-Core PIT has no IRQ\n");
0149         return -ENXIO;
0150     }
0151 
0152     pr_info("Initializing J-Core PIT at %p IRQ %d\n",
0153         jcore_pit_base, pit_irq);
0154 
0155     err = clocksource_mmio_init(jcore_pit_base, "jcore_pit_cs",
0156                     NSEC_PER_SEC, 400, 32,
0157                     jcore_clocksource_read);
0158     if (err) {
0159         pr_err("Error registering clocksource device: %d\n", err);
0160         return err;
0161     }
0162 
0163     sched_clock_register(jcore_sched_clock_read, 32, NSEC_PER_SEC);
0164 
0165     jcore_pit_percpu = alloc_percpu(struct jcore_pit);
0166     if (!jcore_pit_percpu) {
0167         pr_err("Failed to allocate memory for clock event device\n");
0168         return -ENOMEM;
0169     }
0170 
0171     err = request_irq(pit_irq, jcore_timer_interrupt,
0172               IRQF_TIMER | IRQF_PERCPU,
0173               "jcore_pit", jcore_pit_percpu);
0174     if (err) {
0175         pr_err("pit irq request failed: %d\n", err);
0176         free_percpu(jcore_pit_percpu);
0177         return err;
0178     }
0179 
0180     /*
0181      * The J-Core PIT is not hard-wired to a particular IRQ, but
0182      * integrated with the interrupt controller such that the IRQ it
0183      * generates is programmable, as follows:
0184      *
0185      * The bit layout of the PIT enable register is:
0186      *
0187      *  .....e..ppppiiiiiiii............
0188      *
0189      * where the .'s indicate unrelated/unused bits, e is enable,
0190      * p is priority, and i is hard irq number.
0191      *
0192      * For the PIT included in AIC1 (obsolete but still in use),
0193      * any hard irq (trap number) can be programmed via the 8
0194      * iiiiiiii bits, and a priority (0-15) is programmable
0195      * separately in the pppp bits.
0196      *
0197      * For the PIT included in AIC2 (current), the programming
0198      * interface is equivalent modulo interrupt mapping. This is
0199      * why a different compatible tag was not used. However only
0200      * traps 64-127 (the ones actually intended to be used for
0201      * interrupts, rather than syscalls/exceptions/etc.) can be
0202      * programmed (the high 2 bits of i are ignored) and the
0203      * priority pppp is <<2'd and or'd onto the irq number. This
0204      * choice seems to have been made on the hardware engineering
0205      * side under an assumption that preserving old AIC1 priority
0206      * mappings was important. Future models will likely ignore
0207      * the pppp field.
0208      */
0209     hwirq = irq_get_irq_data(pit_irq)->hwirq;
0210     irqprio = (hwirq >> 2) & PIT_PRIO_MASK;
0211     enable_val = (1U << PIT_ENABLE_SHIFT)
0212            | (hwirq << PIT_IRQ_SHIFT)
0213            | (irqprio << PIT_PRIO_SHIFT);
0214 
0215     for_each_present_cpu(cpu) {
0216         struct jcore_pit *pit = per_cpu_ptr(jcore_pit_percpu, cpu);
0217 
0218         pit->base = of_iomap(node, cpu);
0219         if (!pit->base) {
0220             pr_err("Unable to map PIT for cpu %u\n", cpu);
0221             continue;
0222         }
0223 
0224         pit->ced.name = "jcore_pit";
0225         pit->ced.features = CLOCK_EVT_FEAT_PERIODIC
0226                   | CLOCK_EVT_FEAT_ONESHOT
0227                   | CLOCK_EVT_FEAT_PERCPU;
0228         pit->ced.cpumask = cpumask_of(cpu);
0229         pit->ced.rating = 400;
0230         pit->ced.irq = pit_irq;
0231         pit->ced.set_state_shutdown = jcore_pit_set_state_shutdown;
0232         pit->ced.set_state_periodic = jcore_pit_set_state_periodic;
0233         pit->ced.set_state_oneshot = jcore_pit_set_state_oneshot;
0234         pit->ced.set_next_event = jcore_pit_set_next_event;
0235 
0236         pit->enable_val = enable_val;
0237     }
0238 
0239     cpuhp_setup_state(CPUHP_AP_JCORE_TIMER_STARTING,
0240               "clockevents/jcore:starting",
0241               jcore_pit_local_init, NULL);
0242 
0243     return 0;
0244 }
0245 
0246 TIMER_OF_DECLARE(jcore_pit, "jcore,pit", jcore_pit_init);