generic.c 6.91 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
/*
 * linux/arch/arm/mach-sa1100/generic.c
 *
 * Author: Nicolas Pitre
 *
 * Code common to all SA11x0 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.
 */
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/cpufreq.h>
19
#include <linux/ioport.h>
Linus Torvalds's avatar
Linus Torvalds committed
20 21 22 23 24

#include <asm/hardware.h>
#include <asm/system.h>
#include <asm/pgtable.h>
#include <asm/mach/map.h>
25
#include <asm/irq.h>
Linus Torvalds's avatar
Linus Torvalds committed
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52

#include "generic.h"

#define NR_FREQS	16

/*
 * This table is setup for a 3.6864MHz Crystal.
 */
static const unsigned short cclk_frequency_100khz[NR_FREQS] = {
	 590,	/*  59.0 MHz */
	 737,	/*  73.7 MHz */
	 885, 	/*  88.5 MHz */
	1032,	/* 103.2 MHz */
	1180,	/* 118.0 MHz */
	1327,	/* 132.7 MHz */
	1475,	/* 147.5 MHz */
	1622,	/* 162.2 MHz */
	1769,	/* 176.9 MHz */
	1917,	/* 191.7 MHz */
	2064,	/* 206.4 MHz */
	2212,	/* 221.2 MHz */
	2359,   /* 235.9 MHz */
	2507,   /* 250.7 MHz */
	2654,   /* 265.4 MHz */
	2802    /* 280.2 MHz */
};

53 54
#if defined(CONFIG_CPU_FREQ_SA1100) || defined(CONFIG_CPU_FREQ_SA1110)
/* rounds up(!)  */
Linus Torvalds's avatar
Linus Torvalds committed
55
unsigned int sa11x0_freq_to_ppcr(unsigned int khz)
Linus Torvalds's avatar
Linus Torvalds committed
56 57 58 59 60
{
	int i;

	khz /= 100;

61 62
	for (i = 0; i < NR_FREQS; i++)
		if (cclk_frequency_100khz[i] >= khz)
Linus Torvalds's avatar
Linus Torvalds committed
63 64
			break;

Linus Torvalds's avatar
Linus Torvalds committed
65
	return i;
Linus Torvalds's avatar
Linus Torvalds committed
66 67
}

68 69
unsigned int sa11x0_ppcr_to_freq(unsigned int idx)
{
70 71 72 73
	unsigned int freq = 0;
	if (idx < NR_FREQS)
		freq = cclk_frequency_100khz[idx] * 100;
	return freq;
74 75 76 77 78
}


/* make sure that only the "userspace" governor is run -- anything else wouldn't make sense on
 * this platform, anyway.
Linus Torvalds's avatar
Linus Torvalds committed
79
 */
80
int sa11x0_verify_speed(struct cpufreq_policy *policy)
Linus Torvalds's avatar
Linus Torvalds committed
81
{
82 83 84 85 86 87 88 89 90 91 92 93
	unsigned int tmp;
	if (policy->cpu)
		return -EINVAL;

	cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, policy->cpuinfo.max_freq);

	/* make sure that at least one frequency is within the policy */
	tmp = cclk_frequency_100khz[sa11x0_freq_to_ppcr(policy->min)] * 100;
	if (tmp > policy->max)
		policy->max = tmp;

	cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, policy->cpuinfo.max_freq);
94

95
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
96 97
}

98
unsigned int sa11x0_getspeed(void)
Linus Torvalds's avatar
Linus Torvalds committed
99
{
100
	return cclk_frequency_100khz[PPCR & 0xf] * 100;
Linus Torvalds's avatar
Linus Torvalds committed
101
}
102
EXPORT_SYMBOL(sa11x0_getspeed);
Linus Torvalds's avatar
Linus Torvalds committed
103 104 105 106
#else
/*
 * We still need to provide this so building without cpufreq works.
 */ 
107
unsigned int cpufreq_get(unsigned int cpu)
Linus Torvalds's avatar
Linus Torvalds committed
108 109 110 111
{
	return cclk_frequency_100khz[PPCR & 0xf] * 100;
}
EXPORT_SYMBOL(cpufreq_get);
Linus Torvalds's avatar
Linus Torvalds committed
112 113 114 115 116 117 118 119
#endif

/*
 * Default power-off for SA1100
 */
static void sa1100_power_off(void)
{
	mdelay(100);
120
	local_irq_disable();
Linus Torvalds's avatar
Linus Torvalds committed
121 122 123 124 125 126 127 128 129 130 131 132 133
	/* disable internal oscillator, float CS lines */
	PCFR = (PCFR_OPDE | PCFR_FP | PCFR_FS);
	/* enable wake-up on GPIO0 (Assabet...) */
	PWER = GFER = GRER = 1;
	/*
	 * set scratchpad to zero, just in case it is used as a
	 * restart address by the bootloader.
	 */
	PSPR = 0;
	/* enter sleep mode */
	PMCR = PMCR_SF;
}

134 135 136 137 138 139 140 141
static struct resource sa11x0udc_resources[] = {
	[0] = {
		.start	= 0x80000000,
		.end	= 0x8000ffff,
		.flags	= IORESOURCE_MEM,
	},
};

142 143
static u64 sa11x0udc_dma_mask = 0xffffffffUL;

144 145 146 147
static struct platform_device sa11x0udc_device = {
	.name		= "sa11x0-udc",
	.id		= 0,
	.dev		= {
148
		.dma_mask = &sa11x0udc_dma_mask,
149 150 151 152 153 154 155 156 157 158 159 160 161
	},
	.num_resources	= ARRAY_SIZE(sa11x0udc_resources),
	.resource	= sa11x0udc_resources,
};

static struct resource sa11x0mcp_resources[] = {
	[0] = {
		.start	= 0x80060000,
		.end	= 0x8006ffff,
		.flags	= IORESOURCE_MEM,
	},
};

162 163
static u64 sa11x0mcp_dma_mask = 0xffffffffUL;

164 165 166
static struct platform_device sa11x0mcp_device = {
	.name		= "sa11x0-mcp",
	.id		= 0,
167 168 169
	.dev = {
		.dma_mask = &sa11x0mcp_dma_mask,
	},
170 171 172 173
	.num_resources	= ARRAY_SIZE(sa11x0mcp_resources),
	.resource	= sa11x0mcp_resources,
};

174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
static struct resource sa11x0ssp_resources[] = {
	[0] = {
		.start	= 0x80070000,
		.end	= 0x8007ffff,
		.flags	= IORESOURCE_MEM,
	},
};

static u64 sa11x0ssp_dma_mask = 0xffffffffUL;

static struct platform_device sa11x0ssp_device = {
	.name		= "sa11x0-ssp",
	.id		= 0,
	.dev = {
		.dma_mask = &sa11x0ssp_dma_mask,
	},
	.num_resources	= ARRAY_SIZE(sa11x0ssp_resources),
	.resource	= sa11x0ssp_resources,
};

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 221
static struct resource sa11x0fb_resources[] = {
	[0] = {
		.start	= 0xb0100000,
		.end	= 0xb010ffff,
		.flags	= IORESOURCE_MEM,
	},
	[1] = {
		.start	= IRQ_LCD,
		.end	= IRQ_LCD,
		.flags	= IORESOURCE_IRQ,
	},
};

static struct platform_device sa11x0fb_device = {
	.name		= "sa11x0-fb",
	.id		= 0,
	.num_resources	= ARRAY_SIZE(sa11x0fb_resources),
	.resource	= sa11x0fb_resources,
};

static struct platform_device sa11x0pcmcia_device = {
	.name		= "sa11x0-pcmcia",
	.id		= 0,
};

static struct platform_device *sa11x0_devices[] __initdata = {
	&sa11x0udc_device,
	&sa11x0mcp_device,
222
	&sa11x0ssp_device,
223 224 225 226
	&sa11x0pcmcia_device,
	&sa11x0fb_device,
};

Linus Torvalds's avatar
Linus Torvalds committed
227
static int __init sa1100_init(void)
Linus Torvalds's avatar
Linus Torvalds committed
228 229
{
	pm_power_off = sa1100_power_off;
230 231

	return platform_add_devices(sa11x0_devices, ARRAY_SIZE(sa11x0_devices));
Linus Torvalds's avatar
Linus Torvalds committed
232 233
}

234
arch_initcall(sa1100_init);
Linus Torvalds's avatar
Linus Torvalds committed
235 236 237 238 239 240

void (*sa1100fb_backlight_power)(int on);
void (*sa1100fb_lcd_power)(int on);

EXPORT_SYMBOL(sa1100fb_backlight_power);
EXPORT_SYMBOL(sa1100fb_lcd_power);
Linus Torvalds's avatar
Linus Torvalds committed
241 242 243 244 245 246 247 248 249 250


/*
 * Common I/O mapping:
 *
 * Typically, static virtual address mappings are as follow:
 *
 * 0xf0000000-0xf3ffffff:	miscellaneous stuff (CPLDs, etc.)
 * 0xf4000000-0xf4ffffff:	SA-1111
 * 0xf5000000-0xf5ffffff:	reserved (used by cache flushing area)
Linus Torvalds's avatar
Linus Torvalds committed
251 252 253
 * 0xf6000000-0xfffeffff:	reserved (internal SA1100 IO defined above)
 * 0xffff0000-0xffff0fff:	SA1100 exception vectors
 * 0xffff2000-0xffff2fff:	Minicache copy_user_page area
Linus Torvalds's avatar
Linus Torvalds committed
254 255 256 257 258 259 260 261
 *
 * Below 0xe8000000 is reserved for vm allocation.
 *
 * The machine specific code must provide the extra mapping beside the
 * default mapping provided here.
 */

static struct map_desc standard_io_desc[] __initdata = {
262 263 264 265 266
 /* virtual     physical    length      type */
  { 0xf8000000, 0x80000000, 0x00100000, MT_DEVICE }, /* PCM */
  { 0xfa000000, 0x90000000, 0x00100000, MT_DEVICE }, /* SCM */
  { 0xfc000000, 0xa0000000, 0x00100000, MT_DEVICE }, /* MER */
  { 0xfe000000, 0xb0000000, 0x00200000, MT_DEVICE }  /* LCD + DMA */
Linus Torvalds's avatar
Linus Torvalds committed
267 268 269 270
};

void __init sa1100_map_io(void)
{
271
	iotable_init(standard_io_desc, ARRAY_SIZE(standard_io_desc));
Linus Torvalds's avatar
Linus Torvalds committed
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

/*
 * Disable the memory bus request/grant signals on the SA1110 to
 * ensure that we don't receive spurious memory requests.  We set
 * the MBGNT signal false to ensure the SA1111 doesn't own the
 * SDRAM bus.
 */
void __init sa1110_mb_disable(void)
{
	unsigned long flags;

	local_irq_save(flags);
	
	PGSR &= ~GPIO_MBGNT;
	GPCR = GPIO_MBGNT;
	GPDR = (GPDR & ~GPIO_MBREQ) | GPIO_MBGNT;

	GAFR &= ~(GPIO_MBGNT | GPIO_MBREQ);

	local_irq_restore(flags);
}

/*
 * If the system is going to use the SA-1111 DMA engines, set up
 * the memory bus request/grant pins.
 */
void __init sa1110_mb_enable(void)
{
	unsigned long flags;

	local_irq_save(flags);

	PGSR &= ~GPIO_MBGNT;
	GPCR = GPIO_MBGNT;
	GPDR = (GPDR & ~GPIO_MBREQ) | GPIO_MBGNT;

	GAFR |= (GPIO_MBGNT | GPIO_MBREQ);
	TUCR |= TUCR_MR;

	local_irq_restore(flags);
}
314