11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2217dd11eSRalf Baechle /*
3217dd11eSRalf Baechle * Copyright (C) 2000, 2001 Broadcom Corporation
4217dd11eSRalf Baechle */
5217dd11eSRalf Baechle #include <linux/clockchips.h>
6217dd11eSRalf Baechle #include <linux/interrupt.h>
7ca4d3e67SDavid Howells #include <linux/irq.h>
8217dd11eSRalf Baechle #include <linux/percpu.h>
9631330f5SRalf Baechle #include <linux/smp.h>
10217dd11eSRalf Baechle
11217dd11eSRalf Baechle #include <asm/addrspace.h>
12217dd11eSRalf Baechle #include <asm/io.h>
13217dd11eSRalf Baechle #include <asm/time.h>
14217dd11eSRalf Baechle
15217dd11eSRalf Baechle #include <asm/sibyte/sb1250.h>
16217dd11eSRalf Baechle #include <asm/sibyte/sb1250_regs.h>
17217dd11eSRalf Baechle #include <asm/sibyte/sb1250_int.h>
18217dd11eSRalf Baechle #include <asm/sibyte/sb1250_scd.h>
19217dd11eSRalf Baechle
20217dd11eSRalf Baechle #define IMR_IP2_VAL K_INT_MAP_I0
21217dd11eSRalf Baechle #define IMR_IP3_VAL K_INT_MAP_I1
22217dd11eSRalf Baechle #define IMR_IP4_VAL K_INT_MAP_I2
23217dd11eSRalf Baechle
24217dd11eSRalf Baechle /*
25217dd11eSRalf Baechle * The general purpose timer ticks at 1MHz independent if
26217dd11eSRalf Baechle * the rest of the system
27217dd11eSRalf Baechle */
2857e148caSViresh Kumar
sibyte_shutdown(struct clock_event_device * evt)2957e148caSViresh Kumar static int sibyte_shutdown(struct clock_event_device *evt)
3057e148caSViresh Kumar {
3157e148caSViresh Kumar void __iomem *cfg;
3257e148caSViresh Kumar
3357e148caSViresh Kumar cfg = IOADDR(A_SCD_TIMER_REGISTER(smp_processor_id(), R_SCD_TIMER_CFG));
3457e148caSViresh Kumar
3557e148caSViresh Kumar /* Stop the timer until we actually program a shot */
3657e148caSViresh Kumar __raw_writeq(0, cfg);
3757e148caSViresh Kumar
3857e148caSViresh Kumar return 0;
3957e148caSViresh Kumar }
4057e148caSViresh Kumar
sibyte_set_periodic(struct clock_event_device * evt)4157e148caSViresh Kumar static int sibyte_set_periodic(struct clock_event_device *evt)
42217dd11eSRalf Baechle {
43217dd11eSRalf Baechle unsigned int cpu = smp_processor_id();
44217dd11eSRalf Baechle void __iomem *cfg, *init;
45217dd11eSRalf Baechle
46217dd11eSRalf Baechle cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG));
47217dd11eSRalf Baechle init = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_INIT));
48217dd11eSRalf Baechle
49217dd11eSRalf Baechle __raw_writeq(0, cfg);
50217dd11eSRalf Baechle __raw_writeq((V_SCD_TIMER_FREQ / HZ) - 1, init);
5157e148caSViresh Kumar __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, cfg);
52217dd11eSRalf Baechle
5357e148caSViresh Kumar return 0;
54217dd11eSRalf Baechle }
55217dd11eSRalf Baechle
sibyte_next_event(unsigned long delta,struct clock_event_device * cd)56217dd11eSRalf Baechle static int sibyte_next_event(unsigned long delta, struct clock_event_device *cd)
57217dd11eSRalf Baechle {
58217dd11eSRalf Baechle unsigned int cpu = smp_processor_id();
59217dd11eSRalf Baechle void __iomem *cfg, *init;
60217dd11eSRalf Baechle
61217dd11eSRalf Baechle cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG));
62217dd11eSRalf Baechle init = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_INIT));
63217dd11eSRalf Baechle
648dfa741fSRalf Baechle __raw_writeq(0, cfg);
65217dd11eSRalf Baechle __raw_writeq(delta - 1, init);
66217dd11eSRalf Baechle __raw_writeq(M_SCD_TIMER_ENABLE, cfg);
67217dd11eSRalf Baechle
68217dd11eSRalf Baechle return 0;
69217dd11eSRalf Baechle }
70217dd11eSRalf Baechle
sibyte_counter_handler(int irq,void * dev_id)71217dd11eSRalf Baechle static irqreturn_t sibyte_counter_handler(int irq, void *dev_id)
72217dd11eSRalf Baechle {
73217dd11eSRalf Baechle unsigned int cpu = smp_processor_id();
74217dd11eSRalf Baechle struct clock_event_device *cd = dev_id;
75217dd11eSRalf Baechle void __iomem *cfg;
76217dd11eSRalf Baechle unsigned long tmode;
77217dd11eSRalf Baechle
7857e148caSViresh Kumar if (clockevent_state_periodic(cd))
79217dd11eSRalf Baechle tmode = M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS;
80217dd11eSRalf Baechle else
81217dd11eSRalf Baechle tmode = 0;
82217dd11eSRalf Baechle
83217dd11eSRalf Baechle /* ACK interrupt */
84217dd11eSRalf Baechle cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG));
85217dd11eSRalf Baechle ____raw_writeq(tmode, cfg);
86217dd11eSRalf Baechle
87217dd11eSRalf Baechle cd->event_handler(cd);
88217dd11eSRalf Baechle
89217dd11eSRalf Baechle return IRQ_HANDLED;
90217dd11eSRalf Baechle }
91217dd11eSRalf Baechle
92217dd11eSRalf Baechle static DEFINE_PER_CPU(struct clock_event_device, sibyte_hpt_clockevent);
93217dd11eSRalf Baechle static DEFINE_PER_CPU(char [18], sibyte_hpt_name);
94217dd11eSRalf Baechle
sb1250_clockevent_init(void)95078a55fcSPaul Gortmaker void sb1250_clockevent_init(void)
96217dd11eSRalf Baechle {
97217dd11eSRalf Baechle unsigned int cpu = smp_processor_id();
98217dd11eSRalf Baechle unsigned int irq = K_INT_TIMER_0 + cpu;
99217dd11eSRalf Baechle struct clock_event_device *cd = &per_cpu(sibyte_hpt_clockevent, cpu);
100217dd11eSRalf Baechle unsigned char *name = per_cpu(sibyte_hpt_name, cpu);
101ac8fd122Safzal mohammed unsigned long flags = IRQF_PERCPU | IRQF_TIMER;
102217dd11eSRalf Baechle
103217dd11eSRalf Baechle /* Only have 4 general purpose timers, and we use last one as hpt */
104217dd11eSRalf Baechle BUG_ON(cpu > 2);
105217dd11eSRalf Baechle
106217dd11eSRalf Baechle sprintf(name, "sb1250-counter-%d", cpu);
107217dd11eSRalf Baechle cd->name = name;
108217dd11eSRalf Baechle cd->features = CLOCK_EVT_FEAT_PERIODIC |
109217dd11eSRalf Baechle CLOCK_EVT_FEAT_ONESHOT;
110217dd11eSRalf Baechle clockevent_set_clock(cd, V_SCD_TIMER_FREQ);
111217dd11eSRalf Baechle cd->max_delta_ns = clockevent_delta2ns(0x7fffff, cd);
112e4db9253SNicolai Stange cd->max_delta_ticks = 0x7fffff;
11362247753SRalf Baechle cd->min_delta_ns = clockevent_delta2ns(2, cd);
114e4db9253SNicolai Stange cd->min_delta_ticks = 2;
115217dd11eSRalf Baechle cd->rating = 200;
116217dd11eSRalf Baechle cd->irq = irq;
117320ab2b0SRusty Russell cd->cpumask = cpumask_of(cpu);
118217dd11eSRalf Baechle cd->set_next_event = sibyte_next_event;
11957e148caSViresh Kumar cd->set_state_shutdown = sibyte_shutdown;
12057e148caSViresh Kumar cd->set_state_periodic = sibyte_set_periodic;
12157e148caSViresh Kumar cd->set_state_oneshot = sibyte_shutdown;
122217dd11eSRalf Baechle clockevents_register_device(cd);
123217dd11eSRalf Baechle
124217dd11eSRalf Baechle sb1250_mask_irq(cpu, irq);
125217dd11eSRalf Baechle
126217dd11eSRalf Baechle /*
127217dd11eSRalf Baechle * Map the timer interrupt to IP[4] of this cpu
128217dd11eSRalf Baechle */
129217dd11eSRalf Baechle __raw_writeq(IMR_IP4_VAL,
130217dd11eSRalf Baechle IOADDR(A_IMR_REGISTER(cpu, R_IMR_INTERRUPT_MAP_BASE) +
131217dd11eSRalf Baechle (irq << 3)));
132217dd11eSRalf Baechle
133217dd11eSRalf Baechle sb1250_unmask_irq(cpu, irq);
134217dd11eSRalf Baechle
1350de26520SRusty Russell irq_set_affinity(irq, cpumask_of(cpu));
136ac8fd122Safzal mohammed if (request_irq(irq, sibyte_counter_handler, flags, name, cd))
137ac8fd122Safzal mohammed pr_err("Failed to request irq %d (%s)\n", irq, name);
138217dd11eSRalf Baechle }
139