common.c 9.59 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/*
 * arch/arm/mach-ixp4xx/common.c
 *
 * Generic code shared across all IXP4XX platforms
 *
 * Maintainer: Deepak Saxena <dsaxena@plexity.net>
 *
 * Copyright 2002 (c) Intel Corporation
 * Copyright 2003-2004 (c) MontaVista, Software, Inc. 
 * 
 * This file is licensed under  the terms of the GNU General Public 
 * License version 2. This program is licensed "as is" without any 
 * warranty of any kind, whether express or implied.
 */

#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/serial.h>
#include <linux/sched.h>
#include <linux/tty.h>
22
#include <linux/platform_device.h>
Linus Torvalds's avatar
Linus Torvalds committed
23 24 25 26 27 28
#include <linux/serial_core.h>
#include <linux/bootmem.h>
#include <linux/interrupt.h>
#include <linux/bitops.h>
#include <linux/time.h>
#include <linux/timex.h>
29
#include <linux/clocksource.h>
Linus Torvalds's avatar
Linus Torvalds committed
30

31
#include <asm/arch/udc.h>
Linus Torvalds's avatar
Linus Torvalds committed
32 33 34 35 36 37 38 39 40 41 42
#include <asm/hardware.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/page.h>
#include <asm/irq.h>

#include <asm/mach/map.h>
#include <asm/mach/irq.h>
#include <asm/mach/time.h>

43 44
static int __init ixp4xx_clocksource_init(void);

Linus Torvalds's avatar
Linus Torvalds committed
45 46 47 48 49 50
/*************************************************************************
 * IXP4xx chipset I/O mapping
 *************************************************************************/
static struct map_desc ixp4xx_io_desc[] __initdata = {
	{	/* UART, Interrupt ctrl, GPIO, timers, NPEs, MACs, USB .... */
		.virtual	= IXP4XX_PERIPHERAL_BASE_VIRT,
51
		.pfn		= __phys_to_pfn(IXP4XX_PERIPHERAL_BASE_PHYS),
Linus Torvalds's avatar
Linus Torvalds committed
52 53 54 55
		.length		= IXP4XX_PERIPHERAL_REGION_SIZE,
		.type		= MT_DEVICE
	}, {	/* Expansion Bus Config Registers */
		.virtual	= IXP4XX_EXP_CFG_BASE_VIRT,
56
		.pfn		= __phys_to_pfn(IXP4XX_EXP_CFG_BASE_PHYS),
Linus Torvalds's avatar
Linus Torvalds committed
57 58 59 60
		.length		= IXP4XX_EXP_CFG_REGION_SIZE,
		.type		= MT_DEVICE
	}, {	/* PCI Registers */
		.virtual	= IXP4XX_PCI_CFG_BASE_VIRT,
61
		.pfn		= __phys_to_pfn(IXP4XX_PCI_CFG_BASE_PHYS),
Linus Torvalds's avatar
Linus Torvalds committed
62 63
		.length		= IXP4XX_PCI_CFG_REGION_SIZE,
		.type		= MT_DEVICE
64 65 66 67
	},
#ifdef CONFIG_DEBUG_LL
	{	/* Debug UART mapping */
		.virtual	= IXP4XX_DEBUG_UART_BASE_VIRT,
68
		.pfn		= __phys_to_pfn(IXP4XX_DEBUG_UART_BASE_PHYS),
69 70
		.length		= IXP4XX_DEBUG_UART_REGION_SIZE,
		.type		= MT_DEVICE
Linus Torvalds's avatar
Linus Torvalds committed
71
	}
72
#endif
Linus Torvalds's avatar
Linus Torvalds committed
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
};

void __init ixp4xx_map_io(void)
{
  	iotable_init(ixp4xx_io_desc, ARRAY_SIZE(ixp4xx_io_desc));
}


/*************************************************************************
 * IXP4xx chipset IRQ handling
 *
 * TODO: GPIO IRQs should be marked invalid until the user of the IRQ
 *       (be it PCI or something else) configures that GPIO line
 *       as an IRQ.
 **************************************************************************/
88 89 90 91
enum ixp4xx_irq_type {
	IXP4XX_IRQ_LEVEL, IXP4XX_IRQ_EDGE
};

92 93
/* Each bit represents an IRQ: 1: edge-triggered, 0: level triggered */
static unsigned long long ixp4xx_irq_edge = 0;
94 95 96 97

/*
 * IRQ -> GPIO mapping table
 */
98
static signed char irq2gpio[32] = {
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
	-1, -1, -1, -1, -1, -1,  0,  1,
	-1, -1, -1, -1, -1, -1, -1, -1,
	-1, -1, -1,  2,  3,  4,  5,  6,
	 7,  8,  9, 10, 11, 12, -1, -1,
};

static int ixp4xx_set_irq_type(unsigned int irq, unsigned int type)
{
	int line = irq2gpio[irq];
	u32 int_style;
	enum ixp4xx_irq_type irq_type;
	volatile u32 *int_reg;

	/*
	 * Only for GPIO IRQs
	 */
	if (line < 0)
		return -EINVAL;

118 119
	switch (type){
	case IRQT_BOTHEDGE:
120 121
		int_style = IXP4XX_GPIO_STYLE_TRANSITIONAL;
		irq_type = IXP4XX_IRQ_EDGE;
122 123
		break;
	case IRQT_RISING:
124 125
		int_style = IXP4XX_GPIO_STYLE_RISING_EDGE;
		irq_type = IXP4XX_IRQ_EDGE;
126 127
		break;
	case IRQT_FALLING:
128 129
		int_style = IXP4XX_GPIO_STYLE_FALLING_EDGE;
		irq_type = IXP4XX_IRQ_EDGE;
130 131
		break;
	case IRQT_HIGH:
132 133
		int_style = IXP4XX_GPIO_STYLE_ACTIVE_HIGH;
		irq_type = IXP4XX_IRQ_LEVEL;
134 135
		break;
	case IRQT_LOW:
136 137
		int_style = IXP4XX_GPIO_STYLE_ACTIVE_LOW;
		irq_type = IXP4XX_IRQ_LEVEL;
138 139
		break;
	default:
140
		return -EINVAL;
141
	}
142 143 144 145 146

	if (irq_type == IXP4XX_IRQ_EDGE)
		ixp4xx_irq_edge |= (1 << irq);
	else
		ixp4xx_irq_edge &= ~(1 << irq);
147 148 149 150 151 152 153 154 155 156 157 158

	if (line >= 8) {	/* pins 8-15 */
		line -= 8;
		int_reg = IXP4XX_GPIO_GPIT2R;
	} else {		/* pins 0-7 */
		int_reg = IXP4XX_GPIO_GPIT1R;
	}

	/* Clear the style for the appropriate pin */
	*int_reg &= ~(IXP4XX_GPIO_STYLE_CLEAR <<
	    		(line * IXP4XX_GPIO_STYLE_SIZE));

159 160
	*IXP4XX_GPIO_GPISR = (1 << line);

161 162
	/* Set the new style */
	*int_reg |= (int_style << (line * IXP4XX_GPIO_STYLE_SIZE));
163

164 165 166
	/* Configure the line as an input */
	gpio_line_config(line, IXP4XX_GPIO_IN);

167
	return 0;
168 169
}

Linus Torvalds's avatar
Linus Torvalds committed
170 171 172 173 174 175 176 177 178 179 180 181 182
static void ixp4xx_irq_mask(unsigned int irq)
{
	if (cpu_is_ixp46x() && irq >= 32)
		*IXP4XX_ICMR2 &= ~(1 << (irq - 32));
	else
		*IXP4XX_ICMR &= ~(1 << irq);
}

static void ixp4xx_irq_ack(unsigned int irq)
{
	int line = (irq < 32) ? irq2gpio[irq] : -1;

	if (line >= 0)
183
		*IXP4XX_GPIO_GPISR = (1 << line);
Linus Torvalds's avatar
Linus Torvalds committed
184 185 186 187 188 189
}

/*
 * Level triggered interrupts on GPIO lines can only be cleared when the
 * interrupt condition disappears.
 */
190
static void ixp4xx_irq_unmask(unsigned int irq)
Linus Torvalds's avatar
Linus Torvalds committed
191
{
192 193
	if (!(ixp4xx_irq_edge & (1 << irq)))
		ixp4xx_irq_ack(irq);
Linus Torvalds's avatar
Linus Torvalds committed
194

195 196 197 198 199
	if (cpu_is_ixp46x() && irq >= 32)
		*IXP4XX_ICMR2 |= (1 << (irq - 32));
	else
		*IXP4XX_ICMR |= (1 << irq);
}
Linus Torvalds's avatar
Linus Torvalds committed
200

201
static struct irq_chip ixp4xx_irq_chip = {
202
	.name		= "IXP4xx",
203 204 205 206
	.ack		= ixp4xx_irq_ack,
	.mask		= ixp4xx_irq_mask,
	.unmask		= ixp4xx_irq_unmask,
	.set_type	= ixp4xx_set_irq_type,
Linus Torvalds's avatar
Linus Torvalds committed
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
};

void __init ixp4xx_init_irq(void)
{
	int i = 0;

	/* Route all sources to IRQ instead of FIQ */
	*IXP4XX_ICLR = 0x0;

	/* Disable all interrupt */
	*IXP4XX_ICMR = 0x0; 

	if (cpu_is_ixp46x()) {
		/* Route upper 32 sources to IRQ instead of FIQ */
		*IXP4XX_ICLR2 = 0x00;

		/* Disable upper 32 interrupts */
		*IXP4XX_ICMR2 = 0x00;
	}

        /* Default to all level triggered */
228 229
	for(i = 0; i < NR_IRQS; i++) {
		set_irq_chip(i, &ixp4xx_irq_chip);
230
		set_irq_handler(i, handle_level_irq);
231 232
		set_irq_flags(i, IRQF_VALID);
	}
Linus Torvalds's avatar
Linus Torvalds committed
233 234 235 236 237 238 239 240 241 242 243 244 245
}


/*************************************************************************
 * IXP4xx timer tick
 * We use OS timer1 on the CPU for the timer tick and the timestamp 
 * counter as a source of real clock ticks to account for missed jiffies.
 *************************************************************************/

static unsigned volatile last_jiffy_time;

#define CLOCK_TICKS_PER_USEC	((CLOCK_TICK_RATE + USEC_PER_SEC/2) / USEC_PER_SEC)

246
static irqreturn_t ixp4xx_timer_interrupt(int irq, void *dev_id)
Linus Torvalds's avatar
Linus Torvalds committed
247 248 249 250 251 252 253 254 255
{
	write_seqlock(&xtime_lock);

	/* Clear Pending Interrupt by writing '1' to it */
	*IXP4XX_OSST = IXP4XX_OSST_TIMER_1_PEND;

	/*
	 * Catch up with the real idea of time
	 */
256
	while ((signed long)(*IXP4XX_OSTS - last_jiffy_time) >= LATCH) {
257
		timer_tick();
Linus Torvalds's avatar
Linus Torvalds committed
258 259 260 261 262 263 264 265 266 267
		last_jiffy_time += LATCH;
	}

	write_sequnlock(&xtime_lock);

	return IRQ_HANDLED;
}

static struct irqaction ixp4xx_timer_irq = {
	.name		= "IXP4xx Timer Tick",
268
	.flags		= IRQF_DISABLED | IRQF_TIMER,
269
	.handler	= ixp4xx_timer_interrupt,
Linus Torvalds's avatar
Linus Torvalds committed
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
};

static void __init ixp4xx_timer_init(void)
{
	/* Clear Pending Interrupt by writing '1' to it */
	*IXP4XX_OSST = IXP4XX_OSST_TIMER_1_PEND;

	/* Setup the Timer counter value */
	*IXP4XX_OSRT1 = (LATCH & ~IXP4XX_OST_RELOAD_MASK) | IXP4XX_OST_ENABLE;

	/* Reset time-stamp counter */
	*IXP4XX_OSTS = 0;
	last_jiffy_time = 0;

	/* Connect the interrupt handler and enable the interrupt */
	setup_irq(IRQ_IXP4XX_TIMER1, &ixp4xx_timer_irq);
286 287

	ixp4xx_clocksource_init();
Linus Torvalds's avatar
Linus Torvalds committed
288 289 290 291 292 293
}

struct sys_timer ixp4xx_timer = {
	.init		= ixp4xx_timer_init,
};

294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
static struct pxa2xx_udc_mach_info ixp4xx_udc_info;

void __init ixp4xx_set_udc_info(struct pxa2xx_udc_mach_info *info)
{
	memcpy(&ixp4xx_udc_info, info, sizeof *info);
}

static struct resource ixp4xx_udc_resources[] = {
	[0] = {
		.start  = 0xc800b000,
		.end    = 0xc800bfff,
		.flags  = IORESOURCE_MEM,
	},
	[1] = {
		.start  = IRQ_IXP4XX_USB,
		.end    = IRQ_IXP4XX_USB,
		.flags  = IORESOURCE_IRQ,
	},
};

/*
 * USB device controller. The IXP4xx uses the same controller as PXA2XX,
 * so we just use the same device.
 */
static struct platform_device ixp4xx_udc_device = {
	.name           = "pxa2xx-udc",
	.id             = -1,
	.num_resources  = 2,
	.resource       = ixp4xx_udc_resources,
	.dev            = {
		.platform_data = &ixp4xx_udc_info,
	},
};

static struct platform_device *ixp4xx_devices[] __initdata = {
	&ixp4xx_udc_device,
};

Linus Torvalds's avatar
Linus Torvalds committed
332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359
static struct resource ixp46x_i2c_resources[] = {
	[0] = {
		.start 	= 0xc8011000,
		.end	= 0xc801101c,
		.flags	= IORESOURCE_MEM,
	},
	[1] = {
		.start 	= IRQ_IXP4XX_I2C,
		.end	= IRQ_IXP4XX_I2C,
		.flags	= IORESOURCE_IRQ
	}
};

/*
 * I2C controller. The IXP46x uses the same block as the IOP3xx, so
 * we just use the same device name.
 */
static struct platform_device ixp46x_i2c_controller = {
	.name		= "IOP3xx-I2C",
	.id		= 0,
	.num_resources	= 2,
	.resource	= ixp46x_i2c_resources
};

static struct platform_device *ixp46x_devices[] __initdata = {
	&ixp46x_i2c_controller
};

360
unsigned long ixp4xx_exp_bus_size;
361
EXPORT_SYMBOL(ixp4xx_exp_bus_size);
362

Linus Torvalds's avatar
Linus Torvalds committed
363 364
void __init ixp4xx_sys_init(void)
{
365 366
	ixp4xx_exp_bus_size = SZ_16M;

367 368
	platform_add_devices(ixp4xx_devices, ARRAY_SIZE(ixp4xx_devices));

Linus Torvalds's avatar
Linus Torvalds committed
369
	if (cpu_is_ixp46x()) {
370 371
		int region;

Linus Torvalds's avatar
Linus Torvalds committed
372 373
		platform_add_devices(ixp46x_devices,
				ARRAY_SIZE(ixp46x_devices));
374 375 376 377 378 379 380

		for (region = 0; region < 7; region++) {
			if((*(IXP4XX_EXP_REG(0x4 * region)) & 0x200)) {
				ixp4xx_exp_bus_size = SZ_32M;
				break;
			}
		}
Linus Torvalds's avatar
Linus Torvalds committed
381
	}
382

383
	printk("IXP4xx: Using %luMiB expansion bus window size\n",
384
			ixp4xx_exp_bus_size >> 20);
Linus Torvalds's avatar
Linus Torvalds committed
385 386
}

387 388 389 390 391 392 393 394 395 396 397
cycle_t ixp4xx_get_cycles(void)
{
	return *IXP4XX_OSTS;
}

static struct clocksource clocksource_ixp4xx = {
	.name 		= "OSTS",
	.rating		= 200,
	.read		= ixp4xx_get_cycles,
	.mask		= CLOCKSOURCE_MASK(32),
	.shift 		= 20,
398
	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
399 400 401 402 403 404 405 406 407 408 409 410
};

unsigned long ixp4xx_timer_freq = FREQ;
static int __init ixp4xx_clocksource_init(void)
{
	clocksource_ixp4xx.mult =
		clocksource_hz2mult(ixp4xx_timer_freq,
				    clocksource_ixp4xx.shift);
	clocksource_register(&clocksource_ixp4xx);

	return 0;
}