Merge tag 'iio-for-5.11a' of https://git.kernel.org/pub/scm/linux/kernel/git/jic23...
[linux-2.6-microblaze.git] / arch / mips / kernel / cevt-sb1250.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (C) 2000, 2001 Broadcom Corporation
4  */
5 #include <linux/clockchips.h>
6 #include <linux/interrupt.h>
7 #include <linux/irq.h>
8 #include <linux/percpu.h>
9 #include <linux/smp.h>
10
11 #include <asm/addrspace.h>
12 #include <asm/io.h>
13 #include <asm/time.h>
14
15 #include <asm/sibyte/sb1250.h>
16 #include <asm/sibyte/sb1250_regs.h>
17 #include <asm/sibyte/sb1250_int.h>
18 #include <asm/sibyte/sb1250_scd.h>
19
20 #define IMR_IP2_VAL     K_INT_MAP_I0
21 #define IMR_IP3_VAL     K_INT_MAP_I1
22 #define IMR_IP4_VAL     K_INT_MAP_I2
23
24 /*
25  * The general purpose timer ticks at 1MHz independent if
26  * the rest of the system
27  */
28
29 static int sibyte_shutdown(struct clock_event_device *evt)
30 {
31         void __iomem *cfg;
32
33         cfg = IOADDR(A_SCD_TIMER_REGISTER(smp_processor_id(), R_SCD_TIMER_CFG));
34
35         /* Stop the timer until we actually program a shot */
36         __raw_writeq(0, cfg);
37
38         return 0;
39 }
40
41 static int sibyte_set_periodic(struct clock_event_device *evt)
42 {
43         unsigned int cpu = smp_processor_id();
44         void __iomem *cfg, *init;
45
46         cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG));
47         init = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_INIT));
48
49         __raw_writeq(0, cfg);
50         __raw_writeq((V_SCD_TIMER_FREQ / HZ) - 1, init);
51         __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, cfg);
52
53         return 0;
54 }
55
56 static int sibyte_next_event(unsigned long delta, struct clock_event_device *cd)
57 {
58         unsigned int cpu = smp_processor_id();
59         void __iomem *cfg, *init;
60
61         cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG));
62         init = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_INIT));
63
64         __raw_writeq(0, cfg);
65         __raw_writeq(delta - 1, init);
66         __raw_writeq(M_SCD_TIMER_ENABLE, cfg);
67
68         return 0;
69 }
70
71 static irqreturn_t sibyte_counter_handler(int irq, void *dev_id)
72 {
73         unsigned int cpu = smp_processor_id();
74         struct clock_event_device *cd = dev_id;
75         void __iomem *cfg;
76         unsigned long tmode;
77
78         if (clockevent_state_periodic(cd))
79                 tmode = M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS;
80         else
81                 tmode = 0;
82
83         /* ACK interrupt */
84         cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG));
85         ____raw_writeq(tmode, cfg);
86
87         cd->event_handler(cd);
88
89         return IRQ_HANDLED;
90 }
91
92 static DEFINE_PER_CPU(struct clock_event_device, sibyte_hpt_clockevent);
93 static DEFINE_PER_CPU(char [18], sibyte_hpt_name);
94
95 void sb1250_clockevent_init(void)
96 {
97         unsigned int cpu = smp_processor_id();
98         unsigned int irq = K_INT_TIMER_0 + cpu;
99         struct clock_event_device *cd = &per_cpu(sibyte_hpt_clockevent, cpu);
100         unsigned char *name = per_cpu(sibyte_hpt_name, cpu);
101         unsigned long flags = IRQF_PERCPU | IRQF_TIMER;
102
103         /* Only have 4 general purpose timers, and we use last one as hpt */
104         BUG_ON(cpu > 2);
105
106         sprintf(name, "sb1250-counter-%d", cpu);
107         cd->name                = name;
108         cd->features            = CLOCK_EVT_FEAT_PERIODIC |
109                                   CLOCK_EVT_FEAT_ONESHOT;
110         clockevent_set_clock(cd, V_SCD_TIMER_FREQ);
111         cd->max_delta_ns        = clockevent_delta2ns(0x7fffff, cd);
112         cd->max_delta_ticks     = 0x7fffff;
113         cd->min_delta_ns        = clockevent_delta2ns(2, cd);
114         cd->min_delta_ticks     = 2;
115         cd->rating              = 200;
116         cd->irq                 = irq;
117         cd->cpumask             = cpumask_of(cpu);
118         cd->set_next_event      = sibyte_next_event;
119         cd->set_state_shutdown  = sibyte_shutdown;
120         cd->set_state_periodic  = sibyte_set_periodic;
121         cd->set_state_oneshot   = sibyte_shutdown;
122         clockevents_register_device(cd);
123
124         sb1250_mask_irq(cpu, irq);
125
126         /*
127          * Map the timer interrupt to IP[4] of this cpu
128          */
129         __raw_writeq(IMR_IP4_VAL,
130                      IOADDR(A_IMR_REGISTER(cpu, R_IMR_INTERRUPT_MAP_BASE) +
131                             (irq << 3)));
132
133         sb1250_unmask_irq(cpu, irq);
134
135         irq_set_affinity(irq, cpumask_of(cpu));
136         if (request_irq(irq, sibyte_counter_handler, flags, name, cd))
137                 pr_err("Failed to request irq %d (%s)\n", irq, name);
138 }