diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/arm/mach-integrator |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/arm/mach-integrator')
-rw-r--r-- | arch/arm/mach-integrator/Kconfig | 33 | ||||
-rw-r--r-- | arch/arm/mach-integrator/Makefile | 14 | ||||
-rw-r--r-- | arch/arm/mach-integrator/Makefile.boot | 4 | ||||
-rw-r--r-- | arch/arm/mach-integrator/clock.c | 141 | ||||
-rw-r--r-- | arch/arm/mach-integrator/clock.h | 25 | ||||
-rw-r--r-- | arch/arm/mach-integrator/common.h | 2 | ||||
-rw-r--r-- | arch/arm/mach-integrator/core.c | 271 | ||||
-rw-r--r-- | arch/arm/mach-integrator/cpu.c | 221 | ||||
-rw-r--r-- | arch/arm/mach-integrator/dma.c | 35 | ||||
-rw-r--r-- | arch/arm/mach-integrator/impd1.c | 475 | ||||
-rw-r--r-- | arch/arm/mach-integrator/integrator_ap.c | 302 | ||||
-rw-r--r-- | arch/arm/mach-integrator/integrator_cp.c | 528 | ||||
-rw-r--r-- | arch/arm/mach-integrator/leds.c | 88 | ||||
-rw-r--r-- | arch/arm/mach-integrator/lm.c | 96 | ||||
-rw-r--r-- | arch/arm/mach-integrator/pci.c | 132 | ||||
-rw-r--r-- | arch/arm/mach-integrator/pci_v3.c | 604 | ||||
-rw-r--r-- | arch/arm/mach-integrator/time.c | 213 |
17 files changed, 3184 insertions, 0 deletions
diff --git a/arch/arm/mach-integrator/Kconfig b/arch/arm/mach-integrator/Kconfig new file mode 100644 index 00000000000..df97d16390e --- /dev/null +++ b/arch/arm/mach-integrator/Kconfig @@ -0,0 +1,33 @@ +if ARCH_INTEGRATOR + +menu "Integrator Options" + +config ARCH_INTEGRATOR_AP + bool "Support Integrator/AP and Integrator/PP2 platforms" + help + Include support for the ARM(R) Integrator/AP and + Integrator/PP2 platforms. + +config ARCH_INTEGRATOR_CP + bool "Support Integrator/CP platform" + select ARCH_CINTEGRATOR + help + Include support for the ARM(R) Integrator CP platform. + +config ARCH_CINTEGRATOR + bool + +config INTEGRATOR_IMPD1 + tristate "Include support for Integrator/IM-PD1" + depends on ARCH_INTEGRATOR_AP + help + The IM-PD1 is an add-on logic module for the Integrator which + allows ARM(R) Ltd PrimeCells to be developed and evaluated. + The IM-PD1 can be found on the Integrator/PP2 platform. + + To compile this driver as a module, choose M here: the + module will be called impd1. + +endmenu + +endif diff --git a/arch/arm/mach-integrator/Makefile b/arch/arm/mach-integrator/Makefile new file mode 100644 index 00000000000..158daaf9e3b --- /dev/null +++ b/arch/arm/mach-integrator/Makefile @@ -0,0 +1,14 @@ +# +# Makefile for the linux kernel. +# + +# Object file lists. + +obj-y := clock.o core.o lm.o time.o +obj-$(CONFIG_ARCH_INTEGRATOR_AP) += integrator_ap.o +obj-$(CONFIG_ARCH_INTEGRATOR_CP) += integrator_cp.o + +obj-$(CONFIG_LEDS) += leds.o +obj-$(CONFIG_PCI) += pci_v3.o pci.o +obj-$(CONFIG_CPU_FREQ_INTEGRATOR) += cpu.o +obj-$(CONFIG_INTEGRATOR_IMPD1) += impd1.o diff --git a/arch/arm/mach-integrator/Makefile.boot b/arch/arm/mach-integrator/Makefile.boot new file mode 100644 index 00000000000..c7e75acfe6c --- /dev/null +++ b/arch/arm/mach-integrator/Makefile.boot @@ -0,0 +1,4 @@ + zreladdr-y := 0x00008000 +params_phys-y := 0x00000100 +initrd_phys-y := 0x00800000 + diff --git a/arch/arm/mach-integrator/clock.c b/arch/arm/mach-integrator/clock.c new file mode 100644 index 00000000000..56200594db3 --- /dev/null +++ b/arch/arm/mach-integrator/clock.c @@ -0,0 +1,141 @@ +/* + * linux/arch/arm/mach-integrator/clock.c + * + * Copyright (C) 2004 ARM Limited. + * Written by Deep Blue Solutions Limited. + * + * 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/module.h> +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/errno.h> +#include <linux/err.h> + +#include <asm/semaphore.h> +#include <asm/hardware/clock.h> +#include <asm/hardware/icst525.h> + +#include "clock.h" + +static LIST_HEAD(clocks); +static DECLARE_MUTEX(clocks_sem); + +struct clk *clk_get(struct device *dev, const char *id) +{ + struct clk *p, *clk = ERR_PTR(-ENOENT); + + down(&clocks_sem); + list_for_each_entry(p, &clocks, node) { + if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) { + clk = p; + break; + } + } + up(&clocks_sem); + + return clk; +} +EXPORT_SYMBOL(clk_get); + +void clk_put(struct clk *clk) +{ + module_put(clk->owner); +} +EXPORT_SYMBOL(clk_put); + +int clk_enable(struct clk *clk) +{ + return 0; +} +EXPORT_SYMBOL(clk_enable); + +void clk_disable(struct clk *clk) +{ +} +EXPORT_SYMBOL(clk_disable); + +int clk_use(struct clk *clk) +{ + return 0; +} +EXPORT_SYMBOL(clk_use); + +void clk_unuse(struct clk *clk) +{ +} +EXPORT_SYMBOL(clk_unuse); + +unsigned long clk_get_rate(struct clk *clk) +{ + return clk->rate; +} +EXPORT_SYMBOL(clk_get_rate); + +long clk_round_rate(struct clk *clk, unsigned long rate) +{ + struct icst525_vco vco; + + vco = icst525_khz_to_vco(clk->params, rate / 1000); + return icst525_khz(clk->params, vco) * 1000; +} +EXPORT_SYMBOL(clk_round_rate); + +int clk_set_rate(struct clk *clk, unsigned long rate) +{ + int ret = -EIO; + if (clk->setvco) { + struct icst525_vco vco; + + vco = icst525_khz_to_vco(clk->params, rate / 1000); + clk->rate = icst525_khz(clk->params, vco) * 1000; + + printk("Clock %s: setting VCO reg params: S=%d R=%d V=%d\n", + clk->name, vco.s, vco.r, vco.v); + + clk->setvco(clk, vco); + ret = 0; + } + return 0; +} +EXPORT_SYMBOL(clk_set_rate); + +/* + * These are fixed clocks. + */ +static struct clk kmi_clk = { + .name = "KMIREFCLK", + .rate = 24000000, +}; + +static struct clk uart_clk = { + .name = "UARTCLK", + .rate = 14745600, +}; + +int clk_register(struct clk *clk) +{ + down(&clocks_sem); + list_add(&clk->node, &clocks); + up(&clocks_sem); + return 0; +} +EXPORT_SYMBOL(clk_register); + +void clk_unregister(struct clk *clk) +{ + down(&clocks_sem); + list_del(&clk->node); + up(&clocks_sem); +} +EXPORT_SYMBOL(clk_unregister); + +static int __init clk_init(void) +{ + clk_register(&kmi_clk); + clk_register(&uart_clk); + return 0; +} +arch_initcall(clk_init); diff --git a/arch/arm/mach-integrator/clock.h b/arch/arm/mach-integrator/clock.h new file mode 100644 index 00000000000..09e6328ceba --- /dev/null +++ b/arch/arm/mach-integrator/clock.h @@ -0,0 +1,25 @@ +/* + * linux/arch/arm/mach-integrator/clock.h + * + * Copyright (C) 2004 ARM Limited. + * Written by Deep Blue Solutions Limited. + * + * 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. + */ +struct module; +struct icst525_params; + +struct clk { + struct list_head node; + unsigned long rate; + struct module *owner; + const char *name; + const struct icst525_params *params; + void *data; + void (*setvco)(struct clk *, struct icst525_vco vco); +}; + +int clk_register(struct clk *clk); +void clk_unregister(struct clk *clk); diff --git a/arch/arm/mach-integrator/common.h b/arch/arm/mach-integrator/common.h new file mode 100644 index 00000000000..609c49de3d4 --- /dev/null +++ b/arch/arm/mach-integrator/common.h @@ -0,0 +1,2 @@ +extern void integrator_time_init(unsigned long, unsigned int); +extern unsigned long integrator_gettimeoffset(void); diff --git a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c new file mode 100644 index 00000000000..86c50c3889b --- /dev/null +++ b/arch/arm/mach-integrator/core.c @@ -0,0 +1,271 @@ +/* + * linux/arch/arm/mach-integrator/core.c + * + * Copyright (C) 2000-2003 Deep Blue Solutions Ltd + * + * 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/types.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/spinlock.h> +#include <linux/interrupt.h> +#include <linux/sched.h> + +#include <asm/hardware.h> +#include <asm/irq.h> +#include <asm/io.h> +#include <asm/hardware/amba.h> +#include <asm/arch/cm.h> +#include <asm/system.h> +#include <asm/leds.h> +#include <asm/mach/time.h> + +#include "common.h" + +static struct amba_device rtc_device = { + .dev = { + .bus_id = "mb:15", + }, + .res = { + .start = INTEGRATOR_RTC_BASE, + .end = INTEGRATOR_RTC_BASE + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + .irq = { IRQ_RTCINT, NO_IRQ }, + .periphid = 0x00041030, +}; + +static struct amba_device uart0_device = { + .dev = { + .bus_id = "mb:16", + }, + .res = { + .start = INTEGRATOR_UART0_BASE, + .end = INTEGRATOR_UART0_BASE + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + .irq = { IRQ_UARTINT0, NO_IRQ }, + .periphid = 0x0041010, +}; + +static struct amba_device uart1_device = { + .dev = { + .bus_id = "mb:17", + }, + .res = { + .start = INTEGRATOR_UART1_BASE, + .end = INTEGRATOR_UART1_BASE + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + .irq = { IRQ_UARTINT1, NO_IRQ }, + .periphid = 0x0041010, +}; + +static struct amba_device kmi0_device = { + .dev = { + .bus_id = "mb:18", + }, + .res = { + .start = KMI0_BASE, + .end = KMI0_BASE + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + .irq = { IRQ_KMIINT0, NO_IRQ }, + .periphid = 0x00041050, +}; + +static struct amba_device kmi1_device = { + .dev = { + .bus_id = "mb:19", + }, + .res = { + .start = KMI1_BASE, + .end = KMI1_BASE + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + .irq = { IRQ_KMIINT1, NO_IRQ }, + .periphid = 0x00041050, +}; + +static struct amba_device *amba_devs[] __initdata = { + &rtc_device, + &uart0_device, + &uart1_device, + &kmi0_device, + &kmi1_device, +}; + +static int __init integrator_init(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(amba_devs); i++) { + struct amba_device *d = amba_devs[i]; + amba_device_register(d, &iomem_resource); + } + + return 0; +} + +arch_initcall(integrator_init); + +#define CM_CTRL IO_ADDRESS(INTEGRATOR_HDR_BASE) + INTEGRATOR_HDR_CTRL_OFFSET + +static DEFINE_SPINLOCK(cm_lock); + +/** + * cm_control - update the CM_CTRL register. + * @mask: bits to change + * @set: bits to set + */ +void cm_control(u32 mask, u32 set) +{ + unsigned long flags; + u32 val; + + spin_lock_irqsave(&cm_lock, flags); + val = readl(CM_CTRL) & ~mask; + writel(val | set, CM_CTRL); + spin_unlock_irqrestore(&cm_lock, flags); +} + +EXPORT_SYMBOL(cm_control); + +/* + * Where is the timer (VA)? + */ +#define TIMER0_VA_BASE (IO_ADDRESS(INTEGRATOR_CT_BASE)+0x00000000) +#define TIMER1_VA_BASE (IO_ADDRESS(INTEGRATOR_CT_BASE)+0x00000100) +#define TIMER2_VA_BASE (IO_ADDRESS(INTEGRATOR_CT_BASE)+0x00000200) +#define VA_IC_BASE IO_ADDRESS(INTEGRATOR_IC_BASE) + +/* + * How long is the timer interval? + */ +#define TIMER_INTERVAL (TICKS_PER_uSEC * mSEC_10) +#if TIMER_INTERVAL >= 0x100000 +#define TICKS2USECS(x) (256 * (x) / TICKS_PER_uSEC) +#elif TIMER_INTERVAL >= 0x10000 +#define TICKS2USECS(x) (16 * (x) / TICKS_PER_uSEC) +#else +#define TICKS2USECS(x) ((x) / TICKS_PER_uSEC) +#endif + +/* + * What does it look like? + */ +typedef struct TimerStruct { + unsigned long TimerLoad; + unsigned long TimerValue; + unsigned long TimerControl; + unsigned long TimerClear; +} TimerStruct_t; + +static unsigned long timer_reload; + +/* + * Returns number of ms since last clock interrupt. Note that interrupts + * will have been disabled by do_gettimeoffset() + */ +unsigned long integrator_gettimeoffset(void) +{ + volatile TimerStruct_t *timer1 = (TimerStruct_t *)TIMER1_VA_BASE; + unsigned long ticks1, ticks2, status; + + /* + * Get the current number of ticks. Note that there is a race + * condition between us reading the timer and checking for + * an interrupt. We get around this by ensuring that the + * counter has not reloaded between our two reads. + */ + ticks2 = timer1->TimerValue & 0xffff; + do { + ticks1 = ticks2; + status = __raw_readl(VA_IC_BASE + IRQ_RAW_STATUS); + ticks2 = timer1->TimerValue & 0xffff; + } while (ticks2 > ticks1); + + /* + * Number of ticks since last interrupt. + */ + ticks1 = timer_reload - ticks2; + + /* + * Interrupt pending? If so, we've reloaded once already. + */ + if (status & (1 << IRQ_TIMERINT1)) + ticks1 += timer_reload; + + /* + * Convert the ticks to usecs + */ + return TICKS2USECS(ticks1); +} + +/* + * IRQ handler for the timer + */ +static irqreturn_t +integrator_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + volatile TimerStruct_t *timer1 = (volatile TimerStruct_t *)TIMER1_VA_BASE; + + write_seqlock(&xtime_lock); + + // ...clear the interrupt + timer1->TimerClear = 1; + + timer_tick(regs); + + write_sequnlock(&xtime_lock); + + return IRQ_HANDLED; +} + +static struct irqaction integrator_timer_irq = { + .name = "Integrator Timer Tick", + .flags = SA_INTERRUPT, + .handler = integrator_timer_interrupt +}; + +/* + * Set up timer interrupt, and return the current time in seconds. + */ +void __init integrator_time_init(unsigned long reload, unsigned int ctrl) +{ + volatile TimerStruct_t *timer0 = (volatile TimerStruct_t *)TIMER0_VA_BASE; + volatile TimerStruct_t *timer1 = (volatile TimerStruct_t *)TIMER1_VA_BASE; + volatile TimerStruct_t *timer2 = (volatile TimerStruct_t *)TIMER2_VA_BASE; + unsigned int timer_ctrl = 0x80 | 0x40; /* periodic */ + + timer_reload = reload; + timer_ctrl |= ctrl; + + if (timer_reload > 0x100000) { + timer_reload >>= 8; + timer_ctrl |= 0x08; /* /256 */ + } else if (timer_reload > 0x010000) { + timer_reload >>= 4; + timer_ctrl |= 0x04; /* /16 */ + } + + /* + * Initialise to a known state (all timers off) + */ + timer0->TimerControl = 0; + timer1->TimerControl = 0; + timer2->TimerControl = 0; + + timer1->TimerLoad = timer_reload; + timer1->TimerValue = timer_reload; + timer1->TimerControl = timer_ctrl; + + /* + * Make irqs happen for the system timer + */ + setup_irq(IRQ_TIMERINT1, &integrator_timer_irq); +} diff --git a/arch/arm/mach-integrator/cpu.c b/arch/arm/mach-integrator/cpu.c new file mode 100644 index 00000000000..71c58bff304 --- /dev/null +++ b/arch/arm/mach-integrator/cpu.c @@ -0,0 +1,221 @@ +/* + * linux/arch/arm/mach-integrator/cpu.c + * + * Copyright (C) 2001-2002 Deep Blue Solutions Ltd. + * + * $Id: cpu.c,v 1.6 2002/07/18 13:58:51 rmk Exp $ + * + * 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. + * + * CPU support functions + */ +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/cpufreq.h> +#include <linux/slab.h> +#include <linux/sched.h> +#include <linux/smp.h> +#include <linux/init.h> + +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/mach-types.h> +#include <asm/hardware/icst525.h> + +static struct cpufreq_driver integrator_driver; + +#define CM_ID (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_ID_OFFSET) +#define CM_OSC (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_OSC_OFFSET) +#define CM_STAT (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_STAT_OFFSET) +#define CM_LOCK (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_LOCK_OFFSET) + +static const struct icst525_params lclk_params = { + .ref = 24000, + .vco_max = 320000, + .vd_min = 8, + .vd_max = 132, + .rd_min = 24, + .rd_max = 24, +}; + +static const struct icst525_params cclk_params = { + .ref = 24000, + .vco_max = 320000, + .vd_min = 12, + .vd_max = 160, + .rd_min = 24, + .rd_max = 24, +}; + +/* + * Validate the speed policy. + */ +static int integrator_verify_policy(struct cpufreq_policy *policy) +{ + struct icst525_vco vco; + + cpufreq_verify_within_limits(policy, + policy->cpuinfo.min_freq, + policy->cpuinfo.max_freq); + + vco = icst525_khz_to_vco(&cclk_params, policy->max); + policy->max = icst525_khz(&cclk_params, vco); + + vco = icst525_khz_to_vco(&cclk_params, policy->min); + policy->min = icst525_khz(&cclk_params, vco); + + cpufreq_verify_within_limits(policy, + policy->cpuinfo.min_freq, + policy->cpuinfo.max_freq); + + return 0; +} + + +static int integrator_set_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + cpumask_t cpus_allowed; + int cpu = policy->cpu; + struct icst525_vco vco; + struct cpufreq_freqs freqs; + u_int cm_osc; + + /* + * Save this threads cpus_allowed mask. + */ + cpus_allowed = current->cpus_allowed; + + /* + * Bind to the specified CPU. When this call returns, + * we should be running on the right CPU. + */ + set_cpus_allowed(current, cpumask_of_cpu(cpu)); + BUG_ON(cpu != smp_processor_id()); + + /* get current setting */ + cm_osc = __raw_readl(CM_OSC); + + if (machine_is_integrator()) { + vco.s = (cm_osc >> 8) & 7; + } else if (machine_is_cintegrator()) { + vco.s = 1; + } + vco.v = cm_osc & 255; + vco.r = 22; + freqs.old = icst525_khz(&cclk_params, vco); + + /* icst525_khz_to_vco rounds down -- so we need the next + * larger freq in case of CPUFREQ_RELATION_L. + */ + if (relation == CPUFREQ_RELATION_L) + target_freq += 999; + if (target_freq > policy->max) + target_freq = policy->max; + vco = icst525_khz_to_vco(&cclk_params, target_freq); + freqs.new = icst525_khz(&cclk_params, vco); + + freqs.cpu = policy->cpu; + + if (freqs.old == freqs.new) { + set_cpus_allowed(current, cpus_allowed); + return 0; + } + + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + + cm_osc = __raw_readl(CM_OSC); + + if (machine_is_integrator()) { + cm_osc &= 0xfffff800; + cm_osc |= vco.s << 8; + } else if (machine_is_cintegrator()) { + cm_osc &= 0xffffff00; + } + cm_osc |= vco.v; + + __raw_writel(0xa05f, CM_LOCK); + __raw_writel(cm_osc, CM_OSC); + __raw_writel(0, CM_LOCK); + + /* + * Restore the CPUs allowed mask. + */ + set_cpus_allowed(current, cpus_allowed); + + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + + return 0; +} + +static unsigned int integrator_get(unsigned int cpu) +{ + cpumask_t cpus_allowed; + unsigned int current_freq; + u_int cm_osc; + struct icst525_vco vco; + + cpus_allowed = current->cpus_allowed; + + set_cpus_allowed(current, cpumask_of_cpu(cpu)); + BUG_ON(cpu != smp_processor_id()); + + /* detect memory etc. */ + cm_osc = __raw_readl(CM_OSC); + + if (machine_is_integrator()) { + vco.s = (cm_osc >> 8) & 7; + } else if (machine_is_cintegrator()) { + vco.s = 1; + } + vco.v = cm_osc & 255; + vco.r = 22; + + current_freq = icst525_khz(&cclk_params, vco); /* current freq */ + + set_cpus_allowed(current, cpus_allowed); + + return current_freq; +} + +static int integrator_cpufreq_init(struct cpufreq_policy *policy) +{ + + /* set default policy and cpuinfo */ + policy->governor = CPUFREQ_DEFAULT_GOVERNOR; + policy->cpuinfo.max_freq = 160000; + policy->cpuinfo.min_freq = 12000; + policy->cpuinfo.transition_latency = 1000000; /* 1 ms, assumed */ + policy->cur = policy->min = policy->max = integrator_get(policy->cpu); + + return 0; +} + +static struct cpufreq_driver integrator_driver = { + .verify = integrator_verify_policy, + .target = integrator_set_target, + .get = integrator_get, + .init = integrator_cpufreq_init, + .name = "integrator", +}; + +static int __init integrator_cpu_init(void) +{ + return cpufreq_register_driver(&integrator_driver); +} + +static void __exit integrator_cpu_exit(void) +{ + cpufreq_unregister_driver(&integrator_driver); +} + +MODULE_AUTHOR ("Russell M. King"); +MODULE_DESCRIPTION ("cpufreq driver for ARM Integrator CPUs"); +MODULE_LICENSE ("GPL"); + +module_init(integrator_cpu_init); +module_exit(integrator_cpu_exit); diff --git a/arch/arm/mach-integrator/dma.c b/arch/arm/mach-integrator/dma.c new file mode 100644 index 00000000000..aae6f23cd72 --- /dev/null +++ b/arch/arm/mach-integrator/dma.c @@ -0,0 +1,35 @@ +/* + * linux/arch/arm/mach-integrator/dma.c + * + * Copyright (C) 1999 ARM Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <linux/slab.h> +#include <linux/mman.h> +#include <linux/init.h> + +#include <asm/page.h> +#include <asm/pgtable.h> +#include <asm/dma.h> +#include <asm/io.h> +#include <asm/hardware.h> + +#include <asm/mach/dma.h> + +void __init arch_dma_init(dma_t *dma) +{ +} diff --git a/arch/arm/mach-integrator/impd1.c b/arch/arm/mach-integrator/impd1.c new file mode 100644 index 00000000000..c3c2f17d030 --- /dev/null +++ b/arch/arm/mach-integrator/impd1.c @@ -0,0 +1,475 @@ +/* + * linux/arch/arm/mach-integrator/impd1.c + * + * Copyright (C) 2003 Deep Blue Solutions Ltd, All Rights Reserved. + * + * 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. + * + * This file provides the core support for the IM-PD1 module. + * + * Module / boot parameters. + * lmid=n impd1.lmid=n - set the logic module position in stack to 'n' + */ +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/mm.h> + +#include <asm/io.h> +#include <asm/hardware/icst525.h> +#include <asm/hardware/amba.h> +#include <asm/hardware/amba_clcd.h> +#include <asm/arch/lm.h> +#include <asm/arch/impd1.h> +#include <asm/sizes.h> + +#include "clock.h" + +static int module_id; + +module_param_named(lmid, module_id, int, 0444); +MODULE_PARM_DESC(lmid, "logic module stack position"); + +struct impd1_module { + void __iomem *base; + struct clk vcos[2]; +}; + +static const struct icst525_params impd1_vco_params = { + .ref = 24000, /* 24 MHz */ + .vco_max = 200000, /* 200 MHz */ + .vd_min = 12, + .vd_max = 519, + .rd_min = 3, + .rd_max = 120, +}; + +static void impd1_setvco(struct clk *clk, struct icst525_vco vco) +{ + struct impd1_module *impd1 = clk->data; + int vconr = clk - impd1->vcos; + u32 val; + + val = vco.v | (vco.r << 9) | (vco.s << 16); + + writel(0xa05f, impd1->base + IMPD1_LOCK); + switch (vconr) { + case 0: + writel(val, impd1->base + IMPD1_OSC1); + break; + case 1: + writel(val, impd1->base + IMPD1_OSC2); + break; + } + writel(0, impd1->base + IMPD1_LOCK); + +#if DEBUG + vco.v = val & 0x1ff; + vco.r = (val >> 9) & 0x7f; + vco.s = (val >> 16) & 7; + + pr_debug("IM-PD1: VCO%d clock is %ld kHz\n", + vconr, icst525_khz(&impd1_vco_params, vco)); +#endif +} + +void impd1_tweak_control(struct device *dev, u32 mask, u32 val) +{ + struct impd1_module *impd1 = dev_get_drvdata(dev); + u32 cur; + + val &= mask; + cur = readl(impd1->base + IMPD1_CTRL) & ~mask; + writel(cur | val, impd1->base + IMPD1_CTRL); +} + +EXPORT_SYMBOL(impd1_tweak_control); + +/* + * CLCD support + */ +#define PANEL PROSPECTOR + +#define LTM10C209 1 +#define PROSPECTOR 2 +#define SVGA 3 +#define VGA 4 + +#if PANEL == VGA +#define PANELTYPE vga +static struct clcd_panel vga = { + .mode = { + .name = "VGA", + .refresh = 60, + .xres = 640, + .yres = 480, + .pixclock = 39721, + .left_margin = 40, + .right_margin = 24, + .upper_margin = 32, + .lower_margin = 11, + .hsync_len = 96, + .vsync_len = 2, + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED, + }, + .width = -1, + .height = -1, + .tim2 = TIM2_BCD | TIM2_IPC, + .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1), + .connector = IMPD1_CTRL_DISP_VGA, + .bpp = 16, + .grayscale = 0, +}; + +#elif PANEL == SVGA +#define PANELTYPE svga +static struct clcd_panel svga = { + .mode = { + .name = "SVGA", + .refresh = 0, + .xres = 800, + .yres = 600, + .pixclock = 27778, + .left_margin = 20, + .right_margin = 20, + .upper_margin = 5, + .lower_margin = 5, + .hsync_len = 164, + .vsync_len = 62, + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED, + }, + .width = -1, + .height = -1, + .tim2 = TIM2_BCD, + .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1), + .connector = IMPD1_CTRL_DISP_VGA, + .bpp = 16, + .grayscale = 0, +}; + +#elif PANEL == PROSPECTOR +#define PANELTYPE prospector +static struct clcd_panel prospector = { + .mode = { + .name = "PROSPECTOR", + .refresh = 0, + .xres = 640, + .yres = 480, + .pixclock = 40000, + .left_margin = 33, + .right_margin = 64, + .upper_margin = 36, + .lower_margin = 7, + .hsync_len = 64, + .vsync_len = 25, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED, + }, + .width = -1, + .height = -1, + .tim2 = TIM2_BCD, + .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1), + .fixedtimings = 1, + .connector = IMPD1_CTRL_DISP_LCD, + .bpp = 16, + .grayscale = 0, +}; + +#elif PANEL == LTM10C209 +#define PANELTYPE ltm10c209 +/* + * Untested. + */ +static struct clcd_panel ltm10c209 = { + .mode = { + .name = "LTM10C209", + .refresh = 0, + .xres = 640, + .yres = 480, + .pixclock = 40000, + .left_margin = 20, + .right_margin = 20, + .upper_margin = 19, + .lower_margin = 19, + .hsync_len = 20, + .vsync_len = 10, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED, + }, + .width = -1, + .height = -1, + .tim2 = TIM2_BCD, + .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1), + .fixedtimings = 1, + .connector = IMPD1_CTRL_DISP_LCD, + .bpp = 16, + .grayscale = 0, +}; +#endif + +/* + * Disable all display connectors on the interface module. + */ +static void impd1fb_clcd_disable(struct clcd_fb *fb) +{ + impd1_tweak_control(fb->dev->dev.parent, IMPD1_CTRL_DISP_MASK, 0); +} + +/* + * Enable the relevant connector on the interface module. + */ +static void impd1fb_clcd_enable(struct clcd_fb *fb) +{ + impd1_tweak_control(fb->dev->dev.parent, IMPD1_CTRL_DISP_MASK, + fb->panel->connector | IMPD1_CTRL_DISP_ENABLE); +} + +static int impd1fb_clcd_setup(struct clcd_fb *fb) +{ + unsigned long framebase = fb->dev->res.start + 0x01000000; + unsigned long framesize = SZ_1M; + int ret = 0; + + fb->panel = &PANELTYPE; + + if (!request_mem_region(framebase, framesize, "clcd framebuffer")) { + printk(KERN_ERR "IM-PD1: unable to reserve framebuffer\n"); + return -EBUSY; + } + + fb->fb.screen_base = ioremap(framebase, framesize); + if (!fb->fb.screen_base) { + printk(KERN_ERR "IM-PD1: unable to map framebuffer\n"); + ret = -ENOMEM; + goto free_buffer; + } + + fb->fb.fix.smem_start = framebase; + fb->fb.fix.smem_len = framesize; + + return 0; + + free_buffer: + release_mem_region(framebase, framesize); + return ret; +} + +static int impd1fb_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma) +{ + unsigned long start, size; + + start = vma->vm_pgoff + (fb->fb.fix.smem_start >> PAGE_SHIFT); + size = vma->vm_end - vma->vm_start; + + return remap_pfn_range(vma, vma->vm_start, start, size, + vma->vm_page_prot); +} + +static void impd1fb_clcd_remove(struct clcd_fb *fb) +{ + iounmap(fb->fb.screen_base); + release_mem_region(fb->fb.fix.smem_start, fb->fb.fix.smem_len); +} + +static struct clcd_board impd1_clcd_data = { + .name = "IM-PD/1", + .check = clcdfb_check, |