1/*
2 *  linux/arch/arm/mach-integrator/core.c
3 *
4 *  Copyright (C) 2000-2003 Deep Blue Solutions Ltd
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2, as
8 * published by the Free Software Foundation.
9 */
10#include <linux/types.h>
11#include <linux/kernel.h>
12#include <linux/init.h>
13#include <linux/device.h>
14#include <linux/spinlock.h>
15#include <linux/interrupt.h>
16#include <linux/irq.h>
17#include <linux/sched.h>
18#include <linux/smp.h>
19#include <linux/termios.h>
20#include <linux/amba/bus.h>
21#include <linux/amba/serial.h>
22
23#include <asm/hardware.h>
24#include <asm/irq.h>
25#include <asm/io.h>
26#include <asm/hardware/arm_timer.h>
27#include <asm/arch/cm.h>
28#include <asm/system.h>
29#include <asm/leds.h>
30#include <asm/mach/time.h>
31
32#include "common.h"
33
34static struct amba_pl010_data integrator_uart_data;
35
36static struct amba_device rtc_device = {
37	.dev		= {
38		.bus_id	= "mb:15",
39	},
40	.res		= {
41		.start	= INTEGRATOR_RTC_BASE,
42		.end	= INTEGRATOR_RTC_BASE + SZ_4K - 1,
43		.flags	= IORESOURCE_MEM,
44	},
45	.irq		= { IRQ_RTCINT, NO_IRQ },
46	.periphid	= 0x00041030,
47};
48
49static struct amba_device uart0_device = {
50	.dev		= {
51		.bus_id	= "mb:16",
52		.platform_data = &integrator_uart_data,
53	},
54	.res		= {
55		.start	= INTEGRATOR_UART0_BASE,
56		.end	= INTEGRATOR_UART0_BASE + SZ_4K - 1,
57		.flags	= IORESOURCE_MEM,
58	},
59	.irq		= { IRQ_UARTINT0, NO_IRQ },
60	.periphid	= 0x0041010,
61};
62
63static struct amba_device uart1_device = {
64	.dev		= {
65		.bus_id	= "mb:17",
66		.platform_data = &integrator_uart_data,
67	},
68	.res		= {
69		.start	= INTEGRATOR_UART1_BASE,
70		.end	= INTEGRATOR_UART1_BASE + SZ_4K - 1,
71		.flags	= IORESOURCE_MEM,
72	},
73	.irq		= { IRQ_UARTINT1, NO_IRQ },
74	.periphid	= 0x0041010,
75};
76
77static struct amba_device kmi0_device = {
78	.dev		= {
79		.bus_id	= "mb:18",
80	},
81	.res		= {
82		.start	= KMI0_BASE,
83		.end	= KMI0_BASE + SZ_4K - 1,
84		.flags	= IORESOURCE_MEM,
85	},
86	.irq		= { IRQ_KMIINT0, NO_IRQ },
87	.periphid	= 0x00041050,
88};
89
90static struct amba_device kmi1_device = {
91	.dev		= {
92		.bus_id	= "mb:19",
93	},
94	.res		= {
95		.start	= KMI1_BASE,
96		.end	= KMI1_BASE + SZ_4K - 1,
97		.flags	= IORESOURCE_MEM,
98	},
99	.irq		= { IRQ_KMIINT1, NO_IRQ },
100	.periphid	= 0x00041050,
101};
102
103static struct amba_device *amba_devs[] __initdata = {
104	&rtc_device,
105	&uart0_device,
106	&uart1_device,
107	&kmi0_device,
108	&kmi1_device,
109};
110
111static int __init integrator_init(void)
112{
113	int i;
114
115	for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
116		struct amba_device *d = amba_devs[i];
117		amba_device_register(d, &iomem_resource);
118	}
119
120	return 0;
121}
122
123arch_initcall(integrator_init);
124
125/*
126 * On the Integrator platform, the port RTS and DTR are provided by
127 * bits in the following SC_CTRLS register bits:
128 *        RTS  DTR
129 *  UART0  7    6
130 *  UART1  5    4
131 */
132#define SC_CTRLC	(IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLC_OFFSET)
133#define SC_CTRLS	(IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLS_OFFSET)
134
135static void integrator_uart_set_mctrl(struct amba_device *dev, void __iomem *base, unsigned int mctrl)
136{
137	unsigned int ctrls = 0, ctrlc = 0, rts_mask, dtr_mask;
138
139	if (dev == &uart0_device) {
140		rts_mask = 1 << 4;
141		dtr_mask = 1 << 5;
142	} else {
143		rts_mask = 1 << 6;
144		dtr_mask = 1 << 7;
145	}
146
147	if (mctrl & TIOCM_RTS)
148		ctrlc |= rts_mask;
149	else
150		ctrls |= rts_mask;
151
152	if (mctrl & TIOCM_DTR)
153		ctrlc |= dtr_mask;
154	else
155		ctrls |= dtr_mask;
156
157	__raw_writel(ctrls, SC_CTRLS);
158	__raw_writel(ctrlc, SC_CTRLC);
159}
160
161static struct amba_pl010_data integrator_uart_data = {
162	.set_mctrl = integrator_uart_set_mctrl,
163};
164
165#define CM_CTRL	IO_ADDRESS(INTEGRATOR_HDR_BASE) + INTEGRATOR_HDR_CTRL_OFFSET
166
167static DEFINE_SPINLOCK(cm_lock);
168
169/**
170 * cm_control - update the CM_CTRL register.
171 * @mask: bits to change
172 * @set: bits to set
173 */
174void cm_control(u32 mask, u32 set)
175{
176	unsigned long flags;
177	u32 val;
178
179	spin_lock_irqsave(&cm_lock, flags);
180	val = readl(CM_CTRL) & ~mask;
181	writel(val | set, CM_CTRL);
182	spin_unlock_irqrestore(&cm_lock, flags);
183}
184
185EXPORT_SYMBOL(cm_control);
186
187/*
188 * Where is the timer (VA)?
189 */
190#define TIMER0_VA_BASE (IO_ADDRESS(INTEGRATOR_CT_BASE)+0x00000000)
191#define TIMER1_VA_BASE (IO_ADDRESS(INTEGRATOR_CT_BASE)+0x00000100)
192#define TIMER2_VA_BASE (IO_ADDRESS(INTEGRATOR_CT_BASE)+0x00000200)
193#define VA_IC_BASE     IO_ADDRESS(INTEGRATOR_IC_BASE)
194
195/*
196 * How long is the timer interval?
197 */
198#define TIMER_INTERVAL	(TICKS_PER_uSEC * mSEC_10)
199#if TIMER_INTERVAL >= 0x100000
200#define TICKS2USECS(x)	(256 * (x) / TICKS_PER_uSEC)
201#elif TIMER_INTERVAL >= 0x10000
202#define TICKS2USECS(x)	(16 * (x) / TICKS_PER_uSEC)
203#else
204#define TICKS2USECS(x)	((x) / TICKS_PER_uSEC)
205#endif
206
207static unsigned long timer_reload;
208
209/*
210 * Returns number of ms since last clock interrupt.  Note that interrupts
211 * will have been disabled by do_gettimeoffset()
212 */
213unsigned long integrator_gettimeoffset(void)
214{
215	unsigned long ticks1, ticks2, status;
216
217	/*
218	 * Get the current number of ticks.  Note that there is a race
219	 * condition between us reading the timer and checking for
220	 * an interrupt.  We get around this by ensuring that the
221	 * counter has not reloaded between our two reads.
222	 */
223	ticks2 = readl(TIMER1_VA_BASE + TIMER_VALUE) & 0xffff;
224	do {
225		ticks1 = ticks2;
226		status = __raw_readl(VA_IC_BASE + IRQ_RAW_STATUS);
227		ticks2 = readl(TIMER1_VA_BASE + TIMER_VALUE) & 0xffff;
228	} while (ticks2 > ticks1);
229
230	/*
231	 * Number of ticks since last interrupt.
232	 */
233	ticks1 = timer_reload - ticks2;
234
235	/*
236	 * Interrupt pending?  If so, we've reloaded once already.
237	 */
238	if (status & (1 << IRQ_TIMERINT1))
239		ticks1 += timer_reload;
240
241	/*
242	 * Convert the ticks to usecs
243	 */
244	return TICKS2USECS(ticks1);
245}
246
247/*
248 * IRQ handler for the timer
249 */
250static irqreturn_t
251integrator_timer_interrupt(int irq, void *dev_id)
252{
253	write_seqlock(&xtime_lock);
254
255	/*
256	 * clear the interrupt
257	 */
258	writel(1, TIMER1_VA_BASE + TIMER_INTCLR);
259
260	timer_tick();
261
262	write_sequnlock(&xtime_lock);
263
264	return IRQ_HANDLED;
265}
266
267static struct irqaction integrator_timer_irq = {
268	.name		= "Integrator Timer Tick",
269	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
270	.handler	= integrator_timer_interrupt,
271};
272
273/*
274 * Set up timer interrupt, and return the current time in seconds.
275 */
276void __init integrator_time_init(unsigned long reload, unsigned int ctrl)
277{
278	unsigned int timer_ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC;
279
280	timer_reload = reload;
281	timer_ctrl |= ctrl;
282
283	if (timer_reload > 0x100000) {
284		timer_reload >>= 8;
285		timer_ctrl |= TIMER_CTRL_DIV256;
286	} else if (timer_reload > 0x010000) {
287		timer_reload >>= 4;
288		timer_ctrl |= TIMER_CTRL_DIV16;
289	}
290
291	/*
292	 * Initialise to a known state (all timers off)
293	 */
294	writel(0, TIMER0_VA_BASE + TIMER_CTRL);
295	writel(0, TIMER1_VA_BASE + TIMER_CTRL);
296	writel(0, TIMER2_VA_BASE + TIMER_CTRL);
297
298	writel(timer_reload, TIMER1_VA_BASE + TIMER_LOAD);
299	writel(timer_reload, TIMER1_VA_BASE + TIMER_VALUE);
300	writel(timer_ctrl, TIMER1_VA_BASE + TIMER_CTRL);
301
302	/*
303	 * Make irqs happen for the system timer
304	 */
305	setup_irq(IRQ_TIMERINT1, &integrator_timer_irq);
306}
307