xref: /openbmc/linux/arch/mips/kernel/cevt-sb1250.c (revision ac8fd122)
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