Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2020 Western Digital Corporation or its affiliates.
0004  *
0005  * Most of the M-mode (i.e. NoMMU) RISC-V systems usually have a
0006  * CLINT MMIO timer device.
0007  */
0008 
0009 #define pr_fmt(fmt) "clint: " fmt
0010 #include <linux/bitops.h>
0011 #include <linux/clocksource.h>
0012 #include <linux/clockchips.h>
0013 #include <linux/cpu.h>
0014 #include <linux/delay.h>
0015 #include <linux/module.h>
0016 #include <linux/of_address.h>
0017 #include <linux/sched_clock.h>
0018 #include <linux/io-64-nonatomic-lo-hi.h>
0019 #include <linux/interrupt.h>
0020 #include <linux/of_irq.h>
0021 #include <linux/smp.h>
0022 #include <linux/timex.h>
0023 
0024 #ifndef CONFIG_RISCV_M_MODE
0025 #include <asm/clint.h>
0026 #endif
0027 
0028 #define CLINT_IPI_OFF       0
0029 #define CLINT_TIMER_CMP_OFF 0x4000
0030 #define CLINT_TIMER_VAL_OFF 0xbff8
0031 
0032 /* CLINT manages IPI and Timer for RISC-V M-mode  */
0033 static u32 __iomem *clint_ipi_base;
0034 static u64 __iomem *clint_timer_cmp;
0035 static u64 __iomem *clint_timer_val;
0036 static unsigned long clint_timer_freq;
0037 static unsigned int clint_timer_irq;
0038 
0039 #ifdef CONFIG_RISCV_M_MODE
0040 u64 __iomem *clint_time_val;
0041 EXPORT_SYMBOL(clint_time_val);
0042 #endif
0043 
0044 static void clint_send_ipi(const struct cpumask *target)
0045 {
0046     unsigned int cpu;
0047 
0048     for_each_cpu(cpu, target)
0049         writel(1, clint_ipi_base + cpuid_to_hartid_map(cpu));
0050 }
0051 
0052 static void clint_clear_ipi(void)
0053 {
0054     writel(0, clint_ipi_base + cpuid_to_hartid_map(smp_processor_id()));
0055 }
0056 
0057 static struct riscv_ipi_ops clint_ipi_ops = {
0058     .ipi_inject = clint_send_ipi,
0059     .ipi_clear = clint_clear_ipi,
0060 };
0061 
0062 #ifdef CONFIG_64BIT
0063 #define clint_get_cycles()  readq_relaxed(clint_timer_val)
0064 #else
0065 #define clint_get_cycles()  readl_relaxed(clint_timer_val)
0066 #define clint_get_cycles_hi()   readl_relaxed(((u32 *)clint_timer_val) + 1)
0067 #endif
0068 
0069 #ifdef CONFIG_64BIT
0070 static u64 notrace clint_get_cycles64(void)
0071 {
0072     return clint_get_cycles();
0073 }
0074 #else /* CONFIG_64BIT */
0075 static u64 notrace clint_get_cycles64(void)
0076 {
0077     u32 hi, lo;
0078 
0079     do {
0080         hi = clint_get_cycles_hi();
0081         lo = clint_get_cycles();
0082     } while (hi != clint_get_cycles_hi());
0083 
0084     return ((u64)hi << 32) | lo;
0085 }
0086 #endif /* CONFIG_64BIT */
0087 
0088 static u64 clint_rdtime(struct clocksource *cs)
0089 {
0090     return clint_get_cycles64();
0091 }
0092 
0093 static struct clocksource clint_clocksource = {
0094     .name       = "clint_clocksource",
0095     .rating     = 300,
0096     .mask       = CLOCKSOURCE_MASK(64),
0097     .flags      = CLOCK_SOURCE_IS_CONTINUOUS,
0098     .read       = clint_rdtime,
0099 };
0100 
0101 static int clint_clock_next_event(unsigned long delta,
0102                    struct clock_event_device *ce)
0103 {
0104     void __iomem *r = clint_timer_cmp +
0105               cpuid_to_hartid_map(smp_processor_id());
0106 
0107     csr_set(CSR_IE, IE_TIE);
0108     writeq_relaxed(clint_get_cycles64() + delta, r);
0109     return 0;
0110 }
0111 
0112 static DEFINE_PER_CPU(struct clock_event_device, clint_clock_event) = {
0113     .name       = "clint_clockevent",
0114     .features   = CLOCK_EVT_FEAT_ONESHOT,
0115     .rating     = 100,
0116     .set_next_event = clint_clock_next_event,
0117 };
0118 
0119 static int clint_timer_starting_cpu(unsigned int cpu)
0120 {
0121     struct clock_event_device *ce = per_cpu_ptr(&clint_clock_event, cpu);
0122 
0123     ce->cpumask = cpumask_of(cpu);
0124     clockevents_config_and_register(ce, clint_timer_freq, 100, 0x7fffffff);
0125 
0126     enable_percpu_irq(clint_timer_irq,
0127               irq_get_trigger_type(clint_timer_irq));
0128     return 0;
0129 }
0130 
0131 static int clint_timer_dying_cpu(unsigned int cpu)
0132 {
0133     disable_percpu_irq(clint_timer_irq);
0134     return 0;
0135 }
0136 
0137 static irqreturn_t clint_timer_interrupt(int irq, void *dev_id)
0138 {
0139     struct clock_event_device *evdev = this_cpu_ptr(&clint_clock_event);
0140 
0141     csr_clear(CSR_IE, IE_TIE);
0142     evdev->event_handler(evdev);
0143 
0144     return IRQ_HANDLED;
0145 }
0146 
0147 static int __init clint_timer_init_dt(struct device_node *np)
0148 {
0149     int rc;
0150     u32 i, nr_irqs;
0151     void __iomem *base;
0152     struct of_phandle_args oirq;
0153 
0154     /*
0155      * Ensure that CLINT device interrupts are either RV_IRQ_TIMER or
0156      * RV_IRQ_SOFT. If it's anything else then we ignore the device.
0157      */
0158     nr_irqs = of_irq_count(np);
0159     for (i = 0; i < nr_irqs; i++) {
0160         if (of_irq_parse_one(np, i, &oirq)) {
0161             pr_err("%pOFP: failed to parse irq %d.\n", np, i);
0162             continue;
0163         }
0164 
0165         if ((oirq.args_count != 1) ||
0166             (oirq.args[0] != RV_IRQ_TIMER &&
0167              oirq.args[0] != RV_IRQ_SOFT)) {
0168             pr_err("%pOFP: invalid irq %d (hwirq %d)\n",
0169                    np, i, oirq.args[0]);
0170             return -ENODEV;
0171         }
0172 
0173         /* Find parent irq domain and map timer irq */
0174         if (!clint_timer_irq &&
0175             oirq.args[0] == RV_IRQ_TIMER &&
0176             irq_find_host(oirq.np))
0177             clint_timer_irq = irq_of_parse_and_map(np, i);
0178     }
0179 
0180     /* If CLINT timer irq not found then fail */
0181     if (!clint_timer_irq) {
0182         pr_err("%pOFP: timer irq not found\n", np);
0183         return -ENODEV;
0184     }
0185 
0186     base = of_iomap(np, 0);
0187     if (!base) {
0188         pr_err("%pOFP: could not map registers\n", np);
0189         return -ENODEV;
0190     }
0191 
0192     clint_ipi_base = base + CLINT_IPI_OFF;
0193     clint_timer_cmp = base + CLINT_TIMER_CMP_OFF;
0194     clint_timer_val = base + CLINT_TIMER_VAL_OFF;
0195     clint_timer_freq = riscv_timebase;
0196 
0197 #ifdef CONFIG_RISCV_M_MODE
0198     /*
0199      * Yes, that's an odd naming scheme.  time_val is public, but hopefully
0200      * will die in favor of something cleaner.
0201      */
0202     clint_time_val = clint_timer_val;
0203 #endif
0204 
0205     pr_info("%pOFP: timer running at %ld Hz\n", np, clint_timer_freq);
0206 
0207     rc = clocksource_register_hz(&clint_clocksource, clint_timer_freq);
0208     if (rc) {
0209         pr_err("%pOFP: clocksource register failed [%d]\n", np, rc);
0210         goto fail_iounmap;
0211     }
0212 
0213     sched_clock_register(clint_get_cycles64, 64, clint_timer_freq);
0214 
0215     rc = request_percpu_irq(clint_timer_irq, clint_timer_interrupt,
0216                  "clint-timer", &clint_clock_event);
0217     if (rc) {
0218         pr_err("registering percpu irq failed [%d]\n", rc);
0219         goto fail_iounmap;
0220     }
0221 
0222     rc = cpuhp_setup_state(CPUHP_AP_CLINT_TIMER_STARTING,
0223                 "clockevents/clint/timer:starting",
0224                 clint_timer_starting_cpu,
0225                 clint_timer_dying_cpu);
0226     if (rc) {
0227         pr_err("%pOFP: cpuhp setup state failed [%d]\n", np, rc);
0228         goto fail_free_irq;
0229     }
0230 
0231     riscv_set_ipi_ops(&clint_ipi_ops);
0232     clint_clear_ipi();
0233 
0234     return 0;
0235 
0236 fail_free_irq:
0237     free_irq(clint_timer_irq, &clint_clock_event);
0238 fail_iounmap:
0239     iounmap(base);
0240     return rc;
0241 }
0242 
0243 TIMER_OF_DECLARE(clint_timer, "riscv,clint0", clint_timer_init_dt);
0244 TIMER_OF_DECLARE(clint_timer1, "sifive,clint0", clint_timer_init_dt);