blob: 68ee82b49597bedf759cb9b35ba48c0bc682d723 [file] [log] [blame]
Lennert Buytenheke7736d42006-03-20 17:10:13 +00001/*
2 * arch/arm/mach-ep93xx/core.c
3 * Core routines for Cirrus EP93xx chips.
4 *
5 * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
Herbert Valerio Riedel3c9a0712007-11-26 18:49:08 +01006 * Copyright (C) 2007 Herbert Valerio Riedel <hvr@gnu.org>
Lennert Buytenheke7736d42006-03-20 17:10:13 +00007 *
8 * Thanks go to Michael Burian and Ray Lehtiniemi for their key
9 * role in the ep93xx linux community.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or (at
14 * your option) any later version.
15 */
16
Lennert Buytenheke7736d42006-03-20 17:10:13 +000017#include <linux/kernel.h>
18#include <linux/init.h>
19#include <linux/spinlock.h>
20#include <linux/sched.h>
21#include <linux/interrupt.h>
22#include <linux/serial.h>
23#include <linux/tty.h>
24#include <linux/bitops.h>
Lennert Buytenheke7736d42006-03-20 17:10:13 +000025#include <linux/serial_8250.h>
26#include <linux/serial_core.h>
27#include <linux/device.h>
28#include <linux/mm.h>
29#include <linux/time.h>
30#include <linux/timex.h>
31#include <linux/delay.h>
Lennert Buytenhekaee85fe2006-03-26 23:16:39 +010032#include <linux/termios.h>
Lennert Buytenheke7736d42006-03-20 17:10:13 +000033#include <linux/amba/bus.h>
Lennert Buytenhekaee85fe2006-03-26 23:16:39 +010034#include <linux/amba/serial.h>
Lennert Buytenheke7736d42006-03-20 17:10:13 +000035
36#include <asm/types.h>
37#include <asm/setup.h>
38#include <asm/memory.h>
Russell Kinga09e64f2008-08-05 16:14:15 +010039#include <mach/hardware.h>
Lennert Buytenheke7736d42006-03-20 17:10:13 +000040#include <asm/irq.h>
41#include <asm/system.h>
42#include <asm/tlbflush.h>
43#include <asm/pgtable.h>
44#include <asm/io.h>
45
46#include <asm/mach/map.h>
47#include <asm/mach/time.h>
48#include <asm/mach/irq.h>
Russell Kinga09e64f2008-08-05 16:14:15 +010049#include <mach/gpio.h>
Lennert Buytenheke7736d42006-03-20 17:10:13 +000050
51#include <asm/hardware/vic.h>
52
53
54/*************************************************************************
55 * Static I/O mappings that are needed for all EP93xx platforms
56 *************************************************************************/
57static struct map_desc ep93xx_io_desc[] __initdata = {
58 {
59 .virtual = EP93XX_AHB_VIRT_BASE,
60 .pfn = __phys_to_pfn(EP93XX_AHB_PHYS_BASE),
61 .length = EP93XX_AHB_SIZE,
62 .type = MT_DEVICE,
63 }, {
64 .virtual = EP93XX_APB_VIRT_BASE,
65 .pfn = __phys_to_pfn(EP93XX_APB_PHYS_BASE),
66 .length = EP93XX_APB_SIZE,
67 .type = MT_DEVICE,
68 },
69};
70
71void __init ep93xx_map_io(void)
72{
73 iotable_init(ep93xx_io_desc, ARRAY_SIZE(ep93xx_io_desc));
74}
75
76
77/*************************************************************************
78 * Timer handling for EP93xx
79 *************************************************************************
80 * The ep93xx has four internal timers. Timers 1, 2 (both 16 bit) and
81 * 3 (32 bit) count down at 508 kHz, are self-reloading, and can generate
82 * an interrupt on underflow. Timer 4 (40 bit) counts down at 983.04 kHz,
83 * is free-running, and can't generate interrupts.
84 *
85 * The 508 kHz timers are ideal for use for the timer interrupt, as the
86 * most common values of HZ divide 508 kHz nicely. We pick one of the 16
87 * bit timers (timer 1) since we don't need more than 16 bits of reload
88 * value as long as HZ >= 8.
89 *
90 * The higher clock rate of timer 4 makes it a better choice than the
91 * other timers for use in gettimeoffset(), while the fact that it can't
92 * generate interrupts means we don't have to worry about not being able
93 * to use this timer for something else. We also use timer 4 for keeping
94 * track of lost jiffies.
95 */
96static unsigned int last_jiffy_time;
97
98#define TIMER4_TICKS_PER_JIFFY ((CLOCK_TICK_RATE + (HZ/2)) / HZ)
99
Linus Torvalds0cd61b62006-10-06 10:53:39 -0700100static int ep93xx_timer_interrupt(int irq, void *dev_id)
Lennert Buytenheke7736d42006-03-20 17:10:13 +0000101{
Lennert Buytenheke7736d42006-03-20 17:10:13 +0000102 __raw_writel(1, EP93XX_TIMER1_CLEAR);
Lennert Buytenhekf869afa2006-06-22 10:30:53 +0100103 while ((signed long)
104 (__raw_readl(EP93XX_TIMER4_VALUE_LOW) - last_jiffy_time)
Lennert Buytenheke7736d42006-03-20 17:10:13 +0000105 >= TIMER4_TICKS_PER_JIFFY) {
106 last_jiffy_time += TIMER4_TICKS_PER_JIFFY;
Linus Torvalds0cd61b62006-10-06 10:53:39 -0700107 timer_tick();
Lennert Buytenheke7736d42006-03-20 17:10:13 +0000108 }
109
Lennert Buytenheke7736d42006-03-20 17:10:13 +0000110 return IRQ_HANDLED;
111}
112
113static struct irqaction ep93xx_timer_irq = {
114 .name = "ep93xx timer",
Bernhard Walleb30faba2007-05-08 00:35:39 -0700115 .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
Lennert Buytenheke7736d42006-03-20 17:10:13 +0000116 .handler = ep93xx_timer_interrupt,
117};
118
119static void __init ep93xx_timer_init(void)
120{
121 /* Enable periodic HZ timer. */
122 __raw_writel(0x48, EP93XX_TIMER1_CONTROL);
Lennert Buytenheka059e332006-06-22 10:30:54 +0100123 __raw_writel((508469 / HZ) - 1, EP93XX_TIMER1_LOAD);
Lennert Buytenheke7736d42006-03-20 17:10:13 +0000124 __raw_writel(0xc8, EP93XX_TIMER1_CONTROL);
125
126 /* Enable lost jiffy timer. */
127 __raw_writel(0x100, EP93XX_TIMER4_VALUE_HIGH);
128
129 setup_irq(IRQ_EP93XX_TIMER1, &ep93xx_timer_irq);
130}
131
132static unsigned long ep93xx_gettimeoffset(void)
133{
134 int offset;
135
136 offset = __raw_readl(EP93XX_TIMER4_VALUE_LOW) - last_jiffy_time;
137
138 /* Calculate (1000000 / 983040) * offset. */
139 return offset + (53 * offset / 3072);
140}
141
142struct sys_timer ep93xx_timer = {
143 .init = ep93xx_timer_init,
144 .offset = ep93xx_gettimeoffset,
145};
146
147
148/*************************************************************************
Lennert Buytenheka8e19662006-03-20 17:10:14 +0000149 * GPIO handling for EP93xx
150 *************************************************************************/
Lennert Buytenhek271f5ca2007-02-08 01:01:41 +0100151static unsigned char gpio_int_unmasked[3];
152static unsigned char gpio_int_enabled[3];
Lennert Buytenhek4932e392007-02-05 00:38:48 +0100153static unsigned char gpio_int_type1[3];
154static unsigned char gpio_int_type2[3];
Lennert Buytenhekbd20ff52006-03-20 21:02:37 +0000155
Herbert Valerio Riedel7ca72252007-11-26 18:45:59 +0100156/* Port ordering is: A B F */
157static const u8 int_type1_register_offset[3] = { 0x90, 0xac, 0x4c };
158static const u8 int_type2_register_offset[3] = { 0x94, 0xb0, 0x50 };
159static const u8 eoi_register_offset[3] = { 0x98, 0xb4, 0x54 };
160static const u8 int_en_register_offset[3] = { 0x9c, 0xb8, 0x5c };
161
Ryan Mallonb6850042008-04-16 02:56:35 +0100162void ep93xx_gpio_update_int_params(unsigned port)
Lennert Buytenhekbd20ff52006-03-20 21:02:37 +0000163{
Herbert Valerio Riedel7ca72252007-11-26 18:45:59 +0100164 BUG_ON(port > 2);
165
166 __raw_writeb(0, EP93XX_GPIO_REG(int_en_register_offset[port]));
167
168 __raw_writeb(gpio_int_type2[port],
169 EP93XX_GPIO_REG(int_type2_register_offset[port]));
170
171 __raw_writeb(gpio_int_type1[port],
172 EP93XX_GPIO_REG(int_type1_register_offset[port]));
173
174 __raw_writeb(gpio_int_unmasked[port] & gpio_int_enabled[port],
175 EP93XX_GPIO_REG(int_en_register_offset[port]));
Lennert Buytenhekbd20ff52006-03-20 21:02:37 +0000176}
177
Ryan Mallonb6850042008-04-16 02:56:35 +0100178void ep93xx_gpio_int_mask(unsigned line)
Lennert Buytenheka8e19662006-03-20 17:10:14 +0000179{
Ryan Mallonb6850042008-04-16 02:56:35 +0100180 gpio_int_unmasked[line >> 3] &= ~(1 << (line & 7));
Lennert Buytenheka8e19662006-03-20 17:10:14 +0000181}
Lennert Buytenheka8e19662006-03-20 17:10:14 +0000182
Lennert Buytenheka8e19662006-03-20 17:10:14 +0000183/*************************************************************************
Lennert Buytenheke7736d42006-03-20 17:10:13 +0000184 * EP93xx IRQ handling
185 *************************************************************************/
Lennert Buytenhek4932e392007-02-05 00:38:48 +0100186static void ep93xx_gpio_ab_irq_handler(unsigned int irq, struct irq_desc *desc)
Lennert Buytenhekbd20ff52006-03-20 21:02:37 +0000187{
188 unsigned char status;
189 int i;
190
191 status = __raw_readb(EP93XX_GPIO_A_INT_STATUS);
192 for (i = 0; i < 8; i++) {
193 if (status & (1 << i)) {
Herbert Valerio Riedel7ca72252007-11-26 18:45:59 +0100194 int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_A(0)) + i;
Dmitry Baryshkovd8aa0252008-10-09 13:36:24 +0100195 generic_handle_irq(gpio_irq);
Lennert Buytenhekbd20ff52006-03-20 21:02:37 +0000196 }
197 }
198
199 status = __raw_readb(EP93XX_GPIO_B_INT_STATUS);
200 for (i = 0; i < 8; i++) {
201 if (status & (1 << i)) {
Herbert Valerio Riedel7ca72252007-11-26 18:45:59 +0100202 int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_B(0)) + i;
203 desc = irq_desc + gpio_irq;
Dmitry Baryshkovd8aa0252008-10-09 13:36:24 +0100204 generic_handle_irq(gpio_irq);
Lennert Buytenhekbd20ff52006-03-20 21:02:37 +0000205 }
206 }
207}
208
Lennert Buytenhek4932e392007-02-05 00:38:48 +0100209static void ep93xx_gpio_f_irq_handler(unsigned int irq, struct irq_desc *desc)
210{
Herbert Valerio Riedel7ca72252007-11-26 18:45:59 +0100211 /*
212 * map discontiguous hw irq range to continous sw irq range:
213 *
214 * IRQ_EP93XX_GPIO{0..7}MUX -> gpio_to_irq(EP93XX_GPIO_LINE_F({0..7})
215 */
216 int port_f_idx = ((irq + 1) & 7) ^ 4; /* {19..22,47..50} -> {0..7} */
217 int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_F(0)) + port_f_idx;
Lennert Buytenhek4932e392007-02-05 00:38:48 +0100218
Dmitry Baryshkovd8aa0252008-10-09 13:36:24 +0100219 generic_handle_irq(gpio_irq);
Lennert Buytenhek4932e392007-02-05 00:38:48 +0100220}
221
Herbert Valerio Riedel3c9a0712007-11-26 18:49:08 +0100222static void ep93xx_gpio_irq_ack(unsigned int irq)
223{
224 int line = irq_to_gpio(irq);
225 int port = line >> 3;
226 int port_mask = 1 << (line & 7);
227
Dmitry Baryshkov6cab4862008-07-27 04:23:31 +0100228 if ((irq_desc[irq].status & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) {
Herbert Valerio Riedel3c9a0712007-11-26 18:49:08 +0100229 gpio_int_type2[port] ^= port_mask; /* switch edge direction */
Ryan Mallonb6850042008-04-16 02:56:35 +0100230 ep93xx_gpio_update_int_params(port);
Herbert Valerio Riedel3c9a0712007-11-26 18:49:08 +0100231 }
232
233 __raw_writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port]));
234}
235
Lennert Buytenhek4932e392007-02-05 00:38:48 +0100236static void ep93xx_gpio_irq_mask_ack(unsigned int irq)
Lennert Buytenhekbd20ff52006-03-20 21:02:37 +0000237{
Herbert Valerio Riedel7ca72252007-11-26 18:45:59 +0100238 int line = irq_to_gpio(irq);
Lennert Buytenhekbd20ff52006-03-20 21:02:37 +0000239 int port = line >> 3;
Herbert Valerio Riedel7ca72252007-11-26 18:45:59 +0100240 int port_mask = 1 << (line & 7);
Lennert Buytenhekbd20ff52006-03-20 21:02:37 +0000241
Dmitry Baryshkov6cab4862008-07-27 04:23:31 +0100242 if ((irq_desc[irq].status & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH)
Herbert Valerio Riedel3c9a0712007-11-26 18:49:08 +0100243 gpio_int_type2[port] ^= port_mask; /* switch edge direction */
244
Herbert Valerio Riedel7ca72252007-11-26 18:45:59 +0100245 gpio_int_unmasked[port] &= ~port_mask;
Ryan Mallonb6850042008-04-16 02:56:35 +0100246 ep93xx_gpio_update_int_params(port);
Lennert Buytenhekbd20ff52006-03-20 21:02:37 +0000247
Herbert Valerio Riedel7ca72252007-11-26 18:45:59 +0100248 __raw_writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port]));
Lennert Buytenhekbd20ff52006-03-20 21:02:37 +0000249}
250
Lennert Buytenhek4932e392007-02-05 00:38:48 +0100251static void ep93xx_gpio_irq_mask(unsigned int irq)
Lennert Buytenhekbd20ff52006-03-20 21:02:37 +0000252{
Herbert Valerio Riedel7ca72252007-11-26 18:45:59 +0100253 int line = irq_to_gpio(irq);
Lennert Buytenhekbd20ff52006-03-20 21:02:37 +0000254 int port = line >> 3;
255
Lennert Buytenhek271f5ca2007-02-08 01:01:41 +0100256 gpio_int_unmasked[port] &= ~(1 << (line & 7));
Ryan Mallonb6850042008-04-16 02:56:35 +0100257 ep93xx_gpio_update_int_params(port);
Lennert Buytenhekbd20ff52006-03-20 21:02:37 +0000258}
259
Lennert Buytenhek4932e392007-02-05 00:38:48 +0100260static void ep93xx_gpio_irq_unmask(unsigned int irq)
Lennert Buytenhekbd20ff52006-03-20 21:02:37 +0000261{
Herbert Valerio Riedel7ca72252007-11-26 18:45:59 +0100262 int line = irq_to_gpio(irq);
Lennert Buytenhekbd20ff52006-03-20 21:02:37 +0000263 int port = line >> 3;
264
Lennert Buytenhek271f5ca2007-02-08 01:01:41 +0100265 gpio_int_unmasked[port] |= 1 << (line & 7);
Ryan Mallonb6850042008-04-16 02:56:35 +0100266 ep93xx_gpio_update_int_params(port);
Lennert Buytenhekbd20ff52006-03-20 21:02:37 +0000267}
268
269
270/*
271 * gpio_int_type1 controls whether the interrupt is level (0) or
272 * edge (1) triggered, while gpio_int_type2 controls whether it
273 * triggers on low/falling (0) or high/rising (1).
274 */
Lennert Buytenhek4932e392007-02-05 00:38:48 +0100275static int ep93xx_gpio_irq_type(unsigned int irq, unsigned int type)
Lennert Buytenhekbd20ff52006-03-20 21:02:37 +0000276{
Herbert Valerio Riedel3c9a0712007-11-26 18:49:08 +0100277 struct irq_desc *desc = irq_desc + irq;
Herbert Valerio Riedel7ca72252007-11-26 18:45:59 +0100278 const int gpio = irq_to_gpio(irq);
279 const int port = gpio >> 3;
280 const int port_mask = 1 << (gpio & 7);
Lennert Buytenhekbd20ff52006-03-20 21:02:37 +0000281
Ryan Mallonf8b63892008-04-28 23:35:47 +0100282 gpio_direction_input(gpio);
Lennert Buytenhekbd20ff52006-03-20 21:02:37 +0000283
Herbert Valerio Riedel3c9a0712007-11-26 18:49:08 +0100284 switch (type) {
Dmitry Baryshkov6cab4862008-07-27 04:23:31 +0100285 case IRQ_TYPE_EDGE_RISING:
Herbert Valerio Riedel7ca72252007-11-26 18:45:59 +0100286 gpio_int_type1[port] |= port_mask;
287 gpio_int_type2[port] |= port_mask;
Herbert Valerio Riedel3c9a0712007-11-26 18:49:08 +0100288 desc->handle_irq = handle_edge_irq;
289 break;
Dmitry Baryshkov6cab4862008-07-27 04:23:31 +0100290 case IRQ_TYPE_EDGE_FALLING:
Herbert Valerio Riedel7ca72252007-11-26 18:45:59 +0100291 gpio_int_type1[port] |= port_mask;
292 gpio_int_type2[port] &= ~port_mask;
Herbert Valerio Riedel3c9a0712007-11-26 18:49:08 +0100293 desc->handle_irq = handle_edge_irq;
294 break;
Dmitry Baryshkov6cab4862008-07-27 04:23:31 +0100295 case IRQ_TYPE_LEVEL_HIGH:
Herbert Valerio Riedel7ca72252007-11-26 18:45:59 +0100296 gpio_int_type1[port] &= ~port_mask;
297 gpio_int_type2[port] |= port_mask;
Herbert Valerio Riedel3c9a0712007-11-26 18:49:08 +0100298 desc->handle_irq = handle_level_irq;
299 break;
Dmitry Baryshkov6cab4862008-07-27 04:23:31 +0100300 case IRQ_TYPE_LEVEL_LOW:
Herbert Valerio Riedel7ca72252007-11-26 18:45:59 +0100301 gpio_int_type1[port] &= ~port_mask;
302 gpio_int_type2[port] &= ~port_mask;
Herbert Valerio Riedel3c9a0712007-11-26 18:49:08 +0100303 desc->handle_irq = handle_level_irq;
304 break;
Dmitry Baryshkov6cab4862008-07-27 04:23:31 +0100305 case IRQ_TYPE_EDGE_BOTH:
Herbert Valerio Riedel3c9a0712007-11-26 18:49:08 +0100306 gpio_int_type1[port] |= port_mask;
307 /* set initial polarity based on current input level */
308 if (gpio_get_value(gpio))
309 gpio_int_type2[port] &= ~port_mask; /* falling */
310 else
311 gpio_int_type2[port] |= port_mask; /* rising */
312 desc->handle_irq = handle_edge_irq;
313 break;
314 default:
315 pr_err("ep93xx: failed to set irq type %d for gpio %d\n",
316 type, gpio);
317 return -EINVAL;
Lennert Buytenhekbd20ff52006-03-20 21:02:37 +0000318 }
319
Herbert Valerio Riedel3c9a0712007-11-26 18:49:08 +0100320 gpio_int_enabled[port] |= port_mask;
Lennert Buytenhekbd20ff52006-03-20 21:02:37 +0000321
Herbert Valerio Riedel3c9a0712007-11-26 18:49:08 +0100322 desc->status &= ~IRQ_TYPE_SENSE_MASK;
323 desc->status |= type & IRQ_TYPE_SENSE_MASK;
324
Ryan Mallonb6850042008-04-16 02:56:35 +0100325 ep93xx_gpio_update_int_params(port);
Lennert Buytenhekbd20ff52006-03-20 21:02:37 +0000326
327 return 0;
328}
329
Lennert Buytenhek4932e392007-02-05 00:38:48 +0100330static struct irq_chip ep93xx_gpio_irq_chip = {
331 .name = "GPIO",
Herbert Valerio Riedel3c9a0712007-11-26 18:49:08 +0100332 .ack = ep93xx_gpio_irq_ack,
333 .mask_ack = ep93xx_gpio_irq_mask_ack,
Lennert Buytenhek4932e392007-02-05 00:38:48 +0100334 .mask = ep93xx_gpio_irq_mask,
335 .unmask = ep93xx_gpio_irq_unmask,
336 .set_type = ep93xx_gpio_irq_type,
Lennert Buytenhekbd20ff52006-03-20 21:02:37 +0000337};
338
339
Lennert Buytenheke7736d42006-03-20 17:10:13 +0000340void __init ep93xx_init_irq(void)
341{
Herbert Valerio Riedel7ca72252007-11-26 18:45:59 +0100342 int gpio_irq;
Lennert Buytenhekbd20ff52006-03-20 21:02:37 +0000343
Lennert Buytenheke7736d42006-03-20 17:10:13 +0000344 vic_init((void *)EP93XX_VIC1_BASE, 0, EP93XX_VIC1_VALID_IRQ_MASK);
345 vic_init((void *)EP93XX_VIC2_BASE, 32, EP93XX_VIC2_VALID_IRQ_MASK);
Lennert Buytenhekbd20ff52006-03-20 21:02:37 +0000346
Herbert Valerio Riedel7ca72252007-11-26 18:45:59 +0100347 for (gpio_irq = gpio_to_irq(0);
348 gpio_irq <= gpio_to_irq(EP93XX_GPIO_LINE_MAX_IRQ); ++gpio_irq) {
349 set_irq_chip(gpio_irq, &ep93xx_gpio_irq_chip);
350 set_irq_handler(gpio_irq, handle_level_irq);
351 set_irq_flags(gpio_irq, IRQF_VALID);
Lennert Buytenhekbd20ff52006-03-20 21:02:37 +0000352 }
Lennert Buytenhek4932e392007-02-05 00:38:48 +0100353
Lennert Buytenhekbd20ff52006-03-20 21:02:37 +0000354 set_irq_chained_handler(IRQ_EP93XX_GPIO_AB, ep93xx_gpio_ab_irq_handler);
Lennert Buytenhek4932e392007-02-05 00:38:48 +0100355 set_irq_chained_handler(IRQ_EP93XX_GPIO0MUX, ep93xx_gpio_f_irq_handler);
356 set_irq_chained_handler(IRQ_EP93XX_GPIO1MUX, ep93xx_gpio_f_irq_handler);
357 set_irq_chained_handler(IRQ_EP93XX_GPIO2MUX, ep93xx_gpio_f_irq_handler);
358 set_irq_chained_handler(IRQ_EP93XX_GPIO3MUX, ep93xx_gpio_f_irq_handler);
359 set_irq_chained_handler(IRQ_EP93XX_GPIO4MUX, ep93xx_gpio_f_irq_handler);
360 set_irq_chained_handler(IRQ_EP93XX_GPIO5MUX, ep93xx_gpio_f_irq_handler);
361 set_irq_chained_handler(IRQ_EP93XX_GPIO6MUX, ep93xx_gpio_f_irq_handler);
362 set_irq_chained_handler(IRQ_EP93XX_GPIO7MUX, ep93xx_gpio_f_irq_handler);
Lennert Buytenheke7736d42006-03-20 17:10:13 +0000363}
364
365
366/*************************************************************************
367 * EP93xx peripheral handling
368 *************************************************************************/
Lennert Buytenhekaee85fe2006-03-26 23:16:39 +0100369#define EP93XX_UART_MCR_OFFSET (0x0100)
370
371static void ep93xx_uart_set_mctrl(struct amba_device *dev,
372 void __iomem *base, unsigned int mctrl)
373{
374 unsigned int mcr;
375
376 mcr = 0;
377 if (!(mctrl & TIOCM_RTS))
378 mcr |= 2;
379 if (!(mctrl & TIOCM_DTR))
380 mcr |= 1;
381
382 __raw_writel(mcr, base + EP93XX_UART_MCR_OFFSET);
383}
384
385static struct amba_pl010_data ep93xx_uart_data = {
386 .set_mctrl = ep93xx_uart_set_mctrl,
387};
388
389static struct amba_device uart1_device = {
390 .dev = {
391 .bus_id = "apb:uart1",
392 .platform_data = &ep93xx_uart_data,
393 },
394 .res = {
395 .start = EP93XX_UART1_PHYS_BASE,
396 .end = EP93XX_UART1_PHYS_BASE + 0x0fff,
397 .flags = IORESOURCE_MEM,
398 },
399 .irq = { IRQ_EP93XX_UART1, NO_IRQ },
400 .periphid = 0x00041010,
401};
402
403static struct amba_device uart2_device = {
404 .dev = {
405 .bus_id = "apb:uart2",
406 .platform_data = &ep93xx_uart_data,
407 },
408 .res = {
409 .start = EP93XX_UART2_PHYS_BASE,
410 .end = EP93XX_UART2_PHYS_BASE + 0x0fff,
411 .flags = IORESOURCE_MEM,
412 },
413 .irq = { IRQ_EP93XX_UART2, NO_IRQ },
414 .periphid = 0x00041010,
415};
416
417static struct amba_device uart3_device = {
418 .dev = {
419 .bus_id = "apb:uart3",
420 .platform_data = &ep93xx_uart_data,
421 },
422 .res = {
423 .start = EP93XX_UART3_PHYS_BASE,
424 .end = EP93XX_UART3_PHYS_BASE + 0x0fff,
425 .flags = IORESOURCE_MEM,
426 },
427 .irq = { IRQ_EP93XX_UART3, NO_IRQ },
428 .periphid = 0x00041010,
429};
430
Lennert Buytenhek41658132006-04-02 16:17:34 +0100431
432static struct platform_device ep93xx_rtc_device = {
433 .name = "ep93xx-rtc",
434 .id = -1,
435 .num_resources = 0,
436};
437
438
Lennert Buytenhek1f64eb32006-06-24 10:33:03 +0100439static struct resource ep93xx_ohci_resources[] = {
440 [0] = {
441 .start = EP93XX_USB_PHYS_BASE,
442 .end = EP93XX_USB_PHYS_BASE + 0x0fff,
443 .flags = IORESOURCE_MEM,
444 },
445 [1] = {
446 .start = IRQ_EP93XX_USB,
447 .end = IRQ_EP93XX_USB,
448 .flags = IORESOURCE_IRQ,
449 },
450};
451
452static struct platform_device ep93xx_ohci_device = {
453 .name = "ep93xx-ohci",
454 .id = -1,
455 .dev = {
456 .dma_mask = (void *)0xffffffff,
457 .coherent_dma_mask = 0xffffffff,
458 },
459 .num_resources = ARRAY_SIZE(ep93xx_ohci_resources),
460 .resource = ep93xx_ohci_resources,
461};
462
Ryan Mallonb6850042008-04-16 02:56:35 +0100463extern void ep93xx_gpio_init(void);
Lennert Buytenhek1f64eb32006-06-24 10:33:03 +0100464
Lennert Buytenheke7736d42006-03-20 17:10:13 +0000465void __init ep93xx_init_devices(void)
466{
467 unsigned int v;
468
469 /*
470 * Disallow access to MaverickCrunch initially.
471 */
472 v = __raw_readl(EP93XX_SYSCON_DEVICE_CONFIG);
473 v &= ~EP93XX_SYSCON_DEVICE_CONFIG_CRUNCH_ENABLE;
474 __raw_writel(0xaa, EP93XX_SYSCON_SWLOCK);
475 __raw_writel(v, EP93XX_SYSCON_DEVICE_CONFIG);
Lennert Buytenhekaee85fe2006-03-26 23:16:39 +0100476
Ryan Mallonb6850042008-04-16 02:56:35 +0100477 ep93xx_gpio_init();
478
Lennert Buytenhekaee85fe2006-03-26 23:16:39 +0100479 amba_device_register(&uart1_device, &iomem_resource);
480 amba_device_register(&uart2_device, &iomem_resource);
481 amba_device_register(&uart3_device, &iomem_resource);
Lennert Buytenhek41658132006-04-02 16:17:34 +0100482
483 platform_device_register(&ep93xx_rtc_device);
Lennert Buytenhek1f64eb32006-06-24 10:33:03 +0100484 platform_device_register(&ep93xx_ohci_device);
Lennert Buytenheke7736d42006-03-20 17:10:13 +0000485}