generic.c 9.9 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/*
 *  linux/arch/arm/mach-pxa/generic.c
 *
 *  Author:	Nicolas Pitre
 *  Created:	Jun 15, 2001
 *  Copyright:	MontaVista Software Inc.
 *
 * Code common to all PXA machines.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * Since this file should be linked before any other machine specific file,
 * the __initcall() here will be executed first.  This serves as default
 * initialization stuff for PXA machines which can be overridden later if
 * need be.
 */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
23
#include <linux/platform_device.h>
L
Linus Torvalds 已提交
24 25
#include <linux/ioport.h>
#include <linux/pm.h>
T
Tim Schmielau 已提交
26
#include <linux/string.h>
L
Linus Torvalds 已提交
27

28 29 30 31
#include <linux/sched.h>
#include <asm/cnt32_to_63.h>
#include <asm/div64.h>

L
Linus Torvalds 已提交
32 33 34 35 36 37 38
#include <asm/hardware.h>
#include <asm/irq.h>
#include <asm/system.h>
#include <asm/pgtable.h>
#include <asm/mach/map.h>

#include <asm/arch/pxa-regs.h>
39
#include <asm/arch/gpio.h>
L
Linus Torvalds 已提交
40 41 42
#include <asm/arch/udc.h>
#include <asm/arch/pxafb.h>
#include <asm/arch/mmc.h>
N
Nicolas Pitre 已提交
43
#include <asm/arch/irda.h>
44
#include <asm/arch/i2c.h>
L
Linus Torvalds 已提交
45 46 47

#include "generic.h"

48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
/*
 * This is the PXA2xx sched_clock implementation. This has a resolution
 * of at least 308ns and a maximum value that depends on the value of
 * CLOCK_TICK_RATE.
 *
 * The return value is guaranteed to be monotonic in that range as
 * long as there is always less than 582 seconds between successive
 * calls to this function.
 */
unsigned long long sched_clock(void)
{
	unsigned long long v = cnt32_to_63(OSCR);
	/* Note: top bit ov v needs cleared unless multiplier is even. */

#if	CLOCK_TICK_RATE == 3686400
	/* 1E9 / 3686400 => 78125 / 288, max value = 32025597s (370 days). */
	/* The <<1 is used to get rid of tick.hi top bit */
	v *= 78125<<1;
	do_div(v, 288<<1);
#elif	CLOCK_TICK_RATE == 3250000
	/* 1E9 / 3250000 => 4000 / 13, max value = 709490156s (8211 days) */
	v *= 4000;
	do_div(v, 13);
#elif	CLOCK_TICK_RATE == 3249600
	/* 1E9 / 3249600 => 625000 / 2031, max value = 4541295s (52 days) */
	v *= 625000;
	do_div(v, 2031);
#else
#warning "consider fixing sched_clock for your value of CLOCK_TICK_RATE"
	/*
	 * 96-bit math to perform tick * NSEC_PER_SEC / CLOCK_TICK_RATE for
	 * any value of CLOCK_TICK_RATE. Max value is in the 80 thousand
80 81 82
	 * years range and truncation to unsigned long long limits it to
	 * sched_clock's max range of ~584 years.  This is nice but with
	 * higher computation cost.
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
	 */
	{
		union {
			unsigned long long val;
			struct { unsigned long lo, hi; };
		} x;
		unsigned long long y;

		x.val = v;
		x.hi &= 0x7fffffff;
		y = (unsigned long long)x.lo * NSEC_PER_SEC;
		x.lo = y;
		y = (y >> 32) + (unsigned long long)x.hi * NSEC_PER_SEC;
		x.hi = do_div(y, CLOCK_TICK_RATE);
		do_div(x.val, CLOCK_TICK_RATE);
		x.hi += y;
		v = x.val;
	}
#endif

	return v;
}

L
Linus Torvalds 已提交
106 107 108 109
/*
 * Handy function to set GPIO alternate functions
 */

110
int pxa_gpio_mode(int gpio_mode)
L
Linus Torvalds 已提交
111 112 113 114 115 116
{
	unsigned long flags;
	int gpio = gpio_mode & GPIO_MD_MASK_NR;
	int fn = (gpio_mode & GPIO_MD_MASK_FN) >> 8;
	int gafr;

117 118 119
	if (gpio > PXA_LAST_GPIO)
		return -EINVAL;

L
Linus Torvalds 已提交
120 121 122 123 124 125 126 127 128 129 130 131
	local_irq_save(flags);
	if (gpio_mode & GPIO_DFLT_LOW)
		GPCR(gpio) = GPIO_bit(gpio);
	else if (gpio_mode & GPIO_DFLT_HIGH)
		GPSR(gpio) = GPIO_bit(gpio);
	if (gpio_mode & GPIO_MD_MASK_DIR)
		GPDR(gpio) |= GPIO_bit(gpio);
	else
		GPDR(gpio) &= ~GPIO_bit(gpio);
	gafr = GAFR(gpio) & ~(0x3 << (((gpio) & 0xf)*2));
	GAFR(gpio) = gafr |  (fn  << (((gpio) & 0xf)*2));
	local_irq_restore(flags);
132 133

	return 0;
L
Linus Torvalds 已提交
134 135 136 137
}

EXPORT_SYMBOL(pxa_gpio_mode);

138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
/*
 * Return GPIO level
 */
int pxa_gpio_get_value(unsigned gpio)
{
	return __gpio_get_value(gpio);
}

EXPORT_SYMBOL(pxa_gpio_get_value);

/*
 * Set output GPIO level
 */
void pxa_gpio_set_value(unsigned gpio, int value)
{
	__gpio_set_value(gpio, value);
}

EXPORT_SYMBOL(pxa_gpio_set_value);

L
Linus Torvalds 已提交
158 159 160 161 162 163 164 165 166
/*
 * Routine to safely enable or disable a clock in the CKEN
 */
void pxa_set_cken(int clock, int enable)
{
	unsigned long flags;
	local_irq_save(flags);

	if (enable)
167
		CKEN |= (1 << clock);
L
Linus Torvalds 已提交
168
	else
169
		CKEN &= ~(1 << clock);
L
Linus Torvalds 已提交
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184

	local_irq_restore(flags);
}

EXPORT_SYMBOL(pxa_set_cken);

/*
 * Intel PXA2xx internal register mapping.
 *
 * Note 1: not all PXA2xx variants implement all those addresses.
 *
 * Note 2: virtual 0xfffe0000-0xffffffff is reserved for the vector table
 *         and cache flush area.
 */
static struct map_desc standard_io_desc[] __initdata = {
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
  	{	/* Devs */
		.virtual	=  0xf2000000,
		.pfn		= __phys_to_pfn(0x40000000),
		.length		= 0x02000000,
		.type		= MT_DEVICE
	}, {	/* LCD */
		.virtual	=  0xf4000000,
		.pfn		= __phys_to_pfn(0x44000000),
		.length		= 0x00100000,
		.type		= MT_DEVICE
	}, {	/* Mem Ctl */
		.virtual	=  0xf6000000,
		.pfn		= __phys_to_pfn(0x48000000),
		.length		= 0x00100000,
		.type		= MT_DEVICE
	}, {	/* USB host */
		.virtual	=  0xf8000000,
		.pfn		= __phys_to_pfn(0x4c000000),
		.length		= 0x00100000,
		.type		= MT_DEVICE
	}, {	/* Camera */
		.virtual	=  0xfa000000,
		.pfn		= __phys_to_pfn(0x50000000),
		.length		= 0x00100000,
		.type		= MT_DEVICE
	}, {	/* IMem ctl */
		.virtual	=  0xfe000000,
		.pfn		= __phys_to_pfn(0x58000000),
		.length		= 0x00100000,
		.type		= MT_DEVICE
	}, {	/* UNCACHED_PHYS_0 */
		.virtual	= 0xff000000,
		.pfn		= __phys_to_pfn(0x00000000),
		.length		= 0x00100000,
		.type		= MT_DEVICE
	}
L
Linus Torvalds 已提交
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 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
};

void __init pxa_map_io(void)
{
	iotable_init(standard_io_desc, ARRAY_SIZE(standard_io_desc));
	get_clk_frequency_khz(1);
}


static struct resource pxamci_resources[] = {
	[0] = {
		.start	= 0x41100000,
		.end	= 0x41100fff,
		.flags	= IORESOURCE_MEM,
	},
	[1] = {
		.start	= IRQ_MMC,
		.end	= IRQ_MMC,
		.flags	= IORESOURCE_IRQ,
	},
};

static u64 pxamci_dmamask = 0xffffffffUL;

static struct platform_device pxamci_device = {
	.name		= "pxa2xx-mci",
	.id		= -1,
	.dev		= {
		.dma_mask = &pxamci_dmamask,
		.coherent_dma_mask = 0xffffffff,
	},
	.num_resources	= ARRAY_SIZE(pxamci_resources),
	.resource	= pxamci_resources,
};

void __init pxa_set_mci_info(struct pxamci_platform_data *info)
{
	pxamci_device.dev.platform_data = info;
}


static struct pxa2xx_udc_mach_info pxa_udc_info;

void __init pxa_set_udc_info(struct pxa2xx_udc_mach_info *info)
{
	memcpy(&pxa_udc_info, info, sizeof *info);
}

static struct resource pxa2xx_udc_resources[] = {
	[0] = {
		.start	= 0x40600000,
		.end	= 0x4060ffff,
		.flags	= IORESOURCE_MEM,
	},
	[1] = {
		.start	= IRQ_USB,
		.end	= IRQ_USB,
		.flags	= IORESOURCE_IRQ,
	},
};

static u64 udc_dma_mask = ~(u32)0;

static struct platform_device udc_device = {
	.name		= "pxa2xx-udc",
	.id		= -1,
	.resource	= pxa2xx_udc_resources,
	.num_resources	= ARRAY_SIZE(pxa2xx_udc_resources),
	.dev		=  {
		.platform_data	= &pxa_udc_info,
		.dma_mask	= &udc_dma_mask,
	}
};

static struct resource pxafb_resources[] = {
	[0] = {
		.start	= 0x44000000,
		.end	= 0x4400ffff,
		.flags	= IORESOURCE_MEM,
	},
	[1] = {
		.start	= IRQ_LCD,
		.end	= IRQ_LCD,
		.flags	= IORESOURCE_IRQ,
	},
};

static u64 fb_dma_mask = ~(u64)0;

static struct platform_device pxafb_device = {
	.name		= "pxa2xx-fb",
	.id		= -1,
	.dev		= {
		.dma_mask	= &fb_dma_mask,
		.coherent_dma_mask = 0xffffffff,
	},
	.num_resources	= ARRAY_SIZE(pxafb_resources),
	.resource	= pxafb_resources,
};

321 322 323 324 325
void __init set_pxa_fb_info(struct pxafb_mach_info *info)
{
	pxafb_device.dev.platform_data = info;
}

326 327 328 329 330
void __init set_pxa_fb_parent(struct device *parent_dev)
{
	pxafb_device.dev.parent = parent_dev;
}

L
Linus Torvalds 已提交
331 332 333 334 335 336 337 338 339 340 341 342
static struct platform_device ffuart_device = {
	.name		= "pxa2xx-uart",
	.id		= 0,
};
static struct platform_device btuart_device = {
	.name		= "pxa2xx-uart",
	.id		= 1,
};
static struct platform_device stuart_device = {
	.name		= "pxa2xx-uart",
	.id		= 2,
};
343 344 345 346
static struct platform_device hwuart_device = {
	.name		= "pxa2xx-uart",
	.id		= 3,
};
L
Linus Torvalds 已提交
347

348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366
static struct resource i2c_resources[] = {
	{
		.start	= 0x40301680,
		.end	= 0x403016a3,
		.flags	= IORESOURCE_MEM,
	}, {
		.start	= IRQ_I2C,
		.end	= IRQ_I2C,
		.flags	= IORESOURCE_IRQ,
	},
};

static struct platform_device i2c_device = {
	.name		= "pxa2xx-i2c",
	.id		= 0,
	.resource	= i2c_resources,
	.num_resources	= ARRAY_SIZE(i2c_resources),
};

367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387
#ifdef CONFIG_PXA27x
static struct resource i2c_power_resources[] = {
	{
		.start	= 0x40f00180,
		.end	= 0x40f001a3,
		.flags	= IORESOURCE_MEM,
	}, {
		.start	= IRQ_PWRI2C,
		.end	= IRQ_PWRI2C,
		.flags	= IORESOURCE_IRQ,
	},
};

static struct platform_device i2c_power_device = {
	.name		= "pxa2xx-i2c",
	.id		= 1,
	.resource	= i2c_power_resources,
	.num_resources	= ARRAY_SIZE(i2c_resources),
};
#endif

388 389 390 391 392
void __init pxa_set_i2c_info(struct i2c_pxa_platform_data *info)
{
	i2c_device.dev.platform_data = info;
}

393 394 395 396 397 398 399 400 401 402 403 404 405 406 407
static struct resource i2s_resources[] = {
	{
		.start	= 0x40400000,
		.end	= 0x40400083,
		.flags	= IORESOURCE_MEM,
	}, {
		.start	= IRQ_I2S,
		.end	= IRQ_I2S,
		.flags	= IORESOURCE_IRQ,
	},
};

static struct platform_device i2s_device = {
	.name		= "pxa2xx-i2s",
	.id		= -1,
408
	.resource	= i2s_resources,
409 410 411
	.num_resources	= ARRAY_SIZE(i2s_resources),
};

N
Nicolas Pitre 已提交
412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427
static u64 pxaficp_dmamask = ~(u32)0;

static struct platform_device pxaficp_device = {
	.name		= "pxa2xx-ir",
	.id		= -1,
	.dev		= {
		.dma_mask = &pxaficp_dmamask,
		.coherent_dma_mask = 0xffffffff,
	},
};

void __init pxa_set_ficp_info(struct pxaficp_platform_data *info)
{
	pxaficp_device.dev.platform_data = info;
}

428 429 430 431 432
static struct platform_device pxartc_device = {
	.name		= "sa1100-rtc",
	.id		= -1,
};

L
Linus Torvalds 已提交
433 434 435 436 437 438 439
static struct platform_device *devices[] __initdata = {
	&pxamci_device,
	&udc_device,
	&pxafb_device,
	&ffuart_device,
	&btuart_device,
	&stuart_device,
N
Nicolas Pitre 已提交
440
	&pxaficp_device,
441
	&i2c_device,
442 443 444
#ifdef CONFIG_PXA27x
	&i2c_power_device,
#endif
445
	&i2s_device,
446
	&pxartc_device,
L
Linus Torvalds 已提交
447 448 449 450
};

static int __init pxa_init(void)
{
451 452 453 454 455 456 457 458 459 460 461 462 463
	int cpuid, ret;

	ret = platform_add_devices(devices, ARRAY_SIZE(devices));
	if (ret)
		return ret;

	/* Only add HWUART for PXA255/26x; PXA210/250/27x do not have it. */
	cpuid = read_cpuid(CPUID_ID);
	if (((cpuid >> 4) & 0xfff) == 0x2d0 ||
	    ((cpuid >> 4) & 0xfff) == 0x290)
		ret = platform_device_register(&hwuart_device);

	return ret;
L
Linus Torvalds 已提交
464 465 466
}

subsys_initcall(pxa_init);