aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-integrator
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-integrator')
-rw-r--r--arch/arm/mach-integrator/Kconfig33
-rw-r--r--arch/arm/mach-integrator/Makefile14
-rw-r--r--arch/arm/mach-integrator/Makefile.boot4
-rw-r--r--arch/arm/mach-integrator/clock.c141
-rw-r--r--arch/arm/mach-integrator/clock.h25
-rw-r--r--arch/arm/mach-integrator/common.h2
-rw-r--r--arch/arm/mach-integrator/core.c271
-rw-r--r--arch/arm/mach-integrator/cpu.c221
-rw-r--r--arch/arm/mach-integrator/dma.c35
-rw-r--r--arch/arm/mach-integrator/impd1.c475
-rw-r--r--arch/arm/mach-integrator/integrator_ap.c302
-rw-r--r--arch/arm/mach-integrator/integrator_cp.c528
-rw-r--r--arch/arm/mach-integrator/leds.c88
-rw-r--r--arch/arm/mach-integrator/lm.c96
-rw-r--r--arch/arm/mach-integrator/pci.c132
-rw-r--r--arch/arm/mach-integrator/pci_v3.c604
-rw-r--r--arch/arm/mach-integrator/time.c213
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 000000000000..df97d16390e3
--- /dev/null
+++ b/arch/arm/mach-integrator/Kconfig
@@ -0,0 +1,33 @@
1if ARCH_INTEGRATOR
2
3menu "Integrator Options"
4
5config ARCH_INTEGRATOR_AP
6 bool "Support Integrator/AP and Integrator/PP2 platforms"
7 help
8 Include support for the ARM(R) Integrator/AP and
9 Integrator/PP2 platforms.
10
11config ARCH_INTEGRATOR_CP
12 bool "Support Integrator/CP platform"
13 select ARCH_CINTEGRATOR
14 help
15 Include support for the ARM(R) Integrator CP platform.
16
17config ARCH_CINTEGRATOR
18 bool
19
20config INTEGRATOR_IMPD1
21 tristate "Include support for Integrator/IM-PD1"
22 depends on ARCH_INTEGRATOR_AP
23 help
24 The IM-PD1 is an add-on logic module for the Integrator which
25 allows ARM(R) Ltd PrimeCells to be developed and evaluated.
26 The IM-PD1 can be found on the Integrator/PP2 platform.
27
28 To compile this driver as a module, choose M here: the
29 module will be called impd1.
30
31endmenu
32
33endif
diff --git a/arch/arm/mach-integrator/Makefile b/arch/arm/mach-integrator/Makefile
new file mode 100644
index 000000000000..158daaf9e3b0
--- /dev/null
+++ b/arch/arm/mach-integrator/Makefile
@@ -0,0 +1,14 @@
1#
2# Makefile for the linux kernel.
3#
4
5# Object file lists.
6
7obj-y := clock.o core.o lm.o time.o
8obj-$(CONFIG_ARCH_INTEGRATOR_AP) += integrator_ap.o
9obj-$(CONFIG_ARCH_INTEGRATOR_CP) += integrator_cp.o
10
11obj-$(CONFIG_LEDS) += leds.o
12obj-$(CONFIG_PCI) += pci_v3.o pci.o
13obj-$(CONFIG_CPU_FREQ_INTEGRATOR) += cpu.o
14obj-$(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 000000000000..c7e75acfe6c9
--- /dev/null
+++ b/arch/arm/mach-integrator/Makefile.boot
@@ -0,0 +1,4 @@
1 zreladdr-y := 0x00008000
2params_phys-y := 0x00000100
3initrd_phys-y := 0x00800000
4
diff --git a/arch/arm/mach-integrator/clock.c b/arch/arm/mach-integrator/clock.c
new file mode 100644
index 000000000000..56200594db3c
--- /dev/null
+++ b/arch/arm/mach-integrator/clock.c
@@ -0,0 +1,141 @@
1/*
2 * linux/arch/arm/mach-integrator/clock.c
3 *
4 * Copyright (C) 2004 ARM Limited.
5 * Written by Deep Blue Solutions Limited.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11#include <linux/module.h>
12#include <linux/kernel.h>
13#include <linux/list.h>
14#include <linux/errno.h>
15#include <linux/err.h>
16
17#include <asm/semaphore.h>
18#include <asm/hardware/clock.h>
19#include <asm/hardware/icst525.h>
20
21#include "clock.h"
22
23static LIST_HEAD(clocks);
24static DECLARE_MUTEX(clocks_sem);
25
26struct clk *clk_get(struct device *dev, const char *id)
27{
28 struct clk *p, *clk = ERR_PTR(-ENOENT);
29
30 down(&clocks_sem);
31 list_for_each_entry(p, &clocks, node) {
32 if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
33 clk = p;
34 break;
35 }
36 }
37 up(&clocks_sem);
38
39 return clk;
40}
41EXPORT_SYMBOL(clk_get);
42
43void clk_put(struct clk *clk)
44{
45 module_put(clk->owner);
46}
47EXPORT_SYMBOL(clk_put);
48
49int clk_enable(struct clk *clk)
50{
51 return 0;
52}
53EXPORT_SYMBOL(clk_enable);
54
55void clk_disable(struct clk *clk)
56{
57}
58EXPORT_SYMBOL(clk_disable);
59
60int clk_use(struct clk *clk)
61{
62 return 0;
63}
64EXPORT_SYMBOL(clk_use);
65
66void clk_unuse(struct clk *clk)
67{
68}
69EXPORT_SYMBOL(clk_unuse);
70
71unsigned long clk_get_rate(struct clk *clk)
72{
73 return clk->rate;
74}
75EXPORT_SYMBOL(clk_get_rate);
76
77long clk_round_rate(struct clk *clk, unsigned long rate)
78{
79 struct icst525_vco vco;
80
81 vco = icst525_khz_to_vco(clk->params, rate / 1000);
82 return icst525_khz(clk->params, vco) * 1000;
83}
84EXPORT_SYMBOL(clk_round_rate);
85
86int clk_set_rate(struct clk *clk, unsigned long rate)
87{
88 int ret = -EIO;
89 if (clk->setvco) {
90 struct icst525_vco vco;
91
92 vco = icst525_khz_to_vco(clk->params, rate / 1000);
93 clk->rate = icst525_khz(clk->params, vco) * 1000;
94
95 printk("Clock %s: setting VCO reg params: S=%d R=%d V=%d\n",
96 clk->name, vco.s, vco.r, vco.v);
97
98 clk->setvco(clk, vco);
99 ret = 0;
100 }
101 return 0;
102}
103EXPORT_SYMBOL(clk_set_rate);
104
105/*
106 * These are fixed clocks.
107 */
108static struct clk kmi_clk = {
109 .name = "KMIREFCLK",
110 .rate = 24000000,
111};
112
113static struct clk uart_clk = {
114 .name = "UARTCLK",
115 .rate = 14745600,
116};
117
118int clk_register(struct clk *clk)
119{
120 down(&clocks_sem);
121 list_add(&clk->node, &clocks);
122 up(&clocks_sem);
123 return 0;
124}
125EXPORT_SYMBOL(clk_register);
126
127void clk_unregister(struct clk *clk)
128{
129 down(&clocks_sem);
130 list_del(&clk->node);
131 up(&clocks_sem);
132}
133EXPORT_SYMBOL(clk_unregister);
134
135static int __init clk_init(void)
136{
137 clk_register(&kmi_clk);
138 clk_register(&uart_clk);
139 return 0;
140}
141arch_initcall(clk_init);
diff --git a/arch/arm/mach-integrator/clock.h b/arch/arm/mach-integrator/clock.h
new file mode 100644
index 000000000000..09e6328ceba9
--- /dev/null
+++ b/arch/arm/mach-integrator/clock.h
@@ -0,0 +1,25 @@
1/*
2 * linux/arch/arm/mach-integrator/clock.h
3 *
4 * Copyright (C) 2004 ARM Limited.
5 * Written by Deep Blue Solutions Limited.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11struct module;
12struct icst525_params;
13
14struct clk {
15 struct list_head node;
16 unsigned long rate;
17 struct module *owner;
18 const char *name;
19 const struct icst525_params *params;
20 void *data;
21 void (*setvco)(struct clk *, struct icst525_vco vco);
22};
23
24int clk_register(struct clk *clk);
25void 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 000000000000..609c49de3d47
--- /dev/null
+++ b/arch/arm/mach-integrator/common.h
@@ -0,0 +1,2 @@
1extern void integrator_time_init(unsigned long, unsigned int);
2extern 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 000000000000..86c50c3889b7
--- /dev/null
+++ b/arch/arm/mach-integrator/core.c
@@ -0,0 +1,271 @@
1/*
2 * linux/arch/arm/mach-integrator/core.c
3 *
4 * Copyright (C) 2000-2003 Deep Blue Solutions Ltd
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2, as
8 * published by the Free Software Foundation.
9 */
10#include <linux/types.h>
11#include <linux/kernel.h>
12#include <linux/init.h>
13#include <linux/device.h>
14#include <linux/spinlock.h>
15#include <linux/interrupt.h>
16#include <linux/sched.h>
17
18#include <asm/hardware.h>
19#include <asm/irq.h>
20#include <asm/io.h>
21#include <asm/hardware/amba.h>
22#include <asm/arch/cm.h>
23#include <asm/system.h>
24#include <asm/leds.h>
25#include <asm/mach/time.h>
26
27#include "common.h"
28
29static struct amba_device rtc_device = {
30 .dev = {
31 .bus_id = "mb:15",
32 },
33 .res = {
34 .start = INTEGRATOR_RTC_BASE,
35 .end = INTEGRATOR_RTC_BASE + SZ_4K - 1,
36 .flags = IORESOURCE_MEM,
37 },
38 .irq = { IRQ_RTCINT, NO_IRQ },
39 .periphid = 0x00041030,
40};
41
42static struct amba_device uart0_device = {
43 .dev = {
44 .bus_id = "mb:16",
45 },
46 .res = {
47 .start = INTEGRATOR_UART0_BASE,
48 .end = INTEGRATOR_UART0_BASE + SZ_4K - 1,
49 .flags = IORESOURCE_MEM,
50 },
51 .irq = { IRQ_UARTINT0, NO_IRQ },
52 .periphid = 0x0041010,
53};
54
55static struct amba_device uart1_device = {
56 .dev = {
57 .bus_id = "mb:17",
58 },
59 .res = {
60 .start = INTEGRATOR_UART1_BASE,
61 .end = INTEGRATOR_UART1_BASE + SZ_4K - 1,
62 .flags = IORESOURCE_MEM,
63 },
64 .irq = { IRQ_UARTINT1, NO_IRQ },
65 .periphid = 0x0041010,
66};
67
68static struct amba_device kmi0_device = {
69 .dev = {
70 .bus_id = "mb:18",
71 },
72 .res = {
73 .start = KMI0_BASE,
74 .end = KMI0_BASE + SZ_4K - 1,
75 .flags = IORESOURCE_MEM,
76 },
77 .irq = { IRQ_KMIINT0, NO_IRQ },
78 .periphid = 0x00041050,
79};
80
81static struct amba_device kmi1_device = {
82 .dev = {
83 .bus_id = "mb:19",
84 },
85 .res = {
86 .start = KMI1_BASE,
87 .end = KMI1_BASE + SZ_4K - 1,
88 .flags = IORESOURCE_MEM,
89 },
90 .irq = { IRQ_KMIINT1, NO_IRQ },
91 .periphid = 0x00041050,
92};
93
94static struct amba_device *amba_devs[] __initdata = {
95 &rtc_device,
96 &uart0_device,
97 &uart1_device,
98 &kmi0_device,
99 &kmi1_device,
100};
101
102static int __init integrator_init(void)
103{
104 int i;
105
106 for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
107 struct amba_device *d = amba_devs[i];
108 amba_device_register(d, &iomem_resource);
109 }
110
111 return 0;
112}
113
114arch_initcall(integrator_init);
115
116#define CM_CTRL IO_ADDRESS(INTEGRATOR_HDR_BASE) + INTEGRATOR_HDR_CTRL_OFFSET
117
118static DEFINE_SPINLOCK(cm_lock);
119
120/**
121 * cm_control - update the CM_CTRL register.
122 * @mask: bits to change
123 * @set: bits to set
124 */
125void cm_control(u32 mask, u32 set)
126{
127 unsigned long flags;
128 u32 val;
129
130 spin_lock_irqsave(&cm_lock, flags);
131 val = readl(CM_CTRL) & ~mask;
132 writel(val | set, CM_CTRL);
133 spin_unlock_irqrestore(&cm_lock, flags);
134}
135
136EXPORT_SYMBOL(cm_control);
137
138/*
139 * Where is the timer (VA)?
140 */
141#define TIMER0_VA_BASE (IO_ADDRESS(INTEGRATOR_CT_BASE)+0x00000000)
142#define TIMER1_VA_BASE (IO_ADDRESS(INTEGRATOR_CT_BASE)+0x00000100)
143#define TIMER2_VA_BASE (IO_ADDRESS(INTEGRATOR_CT_BASE)+0x00000200)
144#define VA_IC_BASE IO_ADDRESS(INTEGRATOR_IC_BASE)
145
146/*
147 * How long is the timer interval?
148 */
149#define TIMER_INTERVAL (TICKS_PER_uSEC * mSEC_10)
150#if TIMER_INTERVAL >= 0x100000
151#define TICKS2USECS(x) (256 * (x) / TICKS_PER_uSEC)
152#elif TIMER_INTERVAL >= 0x10000
153#define TICKS2USECS(x) (16 * (x) / TICKS_PER_uSEC)
154#else
155#define TICKS2USECS(x) ((x) / TICKS_PER_uSEC)
156#endif
157
158/*
159 * What does it look like?
160 */
161typedef struct TimerStruct {
162 unsigned long TimerLoad;
163 unsigned long TimerValue;
164 unsigned long TimerControl;
165 unsigned long TimerClear;
166} TimerStruct_t;
167
168static unsigned long timer_reload;
169
170/*
171 * Returns number of ms since last clock interrupt. Note that interrupts
172 * will have been disabled by do_gettimeoffset()
173 */
174unsigned long integrator_gettimeoffset(void)
175{
176 volatile TimerStruct_t *timer1 = (TimerStruct_t *)TIMER1_VA_BASE;
177 unsigned long ticks1, ticks2, status;
178
179 /*
180 * Get the current number of ticks. Note that there is a race
181 * condition between us reading the timer and checking for
182 * an interrupt. We get around this by ensuring that the
183 * counter has not reloaded between our two reads.
184 */
185 ticks2 = timer1->TimerValue & 0xffff;
186 do {
187 ticks1 = ticks2;
188 status = __raw_readl(VA_IC_BASE + IRQ_RAW_STATUS);
189 ticks2 = timer1->TimerValue & 0xffff;
190 } while (ticks2 > ticks1);
191
192 /*
193 * Number of ticks since last interrupt.
194 */
195 ticks1 = timer_reload - ticks2;
196
197 /*
198 * Interrupt pending? If so, we've reloaded once already.
199 */
200 if (status & (1 << IRQ_TIMERINT1))
201 ticks1 += timer_reload;
202
203 /*
204 * Convert the ticks to usecs
205 */
206 return TICKS2USECS(ticks1);
207}
208
209/*
210 * IRQ handler for the timer
211 */
212static irqreturn_t
213integrator_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
214{
215 volatile TimerStruct_t *timer1 = (volatile TimerStruct_t *)TIMER1_VA_BASE;
216
217 write_seqlock(&xtime_lock);
218
219 // ...clear the interrupt
220 timer1->TimerClear = 1;
221
222 timer_tick(regs);
223
224 write_sequnlock(&xtime_lock);
225
226 return IRQ_HANDLED;
227}
228
229static struct irqaction integrator_timer_irq = {
230 .name = "Integrator Timer Tick",
231 .flags = SA_INTERRUPT,
232 .handler = integrator_timer_interrupt
233};
234
235/*
236 * Set up timer interrupt, and return the current time in seconds.
237 */
238void __init integrator_time_init(unsigned long reload, unsigned int ctrl)
239{
240 volatile TimerStruct_t *timer0 = (volatile TimerStruct_t *)TIMER0_VA_BASE;
241 volatile TimerStruct_t *timer1 = (volatile TimerStruct_t *)TIMER1_VA_BASE;
242 volatile TimerStruct_t *timer2 = (volatile TimerStruct_t *)TIMER2_VA_BASE;
243 unsigned int timer_ctrl = 0x80 | 0x40; /* periodic */
244
245 timer_reload = reload;
246 timer_ctrl |= ctrl;
247
248 if (timer_reload > 0x100000) {
249 timer_reload >>= 8;
250 timer_ctrl |= 0x08; /* /256 */
251 } else if (timer_reload > 0x010000) {
252 timer_reload >>= 4;
253 timer_ctrl |= 0x04; /* /16 */
254 }
255
256 /*
257 * Initialise to a known state (all timers off)
258 */
259 timer0->TimerControl = 0;
260 timer1->TimerControl = 0;
261 timer2->TimerControl = 0;
262
263 timer1->TimerLoad = timer_reload;
264 timer1->TimerValue = timer_reload;
265 timer1->TimerControl = timer_ctrl;
266
267 /*
268 * Make irqs happen for the system timer
269 */
270 setup_irq(IRQ_TIMERINT1, &integrator_timer_irq);
271}
diff --git a/arch/arm/mach-integrator/cpu.c b/arch/arm/mach-integrator/cpu.c
new file mode 100644
index 000000000000..71c58bff304c
--- /dev/null
+++ b/arch/arm/mach-integrator/cpu.c
@@ -0,0 +1,221 @@
1/*
2 * linux/arch/arm/mach-integrator/cpu.c
3 *
4 * Copyright (C) 2001-2002 Deep Blue Solutions Ltd.
5 *
6 * $Id: cpu.c,v 1.6 2002/07/18 13:58:51 rmk Exp $
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * CPU support functions
13 */
14#include <linux/module.h>
15#include <linux/types.h>
16#include <linux/kernel.h>
17#include <linux/cpufreq.h>
18#include <linux/slab.h>
19#include <linux/sched.h>
20#include <linux/smp.h>
21#include <linux/init.h>
22
23#include <asm/hardware.h>
24#include <asm/io.h>
25#include <asm/mach-types.h>
26#include <asm/hardware/icst525.h>
27
28static struct cpufreq_driver integrator_driver;
29
30#define CM_ID (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_ID_OFFSET)
31#define CM_OSC (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_OSC_OFFSET)
32#define CM_STAT (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_STAT_OFFSET)
33#define CM_LOCK (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_LOCK_OFFSET)
34
35static const struct icst525_params lclk_params = {
36 .ref = 24000,
37 .vco_max = 320000,
38 .vd_min = 8,
39 .vd_max = 132,
40 .rd_min = 24,
41 .rd_max = 24,
42};
43
44static const struct icst525_params cclk_params = {
45 .ref = 24000,
46 .vco_max = 320000,
47 .vd_min = 12,
48 .vd_max = 160,
49 .rd_min = 24,
50 .rd_max = 24,
51};
52
53/*
54 * Validate the speed policy.
55 */
56static int integrator_verify_policy(struct cpufreq_policy *policy)
57{
58 struct icst525_vco vco;
59
60 cpufreq_verify_within_limits(policy,
61 policy->cpuinfo.min_freq,
62 policy->cpuinfo.max_freq);
63
64 vco = icst525_khz_to_vco(&cclk_params, policy->max);
65 policy->max = icst525_khz(&cclk_params, vco);
66
67 vco = icst525_khz_to_vco(&cclk_params, policy->min);
68 policy->min = icst525_khz(&cclk_params, vco);
69
70 cpufreq_verify_within_limits(policy,
71 policy->cpuinfo.min_freq,
72 policy->cpuinfo.max_freq);
73
74 return 0;
75}
76
77
78static int integrator_set_target(struct cpufreq_policy *policy,
79 unsigned int target_freq,
80 unsigned int relation)
81{
82 cpumask_t cpus_allowed;
83 int cpu = policy->cpu;
84 struct icst525_vco vco;
85 struct cpufreq_freqs freqs;
86 u_int cm_osc;
87
88 /*
89 * Save this threads cpus_allowed mask.
90 */
91 cpus_allowed = current->cpus_allowed;
92
93 /*
94 * Bind to the specified CPU. When this call returns,
95 * we should be running on the right CPU.
96 */
97 set_cpus_allowed(current, cpumask_of_cpu(cpu));
98 BUG_ON(cpu != smp_processor_id());
99
100 /* get current setting */
101 cm_osc = __raw_readl(CM_OSC);
102
103 if (machine_is_integrator()) {
104 vco.s = (cm_osc >> 8) & 7;
105 } else if (machine_is_cintegrator()) {
106 vco.s = 1;
107 }
108 vco.v = cm_osc & 255;
109 vco.r = 22;
110 freqs.old = icst525_khz(&cclk_params, vco);
111
112 /* icst525_khz_to_vco rounds down -- so we need the next
113 * larger freq in case of CPUFREQ_RELATION_L.
114 */
115 if (relation == CPUFREQ_RELATION_L)
116 target_freq += 999;
117 if (target_freq > policy->max)
118 target_freq = policy->max;
119 vco = icst525_khz_to_vco(&cclk_params, target_freq);
120 freqs.new = icst525_khz(&cclk_params, vco);
121
122 freqs.cpu = policy->cpu;
123
124 if (freqs.old == freqs.new) {
125 set_cpus_allowed(current, cpus_allowed);
126 return 0;
127 }
128
129 cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
130
131 cm_osc = __raw_readl(CM_OSC);
132
133 if (machine_is_integrator()) {
134 cm_osc &= 0xfffff800;
135 cm_osc |= vco.s << 8;
136 } else if (machine_is_cintegrator()) {
137 cm_osc &= 0xffffff00;
138 }
139 cm_osc |= vco.v;
140
141 __raw_writel(0xa05f, CM_LOCK);
142 __raw_writel(cm_osc, CM_OSC);
143 __raw_writel(0, CM_LOCK);
144
145 /*
146 * Restore the CPUs allowed mask.
147 */
148 set_cpus_allowed(current, cpus_allowed);
149
150 cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
151
152 return 0;
153}
154
155static unsigned int integrator_get(unsigned int cpu)
156{
157 cpumask_t cpus_allowed;
158 unsigned int current_freq;
159 u_int cm_osc;
160 struct icst525_vco vco;
161
162 cpus_allowed = current->cpus_allowed;
163
164 set_cpus_allowed(current, cpumask_of_cpu(cpu));
165 BUG_ON(cpu != smp_processor_id());
166
167 /* detect memory etc. */
168 cm_osc = __raw_readl(CM_OSC);
169
170 if (machine_is_integrator()) {
171 vco.s = (cm_osc >> 8) & 7;
172 } else if (machine_is_cintegrator()) {
173 vco.s = 1;
174 }
175 vco.v = cm_osc & 255;
176 vco.r = 22;
177
178 current_freq = icst525_khz(&cclk_params, vco); /* current freq */
179
180 set_cpus_allowed(current, cpus_allowed);
181
182 return current_freq;
183}
184
185static int integrator_cpufreq_init(struct cpufreq_policy *policy)
186{
187
188 /* set default policy and cpuinfo */
189 policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
190 policy->cpuinfo.max_freq = 160000;
191 policy->cpuinfo.min_freq = 12000;
192 policy->cpuinfo.transition_latency = 1000000; /* 1 ms, assumed */
193 policy->cur = policy->min = policy->max = integrator_get(policy->cpu);
194
195 return 0;
196}
197
198static struct cpufreq_driver integrator_driver = {
199 .verify = integrator_verify_policy,
200 .target = integrator_set_target,
201 .get = integrator_get,
202 .init = integrator_cpufreq_init,
203 .name = "integrator",
204};
205
206static int __init integrator_cpu_init(void)
207{
208 return cpufreq_register_driver(&integrator_driver);
209}
210
211static void __exit integrator_cpu_exit(void)
212{
213 cpufreq_unregister_driver(&integrator_driver);
214}
215
216MODULE_AUTHOR ("Russell M. King");
217MODULE_DESCRIPTION ("cpufreq driver for ARM Integrator CPUs");
218MODULE_LICENSE ("GPL");
219
220module_init(integrator_cpu_init);
221module_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 000000000000..aae6f23cd72b
--- /dev/null
+++ b/arch/arm/mach-integrator/dma.c
@@ -0,0 +1,35 @@
1/*
2 * linux/arch/arm/mach-integrator/dma.c
3 *
4 * Copyright (C) 1999 ARM Limited
5 * Copyright (C) 2000 Deep Blue Solutions Ltd
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21#include <linux/slab.h>
22#include <linux/mman.h>
23#include <linux/init.h>
24
25#include <asm/page.h>
26#include <asm/pgtable.h>
27#include <asm/dma.h>
28#include <asm/io.h>
29#include <asm/hardware.h>
30
31#include <asm/mach/dma.h>
32
33void __init arch_dma_init(dma_t *dma)
34{
35}
diff --git a/arch/arm/mach-integrator/impd1.c b/arch/arm/mach-integrator/impd1.c
new file mode 100644
index 000000000000..c3c2f17d030e
--- /dev/null
+++ b/arch/arm/mach-integrator/impd1.c
@@ -0,0 +1,475 @@
1/*
2 * linux/arch/arm/mach-integrator/impd1.c
3 *
4 * Copyright (C) 2003 Deep Blue Solutions Ltd, All Rights Reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * This file provides the core support for the IM-PD1 module.
11 *
12 * Module / boot parameters.
13 * lmid=n impd1.lmid=n - set the logic module position in stack to 'n'
14 */
15#include <linux/module.h>
16#include <linux/moduleparam.h>
17#include <linux/init.h>
18#include <linux/device.h>
19#include <linux/errno.h>
20#include <linux/mm.h>
21
22#include <asm/io.h>
23#include <asm/hardware/icst525.h>
24#include <asm/hardware/amba.h>
25#include <asm/hardware/amba_clcd.h>
26#include <asm/arch/lm.h>
27#include <asm/arch/impd1.h>
28#include <asm/sizes.h>
29
30#include "clock.h"
31
32static int module_id;
33
34module_param_named(lmid, module_id, int, 0444);
35MODULE_PARM_DESC(lmid, "logic module stack position");
36
37struct impd1_module {
38 void __iomem *base;
39 struct clk vcos[2];
40};
41
42static const struct icst525_params impd1_vco_params = {
43 .ref = 24000, /* 24 MHz */
44 .vco_max = 200000, /* 200 MHz */
45 .vd_min = 12,
46 .vd_max = 519,
47 .rd_min = 3,
48 .rd_max = 120,
49};
50
51static void impd1_setvco(struct clk *clk, struct icst525_vco vco)
52{
53 struct impd1_module *impd1 = clk->data;
54 int vconr = clk - impd1->vcos;
55 u32 val;
56
57 val = vco.v | (vco.r << 9) | (vco.s << 16);
58
59 writel(0xa05f, impd1->base + IMPD1_LOCK);
60 switch (vconr) {
61 case 0:
62 writel(val, impd1->base + IMPD1_OSC1);
63 break;
64 case 1:
65 writel(val, impd1->base + IMPD1_OSC2);
66 break;
67 }
68 writel(0, impd1->base + IMPD1_LOCK);
69
70#if DEBUG
71 vco.v = val & 0x1ff;
72 vco.r = (val >> 9) & 0x7f;
73 vco.s = (val >> 16) & 7;
74
75 pr_debug("IM-PD1: VCO%d clock is %ld kHz\n",
76 vconr, icst525_khz(&impd1_vco_params, vco));
77#endif
78}
79
80void impd1_tweak_control(struct device *dev, u32 mask, u32 val)
81{
82 struct impd1_module *impd1 = dev_get_drvdata(dev);
83 u32 cur;
84
85 val &= mask;
86 cur = readl(impd1->base + IMPD1_CTRL) & ~mask;
87 writel(cur | val, impd1->base + IMPD1_CTRL);
88}
89
90EXPORT_SYMBOL(impd1_tweak_control);
91
92/*
93 * CLCD support
94 */
95#define PANEL PROSPECTOR
96
97#define LTM10C209 1
98#define PROSPECTOR 2
99#define SVGA 3
100#define VGA 4
101
102#if PANEL == VGA
103#define PANELTYPE vga
104static struct clcd_panel vga = {
105 .mode = {
106 .name = "VGA",
107 .refresh = 60,
108 .xres = 640,
109 .yres = 480,
110 .pixclock = 39721,
111 .left_margin = 40,
112 .right_margin = 24,
113 .upper_margin = 32,
114 .lower_margin = 11,
115 .hsync_len = 96,
116 .vsync_len = 2,
117 .sync = 0,
118 .vmode = FB_VMODE_NONINTERLACED,
119 },
120 .width = -1,
121 .height = -1,
122 .tim2 = TIM2_BCD | TIM2_IPC,
123 .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1),
124 .connector = IMPD1_CTRL_DISP_VGA,
125 .bpp = 16,
126 .grayscale = 0,
127};
128
129#elif PANEL == SVGA
130#define PANELTYPE svga
131static struct clcd_panel svga = {
132 .mode = {
133 .name = "SVGA",
134 .refresh = 0,
135 .xres = 800,
136 .yres = 600,
137 .pixclock = 27778,
138 .left_margin = 20,
139 .right_margin = 20,
140 .upper_margin = 5,
141 .lower_margin = 5,
142 .hsync_len = 164,
143 .vsync_len = 62,
144 .sync = 0,
145 .vmode = FB_VMODE_NONINTERLACED,
146 },
147 .width = -1,
148 .height = -1,
149 .tim2 = TIM2_BCD,
150 .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1),
151 .connector = IMPD1_CTRL_DISP_VGA,
152 .bpp = 16,
153 .grayscale = 0,
154};
155
156#elif PANEL == PROSPECTOR
157#define PANELTYPE prospector
158static struct clcd_panel prospector = {
159 .mode = {
160 .name = "PROSPECTOR",
161 .refresh = 0,
162 .xres = 640,
163 .yres = 480,
164 .pixclock = 40000,
165 .left_margin = 33,
166 .right_margin = 64,
167 .upper_margin = 36,
168 .lower_margin = 7,
169 .hsync_len = 64,
170 .vsync_len = 25,
171 .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
172 .vmode = FB_VMODE_NONINTERLACED,
173 },
174 .width = -1,
175 .height = -1,
176 .tim2 = TIM2_BCD,
177 .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1),
178 .fixedtimings = 1,
179 .connector = IMPD1_CTRL_DISP_LCD,
180 .bpp = 16,
181 .grayscale = 0,
182};
183
184#elif PANEL == LTM10C209
185#define PANELTYPE ltm10c209
186/*
187 * Untested.
188 */
189static struct clcd_panel ltm10c209 = {
190 .mode = {
191 .name = "LTM10C209",
192 .refresh = 0,
193 .xres = 640,
194 .yres = 480,
195 .pixclock = 40000,
196 .left_margin = 20,
197 .right_margin = 20,
198 .upper_margin = 19,
199 .lower_margin = 19,
200 .hsync_len = 20,
201 .vsync_len = 10,
202 .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
203 .vmode = FB_VMODE_NONINTERLACED,
204 },
205 .width = -1,
206 .height = -1,
207 .tim2 = TIM2_BCD,
208 .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1),
209 .fixedtimings = 1,
210 .connector = IMPD1_CTRL_DISP_LCD,
211 .bpp = 16,
212 .grayscale = 0,
213};
214#endif
215
216/*
217 * Disable all display connectors on the interface module.
218 */
219static void impd1fb_clcd_disable(struct clcd_fb *fb)
220{
221 impd1_tweak_control(fb->dev->dev.parent, IMPD1_CTRL_DISP_MASK, 0);
222}
223
224/*
225 * Enable the relevant connector on the interface module.
226 */
227static void impd1fb_clcd_enable(struct clcd_fb *fb)
228{
229 impd1_tweak_control(fb->dev->dev.parent, IMPD1_CTRL_DISP_MASK,
230 fb->panel->connector | IMPD1_CTRL_DISP_ENABLE);
231}
232
233static int impd1fb_clcd_setup(struct clcd_fb *fb)
234{
235 unsigned long framebase = fb->dev->res.start + 0x01000000;
236 unsigned long framesize = SZ_1M;
237 int ret = 0;
238
239 fb->panel = &PANELTYPE;
240
241 if (!request_mem_region(framebase, framesize, "clcd framebuffer")) {
242 printk(KERN_ERR "IM-PD1: unable to reserve framebuffer\n");
243 return -EBUSY;
244 }
245
246 fb->fb.screen_base = ioremap(framebase, framesize);
247 if (!fb->fb.screen_base) {
248 printk(KERN_ERR "IM-PD1: unable to map framebuffer\n");
249 ret = -ENOMEM;
250 goto free_buffer;
251 }
252
253 fb->fb.fix.smem_start = framebase;
254 fb->fb.fix.smem_len = framesize;
255
256 return 0;
257
258 free_buffer:
259 release_mem_region(framebase, framesize);
260 return ret;
261}
262
263static int impd1fb_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
264{
265 unsigned long start, size;
266
267 start = vma->vm_pgoff + (fb->fb.fix.smem_start >> PAGE_SHIFT);
268 size = vma->vm_end - vma->vm_start;
269
270 return remap_pfn_range(vma, vma->vm_start, start, size,
271 vma->vm_page_prot);
272}
273
274static void impd1fb_clcd_remove(struct clcd_fb *fb)
275{
276 iounmap(fb->fb.screen_base);
277 release_mem_region(fb->fb.fix.smem_start, fb->fb.fix.smem_len);
278}
279
280static struct clcd_board impd1_clcd_data = {
281 .name = "IM-PD/1",
282 .check = clcdfb_check,
283 .decode = clcdfb_decode,
284 .disable = impd1fb_clcd_disable,
285 .enable = impd1fb_clcd_enable,
286 .setup = impd1fb_clcd_setup,
287 .mmap = impd1fb_clcd_mmap,
288 .remove = impd1fb_clcd_remove,
289};
290
291struct impd1_device {
292 unsigned long offset;
293 unsigned int irq[2];
294 unsigned int id;
295 void *platform_data;
296};
297
298static struct impd1_device impd1_devs[] = {
299 {
300 .offset = 0x03000000,
301 .id = 0x00041190,
302 }, {
303 .offset = 0x00100000,
304 .irq = { 1 },
305 .id = 0x00141011,
306 }, {
307 .offset = 0x00200000,
308 .irq = { 2 },
309 .id = 0x00141011,
310 }, {
311 .offset = 0x00300000,
312 .irq = { 3 },
313 .id = 0x00041022,
314 }, {
315 .offset = 0x00400000,
316 .irq = { 4 },
317 .id = 0x00041061,
318 }, {
319 .offset = 0x00500000,
320 .irq = { 5 },
321 .id = 0x00041061,
322 }, {
323 .offset = 0x00600000,
324 .irq = { 6 },
325 .id = 0x00041130,
326 }, {
327 .offset = 0x00700000,
328 .irq = { 7, 8 },
329 .id = 0x00041181,
330 }, {
331 .offset = 0x00800000,
332 .irq = { 9 },
333 .id = 0x00041041,
334 }, {
335 .offset = 0x01000000,
336 .irq = { 11 },
337 .id = 0x00041110,
338 .platform_data = &impd1_clcd_data,
339 }
340};
341
342static const char *impd1_vconames[2] = {
343 "CLCDCLK",
344 "AUXVCO2",
345};
346
347static int impd1_probe(struct lm_device *dev)
348{
349 struct impd1_module *impd1;
350 int i, ret;
351
352 if (dev->id != module_id)
353 return -EINVAL;
354
355 if (!request_mem_region(dev->resource.start, SZ_4K, "LM registers"))
356 return -EBUSY;
357
358 impd1 = kmalloc(sizeof(struct impd1_module), GFP_KERNEL);
359 if (!impd1) {
360 ret = -ENOMEM;
361 goto release_lm;
362 }
363 memset(impd1, 0, sizeof(struct impd1_module));
364
365 impd1->base = ioremap(dev->resource.start, SZ_4K);
366 if (!impd1->base) {
367 ret = -ENOMEM;
368 goto free_impd1;
369 }
370
371 lm_set_drvdata(dev, impd1);
372
373 printk("IM-PD1 found at 0x%08lx\n", dev->resource.start);
374
375 for (i = 0; i < ARRAY_SIZE(impd1->vcos); i++) {
376 impd1->vcos[i].owner = THIS_MODULE,
377 impd1->vcos[i].name = impd1_vconames[i],
378 impd1->vcos[i].params = &impd1_vco_params,
379 impd1->vcos[i].data = impd1,
380 impd1->vcos[i].setvco = impd1_setvco;
381
382 clk_register(&impd1->vcos[i]);
383 }
384
385 for (i = 0; i < ARRAY_SIZE(impd1_devs); i++) {
386 struct impd1_device *idev = impd1_devs + i;
387 struct amba_device *d;
388 unsigned long pc_base;
389
390 pc_base = dev->resource.start + idev->offset;
391
392 d = kmalloc(sizeof(struct amba_device), GFP_KERNEL);
393 if (!d)
394 continue;
395
396 memset(d, 0, sizeof(struct amba_device));
397
398 snprintf(d->dev.bus_id, sizeof(d->dev.bus_id),
399 "lm%x:%5.5lx", dev->id, idev->offset >> 12);
400
401 d->dev.parent = &dev->dev;
402 d->res.start = dev->resource.start + idev->offset;
403 d->res.end = d->res.start + SZ_4K - 1;
404 d->res.flags = IORESOURCE_MEM;
405 d->irq[0] = dev->irq;
406 d->irq[1] = dev->irq;
407 d->periphid = idev->id;
408 d->dev.platform_data = idev->platform_data;
409
410 ret = amba_device_register(d, &dev->resource);
411 if (ret) {
412 printk("unable to register device %s: %d\n",
413 d->dev.bus_id, ret);
414 kfree(d);
415 }
416 }
417
418 return 0;
419
420 free_impd1:
421 if (impd1 && impd1->base)
422 iounmap(impd1->base);
423 if (impd1)
424 kfree(impd1);
425 release_lm:
426 release_mem_region(dev->resource.start, SZ_4K);
427 return ret;
428}
429
430static void impd1_remove(struct lm_device *dev)
431{
432 struct impd1_module *impd1 = lm_get_drvdata(dev);
433 struct list_head *l, *n;
434 int i;
435
436 list_for_each_safe(l, n, &dev->dev.children) {
437 struct device *d = list_to_dev(l);
438
439 device_unregister(d);
440 }
441
442 for (i = 0; i < ARRAY_SIZE(impd1->vcos); i++)
443 clk_unregister(&impd1->vcos[i]);
444
445 lm_set_drvdata(dev, NULL);
446
447 iounmap(impd1->base);
448 kfree(impd1);
449 release_mem_region(dev->resource.start, SZ_4K);
450}
451
452static struct lm_driver impd1_driver = {
453 .drv = {
454 .name = "impd1",
455 },
456 .probe = impd1_probe,
457 .remove = impd1_remove,
458};
459
460static int __init impd1_init(void)
461{
462 return lm_driver_register(&impd1_driver);
463}
464
465static void __exit impd1_exit(void)
466{
467 lm_driver_unregister(&impd1_driver);
468}
469
470module_init(impd1_init);
471module_exit(impd1_exit);
472
473MODULE_LICENSE("GPL");
474MODULE_DESCRIPTION("Integrator/IM-PD1 logic module core driver");
475MODULE_AUTHOR("Deep Blue Solutions Ltd");
diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c
new file mode 100644
index 000000000000..91ba9fd79c87
--- /dev/null
+++ b/arch/arm/mach-integrator/integrator_ap.c
@@ -0,0 +1,302 @@
1/*
2 * linux/arch/arm/mach-integrator/integrator_ap.c
3 *
4 * Copyright (C) 2000-2003 Deep Blue Solutions Ltd
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20#include <linux/types.h>
21#include <linux/kernel.h>
22#include <linux/init.h>
23#include <linux/list.h>
24#include <linux/device.h>
25#include <linux/slab.h>
26#include <linux/string.h>
27#include <linux/sysdev.h>
28
29#include <asm/hardware.h>
30#include <asm/io.h>
31#include <asm/irq.h>
32#include <asm/setup.h>
33#include <asm/mach-types.h>
34#include <asm/hardware/amba.h>
35#include <asm/hardware/amba_kmi.h>
36
37#include <asm/arch/lm.h>
38
39#include <asm/mach/arch.h>
40#include <asm/mach/flash.h>
41#include <asm/mach/irq.h>
42#include <asm/mach/map.h>
43#include <asm/mach/time.h>
44
45#include "common.h"
46
47/*
48 * All IO addresses are mapped onto VA 0xFFFx.xxxx, where x.xxxx
49 * is the (PA >> 12).
50 *
51 * Setup a VA for the Integrator interrupt controller (for header #0,
52 * just for now).
53 */
54#define VA_IC_BASE IO_ADDRESS(INTEGRATOR_IC_BASE)
55#define VA_SC_BASE IO_ADDRESS(INTEGRATOR_SC_BASE)
56#define VA_EBI_BASE IO_ADDRESS(INTEGRATOR_EBI_BASE)
57#define VA_CMIC_BASE IO_ADDRESS(INTEGRATOR_HDR_BASE) + INTEGRATOR_HDR_IC_OFFSET
58
59/*
60 * Logical Physical
61 * e8000000 40000000 PCI memory PHYS_PCI_MEM_BASE (max 512M)
62 * ec000000 61000000 PCI config space PHYS_PCI_CONFIG_BASE (max 16M)
63 * ed000000 62000000 PCI V3 regs PHYS_PCI_V3_BASE (max 64k)
64 * ee000000 60000000 PCI IO PHYS_PCI_IO_BASE (max 16M)
65 * ef000000 Cache flush
66 * f1000000 10000000 Core module registers
67 * f1100000 11000000 System controller registers
68 * f1200000 12000000 EBI registers
69 * f1300000 13000000 Counter/Timer
70 * f1400000 14000000 Interrupt controller
71 * f1600000 16000000 UART 0
72 * f1700000 17000000 UART 1
73 * f1a00000 1a000000 Debug LEDs
74 * f1b00000 1b000000 GPIO
75 */
76
77static struct map_desc ap_io_desc[] __initdata = {
78 { IO_ADDRESS(INTEGRATOR_HDR_BASE), INTEGRATOR_HDR_BASE, SZ_4K, MT_DEVICE },
79 { IO_ADDRESS(INTEGRATOR_SC_BASE), INTEGRATOR_SC_BASE, SZ_4K, MT_DEVICE },
80 { IO_ADDRESS(INTEGRATOR_EBI_BASE), INTEGRATOR_EBI_BASE, SZ_4K, MT_DEVICE },
81 { IO_ADDRESS(INTEGRATOR_CT_BASE), INTEGRATOR_CT_BASE, SZ_4K, MT_DEVICE },
82 { IO_ADDRESS(INTEGRATOR_IC_BASE), INTEGRATOR_IC_BASE, SZ_4K, MT_DEVICE },
83 { IO_ADDRESS(INTEGRATOR_UART0_BASE), INTEGRATOR_UART0_BASE, SZ_4K, MT_DEVICE },
84 { IO_ADDRESS(INTEGRATOR_UART1_BASE), INTEGRATOR_UART1_BASE, SZ_4K, MT_DEVICE },
85 { IO_ADDRESS(INTEGRATOR_DBG_BASE), INTEGRATOR_DBG_BASE, SZ_4K, MT_DEVICE },
86 { IO_ADDRESS(INTEGRATOR_GPIO_BASE), INTEGRATOR_GPIO_BASE, SZ_4K, MT_DEVICE },
87 { PCI_MEMORY_VADDR, PHYS_PCI_MEM_BASE, SZ_16M, MT_DEVICE },
88 { PCI_CONFIG_VADDR, PHYS_PCI_CONFIG_BASE, SZ_16M, MT_DEVICE },
89 { PCI_V3_VADDR, PHYS_PCI_V3_BASE, SZ_64K, MT_DEVICE },
90 { PCI_IO_VADDR, PHYS_PCI_IO_BASE, SZ_64K, MT_DEVICE }
91};
92
93static void __init ap_map_io(void)
94{
95 iotable_init(ap_io_desc, ARRAY_SIZE(ap_io_desc));
96}
97
98#define INTEGRATOR_SC_VALID_INT 0x003fffff
99
100static void sc_mask_irq(unsigned int irq)
101{
102 writel(1 << irq, VA_IC_BASE + IRQ_ENABLE_CLEAR);
103}
104
105static void sc_unmask_irq(unsigned int irq)
106{
107 writel(1 << irq, VA_IC_BASE + IRQ_ENABLE_SET);
108}
109
110static struct irqchip sc_chip = {
111 .ack = sc_mask_irq,
112 .mask = sc_mask_irq,
113 .unmask = sc_unmask_irq,
114};
115
116static void __init ap_init_irq(void)
117{
118 unsigned int i;
119
120 /* Disable all interrupts initially. */
121 /* Do the core module ones */
122 writel(-1, VA_CMIC_BASE + IRQ_ENABLE_CLEAR);
123
124 /* do the header card stuff next */
125 writel(-1, VA_IC_BASE + IRQ_ENABLE_CLEAR);
126 writel(-1, VA_IC_BASE + FIQ_ENABLE_CLEAR);
127
128 for (i = 0; i < NR_IRQS; i++) {
129 if (((1 << i) & INTEGRATOR_SC_VALID_INT) != 0) {
130 set_irq_chip(i, &sc_chip);
131 set_irq_handler(i, do_level_IRQ);
132 set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
133 }
134 }
135}
136
137#ifdef CONFIG_PM
138static unsigned long ic_irq_enable;
139
140static int irq_suspend(struct sys_device *dev, pm_message_t state)
141{
142 ic_irq_enable = readl(VA_IC_BASE + IRQ_ENABLE);
143 return 0;
144}
145
146static int irq_resume(struct sys_device *dev)
147{
148 /* disable all irq sources */
149 writel(-1, VA_CMIC_BASE + IRQ_ENABLE_CLEAR);
150 writel(-1, VA_IC_BASE + IRQ_ENABLE_CLEAR);
151 writel(-1, VA_IC_BASE + FIQ_ENABLE_CLEAR);
152
153 writel(ic_irq_enable, VA_IC_BASE + IRQ_ENABLE_SET);
154 return 0;
155}
156#else
157#define irq_suspend NULL
158#define irq_resume NULL
159#endif
160
161static struct sysdev_class irq_class = {
162 set_kset_name("irq"),
163 .suspend = irq_suspend,
164 .resume = irq_resume,
165};
166
167static struct sys_device irq_device = {
168 .id = 0,
169 .cls = &irq_class,
170};
171
172static int __init irq_init_sysfs(void)
173{
174 int ret = sysdev_class_register(&irq_class);
175 if (ret == 0)
176 ret = sysdev_register(&irq_device);
177 return ret;
178}
179
180device_initcall(irq_init_sysfs);
181
182/*
183 * Flash handling.
184 */
185#define SC_CTRLC (VA_SC_BASE + INTEGRATOR_SC_CTRLC_OFFSET)
186#define SC_CTRLS (VA_SC_BASE + INTEGRATOR_SC_CTRLS_OFFSET)
187#define EBI_CSR1 (VA_EBI_BASE + INTEGRATOR_EBI_CSR1_OFFSET)
188#define EBI_LOCK (VA_EBI_BASE + INTEGRATOR_EBI_LOCK_OFFSET)
189
190static int ap_flash_init(void)
191{
192 u32 tmp;
193
194 writel(INTEGRATOR_SC_CTRL_nFLVPPEN | INTEGRATOR_SC_CTRL_nFLWP, SC_CTRLC);
195
196 tmp = readl(EBI_CSR1) | INTEGRATOR_EBI_WRITE_ENABLE;
197 writel(tmp, EBI_CSR1);
198
199 if (!(readl(EBI_CSR1) & INTEGRATOR_EBI_WRITE_ENABLE)) {
200 writel(0xa05f, EBI_LOCK);
201 writel(tmp, EBI_CSR1);
202 writel(0, EBI_LOCK);
203 }
204 return 0;
205}
206
207static void ap_flash_exit(void)
208{
209 u32 tmp;
210
211 writel(INTEGRATOR_SC_CTRL_nFLVPPEN | INTEGRATOR_SC_CTRL_nFLWP, SC_CTRLC);
212
213 tmp = readl(EBI_CSR1) & ~INTEGRATOR_EBI_WRITE_ENABLE;
214 writel(tmp, EBI_CSR1);
215
216 if (readl(EBI_CSR1) & INTEGRATOR_EBI_WRITE_ENABLE) {
217 writel(0xa05f, EBI_LOCK);
218 writel(tmp, EBI_CSR1);
219 writel(0, EBI_LOCK);
220 }
221}
222
223static void ap_flash_set_vpp(int on)
224{
225 unsigned long reg = on ? SC_CTRLS : SC_CTRLC;
226
227 writel(INTEGRATOR_SC_CTRL_nFLVPPEN, reg);
228}
229
230static struct flash_platform_data ap_flash_data = {
231 .map_name = "cfi_probe",
232 .width = 4,
233 .init = ap_flash_init,
234 .exit = ap_flash_exit,
235 .set_vpp = ap_flash_set_vpp,
236};
237
238static struct resource cfi_flash_resource = {
239 .start = INTEGRATOR_FLASH_BASE,
240 .end = INTEGRATOR_FLASH_BASE + INTEGRATOR_FLASH_SIZE - 1,
241 .flags = IORESOURCE_MEM,
242};
243
244static struct platform_device cfi_flash_device = {
245 .name = "armflash",
246 .id = 0,
247 .dev = {
248 .platform_data = &ap_flash_data,
249 },
250 .num_resources = 1,
251 .resource = &cfi_flash_resource,
252};
253
254static void __init ap_init(void)
255{
256 unsigned long sc_dec;
257 int i;
258
259 platform_device_register(&cfi_flash_device);
260
261 sc_dec = readl(VA_SC_BASE + INTEGRATOR_SC_DEC_OFFSET);
262 for (i = 0; i < 4; i++) {
263 struct lm_device *lmdev;
264
265 if ((sc_dec & (16 << i)) == 0)
266 continue;
267
268 lmdev = kmalloc(sizeof(struct lm_device), GFP_KERNEL);
269 if (!lmdev)
270 continue;
271
272 memset(lmdev, 0, sizeof(struct lm_device));
273
274 lmdev->resource.start = 0xc0000000 + 0x10000000 * i;
275 lmdev->resource.end = lmdev->resource.start + 0x0fffffff;
276 lmdev->resource.flags = IORESOURCE_MEM;
277 lmdev->irq = IRQ_AP_EXPINT0 + i;
278 lmdev->id = i;
279
280 lm_device_register(lmdev);
281 }
282}
283
284static void __init ap_init_timer(void)
285{
286 integrator_time_init(1000000 * TICKS_PER_uSEC / HZ, 0);
287}
288
289static struct sys_timer ap_timer = {
290 .init = ap_init_timer,
291 .offset = integrator_gettimeoffset,
292};
293
294MACHINE_START(INTEGRATOR, "ARM-Integrator")
295 MAINTAINER("ARM Ltd/Deep Blue Solutions Ltd")
296 BOOT_MEM(0x00000000, 0x16000000, 0xf1600000)
297 BOOT_PARAMS(0x00000100)
298 MAPIO(ap_map_io)
299 INITIRQ(ap_init_irq)
300 .timer = &ap_timer,
301 INIT_MACHINE(ap_init)
302MACHINE_END
diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c
new file mode 100644
index 000000000000..68e15c36e336
--- /dev/null
+++ b/arch/arm/mach-integrator/integrator_cp.c
@@ -0,0 +1,528 @@
1/*
2 * linux/arch/arm/mach-integrator/integrator_cp.c
3 *
4 * Copyright (C) 2003 Deep Blue Solutions Ltd
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License.
9 */
10#include <linux/types.h>
11#include <linux/kernel.h>
12#include <linux/init.h>
13#include <linux/list.h>
14#include <linux/device.h>
15#include <linux/dma-mapping.h>
16#include <linux/slab.h>
17#include <linux/string.h>
18#include <linux/sysdev.h>
19
20#include <asm/hardware.h>
21#include <asm/io.h>
22#include <asm/irq.h>
23#include <asm/setup.h>
24#include <asm/mach-types.h>
25#include <asm/hardware/amba.h>
26#include <asm/hardware/amba_kmi.h>
27#include <asm/hardware/amba_clcd.h>
28#include <asm/hardware/icst525.h>
29
30#include <asm/arch/cm.h>
31#include <asm/arch/lm.h>
32
33#include <asm/mach/arch.h>
34#include <asm/mach/flash.h>
35#include <asm/mach/irq.h>
36#include <asm/mach/mmc.h>
37#include <asm/mach/map.h>
38#include <asm/mach/time.h>
39
40#include "common.h"
41#include "clock.h"
42
43#define INTCP_PA_MMC_BASE 0x1c000000
44#define INTCP_PA_AACI_BASE 0x1d000000
45
46#define INTCP_PA_FLASH_BASE 0x24000000
47#define INTCP_FLASH_SIZE SZ_32M
48
49#define INTCP_PA_CLCD_BASE 0xc0000000
50
51#define INTCP_VA_CIC_BASE 0xf1000040
52#define INTCP_VA_PIC_BASE 0xf1400000
53#define INTCP_VA_SIC_BASE 0xfca00000
54
55#define INTCP_PA_ETH_BASE 0xc8000000
56#define INTCP_ETH_SIZE 0x10
57
58#define INTCP_VA_CTRL_BASE 0xfcb00000
59#define INTCP_FLASHPROG 0x04
60#define CINTEGRATOR_FLASHPROG_FLVPPEN (1 << 0)
61#define CINTEGRATOR_FLASHPROG_FLWREN (1 << 1)
62
63/*
64 * Logical Physical
65 * f1000000 10000000 Core module registers
66 * f1100000 11000000 System controller registers
67 * f1200000 12000000 EBI registers
68 * f1300000 13000000 Counter/Timer
69 * f1400000 14000000 Interrupt controller
70 * f1600000 16000000 UART 0
71 * f1700000 17000000 UART 1
72 * f1a00000 1a000000 Debug LEDs
73 * f1b00000 1b000000 GPIO
74 */
75
76static struct map_desc intcp_io_desc[] __initdata = {
77 { IO_ADDRESS(INTEGRATOR_HDR_BASE), INTEGRATOR_HDR_BASE, SZ_4K, MT_DEVICE },
78 { IO_ADDRESS(INTEGRATOR_SC_BASE), INTEGRATOR_SC_BASE, SZ_4K, MT_DEVICE },
79 { IO_ADDRESS(INTEGRATOR_EBI_BASE), INTEGRATOR_EBI_BASE, SZ_4K, MT_DEVICE },
80 { IO_ADDRESS(INTEGRATOR_CT_BASE), INTEGRATOR_CT_BASE, SZ_4K, MT_DEVICE },
81 { IO_ADDRESS(INTEGRATOR_IC_BASE), INTEGRATOR_IC_BASE, SZ_4K, MT_DEVICE },
82 { IO_ADDRESS(INTEGRATOR_UART0_BASE), INTEGRATOR_UART0_BASE, SZ_4K, MT_DEVICE },
83 { IO_ADDRESS(INTEGRATOR_UART1_BASE), INTEGRATOR_UART1_BASE, SZ_4K, MT_DEVICE },
84 { IO_ADDRESS(INTEGRATOR_DBG_BASE), INTEGRATOR_DBG_BASE, SZ_4K, MT_DEVICE },
85 { IO_ADDRESS(INTEGRATOR_GPIO_BASE), INTEGRATOR_GPIO_BASE, SZ_4K, MT_DEVICE },
86 { 0xfc900000, 0xc9000000, SZ_4K, MT_DEVICE },
87 { 0xfca00000, 0xca000000, SZ_4K, MT_DEVICE },
88 { 0xfcb00000, 0xcb000000, SZ_4K, MT_DEVICE },
89};
90
91static void __init intcp_map_io(void)
92{
93 iotable_init(intcp_io_desc, ARRAY_SIZE(intcp_io_desc));
94}
95
96#define cic_writel __raw_writel
97#define cic_readl __raw_readl
98#define pic_writel __raw_writel
99#define pic_readl __raw_readl
100#define sic_writel __raw_writel
101#define sic_readl __raw_readl
102
103static void cic_mask_irq(unsigned int irq)
104{
105 irq -= IRQ_CIC_START;
106 cic_writel(1 << irq, INTCP_VA_CIC_BASE + IRQ_ENABLE_CLEAR);
107}
108
109static void cic_unmask_irq(unsigned int irq)
110{
111 irq -= IRQ_CIC_START;
112 cic_writel(1 << irq, INTCP_VA_CIC_BASE + IRQ_ENABLE_SET);
113}
114
115static struct irqchip cic_chip = {
116 .ack = cic_mask_irq,
117 .mask = cic_mask_irq,
118 .unmask = cic_unmask_irq,
119};
120
121static void pic_mask_irq(unsigned int irq)
122{
123 irq -= IRQ_PIC_START;
124 pic_writel(1 << irq, INTCP_VA_PIC_BASE + IRQ_ENABLE_CLEAR);
125}
126
127static void pic_unmask_irq(unsigned int irq)
128{
129 irq -= IRQ_PIC_START;
130 pic_writel(1 << irq, INTCP_VA_PIC_BASE + IRQ_ENABLE_SET);
131}
132
133static struct irqchip pic_chip = {
134 .ack = pic_mask_irq,
135 .mask = pic_mask_irq,
136 .unmask = pic_unmask_irq,
137};
138
139static void sic_mask_irq(unsigned int irq)
140{
141 irq -= IRQ_SIC_START;
142 sic_writel(1 << irq, INTCP_VA_SIC_BASE + IRQ_ENABLE_CLEAR);
143}
144
145static void sic_unmask_irq(unsigned int irq)
146{
147 irq -= IRQ_SIC_START;
148 sic_writel(1 << irq, INTCP_VA_SIC_BASE + IRQ_ENABLE_SET);
149}
150
151static struct irqchip sic_chip = {
152 .ack = sic_mask_irq,
153 .mask = sic_mask_irq,
154 .unmask = sic_unmask_irq,
155};
156
157static void
158sic_handle_irq(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
159{
160 unsigned long status = sic_readl(INTCP_VA_SIC_BASE + IRQ_STATUS);
161
162 if (status == 0) {
163 do_bad_IRQ(irq, desc, regs);
164 return;
165 }
166
167 do {
168 irq = ffs(status) - 1;
169 status &= ~(1 << irq);
170
171 irq += IRQ_SIC_START;
172
173 desc = irq_desc + irq;
174 desc->handle(irq, desc, regs);
175 } while (status);
176}
177
178static void __init intcp_init_irq(void)
179{
180 unsigned int i;
181
182 /*
183 * Disable all interrupt sources
184 */
185 pic_writel(0xffffffff, INTCP_VA_PIC_BASE + IRQ_ENABLE_CLEAR);
186 pic_writel(0xffffffff, INTCP_VA_PIC_BASE + FIQ_ENABLE_CLEAR);
187
188 for (i = IRQ_PIC_START; i <= IRQ_PIC_END; i++) {
189 if (i == 11)
190 i = 22;
191 if (i == IRQ_CP_CPPLDINT)
192 i++;
193 if (i == 29)
194 break;
195 set_irq_chip(i, &pic_chip);
196 set_irq_handler(i, do_level_IRQ);
197 set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
198 }
199
200 cic_writel(0xffffffff, INTCP_VA_CIC_BASE + IRQ_ENABLE_CLEAR);
201 cic_writel(0xffffffff, INTCP_VA_CIC_BASE + FIQ_ENABLE_CLEAR);
202
203 for (i = IRQ_CIC_START; i <= IRQ_CIC_END; i++) {
204 set_irq_chip(i, &cic_chip);
205 set_irq_handler(i, do_level_IRQ);
206 set_irq_flags(i, IRQF_VALID);
207 }
208
209 sic_writel(0x00000fff, INTCP_VA_SIC_BASE + IRQ_ENABLE_CLEAR);
210 sic_writel(0x00000fff, INTCP_VA_SIC_BASE + FIQ_ENABLE_CLEAR);
211
212 for (i = IRQ_SIC_START; i <= IRQ_SIC_END; i++) {
213 set_irq_chip(i, &sic_chip);
214 set_irq_handler(i, do_level_IRQ);
215 set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
216 }
217
218 set_irq_handler(IRQ_CP_CPPLDINT, sic_handle_irq);
219 pic_unmask_irq(IRQ_CP_CPPLDINT);
220}
221
222/*
223 * Clock handling
224 */
225#define CM_LOCK (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_LOCK_OFFSET)
226#define CM_AUXOSC (IO_ADDRESS(INTEGRATOR_HDR_BASE)+0x1c)
227
228static const struct icst525_params cp_auxvco_params = {
229 .ref = 24000,
230 .vco_max = 320000,
231 .vd_min = 8,
232 .vd_max = 263,
233 .rd_min = 3,
234 .rd_max = 65,
235};
236
237static void cp_auxvco_set(struct clk *clk, struct icst525_vco vco)
238{
239 u32 val;
240
241 val = readl(CM_AUXOSC) & ~0x7ffff;
242 val |= vco.v | (vco.r << 9) | (vco.s << 16);
243
244 writel(0xa05f, CM_LOCK);
245 writel(val, CM_AUXOSC);
246 writel(0, CM_LOCK);
247}
248
249static struct clk cp_clcd_clk = {
250 .name = "CLCDCLK",
251 .params = &cp_auxvco_params,
252 .setvco = cp_auxvco_set,
253};
254
255static struct clk cp_mmci_clk = {
256 .name = "MCLK",
257 .rate = 14745600,
258};
259
260/*
261 * Flash handling.
262 */
263static int intcp_flash_init(void)
264{
265 u32 val;
266
267 val = readl(INTCP_VA_CTRL_BASE + INTCP_FLASHPROG);
268 val |= CINTEGRATOR_FLASHPROG_FLWREN;
269 writel(val, INTCP_VA_CTRL_BASE + INTCP_FLASHPROG);
270
271 return 0;
272}
273
274static void intcp_flash_exit(void)
275{
276 u32 val;
277
278 val = readl(INTCP_VA_CTRL_BASE + INTCP_FLASHPROG);
279 val &= ~(CINTEGRATOR_FLASHPROG_FLVPPEN|CINTEGRATOR_FLASHPROG_FLWREN);
280 writel(val, INTCP_VA_CTRL_BASE + INTCP_FLASHPROG);
281}
282
283static void intcp_flash_set_vpp(int on)
284{
285 u32 val;
286
287 val = readl(INTCP_VA_CTRL_BASE + INTCP_FLASHPROG);
288 if (on)
289 val |= CINTEGRATOR_FLASHPROG_FLVPPEN;
290 else
291 val &= ~CINTEGRATOR_FLASHPROG_FLVPPEN;
292 writel(val, INTCP_VA_CTRL_BASE + INTCP_FLASHPROG);
293}
294
295static struct flash_platform_data intcp_flash_data = {
296 .map_name = "cfi_probe",
297 .width = 4,
298 .init = intcp_flash_init,
299 .exit = intcp_flash_exit,
300 .set_vpp = intcp_flash_set_vpp,
301};
302
303static struct resource intcp_flash_resource = {
304 .start = INTCP_PA_FLASH_BASE,
305 .end = INTCP_PA_FLASH_BASE + INTCP_FLASH_SIZE - 1,
306 .flags = IORESOURCE_MEM,
307};
308
309static struct platform_device intcp_flash_device = {
310 .name = "armflash",
311 .id = 0,
312 .dev = {
313 .platform_data = &intcp_flash_data,
314 },
315 .num_resources = 1,
316 .resource = &intcp_flash_resource,
317};
318
319static struct resource smc91x_resources[] = {
320 [0] = {
321 .start = INTCP_PA_ETH_BASE,
322 .end = INTCP_PA_ETH_BASE + INTCP_ETH_SIZE - 1,
323 .flags = IORESOURCE_MEM,
324 },
325 [1] = {
326 .start = IRQ_CP_ETHINT,
327 .end = IRQ_CP_ETHINT,
328 .flags = IORESOURCE_IRQ,
329 },
330};
331
332static struct platform_device smc91x_device = {
333 .name = "smc91x",
334 .id = 0,
335 .num_resources = ARRAY_SIZE(smc91x_resources),
336 .resource = smc91x_resources,
337};
338
339static struct platform_device *intcp_devs[] __initdata = {
340 &intcp_flash_device,
341 &smc91x_device,
342};
343
344/*
345 * It seems that the card insertion interrupt remains active after
346 * we've acknowledged it. We therefore ignore the interrupt, and
347 * rely on reading it from the SIC. This also means that we must
348 * clear the latched interrupt.
349 */
350static unsigned int mmc_status(struct device *dev)
351{
352 unsigned int status = readl(0xfca00004);
353 writel(8, 0xfcb00008);
354
355 return status & 8;
356}
357
358static struct mmc_platform_data mmc_data = {
359 .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
360 .status = mmc_status,
361};
362
363static struct amba_device mmc_device = {
364 .dev = {
365 .bus_id = "mb:1c",
366 .platform_data = &mmc_data,
367 },
368 .res = {
369 .start = INTCP_PA_MMC_BASE,
370 .end = INTCP_PA_MMC_BASE + SZ_4K - 1,
371 .flags = IORESOURCE_MEM,
372 },
373 .irq = { IRQ_CP_MMCIINT0, IRQ_CP_MMCIINT1 },
374 .periphid = 0,
375};
376
377static struct amba_device aaci_device = {
378 .dev = {
379 .bus_id = "mb:1d",
380 },
381 .res = {
382 .start = INTCP_PA_AACI_BASE,
383 .end = INTCP_PA_AACI_BASE + SZ_4K - 1,
384 .flags = IORESOURCE_MEM,
385 },
386 .irq = { IRQ_CP_AACIINT, NO_IRQ },
387 .periphid = 0,
388};
389
390
391/*
392 * CLCD support
393 */
394static struct clcd_panel vga = {
395 .mode = {
396 .name = "VGA",
397 .refresh = 60,
398 .xres = 640,
399 .yres = 480,
400 .pixclock = 39721,
401 .left_margin = 40,
402 .right_margin = 24,
403 .upper_margin = 32,
404 .lower_margin = 11,
405 .hsync_len = 96,
406 .vsync_len = 2,
407 .sync = 0,
408 .vmode = FB_VMODE_NONINTERLACED,
409 },
410 .width = -1,
411 .height = -1,
412 .tim2 = TIM2_BCD | TIM2_IPC,
413 .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1),
414 .bpp = 16,
415 .grayscale = 0,
416};
417
418/*
419 * Ensure VGA is selected.
420 */
421static void cp_clcd_enable(struct clcd_fb *fb)
422{
423 cm_control(CM_CTRL_LCDMUXSEL_MASK, CM_CTRL_LCDMUXSEL_VGA);
424}
425
426static unsigned long framesize = SZ_1M;
427
428static int cp_clcd_setup(struct clcd_fb *fb)
429{
430 dma_addr_t dma;
431
432 fb->panel = &vga;
433
434 fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev, framesize,
435 &dma, GFP_KERNEL);
436 if (!fb->fb.screen_base) {
437 printk(KERN_ERR "CLCD: unable to map framebuffer\n");
438 return -ENOMEM;
439 }
440
441 fb->fb.fix.smem_start = dma;
442 fb->fb.fix.smem_len = framesize;
443
444 return 0;
445}
446
447static int cp_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
448{
449 return dma_mmap_writecombine(&fb->dev->dev, vma,
450 fb->fb.screen_base,
451 fb->fb.fix.smem_start,
452 fb->fb.fix.smem_len);
453}
454
455static void cp_clcd_remove(struct clcd_fb *fb)
456{
457 dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len,
458 fb->fb.screen_base, fb->fb.fix.smem_start);
459}
460
461static struct clcd_board clcd_data = {
462 .name = "Integrator/CP",
463 .check = clcdfb_check,
464 .decode = clcdfb_decode,
465 .enable = cp_clcd_enable,
466 .setup = cp_clcd_setup,
467 .mmap = cp_clcd_mmap,
468 .remove = cp_clcd_remove,
469};
470
471static struct amba_device clcd_device = {
472 .dev = {
473 .bus_id = "mb:c0",
474 .coherent_dma_mask = ~0,
475 .platform_data = &clcd_data,
476 },
477 .res = {
478 .start = INTCP_PA_CLCD_BASE,
479 .end = INTCP_PA_CLCD_BASE + SZ_4K - 1,
480 .flags = IORESOURCE_MEM,
481 },
482 .dma_mask = ~0,
483 .irq = { IRQ_CP_CLCDCINT, NO_IRQ },
484 .periphid = 0,
485};
486
487static struct amba_device *amba_devs[] __initdata = {
488 &mmc_device,
489 &aaci_device,
490 &clcd_device,
491};
492
493static void __init intcp_init(void)
494{
495 int i;
496
497 clk_register(&cp_clcd_clk);
498 clk_register(&cp_mmci_clk);
499
500 platform_add_devices(intcp_devs, ARRAY_SIZE(intcp_devs));
501
502 for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
503 struct amba_device *d = amba_devs[i];
504 amba_device_register(d, &iomem_resource);
505 }
506}
507
508#define TIMER_CTRL_IE (1 << 5) /* Interrupt Enable */
509
510static void __init intcp_timer_init(void)
511{
512 integrator_time_init(1000000 / HZ, TIMER_CTRL_IE);
513}
514
515static struct sys_timer cp_timer = {
516 .init = intcp_timer_init,
517 .offset = integrator_gettimeoffset,
518};
519
520MACHINE_START(CINTEGRATOR, "ARM-IntegratorCP")
521 MAINTAINER("ARM Ltd/Deep Blue Solutions Ltd")
522 BOOT_MEM(0x00000000, 0x16000000, 0xf1600000)
523 BOOT_PARAMS(0x00000100)
524 MAPIO(intcp_map_io)
525 INITIRQ(intcp_init_irq)
526 .timer = &cp_timer,
527 INIT_MACHINE(intcp_init)
528MACHINE_END
diff --git a/arch/arm/mach-integrator/leds.c b/arch/arm/mach-integrator/leds.c
new file mode 100644
index 000000000000..9d182b77b312
--- /dev/null
+++ b/arch/arm/mach-integrator/leds.c
@@ -0,0 +1,88 @@
1/*
2 * linux/arch/arm/mach-integrator/leds.c
3 *
4 * Integrator/AP and Integrator/CP LED control routines
5 *
6 * Copyright (C) 1999 ARM Limited
7 * Copyright (C) 2000 Deep Blue Solutions Ltd
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23#include <linux/kernel.h>
24#include <linux/init.h>
25
26#include <asm/hardware.h>
27#include <asm/io.h>
28#include <asm/leds.h>
29#include <asm/system.h>
30#include <asm/mach-types.h>
31#include <asm/arch/cm.h>
32
33static int saved_leds;
34
35static void integrator_leds_event(led_event_t ledevt)
36{
37 unsigned long flags;
38 const unsigned int dbg_base = IO_ADDRESS(INTEGRATOR_DBG_BASE);
39 unsigned int update_alpha_leds;
40
41 // yup, change the LEDs
42 local_irq_save(flags);
43 update_alpha_leds = 0;
44
45 switch(ledevt) {
46 case led_idle_start:
47 cm_control(CM_CTRL_LED, 0);
48 break;
49
50 case led_idle_end:
51 cm_control(CM_CTRL_LED, CM_CTRL_LED);
52 break;
53
54 case led_timer:
55 saved_leds ^= GREEN_LED;
56 update_alpha_leds = 1;
57 break;
58
59 case led_red_on:
60 saved_leds |= RED_LED;
61 update_alpha_leds = 1;
62 break;
63
64 case led_red_off:
65 saved_leds &= ~RED_LED;
66 update_alpha_leds = 1;
67 break;
68
69 default:
70 break;
71 }
72
73 if (update_alpha_leds) {
74 while (__raw_readl(dbg_base + INTEGRATOR_DBG_ALPHA_OFFSET) & 1);
75 __raw_writel(saved_leds, dbg_base + INTEGRATOR_DBG_LEDS_OFFSET);
76 }
77 local_irq_restore(flags);
78}
79
80static int __init leds_init(void)
81{
82 if (machine_is_integrator() || machine_is_cintegrator())
83 leds_event = integrator_leds_event;
84
85 return 0;
86}
87
88__initcall(leds_init);
diff --git a/arch/arm/mach-integrator/lm.c b/arch/arm/mach-integrator/lm.c
new file mode 100644
index 000000000000..c5f19d160598
--- /dev/null
+++ b/arch/arm/mach-integrator/lm.c
@@ -0,0 +1,96 @@
1/*
2 * linux/arch/arm/mach-integrator/lm.c
3 *
4 * Copyright (C) 2003 Deep Blue Solutions Ltd, All Rights Reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10#include <linux/module.h>
11#include <linux/init.h>
12#include <linux/device.h>
13
14#include <asm/arch/lm.h>
15
16#define to_lm_device(d) container_of(d, struct lm_device, dev)
17#define to_lm_driver(d) container_of(d, struct lm_driver, drv)
18
19static int lm_match(struct device *dev, struct device_driver *drv)
20{
21 return 1;
22}
23
24static struct bus_type lm_bustype = {
25 .name = "logicmodule",
26 .match = lm_match,
27// .suspend = lm_suspend,
28// .resume = lm_resume,
29};
30
31static int __init lm_init(void)
32{
33 return bus_register(&lm_bustype);
34}
35
36postcore_initcall(lm_init);
37
38static int lm_bus_probe(struct device *dev)
39{
40 struct lm_device *lmdev = to_lm_device(dev);
41 struct lm_driver *lmdrv = to_lm_driver(dev->driver);
42
43 return lmdrv->probe(lmdev);
44}
45
46static int lm_bus_remove(struct device *dev)
47{
48 struct lm_device *lmdev = to_lm_device(dev);
49 struct lm_driver *lmdrv = to_lm_driver(dev->driver);
50
51 lmdrv->remove(lmdev);
52 return 0;
53}
54
55int lm_driver_register(struct lm_driver *drv)
56{
57 drv->drv.bus = &lm_bustype;
58 drv->drv.probe = lm_bus_probe;
59 drv->drv.remove = lm_bus_remove;
60
61 return driver_register(&drv->drv);
62}
63
64void lm_driver_unregister(struct lm_driver *drv)
65{
66 driver_unregister(&drv->drv);
67}
68
69static void lm_device_release(struct device *dev)
70{
71 struct lm_device *d = to_lm_device(dev);
72
73 kfree(d);
74}
75
76int lm_device_register(struct lm_device *dev)
77{
78 int ret;
79
80 dev->dev.release = lm_device_release;
81 dev->dev.bus = &lm_bustype;
82
83 snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id), "lm%d", dev->id);
84 dev->resource.name = dev->dev.bus_id;
85
86 ret = request_resource(&iomem_resource, &dev->resource);
87 if (ret == 0) {
88 ret = device_register(&dev->dev);
89 if (ret)
90 release_resource(&dev->resource);
91 }
92 return ret;
93}
94
95EXPORT_SYMBOL(lm_driver_register);
96EXPORT_SYMBOL(lm_driver_unregister);
diff --git a/arch/arm/mach-integrator/pci.c b/arch/arm/mach-integrator/pci.c
new file mode 100644
index 000000000000..394ec9261c4e
--- /dev/null
+++ b/arch/arm/mach-integrator/pci.c
@@ -0,0 +1,132 @@
1/*
2 * linux/arch/arm/mach-integrator/pci-integrator.c
3 *
4 * Copyright (C) 1999 ARM Limited
5 * Copyright (C) 2000 Deep Blue Solutions Ltd
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 *
22 * PCI functions for Integrator
23 */
24#include <linux/kernel.h>
25#include <linux/pci.h>
26#include <linux/ptrace.h>
27#include <linux/interrupt.h>
28#include <linux/init.h>
29
30#include <asm/irq.h>
31#include <asm/system.h>
32#include <asm/mach/pci.h>
33#include <asm/mach-types.h>
34
35/*
36 * A small note about bridges and interrupts. The DECchip 21050 (and
37 * later) adheres to the PCI-PCI bridge specification. This says that
38 * the interrupts on the other side of a bridge are swizzled in the
39 * following manner:
40 *
41 * Dev Interrupt Interrupt
42 * Pin on Pin on
43 * Device Connector
44 *
45 * 4 A A
46 * B B
47 * C C
48 * D D
49 *
50 * 5 A B
51 * B C
52 * C D
53 * D A
54 *
55 * 6 A C
56 * B D
57 * C A
58 * D B
59 *
60 * 7 A D
61 * B A
62 * C B
63 * D C
64 *
65 * Where A = pin 1, B = pin 2 and so on and pin=0 = default = A.
66 * Thus, each swizzle is ((pin-1) + (device#-4)) % 4
67 *
68 * The following code swizzles for exactly one bridge.
69 */
70static inline int bridge_swizzle(int pin, unsigned int slot)
71{
72 return (pin + slot) & 3;
73}
74
75/*
76 * This routine handles multiple bridges.
77 */
78static u8 __init integrator_swizzle(struct pci_dev *dev, u8 *pinp)
79{
80 int pin = *pinp;
81
82 if (pin == 0)
83 pin = 1;
84
85 pin -= 1;
86 while (dev->bus->self) {
87 pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn));
88 /*
89 * move up the chain of bridges, swizzling as we go.
90 */
91 dev = dev->bus->self;
92 }
93 *pinp = pin + 1;
94
95 return PCI_SLOT(dev->devfn);
96}
97
98static int irq_tab[4] __initdata = {
99 IRQ_AP_PCIINT0, IRQ_AP_PCIINT1, IRQ_AP_PCIINT2, IRQ_AP_PCIINT3
100};
101
102/*
103 * map the specified device/slot/pin to an IRQ. This works out such
104 * that slot 9 pin 1 is INT0, pin 2 is INT1, and slot 10 pin 1 is INT1.
105 */
106static int __init integrator_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
107{
108 int intnr = ((slot - 9) + (pin - 1)) & 3;
109
110 return irq_tab[intnr];
111}
112
113extern void pci_v3_init(void *);
114
115static struct hw_pci integrator_pci __initdata = {
116 .swizzle = integrator_swizzle,
117 .map_irq = integrator_map_irq,
118 .setup = pci_v3_setup,
119 .nr_controllers = 1,
120 .scan = pci_v3_scan_bus,
121 .preinit = pci_v3_preinit,
122 .postinit = pci_v3_postinit,
123};
124
125static int __init integrator_pci_init(void)
126{
127 if (machine_is_integrator())
128 pci_common_init(&integrator_pci);
129 return 0;
130}
131
132subsys_initcall(integrator_pci_init);
diff --git a/arch/arm/mach-integrator/pci_v3.c b/arch/arm/mach-integrator/pci_v3.c
new file mode 100644
index 000000000000..229a63a525cd
--- /dev/null
+++ b/arch/arm/mach-integrator/pci_v3.c
@@ -0,0 +1,604 @@
1/*
2 * linux/arch/arm/mach-integrator/pci_v3.c
3 *
4 * PCI functions for V3 host PCI bridge
5 *
6 * Copyright (C) 1999 ARM Limited
7 * Copyright (C) 2000-2001 Deep Blue Solutions Ltd
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23#include <linux/config.h>
24#include <linux/kernel.h>
25#include <linux/pci.h>
26#include <linux/ptrace.h>
27#include <linux/slab.h>
28#include <linux/ioport.h>
29#include <linux/interrupt.h>
30#include <linux/spinlock.h>
31#include <linux/init.h>
32
33#include <asm/hardware.h>
34#include <asm/io.h>
35#include <asm/irq.h>
36#include <asm/system.h>
37#include <asm/mach/pci.h>
38
39#include <asm/hardware/pci_v3.h>
40
41/*
42 * The V3 PCI interface chip in Integrator provides several windows from
43 * local bus memory into the PCI memory areas. Unfortunately, there
44 * are not really enough windows for our usage, therefore we reuse
45 * one of the windows for access to PCI configuration space. The
46 * memory map is as follows:
47 *
48 * Local Bus Memory Usage
49 *
50 * 40000000 - 4FFFFFFF PCI memory. 256M non-prefetchable
51 * 50000000 - 5FFFFFFF PCI memory. 256M prefetchable
52 * 60000000 - 60FFFFFF PCI IO. 16M
53 * 61000000 - 61FFFFFF PCI Configuration. 16M
54 *
55 * There are three V3 windows, each described by a pair of V3 registers.
56 * These are LB_BASE0/LB_MAP0, LB_BASE1/LB_MAP1 and LB_BASE2/LB_MAP2.
57 * Base0 and Base1 can be used for any type of PCI memory access. Base2
58 * can be used either for PCI I/O or for I20 accesses. By default, uHAL
59 * uses this only for PCI IO space.
60 *
61 * Normally these spaces are mapped using the following base registers:
62 *
63 * Usage Local Bus Memory Base/Map registers used
64 *
65 * Mem 40000000 - 4FFFFFFF LB_BASE0/LB_MAP0
66 * Mem 50000000 - 5FFFFFFF LB_BASE1/LB_MAP1
67 * IO 60000000 - 60FFFFFF LB_BASE2/LB_MAP2
68 * Cfg 61000000 - 61FFFFFF
69 *
70 * This means that I20 and PCI configuration space accesses will fail.
71 * When PCI configuration accesses are needed (via the uHAL PCI
72 * configuration space primitives) we must remap the spaces as follows:
73 *
74 * Usage Local Bus Memory Base/Map registers used
75 *
76 * Mem 40000000 - 4FFFFFFF LB_BASE0/LB_MAP0
77 * Mem 50000000 - 5FFFFFFF LB_BASE0/LB_MAP0
78 * IO 60000000 - 60FFFFFF LB_BASE2/LB_MAP2
79 * Cfg 61000000 - 61FFFFFF LB_BASE1/LB_MAP1
80 *
81 * To make this work, the code depends on overlapping windows working.
82 * The V3 chip translates an address by checking its range within
83 * each of the BASE/MAP pairs in turn (in ascending register number
84 * order). It will use the first matching pair. So, for example,
85 * if the same address is mapped by both LB_BASE0/LB_MAP0 and
86 * LB_BASE1/LB_MAP1, the V3 will use the translation from
87 * LB_BASE0/LB_MAP0.
88 *
89 * To allow PCI Configuration space access, the code enlarges the
90 * window mapped by LB_BASE0/LB_MAP0 from 256M to 512M. This occludes
91 * the windows currently mapped by LB_BASE1/LB_MAP1 so that it can
92 * be remapped for use by configuration cycles.
93 *
94 * At the end of the PCI Configuration space accesses,
95 * LB_BASE1/LB_MAP1 is reset to map PCI Memory. Finally the window
96 * mapped by LB_BASE0/LB_MAP0 is reduced in size from 512M to 256M to
97 * reveal the now restored LB_BASE1/LB_MAP1 window.
98 *
99 * NOTE: We do not set up I2O mapping. I suspect that this is only
100 * for an intelligent (target) device. Using I2O disables most of
101 * the mappings into PCI memory.
102 */
103
104// V3 access routines
105#define v3_writeb(o,v) __raw_writeb(v, PCI_V3_VADDR + (unsigned int)(o))
106#define v3_readb(o) (__raw_readb(PCI_V3_VADDR + (unsigned int)(o)))
107
108#define v3_writew(o,v) __raw_writew(v, PCI_V3_VADDR + (unsigned int)(o))
109#define v3_readw(o) (__raw_readw(PCI_V3_VADDR + (unsigned int)(o)))
110
111#define v3_writel(o,v) __raw_writel(v, PCI_V3_VADDR + (unsigned int)(o))
112#define v3_readl(o) (__raw_readl(PCI_V3_VADDR + (unsigned int)(o)))
113
114/*============================================================================
115 *
116 * routine: uHALir_PCIMakeConfigAddress()
117 *
118 * parameters: bus = which bus
119 * device = which device
120 * function = which function
121 * offset = configuration space register we are interested in
122 *
123 * description: this routine will generate a platform dependent config
124 * address.
125 *
126 * calls: none
127 *
128 * returns: configuration address to play on the PCI bus
129 *
130 * To generate the appropriate PCI configuration cycles in the PCI
131 * configuration address space, you present the V3 with the following pattern
132 * (which is very nearly a type 1 (except that the lower two bits are 00 and
133 * not 01). In order for this mapping to work you need to set up one of
134 * the local to PCI aperatures to 16Mbytes in length translating to
135 * PCI configuration space starting at 0x0000.0000.
136 *
137 * PCI configuration cycles look like this:
138 *
139 * Type 0:
140 *
141 * 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1
142 * 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
143 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
144 * | | |D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|0|
145 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
146 *
147 * 31:11 Device select bit.
148 * 10:8 Function number
149 * 7:2 Register number
150 *
151 * Type 1:
152 *
153 * 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1
154 * 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
155 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
156 * | | | | | | | | | | |B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|1|
157 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
158 *
159 * 31:24 reserved
160 * 23:16 bus number (8 bits = 128 possible buses)
161 * 15:11 Device number (5 bits)
162 * 10:8 function number
163 * 7:2 register number
164 *
165 */
166static DEFINE_SPINLOCK(v3_lock);
167
168#define PCI_BUS_NONMEM_START 0x00000000
169#define PCI_BUS_NONMEM_SIZE SZ_256M
170
171#define PCI_BUS_PREMEM_START PCI_BUS_NONMEM_START + PCI_BUS_NONMEM_SIZE
172#define PCI_BUS_PREMEM_SIZE SZ_256M
173
174#if PCI_BUS_NONMEM_START & 0x000fffff
175#error PCI_BUS_NONMEM_START must be megabyte aligned
176#endif
177#if PCI_BUS_PREMEM_START & 0x000fffff
178#error PCI_BUS_PREMEM_START must be megabyte aligned
179#endif
180
181#undef V3_LB_BASE_PREFETCH
182#define V3_LB_BASE_PREFETCH 0
183
184static unsigned long v3_open_config_window(struct pci_bus *bus,
185 unsigned int devfn, int offset)
186{
187 unsigned int address, mapaddress, busnr;
188
189 busnr = bus->number;
190
191 /*
192 * Trap out illegal values
193 */
194 if (offset > 255)
195 BUG();
196 if (busnr > 255)
197 BUG();
198 if (devfn > 255)
199 BUG();
200
201 if (busnr == 0) {
202 int slot = PCI_SLOT(devfn);
203
204 /*
205 * local bus segment so need a type 0 config cycle
206 *
207 * build the PCI configuration "address" with one-hot in
208 * A31-A11
209 *
210 * mapaddress:
211 * 3:1 = config cycle (101)
212 * 0 = PCI A1 & A0 are 0 (0)
213 */
214 address = PCI_FUNC(devfn) << 8;
215 mapaddress = V3_LB_MAP_TYPE_CONFIG;
216
217 if (slot > 12)
218 /*
219 * high order bits are handled by the MAP register
220 */
221 mapaddress |= 1 << (slot - 5);
222 else
223 /*
224 * low order bits handled directly in the address
225 */
226 address |= 1 << (slot + 11);
227 } else {
228 /*
229 * not the local bus segment so need a type 1 config cycle
230 *
231 * address:
232 * 23:16 = bus number
233 * 15:11 = slot number (7:3 of devfn)
234 * 10:8 = func number (2:0 of devfn)
235 *
236 * mapaddress:
237 * 3:1 = config cycle (101)
238 * 0 = PCI A1 & A0 from host bus (1)
239 */
240 mapaddress = V3_LB_MAP_TYPE_CONFIG | V3_LB_MAP_AD_LOW_EN;
241 address = (busnr << 16) | (devfn << 8);
242 }
243
244 /*
245 * Set up base0 to see all 512Mbytes of memory space (not
246 * prefetchable), this frees up base1 for re-use by
247 * configuration memory
248 */
249 v3_writel(V3_LB_BASE0, v3_addr_to_lb_base(PHYS_PCI_MEM_BASE) |
250 V3_LB_BASE_ADR_SIZE_512MB | V3_LB_BASE_ENABLE);
251
252 /*
253 * Set up base1/map1 to point into configuration space.
254 */
255 v3_writel(V3_LB_BASE1, v3_addr_to_lb_base(PHYS_PCI_CONFIG_BASE) |
256 V3_LB_BASE_ADR_SIZE_16MB | V3_LB_BASE_ENABLE);
257 v3_writew(V3_LB_MAP1, mapaddress);
258
259 return PCI_CONFIG_VADDR + address + offset;
260}
261
262static void v3_close_config_window(void)
263{
264 /*
265 * Reassign base1 for use by prefetchable PCI memory
266 */
267 v3_writel(V3_LB_BASE1, v3_addr_to_lb_base(PHYS_PCI_MEM_BASE + SZ_256M) |
268 V3_LB_BASE_ADR_SIZE_256MB | V3_LB_BASE_PREFETCH |
269 V3_LB_BASE_ENABLE);
270 v3_writew(V3_LB_MAP1, v3_addr_to_lb_map(PCI_BUS_PREMEM_START) |
271 V3_LB_MAP_TYPE_MEM_MULTIPLE);
272
273 /*
274 * And shrink base0 back to a 256M window (NOTE: MAP0 already correct)
275 */
276 v3_writel(V3_LB_BASE0, v3_addr_to_lb_base(PHYS_PCI_MEM_BASE) |
277 V3_LB_BASE_ADR_SIZE_256MB | V3_LB_BASE_ENABLE);
278}
279
280static int v3_read_config(struct pci_bus *bus, unsigned int devfn, int where,
281 int size, u32 *val)
282{
283 unsigned long addr;
284 unsigned long flags;
285 u32 v;
286
287 spin_lock_irqsave(&v3_lock, flags);
288 addr = v3_open_config_window(bus, devfn, where);
289
290 switch (size) {
291 case 1:
292 v = __raw_readb(addr);
293 break;
294
295 case 2:
296 v = __raw_readw(addr);
297 break;
298
299 default:
300 v = __raw_readl(addr);
301 break;
302 }
303
304 v3_close_config_window();
305 spin_unlock_irqrestore(&v3_lock, flags);
306
307 *val = v;
308 return PCIBIOS_SUCCESSFUL;
309}
310
311static int v3_write_config(struct pci_bus *bus, unsigned int devfn, int where,
312 int size, u32 val)
313{
314 unsigned long addr;
315 unsigned long flags;
316
317 spin_lock_irqsave(&v3_lock, flags);
318 addr = v3_open_config_window(bus, devfn, where);
319
320 switch (size) {
321 case 1:
322 __raw_writeb((u8)val, addr);
323 __raw_readb(addr);
324 break;
325
326 case 2:
327 __raw_writew((u16)val, addr);
328 __raw_readw(addr);
329 break;
330
331 case 4:
332 __raw_writel(val, addr);
333 __raw_readl(addr);
334 break;
335 }
336
337 v3_close_config_window();
338 spin_unlock_irqrestore(&v3_lock, flags);
339
340 return PCIBIOS_SUCCESSFUL;
341}
342
343static struct pci_ops pci_v3_ops = {
344 .read = v3_read_config,
345 .write = v3_write_config,
346};
347
348static struct resource non_mem = {
349 .name = "PCI non-prefetchable",
350 .start = PHYS_PCI_MEM_BASE + PCI_BUS_NONMEM_START,
351 .end = PHYS_PCI_MEM_BASE + PCI_BUS_NONMEM_START + PCI_BUS_NONMEM_SIZE - 1,
352 .flags = IORESOURCE_MEM,
353};
354
355static struct resource pre_mem = {
356 .name = "PCI prefetchable",
357 .start = PHYS_PCI_MEM_BASE + PCI_BUS_PREMEM_START,
358 .end = PHYS_PCI_MEM_BASE + PCI_BUS_PREMEM_START + PCI_BUS_PREMEM_SIZE - 1,
359 .flags = IORESOURCE_MEM | IORESOURCE_PREFETCH,
360};
361
362static int __init pci_v3_setup_resources(struct resource **resource)
363{
364 if (request_resource(&iomem_resource, &non_mem)) {
365 printk(KERN_ERR "PCI: unable to allocate non-prefetchable "
366 "memory region\n");
367 return -EBUSY;
368 }
369 if (request_resource(&iomem_resource, &pre_mem)) {
370 release_resource(&non_mem);
371 printk(KERN_ERR "PCI: unable to allocate prefetchable "
372 "memory region\n");
373 return -EBUSY;
374 }
375
376 /*
377 * bus->resource[0] is the IO resource for this bus
378 * bus->resource[1] is the mem resource for this bus
379 * bus->resource[2] is the prefetch mem resource for this bus
380 */
381 resource[0] = &ioport_resource;
382 resource[1] = &non_mem;
383 resource[2] = &pre_mem;
384
385 return 1;
386}
387
388/*
389 * These don't seem to be implemented on the Integrator I have, which
390 * means I can't get additional information on the reason for the pm2fb
391 * problems. I suppose I'll just have to mind-meld with the machine. ;)
392 */
393#define SC_PCI (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_PCIENABLE_OFFSET)
394#define SC_LBFADDR (IO_ADDRESS(INTEGRATOR_SC_BASE) + 0x20)
395#define SC_LBFCODE (IO_ADDRESS(INTEGRATOR_SC_BASE) + 0x24)
396
397static int
398v3_pci_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
399{
400 unsigned long pc = instruction_pointer(regs);
401 unsigned long instr = *(unsigned long *)pc;
402#if 0
403 char buf[128];
404
405 sprintf(buf, "V3 fault: addr 0x%08lx, FSR 0x%03x, PC 0x%08lx [%08lx] LBFADDR=%08x LBFCODE=%02x ISTAT=%02x\n",
406 addr, fsr, pc, instr, __raw_readl(SC_LBFADDR), __raw_readl(SC_LBFCODE) & 255,
407 v3_readb(V3_LB_ISTAT));
408 printk(KERN_DEBUG "%s", buf);
409 printascii(buf);
410#endif
411
412 v3_writeb(V3_LB_ISTAT, 0);
413 __raw_writel(3, SC_PCI);
414
415 /*
416 * If the instruction being executed was a read,
417 * make it look like it read all-ones.
418 */
419 if ((instr & 0x0c100000) == 0x04100000) {
420 int reg = (instr >> 12) & 15;
421 unsigned long val;
422
423 if (instr & 0x00400000)
424 val = 255;
425 else
426 val = -1;
427
428 regs->uregs[reg] = val;
429 regs->ARM_pc += 4;
430 return 0;
431 }
432
433 if ((instr & 0x0e100090) == 0x00100090) {
434 int reg = (instr >> 12) & 15;
435
436 regs->uregs[reg] = -1;
437 regs->ARM_pc += 4;
438 return 0;
439 }
440
441 return 1;
442}
443
444static irqreturn_t v3_irq(int irq, void *devid, struct pt_regs *regs)
445{
446#ifdef CONFIG_DEBUG_LL
447 unsigned long pc = instruction_pointer(regs);
448 unsigned long instr = *(unsigned long *)pc;
449 char buf[128];
450
451 sprintf(buf, "V3 int %d: pc=0x%08lx [%08lx] LBFADDR=%08x LBFCODE=%02x ISTAT=%02x\n", irq,
452 pc, instr, __raw_readl(SC_LBFADDR), __raw_readl(SC_LBFCODE) & 255,
453 v3_readb(V3_LB_ISTAT));
454 printascii(buf);
455#endif
456
457 v3_writew(V3_PCI_STAT, 0xf000);
458 v3_writeb(V3_LB_ISTAT, 0);
459 __raw_writel(3, SC_PCI);
460
461#ifdef CONFIG_DEBUG_LL
462 /*
463 * If the instruction being executed was a read,
464 * make it look like it read all-ones.
465 */
466 if ((instr & 0x0c100000) == 0x04100000) {
467 int reg = (instr >> 16) & 15;
468 sprintf(buf, " reg%d = %08lx\n", reg, regs->uregs[reg]);
469 printascii(buf);
470 }
471#endif
472 return IRQ_HANDLED;
473}
474
475int __init pci_v3_setup(int nr, struct pci_sys_data *sys)
476{
477 int ret = 0;
478
479 if (nr == 0) {
480 sys->mem_offset = PHYS_PCI_MEM_BASE;
481 ret = pci_v3_setup_resources(sys->resource);
482 }
483
484 return ret;
485}
486
487struct pci_bus *pci_v3_scan_bus(int nr, struct pci_sys_data *sys)
488{
489 return pci_scan_bus(sys->busnr, &pci_v3_ops, sys);
490}
491
492/*
493 * V3_LB_BASE? - local bus address
494 * V3_LB_MAP? - pci bus address
495 */
496void __init pci_v3_preinit(void)
497{
498 unsigned long flags;
499 unsigned int temp;
500 int ret;
501
502 /*
503 * Hook in our fault handler for PCI errors
504 */
505 hook_fault_code(4, v3_pci_fault, SIGBUS, "external abort on linefetch");
506 hook_fault_code(6, v3_pci_fault, SIGBUS, "external abort on linefetch");
507 hook_fault_code(8, v3_pci_fault, SIGBUS, "external abort on non-linefetch");
508 hook_fault_code(10, v3_pci_fault, SIGBUS, "external abort on non-linefetch");
509
510 spin_lock_irqsave(&v3_lock, flags);
511
512 /*
513 * Unlock V3 registers, but only if they were previously locked.
514 */
515 if (v3_readw(V3_SYSTEM) & V3_SYSTEM_M_LOCK)
516 v3_writew(V3_SYSTEM, 0xa05f);
517
518 /*
519 * Setup window 0 - PCI non-prefetchable memory
520 * Local: 0x40000000 Bus: 0x00000000 Size: 256MB
521 */
522 v3_writel(V3_LB_BASE0, v3_addr_to_lb_base(PHYS_PCI_MEM_BASE) |
523 V3_LB_BASE_ADR_SIZE_256MB | V3_LB_BASE_ENABLE);
524 v3_writew(V3_LB_MAP0, v3_addr_to_lb_map(PCI_BUS_NONMEM_START) |
525 V3_LB_MAP_TYPE_MEM);
526
527 /*
528 * Setup window 1 - PCI prefetchable memory
529 * Local: 0x50000000 Bus: 0x10000000 Size: 256MB
530 */
531 v3_writel(V3_LB_BASE1, v3_addr_to_lb_base(PHYS_PCI_MEM_BASE + SZ_256M) |
532 V3_LB_BASE_ADR_SIZE_256MB | V3_LB_BASE_PREFETCH |
533 V3_LB_BASE_ENABLE);
534 v3_writew(V3_LB_MAP1, v3_addr_to_lb_map(PCI_BUS_PREMEM_START) |
535 V3_LB_MAP_TYPE_MEM_MULTIPLE);
536
537 /*
538 * Setup window 2 - PCI IO
539 */
540 v3_writel(V3_LB_BASE2, v3_addr_to_lb_base2(PHYS_PCI_IO_BASE) |
541 V3_LB_BASE_ENABLE);
542 v3_writew(V3_LB_MAP2, v3_addr_to_lb_map2(0));
543
544 /*
545 * Disable PCI to host IO cycles
546 */
547 temp = v3_readw(V3_PCI_CFG) & ~V3_PCI_CFG_M_I2O_EN;
548 temp |= V3_PCI_CFG_M_IO_REG_DIS | V3_PCI_CFG_M_IO_DIS;
549 v3_writew(V3_PCI_CFG, temp);
550
551 printk(KERN_DEBUG "FIFO_CFG: %04x FIFO_PRIO: %04x\n",
552 v3_readw(V3_FIFO_CFG), v3_readw(V3_FIFO_PRIORITY));
553
554 /*
555 * Set the V3 FIFO such that writes have higher priority than
556 * reads, and local bus write causes local bus read fifo flush.
557 * Same for PCI.
558 */
559 v3_writew(V3_FIFO_PRIORITY, 0x0a0a);
560
561 /*
562 * Re-lock the system register.
563 */
564 temp = v3_readw(V3_SYSTEM) | V3_SYSTEM_M_LOCK;
565 v3_writew(V3_SYSTEM, temp);
566
567 /*
568 * Clear any error conditions, and enable write errors.
569 */
570 v3_writeb(V3_LB_ISTAT, 0);
571 v3_writew(V3_LB_CFG, v3_readw(V3_LB_CFG) | (1 << 10));
572 v3_writeb(V3_LB_IMASK, 0x28);
573 __raw_writel(3, SC_PCI);
574
575 /*
576 * Grab the PCI error interrupt.
577 */
578 ret = request_irq(IRQ_AP_V3INT, v3_irq, 0, "V3", NULL);
579 if (ret)
580 printk(KERN_ERR "PCI: unable to grab PCI error "
581 "interrupt: %d\n", ret);
582
583 spin_unlock_irqrestore(&v3_lock, flags);
584}
585
586void __init pci_v3_postinit(void)
587{
588 unsigned int pci_cmd;
589
590 pci_cmd = PCI_COMMAND_MEMORY |
591 PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE;
592
593 v3_writew(V3_PCI_CMD, pci_cmd);
594
595 v3_writeb(V3_LB_ISTAT, ~0x40);
596 v3_writeb(V3_LB_IMASK, 0x68);
597
598#if 0
599 ret = request_irq(IRQ_AP_LBUSTIMEOUT, lb_timeout, 0, "bus timeout", NULL);
600 if (ret)
601 printk(KERN_ERR "PCI: unable to grab local bus timeout "
602 "interrupt: %d\n", ret);
603#endif
604}
diff --git a/arch/arm/mach-integrator/time.c b/arch/arm/mach-integrator/time.c
new file mode 100644
index 000000000000..20729de2af28
--- /dev/null
+++ b/arch/arm/mach-integrator/time.c
@@ -0,0 +1,213 @@
1/*
2 * linux/arch/arm/mach-integrator/time.c
3 *
4 * Copyright (C) 2000-2001 Deep Blue Solutions Ltd.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10#include <linux/module.h>
11#include <linux/kernel.h>
12#include <linux/time.h>
13#include <linux/mc146818rtc.h>
14#include <linux/interrupt.h>
15#include <linux/init.h>
16#include <linux/device.h>
17
18#include <asm/hardware/amba.h>
19#include <asm/hardware.h>
20#include <asm/io.h>
21#include <asm/uaccess.h>
22#include <asm/rtc.h>
23
24#include <asm/mach/time.h>
25
26#define RTC_DR (0)
27#define RTC_MR (4)
28#define RTC_STAT (8)
29#define RTC_EOI (8)
30#define RTC_LR (12)
31#define RTC_CR (16)
32#define RTC_CR_MIE (1 << 0)
33
34extern int (*set_rtc)(void);
35static void __iomem *rtc_base;
36
37static int integrator_set_rtc(void)
38{
39 __raw_writel(xtime.tv_sec, rtc_base + RTC_LR);
40 return 1;
41}
42
43static void rtc_read_alarm(struct rtc_wkalrm *alrm)
44{
45 rtc_time_to_tm(readl(rtc_base + RTC_MR), &alrm->time);
46}
47
48static int rtc_set_alarm(struct rtc_wkalrm *alrm)
49{
50 unsigned long time;
51 int ret;
52
53 ret = rtc_tm_to_time(&alrm->time, &time);
54 if (ret == 0)
55 writel(time, rtc_base + RTC_MR);
56 return ret;
57}
58
59static void rtc_read_time(struct rtc_time *tm)
60{
61 rtc_time_to_tm(readl(rtc_base + RTC_DR), tm);
62}
63
64/*
65 * Set the RTC time. Unfortunately, we can't accurately set
66 * the point at which the counter updates.
67 *
68 * Also, since RTC_LR is transferred to RTC_CR on next rising
69 * edge of the 1Hz clock, we must write the time one second
70 * in advance.
71 */
72static int rtc_set_time(struct rtc_time *tm)
73{
74 unsigned long time;
75 int ret;
76
77 ret = rtc_tm_to_time(tm, &time);
78 if (ret == 0)
79 writel(time + 1, rtc_base + RTC_LR);
80
81 return ret;
82}
83
84static struct rtc_ops rtc_ops = {
85 .owner = THIS_MODULE,
86 .read_time = rtc_read_time,
87 .set_time = rtc_set_time,
88 .read_alarm = rtc_read_alarm,
89 .set_alarm = rtc_set_alarm,
90};
91
92static irqreturn_t rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
93{
94 writel(0, rtc_base + RTC_EOI);
95 return IRQ_HANDLED;
96}
97
98static int rtc_probe(struct amba_device *dev, void *id)
99{
100 int ret;
101
102 if (rtc_base)
103 return -EBUSY;
104
105 ret = amba_request_regions(dev, NULL);
106 if (ret)
107 goto out;
108
109 rtc_base = ioremap(dev->res.start, SZ_4K);
110 if (!rtc_base) {
111 ret = -ENOMEM;
112 goto res_out;
113 }
114
115 __raw_writel(0, rtc_base + RTC_CR);
116 __raw_writel(0, rtc_base + RTC_EOI);
117
118 xtime.tv_sec = __raw_readl(rtc_base + RTC_DR);
119
120 ret = request_irq(dev->irq[0], rtc_interrupt, SA_INTERRUPT,
121 "rtc-pl030", dev);
122 if (ret)
123 goto map_out;
124
125 ret = register_rtc(&rtc_ops);
126 if (ret)
127 goto irq_out;
128
129 set_rtc = integrator_set_rtc;
130 return 0;
131
132 irq_out:
133 free_irq(dev->irq[0], dev);
134 map_out:
135 iounmap(rtc_base);
136 rtc_base = NULL;
137 res_out:
138 amba_release_regions(dev);
139 out:
140 return ret;
141}
142
143static int rtc_remove(struct amba_device *dev)
144{
145 set_rtc = NULL;
146
147 writel(0, rtc_base + RTC_CR);
148
149 free_irq(dev->irq[0], dev);
150 unregister_rtc(&rtc_ops);
151
152 iounmap(rtc_base);
153 rtc_base = NULL;
154 amba_release_regions(dev);
155
156 return 0;
157}
158
159static struct timespec rtc_delta;
160
161static int rtc_suspend(struct amba_device *dev, pm_message_t state)
162{
163 struct timespec rtc;
164
165 rtc.tv_sec = readl(rtc_base + RTC_DR);
166 rtc.tv_nsec = 0;
167 save_time_delta(&rtc_delta, &rtc);
168
169 return 0;
170}
171
172static int rtc_resume(struct amba_device *dev)
173{
174 struct timespec rtc;
175
176 rtc.tv_sec = readl(rtc_base + RTC_DR);
177 rtc.tv_nsec = 0;
178 restore_time_delta(&rtc_delta, &rtc);
179
180 return 0;
181}
182
183static struct amba_id rtc_ids[] = {
184 {
185 .id = 0x00041030,
186 .mask = 0x000fffff,
187 },
188 { 0, 0 },
189};
190
191static struct amba_driver rtc_driver = {
192 .drv = {
193 .name = "rtc-pl030",
194 },
195 .probe = rtc_probe,
196 .remove = rtc_remove,
197 .suspend = rtc_suspend,
198 .resume = rtc_resume,
199 .id_table = rtc_ids,
200};
201
202static int __init integrator_rtc_init(void)
203{
204 return amba_driver_register(&rtc_driver);
205}
206
207static void __exit integrator_rtc_exit(void)
208{
209 amba_driver_unregister(&rtc_driver);
210}
211
212module_init(integrator_rtc_init);
213module_exit(integrator_rtc_exit);