diff options
Diffstat (limited to 'arch/arm/mach-versatile')
-rw-r--r-- | arch/arm/mach-versatile/Kconfig | 16 | ||||
-rw-r--r-- | arch/arm/mach-versatile/Makefile | 7 | ||||
-rw-r--r-- | arch/arm/mach-versatile/Makefile.boot | 4 | ||||
-rw-r--r-- | arch/arm/mach-versatile/clock.c | 145 | ||||
-rw-r--r-- | arch/arm/mach-versatile/clock.h | 25 | ||||
-rw-r--r-- | arch/arm/mach-versatile/core.c | 918 | ||||
-rw-r--r-- | arch/arm/mach-versatile/core.h | 50 | ||||
-rw-r--r-- | arch/arm/mach-versatile/versatile_ab.c | 45 | ||||
-rw-r--r-- | arch/arm/mach-versatile/versatile_pb.c | 109 |
9 files changed, 1319 insertions, 0 deletions
diff --git a/arch/arm/mach-versatile/Kconfig b/arch/arm/mach-versatile/Kconfig new file mode 100644 index 000000000000..8d787f4c78e6 --- /dev/null +++ b/arch/arm/mach-versatile/Kconfig | |||
@@ -0,0 +1,16 @@ | |||
1 | menu "Versatile platform type" | ||
2 | depends on ARCH_VERSATILE | ||
3 | |||
4 | config ARCH_VERSATILE_PB | ||
5 | bool "Support Versatile/PB platform" | ||
6 | default y | ||
7 | help | ||
8 | Include support for the ARM(R) Versatile/PB platform. | ||
9 | |||
10 | config MACH_VERSATILE_AB | ||
11 | bool "Support Versatile/AB platform" | ||
12 | default n | ||
13 | help | ||
14 | Include support for the ARM(R) Versatile/AP platform. | ||
15 | |||
16 | endmenu | ||
diff --git a/arch/arm/mach-versatile/Makefile b/arch/arm/mach-versatile/Makefile new file mode 100644 index 000000000000..5d608837757a --- /dev/null +++ b/arch/arm/mach-versatile/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | # | ||
2 | # Makefile for the linux kernel. | ||
3 | # | ||
4 | |||
5 | obj-y := core.o clock.o | ||
6 | obj-$(CONFIG_ARCH_VERSATILE_PB) += versatile_pb.o | ||
7 | obj-$(CONFIG_MACH_VERSATILE_AB) += versatile_ab.o | ||
diff --git a/arch/arm/mach-versatile/Makefile.boot b/arch/arm/mach-versatile/Makefile.boot new file mode 100644 index 000000000000..c7e75acfe6c9 --- /dev/null +++ b/arch/arm/mach-versatile/Makefile.boot | |||
@@ -0,0 +1,4 @@ | |||
1 | zreladdr-y := 0x00008000 | ||
2 | params_phys-y := 0x00000100 | ||
3 | initrd_phys-y := 0x00800000 | ||
4 | |||
diff --git a/arch/arm/mach-versatile/clock.c b/arch/arm/mach-versatile/clock.c new file mode 100644 index 000000000000..48025c2b9987 --- /dev/null +++ b/arch/arm/mach-versatile/clock.c | |||
@@ -0,0 +1,145 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-versatile/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/icst307.h> | ||
20 | |||
21 | #include "clock.h" | ||
22 | |||
23 | static LIST_HEAD(clocks); | ||
24 | static DECLARE_MUTEX(clocks_sem); | ||
25 | |||
26 | struct 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 | } | ||
41 | EXPORT_SYMBOL(clk_get); | ||
42 | |||
43 | void clk_put(struct clk *clk) | ||
44 | { | ||
45 | module_put(clk->owner); | ||
46 | } | ||
47 | EXPORT_SYMBOL(clk_put); | ||
48 | |||
49 | int clk_enable(struct clk *clk) | ||
50 | { | ||
51 | return 0; | ||
52 | } | ||
53 | EXPORT_SYMBOL(clk_enable); | ||
54 | |||
55 | void clk_disable(struct clk *clk) | ||
56 | { | ||
57 | } | ||
58 | EXPORT_SYMBOL(clk_disable); | ||
59 | |||
60 | int clk_use(struct clk *clk) | ||
61 | { | ||
62 | return 0; | ||
63 | } | ||
64 | EXPORT_SYMBOL(clk_use); | ||
65 | |||
66 | void clk_unuse(struct clk *clk) | ||
67 | { | ||
68 | } | ||
69 | EXPORT_SYMBOL(clk_unuse); | ||
70 | |||
71 | unsigned long clk_get_rate(struct clk *clk) | ||
72 | { | ||
73 | return clk->rate; | ||
74 | } | ||
75 | EXPORT_SYMBOL(clk_get_rate); | ||
76 | |||
77 | long clk_round_rate(struct clk *clk, unsigned long rate) | ||
78 | { | ||
79 | return rate; | ||
80 | } | ||
81 | EXPORT_SYMBOL(clk_round_rate); | ||
82 | |||
83 | int clk_set_rate(struct clk *clk, unsigned long rate) | ||
84 | { | ||
85 | int ret = -EIO; | ||
86 | |||
87 | if (clk->setvco) { | ||
88 | struct icst307_vco vco; | ||
89 | |||
90 | vco = icst307_khz_to_vco(clk->params, rate / 1000); | ||
91 | clk->rate = icst307_khz(clk->params, vco) * 1000; | ||
92 | |||
93 | printk("Clock %s: setting VCO reg params: S=%d R=%d V=%d\n", | ||
94 | clk->name, vco.s, vco.r, vco.v); | ||
95 | |||
96 | clk->setvco(clk, vco); | ||
97 | ret = 0; | ||
98 | } | ||
99 | return ret; | ||
100 | } | ||
101 | EXPORT_SYMBOL(clk_set_rate); | ||
102 | |||
103 | /* | ||
104 | * These are fixed clocks. | ||
105 | */ | ||
106 | static struct clk kmi_clk = { | ||
107 | .name = "KMIREFCLK", | ||
108 | .rate = 24000000, | ||
109 | }; | ||
110 | |||
111 | static struct clk uart_clk = { | ||
112 | .name = "UARTCLK", | ||
113 | .rate = 24000000, | ||
114 | }; | ||
115 | |||
116 | static struct clk mmci_clk = { | ||
117 | .name = "MCLK", | ||
118 | .rate = 33000000, | ||
119 | }; | ||
120 | |||
121 | int clk_register(struct clk *clk) | ||
122 | { | ||
123 | down(&clocks_sem); | ||
124 | list_add(&clk->node, &clocks); | ||
125 | up(&clocks_sem); | ||
126 | return 0; | ||
127 | } | ||
128 | EXPORT_SYMBOL(clk_register); | ||
129 | |||
130 | void clk_unregister(struct clk *clk) | ||
131 | { | ||
132 | down(&clocks_sem); | ||
133 | list_del(&clk->node); | ||
134 | up(&clocks_sem); | ||
135 | } | ||
136 | EXPORT_SYMBOL(clk_unregister); | ||
137 | |||
138 | static int __init clk_init(void) | ||
139 | { | ||
140 | clk_register(&kmi_clk); | ||
141 | clk_register(&uart_clk); | ||
142 | clk_register(&mmci_clk); | ||
143 | return 0; | ||
144 | } | ||
145 | arch_initcall(clk_init); | ||
diff --git a/arch/arm/mach-versatile/clock.h b/arch/arm/mach-versatile/clock.h new file mode 100644 index 000000000000..8b0b61dd17e4 --- /dev/null +++ b/arch/arm/mach-versatile/clock.h | |||
@@ -0,0 +1,25 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-versatile/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 | */ | ||
11 | struct module; | ||
12 | struct icst307_params; | ||
13 | |||
14 | struct clk { | ||
15 | struct list_head node; | ||
16 | unsigned long rate; | ||
17 | struct module *owner; | ||
18 | const char *name; | ||
19 | const struct icst307_params *params; | ||
20 | void *data; | ||
21 | void (*setvco)(struct clk *, struct icst307_vco vco); | ||
22 | }; | ||
23 | |||
24 | int clk_register(struct clk *clk); | ||
25 | void clk_unregister(struct clk *clk); | ||
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c new file mode 100644 index 000000000000..554e1bd30d6e --- /dev/null +++ b/arch/arm/mach-versatile/core.c | |||
@@ -0,0 +1,918 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-versatile/core.c | ||
3 | * | ||
4 | * Copyright (C) 1999 - 2003 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/config.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/device.h> | ||
24 | #include <linux/dma-mapping.h> | ||
25 | #include <linux/sysdev.h> | ||
26 | #include <linux/interrupt.h> | ||
27 | |||
28 | #include <asm/system.h> | ||
29 | #include <asm/hardware.h> | ||
30 | #include <asm/io.h> | ||
31 | #include <asm/irq.h> | ||
32 | #include <asm/leds.h> | ||
33 | #include <asm/mach-types.h> | ||
34 | #include <asm/hardware/amba.h> | ||
35 | #include <asm/hardware/amba_clcd.h> | ||
36 | #include <asm/hardware/icst307.h> | ||
37 | |||
38 | #include <asm/mach/arch.h> | ||
39 | #include <asm/mach/flash.h> | ||
40 | #include <asm/mach/irq.h> | ||
41 | #include <asm/mach/time.h> | ||
42 | #include <asm/mach/map.h> | ||
43 | #include <asm/mach/mmc.h> | ||
44 | |||
45 | #include "core.h" | ||
46 | #include "clock.h" | ||
47 | |||
48 | /* | ||
49 | * All IO addresses are mapped onto VA 0xFFFx.xxxx, where x.xxxx | ||
50 | * is the (PA >> 12). | ||
51 | * | ||
52 | * Setup a VA for the Versatile Vectored Interrupt Controller. | ||
53 | */ | ||
54 | #define VA_VIC_BASE IO_ADDRESS(VERSATILE_VIC_BASE) | ||
55 | #define VA_SIC_BASE IO_ADDRESS(VERSATILE_SIC_BASE) | ||
56 | |||
57 | static void vic_mask_irq(unsigned int irq) | ||
58 | { | ||
59 | irq -= IRQ_VIC_START; | ||
60 | writel(1 << irq, VA_VIC_BASE + VIC_IRQ_ENABLE_CLEAR); | ||
61 | } | ||
62 | |||
63 | static void vic_unmask_irq(unsigned int irq) | ||
64 | { | ||
65 | irq -= IRQ_VIC_START; | ||
66 | writel(1 << irq, VA_VIC_BASE + VIC_IRQ_ENABLE); | ||
67 | } | ||
68 | |||
69 | static struct irqchip vic_chip = { | ||
70 | .ack = vic_mask_irq, | ||
71 | .mask = vic_mask_irq, | ||
72 | .unmask = vic_unmask_irq, | ||
73 | }; | ||
74 | |||
75 | static void sic_mask_irq(unsigned int irq) | ||
76 | { | ||
77 | irq -= IRQ_SIC_START; | ||
78 | writel(1 << irq, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR); | ||
79 | } | ||
80 | |||
81 | static void sic_unmask_irq(unsigned int irq) | ||
82 | { | ||
83 | irq -= IRQ_SIC_START; | ||
84 | writel(1 << irq, VA_SIC_BASE + SIC_IRQ_ENABLE_SET); | ||
85 | } | ||
86 | |||
87 | static struct irqchip sic_chip = { | ||
88 | .ack = sic_mask_irq, | ||
89 | .mask = sic_mask_irq, | ||
90 | .unmask = sic_unmask_irq, | ||
91 | }; | ||
92 | |||
93 | static void | ||
94 | sic_handle_irq(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) | ||
95 | { | ||
96 | unsigned long status = readl(VA_SIC_BASE + SIC_IRQ_STATUS); | ||
97 | |||
98 | if (status == 0) { | ||
99 | do_bad_IRQ(irq, desc, regs); | ||
100 | return; | ||
101 | } | ||
102 | |||
103 | do { | ||
104 | irq = ffs(status) - 1; | ||
105 | status &= ~(1 << irq); | ||
106 | |||
107 | irq += IRQ_SIC_START; | ||
108 | |||
109 | desc = irq_desc + irq; | ||
110 | desc->handle(irq, desc, regs); | ||
111 | } while (status); | ||
112 | } | ||
113 | |||
114 | #if 1 | ||
115 | #define IRQ_MMCI0A IRQ_VICSOURCE22 | ||
116 | #define IRQ_AACI IRQ_VICSOURCE24 | ||
117 | #define IRQ_ETH IRQ_VICSOURCE25 | ||
118 | #define PIC_MASK 0xFFD00000 | ||
119 | #else | ||
120 | #define IRQ_MMCI0A IRQ_SIC_MMCI0A | ||
121 | #define IRQ_AACI IRQ_SIC_AACI | ||
122 | #define IRQ_ETH IRQ_SIC_ETH | ||
123 | #define PIC_MASK 0 | ||
124 | #endif | ||
125 | |||
126 | void __init versatile_init_irq(void) | ||
127 | { | ||
128 | unsigned int i, value; | ||
129 | |||
130 | /* Disable all interrupts initially. */ | ||
131 | |||
132 | writel(0, VA_VIC_BASE + VIC_INT_SELECT); | ||
133 | writel(0, VA_VIC_BASE + VIC_IRQ_ENABLE); | ||
134 | writel(~0, VA_VIC_BASE + VIC_IRQ_ENABLE_CLEAR); | ||
135 | writel(0, VA_VIC_BASE + VIC_IRQ_STATUS); | ||
136 | writel(0, VA_VIC_BASE + VIC_ITCR); | ||
137 | writel(~0, VA_VIC_BASE + VIC_IRQ_SOFT_CLEAR); | ||
138 | |||
139 | /* | ||
140 | * Make sure we clear all existing interrupts | ||
141 | */ | ||
142 | writel(0, VA_VIC_BASE + VIC_VECT_ADDR); | ||
143 | for (i = 0; i < 19; i++) { | ||
144 | value = readl(VA_VIC_BASE + VIC_VECT_ADDR); | ||
145 | writel(value, VA_VIC_BASE + VIC_VECT_ADDR); | ||
146 | } | ||
147 | |||
148 | for (i = 0; i < 16; i++) { | ||
149 | value = readl(VA_VIC_BASE + VIC_VECT_CNTL0 + (i * 4)); | ||
150 | writel(value | VICVectCntl_Enable | i, VA_VIC_BASE + VIC_VECT_CNTL0 + (i * 4)); | ||
151 | } | ||
152 | |||
153 | writel(32, VA_VIC_BASE + VIC_DEF_VECT_ADDR); | ||
154 | |||
155 | for (i = IRQ_VIC_START; i <= IRQ_VIC_END; i++) { | ||
156 | if (i != IRQ_VICSOURCE31) { | ||
157 | set_irq_chip(i, &vic_chip); | ||
158 | set_irq_handler(i, do_level_IRQ); | ||
159 | set_irq_flags(i, IRQF_VALID | IRQF_PROBE); | ||
160 | } | ||
161 | } | ||
162 | |||
163 | set_irq_handler(IRQ_VICSOURCE31, sic_handle_irq); | ||
164 | vic_unmask_irq(IRQ_VICSOURCE31); | ||
165 | |||
166 | /* Do second interrupt controller */ | ||
167 | writel(~0, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR); | ||
168 | |||
169 | for (i = IRQ_SIC_START; i <= IRQ_SIC_END; i++) { | ||
170 | if ((PIC_MASK & (1 << (i - IRQ_SIC_START))) == 0) { | ||
171 | set_irq_chip(i, &sic_chip); | ||
172 | set_irq_handler(i, do_level_IRQ); | ||
173 | set_irq_flags(i, IRQF_VALID | IRQF_PROBE); | ||
174 | } | ||
175 | } | ||
176 | |||
177 | /* | ||
178 | * Interrupts on secondary controller from 0 to 8 are routed to | ||
179 | * source 31 on PIC. | ||
180 | * Interrupts from 21 to 31 are routed directly to the VIC on | ||
181 | * the corresponding number on primary controller. This is controlled | ||
182 | * by setting PIC_ENABLEx. | ||
183 | */ | ||
184 | writel(PIC_MASK, VA_SIC_BASE + SIC_INT_PIC_ENABLE); | ||
185 | } | ||
186 | |||
187 | static struct map_desc versatile_io_desc[] __initdata = { | ||
188 | { IO_ADDRESS(VERSATILE_SYS_BASE), VERSATILE_SYS_BASE, SZ_4K, MT_DEVICE }, | ||
189 | { IO_ADDRESS(VERSATILE_SIC_BASE), VERSATILE_SIC_BASE, SZ_4K, MT_DEVICE }, | ||
190 | { IO_ADDRESS(VERSATILE_VIC_BASE), VERSATILE_VIC_BASE, SZ_4K, MT_DEVICE }, | ||
191 | { IO_ADDRESS(VERSATILE_SCTL_BASE), VERSATILE_SCTL_BASE, SZ_4K * 9, MT_DEVICE }, | ||
192 | #ifdef CONFIG_MACH_VERSATILE_AB | ||
193 | { IO_ADDRESS(VERSATILE_GPIO0_BASE), VERSATILE_GPIO0_BASE, SZ_4K, MT_DEVICE }, | ||
194 | { IO_ADDRESS(VERSATILE_IB2_BASE), VERSATILE_IB2_BASE, SZ_64M, MT_DEVICE }, | ||
195 | #endif | ||
196 | #ifdef CONFIG_DEBUG_LL | ||
197 | { IO_ADDRESS(VERSATILE_UART0_BASE), VERSATILE_UART0_BASE, SZ_4K, MT_DEVICE }, | ||
198 | #endif | ||
199 | #ifdef FIXME | ||
200 | { PCI_MEMORY_VADDR, PHYS_PCI_MEM_BASE, SZ_16M, MT_DEVICE }, | ||
201 | { PCI_CONFIG_VADDR, PHYS_PCI_CONFIG_BASE, SZ_16M, MT_DEVICE }, | ||
202 | { PCI_V3_VADDR, PHYS_PCI_V3_BASE, SZ_512K, MT_DEVICE }, | ||
203 | { PCI_IO_VADDR, PHYS_PCI_IO_BASE, SZ_64K, MT_DEVICE }, | ||
204 | #endif | ||
205 | }; | ||
206 | |||
207 | void __init versatile_map_io(void) | ||
208 | { | ||
209 | iotable_init(versatile_io_desc, ARRAY_SIZE(versatile_io_desc)); | ||
210 | } | ||
211 | |||
212 | #define VERSATILE_REFCOUNTER (IO_ADDRESS(VERSATILE_SYS_BASE) + VERSATILE_SYS_24MHz_OFFSET) | ||
213 | |||
214 | /* | ||
215 | * This is the Versatile sched_clock implementation. This has | ||
216 | * a resolution of 41.7ns, and a maximum value of about 179s. | ||
217 | */ | ||
218 | unsigned long long sched_clock(void) | ||
219 | { | ||
220 | unsigned long long v; | ||
221 | |||
222 | v = (unsigned long long)readl(VERSATILE_REFCOUNTER) * 125; | ||
223 | do_div(v, 3); | ||
224 | |||
225 | return v; | ||
226 | } | ||
227 | |||
228 | |||
229 | #define VERSATILE_FLASHCTRL (IO_ADDRESS(VERSATILE_SYS_BASE) + VERSATILE_SYS_FLASH_OFFSET) | ||
230 | |||
231 | static int versatile_flash_init(void) | ||
232 | { | ||
233 | u32 val; | ||
234 | |||
235 | val = __raw_readl(VERSATILE_FLASHCTRL); | ||
236 | val &= ~VERSATILE_FLASHPROG_FLVPPEN; | ||
237 | __raw_writel(val, VERSATILE_FLASHCTRL); | ||
238 | |||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | static void versatile_flash_exit(void) | ||
243 | { | ||
244 | u32 val; | ||
245 | |||
246 | val = __raw_readl(VERSATILE_FLASHCTRL); | ||
247 | val &= ~VERSATILE_FLASHPROG_FLVPPEN; | ||
248 | __raw_writel(val, VERSATILE_FLASHCTRL); | ||
249 | } | ||
250 | |||
251 | static void versatile_flash_set_vpp(int on) | ||
252 | { | ||
253 | u32 val; | ||
254 | |||
255 | val = __raw_readl(VERSATILE_FLASHCTRL); | ||
256 | if (on) | ||
257 | val |= VERSATILE_FLASHPROG_FLVPPEN; | ||
258 | else | ||
259 | val &= ~VERSATILE_FLASHPROG_FLVPPEN; | ||
260 | __raw_writel(val, VERSATILE_FLASHCTRL); | ||
261 | } | ||
262 | |||
263 | static struct flash_platform_data versatile_flash_data = { | ||
264 | .map_name = "cfi_probe", | ||
265 | .width = 4, | ||
266 | .init = versatile_flash_init, | ||
267 | .exit = versatile_flash_exit, | ||
268 | .set_vpp = versatile_flash_set_vpp, | ||
269 | }; | ||
270 | |||
271 | static struct resource versatile_flash_resource = { | ||
272 | .start = VERSATILE_FLASH_BASE, | ||
273 | .end = VERSATILE_FLASH_BASE + VERSATILE_FLASH_SIZE, | ||
274 | .flags = IORESOURCE_MEM, | ||
275 | }; | ||
276 | |||
277 | static struct platform_device versatile_flash_device = { | ||
278 | .name = "armflash", | ||
279 | .id = 0, | ||
280 | .dev = { | ||
281 | .platform_data = &versatile_flash_data, | ||
282 | }, | ||
283 | .num_resources = 1, | ||
284 | .resource = &versatile_flash_resource, | ||
285 | }; | ||
286 | |||
287 | static struct resource smc91x_resources[] = { | ||
288 | [0] = { | ||
289 | .start = VERSATILE_ETH_BASE, | ||
290 | .end = VERSATILE_ETH_BASE + SZ_64K - 1, | ||
291 | .flags = IORESOURCE_MEM, | ||
292 | }, | ||
293 | [1] = { | ||
294 | .start = IRQ_ETH, | ||
295 | .end = IRQ_ETH, | ||
296 | .flags = IORESOURCE_IRQ, | ||
297 | }, | ||
298 | }; | ||
299 | |||
300 | static struct platform_device smc91x_device = { | ||
301 | .name = "smc91x", | ||
302 | .id = 0, | ||
303 | .num_resources = ARRAY_SIZE(smc91x_resources), | ||
304 | .resource = smc91x_resources, | ||
305 | }; | ||
306 | |||
307 | #define VERSATILE_SYSMCI (IO_ADDRESS(VERSATILE_SYS_BASE) + VERSATILE_SYS_MCI_OFFSET) | ||
308 | |||
309 | unsigned int mmc_status(struct device *dev) | ||
310 | { | ||
311 | struct amba_device *adev = container_of(dev, struct amba_device, dev); | ||
312 | u32 mask; | ||
313 | |||
314 | if (adev->res.start == VERSATILE_MMCI0_BASE) | ||
315 | mask = 1; | ||
316 | else | ||
317 | mask = 2; | ||
318 | |||
319 | return readl(VERSATILE_SYSMCI) & mask; | ||
320 | } | ||
321 | |||
322 | static struct mmc_platform_data mmc0_plat_data = { | ||
323 | .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, | ||
324 | .status = mmc_status, | ||
325 | }; | ||
326 | |||
327 | /* | ||
328 | * Clock handling | ||
329 | */ | ||
330 | static const struct icst307_params versatile_oscvco_params = { | ||
331 | .ref = 24000, | ||
332 | .vco_max = 200000, | ||
333 | .vd_min = 4 + 8, | ||
334 | .vd_max = 511 + 8, | ||
335 | .rd_min = 1 + 2, | ||
336 | .rd_max = 127 + 2, | ||
337 | }; | ||
338 | |||
339 | static void versatile_oscvco_set(struct clk *clk, struct icst307_vco vco) | ||
340 | { | ||
341 | unsigned long sys_lock = IO_ADDRESS(VERSATILE_SYS_BASE) + VERSATILE_SYS_LOCK_OFFSET; | ||
342 | #if defined(CONFIG_ARCH_VERSATILE_PB) | ||
343 | unsigned long sys_osc = IO_ADDRESS(VERSATILE_SYS_BASE) + VERSATILE_SYS_OSC4_OFFSET; | ||
344 | #elif defined(CONFIG_MACH_VERSATILE_AB) | ||
345 | unsigned long sys_osc = IO_ADDRESS(VERSATILE_SYS_BASE) + VERSATILE_SYS_OSC1_OFFSET; | ||
346 | #endif | ||
347 | u32 val; | ||
348 | |||
349 | val = readl(sys_osc) & ~0x7ffff; | ||
350 | val |= vco.v | (vco.r << 9) | (vco.s << 16); | ||
351 | |||
352 | writel(0xa05f, sys_lock); | ||
353 | writel(val, sys_osc); | ||
354 | writel(0, sys_lock); | ||
355 | } | ||
356 | |||
357 | static struct clk versatile_clcd_clk = { | ||
358 | .name = "CLCDCLK", | ||
359 | .params = &versatile_oscvco_params, | ||
360 | .setvco = versatile_oscvco_set, | ||
361 | }; | ||
362 | |||
363 | /* | ||
364 | * CLCD support. | ||
365 | */ | ||
366 | #define SYS_CLCD_MODE_MASK (3 << 0) | ||
367 | #define SYS_CLCD_MODE_888 (0 << 0) | ||
368 | #define SYS_CLCD_MODE_5551 (1 << 0) | ||
369 | #define SYS_CLCD_MODE_565_RLSB (2 << 0) | ||
370 | #define SYS_CLCD_MODE_565_BLSB (3 << 0) | ||
371 | #define SYS_CLCD_NLCDIOON (1 << 2) | ||
372 | #define SYS_CLCD_VDDPOSSWITCH (1 << 3) | ||
373 | #define SYS_CLCD_PWR3V5SWITCH (1 << 4) | ||
374 | #define SYS_CLCD_ID_MASK (0x1f << 8) | ||
375 | #define SYS_CLCD_ID_SANYO_3_8 (0x00 << 8) | ||
376 | #define SYS_CLCD_ID_UNKNOWN_8_4 (0x01 << 8) | ||
377 | #define SYS_CLCD_ID_EPSON_2_2 (0x02 << 8) | ||
378 | #define SYS_CLCD_ID_SANYO_2_5 (0x07 << 8) | ||
379 | #define SYS_CLCD_ID_VGA (0x1f << 8) | ||
380 | |||
381 | static struct clcd_panel vga = { | ||
382 | .mode = { | ||
383 | .name = "VGA", | ||
384 | .refresh = 60, | ||
385 | .xres = 640, | ||
386 | .yres = 480, | ||
387 | .pixclock = 39721, | ||
388 | .left_margin = 40, | ||
389 | .right_margin = 24, | ||
390 | .upper_margin = 32, | ||
391 | .lower_margin = 11, | ||
392 | .hsync_len = 96, | ||
393 | .vsync_len = 2, | ||
394 | .sync = 0, | ||
395 | .vmode = FB_VMODE_NONINTERLACED, | ||
396 | }, | ||
397 | .width = -1, | ||
398 | .height = -1, | ||
399 | .tim2 = TIM2_BCD | TIM2_IPC, | ||
400 | .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1), | ||
401 | .bpp = 16, | ||
402 | }; | ||
403 | |||
404 | static struct clcd_panel sanyo_3_8_in = { | ||
405 | .mode = { | ||
406 | .name = "Sanyo QVGA", | ||
407 | .refresh = 116, | ||
408 | .xres = 320, | ||
409 | .yres = 240, | ||
410 | .pixclock = 100000, | ||
411 | .left_margin = 6, | ||
412 | .right_margin = 6, | ||
413 | .upper_margin = 5, | ||
414 | .lower_margin = 5, | ||
415 | .hsync_len = 6, | ||
416 | .vsync_len = 6, | ||
417 | .sync = 0, | ||
418 | .vmode = FB_VMODE_NONINTERLACED, | ||
419 | }, | ||
420 | .width = -1, | ||
421 | .height = -1, | ||
422 | .tim2 = TIM2_BCD, | ||
423 | .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1), | ||
424 | .bpp = 16, | ||
425 | }; | ||
426 | |||
427 | static struct clcd_panel sanyo_2_5_in = { | ||
428 | .mode = { | ||
429 | .name = "Sanyo QVGA Portrait", | ||
430 | .refresh = 116, | ||
431 | .xres = 240, | ||
432 | .yres = 320, | ||
433 | .pixclock = 100000, | ||
434 | .left_margin = 20, | ||
435 | .right_margin = 10, | ||
436 | .upper_margin = 2, | ||
437 | .lower_margin = 2, | ||
438 | .hsync_len = 10, | ||
439 | .vsync_len = 2, | ||
440 | .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
441 | .vmode = FB_VMODE_NONINTERLACED, | ||
442 | }, | ||
443 | .width = -1, | ||
444 | .height = -1, | ||
445 | .tim2 = TIM2_IVS | TIM2_IHS | TIM2_IPC, | ||
446 | .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1), | ||
447 | .bpp = 16, | ||
448 | }; | ||
449 | |||
450 | static struct clcd_panel epson_2_2_in = { | ||
451 | .mode = { | ||
452 | .name = "Epson QCIF", | ||
453 | .refresh = 390, | ||
454 | .xres = 176, | ||
455 | .yres = 220, | ||
456 | .pixclock = 62500, | ||
457 | .left_margin = 3, | ||
458 | .right_margin = 2, | ||
459 | .upper_margin = 1, | ||
460 | .lower_margin = 0, | ||
461 | .hsync_len = 3, | ||
462 | .vsync_len = 2, | ||
463 | .sync = 0, | ||
464 | .vmode = FB_VMODE_NONINTERLACED, | ||
465 | }, | ||
466 | .width = -1, | ||
467 | .height = -1, | ||
468 | .tim2 = TIM2_BCD | TIM2_IPC, | ||
469 | .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1), | ||
470 | .bpp = 16, | ||
471 | }; | ||
472 | |||
473 | /* | ||
474 | * Detect which LCD panel is connected, and return the appropriate | ||
475 | * clcd_panel structure. Note: we do not have any information on | ||
476 | * the required timings for the 8.4in panel, so we presently assume | ||
477 | * VGA timings. | ||
478 | */ | ||
479 | static struct clcd_panel *versatile_clcd_panel(void) | ||
480 | { | ||
481 | unsigned long sys_clcd = IO_ADDRESS(VERSATILE_SYS_BASE) + VERSATILE_SYS_CLCD_OFFSET; | ||
482 | struct clcd_panel *panel = &vga; | ||
483 | u32 val; | ||
484 | |||
485 | val = readl(sys_clcd) & SYS_CLCD_ID_MASK; | ||
486 | if (val == SYS_CLCD_ID_SANYO_3_8) | ||
487 | panel = &sanyo_3_8_in; | ||
488 | else if (val == SYS_CLCD_ID_SANYO_2_5) | ||
489 | panel = &sanyo_2_5_in; | ||
490 | else if (val == SYS_CLCD_ID_EPSON_2_2) | ||
491 | panel = &epson_2_2_in; | ||
492 | else if (val == SYS_CLCD_ID_VGA) | ||
493 | panel = &vga; | ||
494 | else { | ||
495 | printk(KERN_ERR "CLCD: unknown LCD panel ID 0x%08x, using VGA\n", | ||
496 | val); | ||
497 | panel = &vga; | ||
498 | } | ||
499 | |||
500 | return panel; | ||
501 | } | ||
502 | |||
503 | /* | ||
504 | * Disable all display connectors on the interface module. | ||
505 | */ | ||
506 | static void versatile_clcd_disable(struct clcd_fb *fb) | ||
507 | { | ||
508 | unsigned long sys_clcd = IO_ADDRESS(VERSATILE_SYS_BASE) + VERSATILE_SYS_CLCD_OFFSET; | ||
509 | u32 val; | ||
510 | |||
511 | val = readl(sys_clcd); | ||
512 | val &= ~SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH; | ||
513 | writel(val, sys_clcd); | ||
514 | |||
515 | #ifdef CONFIG_MACH_VERSATILE_AB | ||
516 | /* | ||
517 | * If the LCD is Sanyo 2x5 in on the IB2 board, turn the back-light off | ||
518 | */ | ||
519 | if (fb->panel == &sanyo_2_5_in) { | ||
520 | unsigned long versatile_ib2_ctrl = IO_ADDRESS(VERSATILE_IB2_CTRL); | ||
521 | unsigned long ctrl; | ||
522 | |||
523 | ctrl = readl(versatile_ib2_ctrl); | ||
524 | ctrl &= ~0x01; | ||
525 | writel(ctrl, versatile_ib2_ctrl); | ||
526 | } | ||
527 | #endif | ||
528 | } | ||
529 | |||
530 | /* | ||
531 | * Enable the relevant connector on the interface module. | ||
532 | */ | ||
533 | static void versatile_clcd_enable(struct clcd_fb *fb) | ||
534 | { | ||
535 | unsigned long sys_clcd = IO_ADDRESS(VERSATILE_SYS_BASE) + VERSATILE_SYS_CLCD_OFFSET; | ||
536 | u32 val; | ||
537 | |||
538 | val = readl(sys_clcd); | ||
539 | val &= ~SYS_CLCD_MODE_MASK; | ||
540 | |||
541 | switch (fb->fb.var.green.length) { | ||
542 | case 5: | ||
543 | val |= SYS_CLCD_MODE_5551; | ||
544 | break; | ||
545 | case 6: | ||
546 | val |= SYS_CLCD_MODE_565_BLSB; | ||
547 | break; | ||
548 | case 8: | ||
549 | val |= SYS_CLCD_MODE_888; | ||
550 | break; | ||
551 | } | ||
552 | |||
553 | /* | ||
554 | * Set the MUX | ||
555 | */ | ||
556 | writel(val, sys_clcd); | ||
557 | |||
558 | /* | ||
559 | * And now enable the PSUs | ||
560 | */ | ||
561 | val |= SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH; | ||
562 | writel(val, sys_clcd); | ||
563 | |||
564 | #ifdef CONFIG_MACH_VERSATILE_AB | ||
565 | /* | ||
566 | * If the LCD is Sanyo 2x5 in on the IB2 board, turn the back-light on | ||
567 | */ | ||
568 | if (fb->panel == &sanyo_2_5_in) { | ||
569 | unsigned long versatile_ib2_ctrl = IO_ADDRESS(VERSATILE_IB2_CTRL); | ||
570 | unsigned long ctrl; | ||
571 | |||
572 | ctrl = readl(versatile_ib2_ctrl); | ||
573 | ctrl |= 0x01; | ||
574 | writel(ctrl, versatile_ib2_ctrl); | ||
575 | } | ||
576 | #endif | ||
577 | } | ||
578 | |||
579 | static unsigned long framesize = SZ_1M; | ||
580 | |||
581 | static int versatile_clcd_setup(struct clcd_fb *fb) | ||
582 | { | ||
583 | dma_addr_t dma; | ||
584 | |||
585 | fb->panel = versatile_clcd_panel(); | ||
586 | |||
587 | fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev, framesize, | ||
588 | &dma, GFP_KERNEL); | ||
589 | if (!fb->fb.screen_base) { | ||
590 | printk(KERN_ERR "CLCD: unable to map framebuffer\n"); | ||
591 | return -ENOMEM; | ||
592 | } | ||
593 | |||
594 | fb->fb.fix.smem_start = dma; | ||
595 | fb->fb.fix.smem_len = framesize; | ||
596 | |||
597 | return 0; | ||
598 | } | ||
599 | |||
600 | static int versatile_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma) | ||
601 | { | ||
602 | return dma_mmap_writecombine(&fb->dev->dev, vma, | ||
603 | fb->fb.screen_base, | ||
604 | fb->fb.fix.smem_start, | ||
605 | fb->fb.fix.smem_len); | ||
606 | } | ||
607 | |||
608 | static void versatile_clcd_remove(struct clcd_fb *fb) | ||
609 | { | ||
610 | dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len, | ||
611 | fb->fb.screen_base, fb->fb.fix.smem_start); | ||
612 | } | ||
613 | |||
614 | static struct clcd_board clcd_plat_data = { | ||
615 | .name = "Versatile", | ||
616 | .check = clcdfb_check, | ||
617 | .decode = clcdfb_decode, | ||
618 | .disable = versatile_clcd_disable, | ||
619 | .enable = versatile_clcd_enable, | ||
620 | .setup = versatile_clcd_setup, | ||
621 | .mmap = versatile_clcd_mmap, | ||
622 | .remove = versatile_clcd_remove, | ||
623 | }; | ||
624 | |||
625 | #define AACI_IRQ { IRQ_AACI, NO_IRQ } | ||
626 | #define AACI_DMA { 0x80, 0x81 } | ||
627 | #define MMCI0_IRQ { IRQ_MMCI0A,IRQ_SIC_MMCI0B } | ||
628 | #define MMCI0_DMA { 0x84, 0 } | ||
629 | #define KMI0_IRQ { IRQ_SIC_KMI0, NO_IRQ } | ||
630 | #define KMI0_DMA { 0, 0 } | ||
631 | #define KMI1_IRQ { IRQ_SIC_KMI1, NO_IRQ } | ||
632 | #define KMI1_DMA { 0, 0 } | ||
633 | |||
634 | /* | ||
635 | * These devices are connected directly to the multi-layer AHB switch | ||
636 | */ | ||
637 | #define SMC_IRQ { NO_IRQ, NO_IRQ } | ||
638 | #define SMC_DMA { 0, 0 } | ||
639 | #define MPMC_IRQ { NO_IRQ, NO_IRQ } | ||
640 | #define MPMC_DMA { 0, 0 } | ||
641 | #define CLCD_IRQ { IRQ_CLCDINT, NO_IRQ } | ||
642 | #define CLCD_DMA { 0, 0 } | ||
643 | #define DMAC_IRQ { IRQ_DMAINT, NO_IRQ } | ||
644 | #define DMAC_DMA { 0, 0 } | ||
645 | |||
646 | /* | ||
647 | * These devices are connected via the core APB bridge | ||
648 | */ | ||
649 | #define SCTL_IRQ { NO_IRQ, NO_IRQ } | ||
650 | #define SCTL_DMA { 0, 0 } | ||
651 | #define WATCHDOG_IRQ { IRQ_WDOGINT, NO_IRQ } | ||
652 | #define WATCHDOG_DMA { 0, 0 } | ||
653 | #define GPIO0_IRQ { IRQ_GPIOINT0, NO_IRQ } | ||
654 | #define GPIO0_DMA { 0, 0 } | ||
655 | #define GPIO1_IRQ { IRQ_GPIOINT1, NO_IRQ } | ||
656 | #define GPIO1_DMA { 0, 0 } | ||
657 | #define RTC_IRQ { IRQ_RTCINT, NO_IRQ } | ||
658 | #define RTC_DMA { 0, 0 } | ||
659 | |||
660 | /* | ||
661 | * These devices are connected via the DMA APB bridge | ||
662 | */ | ||
663 | #define SCI_IRQ { IRQ_SCIINT, NO_IRQ } | ||
664 | #define SCI_DMA { 7, 6 } | ||
665 | #define UART0_IRQ { IRQ_UARTINT0, NO_IRQ } | ||
666 | #define UART0_DMA { 15, 14 } | ||
667 | #define UART1_IRQ { IRQ_UARTINT1, NO_IRQ } | ||
668 | #define UART1_DMA { 13, 12 } | ||
669 | #define UART2_IRQ { IRQ_UARTINT2, NO_IRQ } | ||
670 | #define UART2_DMA { 11, 10 } | ||
671 | #define SSP_IRQ { IRQ_SSPINT, NO_IRQ } | ||
672 | #define SSP_DMA { 9, 8 } | ||
673 | |||
674 | /* FPGA Primecells */ | ||
675 | AMBA_DEVICE(aaci, "fpga:04", AACI, NULL); | ||
676 | AMBA_DEVICE(mmc0, "fpga:05", MMCI0, &mmc0_plat_data); | ||
677 | AMBA_DEVICE(kmi0, "fpga:06", KMI0, NULL); | ||
678 | AMBA_DEVICE(kmi1, "fpga:07", KMI1, NULL); | ||
679 | |||
680 | /* DevChip Primecells */ | ||
681 | AMBA_DEVICE(smc, "dev:00", SMC, NULL); | ||
682 | AMBA_DEVICE(mpmc, "dev:10", MPMC, NULL); | ||
683 | AMBA_DEVICE(clcd, "dev:20", CLCD, &clcd_plat_data); | ||
684 | AMBA_DEVICE(dmac, "dev:30", DMAC, NULL); | ||
685 | AMBA_DEVICE(sctl, "dev:e0", SCTL, NULL); | ||
686 | AMBA_DEVICE(wdog, "dev:e1", WATCHDOG, NULL); | ||
687 | AMBA_DEVICE(gpio0, "dev:e4", GPIO0, NULL); | ||
688 | AMBA_DEVICE(gpio1, "dev:e5", GPIO1, NULL); | ||
689 | AMBA_DEVICE(rtc, "dev:e8", RTC, NULL); | ||
690 | AMBA_DEVICE(sci0, "dev:f0", SCI, NULL); | ||
691 | AMBA_DEVICE(uart0, "dev:f1", UART0, NULL); | ||
692 | AMBA_DEVICE(uart1, "dev:f2", UART1, NULL); | ||
693 | AMBA_DEVICE(uart2, "dev:f3", UART2, NULL); | ||
694 | AMBA_DEVICE(ssp0, "dev:f4", SSP, NULL); | ||
695 | |||
696 | static struct amba_device *amba_devs[] __initdata = { | ||
697 | &dmac_device, | ||
698 | &uart0_device, | ||
699 | &uart1_device, | ||
700 | &uart2_device, | ||
701 | &smc_device, | ||
702 | &mpmc_device, | ||
703 | &clcd_device, | ||
704 | &sctl_device, | ||
705 | &wdog_device, | ||
706 | &gpio0_device, | ||
707 | &gpio1_device, | ||
708 | &rtc_device, | ||
709 | &sci0_device, | ||
710 | &ssp0_device, | ||
711 | &aaci_device, | ||
712 | &mmc0_device, | ||
713 | &kmi0_device, | ||
714 | &kmi1_device, | ||
715 | }; | ||
716 | |||
717 | #ifdef CONFIG_LEDS | ||
718 | #define VA_LEDS_BASE (IO_ADDRESS(VERSATILE_SYS_BASE) + VERSATILE_SYS_LED_OFFSET) | ||
719 | |||
720 | static void versatile_leds_event(led_event_t ledevt) | ||
721 | { | ||
722 | unsigned long flags; | ||
723 | u32 val; | ||
724 | |||
725 | local_irq_save(flags); | ||
726 | val = readl(VA_LEDS_BASE); | ||
727 | |||
728 | switch (ledevt) { | ||
729 | case led_idle_start: | ||
730 | val = val & ~VERSATILE_SYS_LED0; | ||
731 | break; | ||
732 | |||
733 | case led_idle_end: | ||
734 | val = val | VERSATILE_SYS_LED0; | ||
735 | break; | ||
736 | |||
737 | case led_timer: | ||
738 | val = val ^ VERSATILE_SYS_LED1; | ||
739 | break; | ||
740 | |||
741 | case led_halted: | ||
742 | val = 0; | ||
743 | break; | ||
744 | |||
745 | default: | ||
746 | break; | ||
747 | } | ||
748 | |||
749 | writel(val, VA_LEDS_BASE); | ||
750 | local_irq_restore(flags); | ||
751 | } | ||
752 | #endif /* CONFIG_LEDS */ | ||
753 | |||
754 | void __init versatile_init(void) | ||
755 | { | ||
756 | int i; | ||
757 | |||
758 | clk_register(&versatile_clcd_clk); | ||
759 | |||
760 | platform_device_register(&versatile_flash_device); | ||
761 | platform_device_register(&smc91x_device); | ||
762 | |||
763 | for (i = 0; i < ARRAY_SIZE(amba_devs); i++) { | ||
764 | struct amba_device *d = amba_devs[i]; | ||
765 | amba_device_register(d, &iomem_resource); | ||
766 | } | ||
767 | |||
768 | #ifdef CONFIG_LEDS | ||
769 | leds_event = versatile_leds_event; | ||
770 | #endif | ||
771 | } | ||
772 | |||
773 | /* | ||
774 | * Where is the timer (VA)? | ||
775 | */ | ||
776 | #define TIMER0_VA_BASE IO_ADDRESS(VERSATILE_TIMER0_1_BASE) | ||
777 | #define TIMER1_VA_BASE (IO_ADDRESS(VERSATILE_TIMER0_1_BASE) + 0x20) | ||
778 | #define TIMER2_VA_BASE IO_ADDRESS(VERSATILE_TIMER2_3_BASE) | ||
779 | #define TIMER3_VA_BASE (IO_ADDRESS(VERSATILE_TIMER2_3_BASE) + 0x20) | ||
780 | #define VA_IC_BASE IO_ADDRESS(VERSATILE_VIC_BASE) | ||
781 | |||
782 | /* | ||
783 | * How long is the timer interval? | ||
784 | */ | ||
785 | #define TIMER_INTERVAL (TICKS_PER_uSEC * mSEC_10) | ||
786 | #if TIMER_INTERVAL >= 0x100000 | ||
787 | #define TIMER_RELOAD (TIMER_INTERVAL >> 8) /* Divide by 256 */ | ||
788 | #define TIMER_CTRL 0x88 /* Enable, Clock / 256 */ | ||
789 | #define TICKS2USECS(x) (256 * (x) / TICKS_PER_uSEC) | ||
790 | #elif TIMER_INTERVAL >= 0x10000 | ||
791 | #define TIMER_RELOAD (TIMER_INTERVAL >> 4) /* Divide by 16 */ | ||
792 | #define TIMER_CTRL 0x84 /* Enable, Clock / 16 */ | ||
793 | #define TICKS2USECS(x) (16 * (x) / TICKS_PER_uSEC) | ||
794 | #else | ||
795 | #define TIMER_RELOAD (TIMER_INTERVAL) | ||
796 | #define TIMER_CTRL 0x80 /* Enable */ | ||
797 | #define TICKS2USECS(x) ((x) / TICKS_PER_uSEC) | ||
798 | #endif | ||
799 | |||
800 | #define TIMER_CTRL_IE (1 << 5) /* Interrupt Enable */ | ||
801 | |||
802 | /* | ||
803 | * What does it look like? | ||
804 | */ | ||
805 | typedef struct TimerStruct { | ||
806 | unsigned long TimerLoad; | ||
807 | unsigned long TimerValue; | ||
808 | unsigned long TimerControl; | ||
809 | unsigned long TimerClear; | ||
810 | } TimerStruct_t; | ||
811 | |||
812 | /* | ||
813 | * Returns number of ms since last clock interrupt. Note that interrupts | ||
814 | * will have been disabled by do_gettimeoffset() | ||
815 | */ | ||
816 | static unsigned long versatile_gettimeoffset(void) | ||
817 | { | ||
818 | volatile TimerStruct_t *timer0 = (TimerStruct_t *)TIMER0_VA_BASE; | ||
819 | unsigned long ticks1, ticks2, status; | ||
820 | |||
821 | /* | ||
822 | * Get the current number of ticks. Note that there is a race | ||
823 | * condition between us reading the timer and checking for | ||
824 | * an interrupt. We get around this by ensuring that the | ||
825 | * counter has not reloaded between our two reads. | ||
826 | */ | ||
827 | ticks2 = timer0->TimerValue & 0xffff; | ||
828 | do { | ||
829 | ticks1 = ticks2; | ||
830 | status = __raw_readl(VA_IC_BASE + VIC_IRQ_RAW_STATUS); | ||
831 | ticks2 = timer0->TimerValue & 0xffff; | ||
832 | } while (ticks2 > ticks1); | ||
833 | |||
834 | /* | ||
835 | * Number of ticks since last interrupt. | ||
836 | */ | ||
837 | ticks1 = TIMER_RELOAD - ticks2; | ||
838 | |||
839 | /* | ||
840 | * Interrupt pending? If so, we've reloaded once already. | ||
841 | * | ||
842 | * FIXME: Need to check this is effectively timer 0 that expires | ||
843 | */ | ||
844 | if (status & IRQMASK_TIMERINT0_1) | ||
845 | ticks1 += TIMER_RELOAD; | ||
846 | |||
847 | /* | ||
848 | * Convert the ticks to usecs | ||
849 | */ | ||
850 | return TICKS2USECS(ticks1); | ||
851 | } | ||
852 | |||
853 | /* | ||
854 | * IRQ handler for the timer | ||
855 | */ | ||
856 | static irqreturn_t versatile_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
857 | { | ||
858 | volatile TimerStruct_t *timer0 = (volatile TimerStruct_t *)TIMER0_VA_BASE; | ||
859 | |||
860 | write_seqlock(&xtime_lock); | ||
861 | |||
862 | // ...clear the interrupt | ||
863 | timer0->TimerClear = 1; | ||
864 | |||
865 | timer_tick(regs); | ||
866 | |||
867 | write_sequnlock(&xtime_lock); | ||
868 | |||
869 | return IRQ_HANDLED; | ||
870 | } | ||
871 | |||
872 | static struct irqaction versatile_timer_irq = { | ||
873 | .name = "Versatile Timer Tick", | ||
874 | .flags = SA_INTERRUPT, | ||
875 | .handler = versatile_timer_interrupt | ||
876 | }; | ||
877 | |||
878 | /* | ||
879 | * Set up timer interrupt, and return the current time in seconds. | ||
880 | */ | ||
881 | static void __init versatile_timer_init(void) | ||
882 | { | ||
883 | volatile TimerStruct_t *timer0 = (volatile TimerStruct_t *)TIMER0_VA_BASE; | ||
884 | volatile TimerStruct_t *timer1 = (volatile TimerStruct_t *)TIMER1_VA_BASE; | ||
885 | volatile TimerStruct_t *timer2 = (volatile TimerStruct_t *)TIMER2_VA_BASE; | ||
886 | volatile TimerStruct_t *timer3 = (volatile TimerStruct_t *)TIMER3_VA_BASE; | ||
887 | |||
888 | /* | ||
889 | * set clock frequency: | ||
890 | * VERSATILE_REFCLK is 32KHz | ||
891 | * VERSATILE_TIMCLK is 1MHz | ||
892 | */ | ||
893 | *(volatile unsigned int *)IO_ADDRESS(VERSATILE_SCTL_BASE) |= | ||
894 | ((VERSATILE_TIMCLK << VERSATILE_TIMER1_EnSel) | (VERSATILE_TIMCLK << VERSATILE_TIMER2_EnSel) | | ||
895 | (VERSATILE_TIMCLK << VERSATILE_TIMER3_EnSel) | (VERSATILE_TIMCLK << VERSATILE_TIMER4_EnSel)); | ||
896 | |||
897 | /* | ||
898 | * Initialise to a known state (all timers off) | ||
899 | */ | ||
900 | timer0->TimerControl = 0; | ||
901 | timer1->TimerControl = 0; | ||
902 | timer2->TimerControl = 0; | ||
903 | timer3->TimerControl = 0; | ||
904 | |||
905 | timer0->TimerLoad = TIMER_RELOAD; | ||
906 | timer0->TimerValue = TIMER_RELOAD; | ||
907 | timer0->TimerControl = TIMER_CTRL | 0x40 | TIMER_CTRL_IE; /* periodic + IE */ | ||
908 | |||
909 | /* | ||
910 | * Make irqs happen for the system timer | ||
911 | */ | ||
912 | setup_irq(IRQ_TIMERINT0_1, &versatile_timer_irq); | ||
913 | } | ||
914 | |||
915 | struct sys_timer versatile_timer = { | ||
916 | .init = versatile_timer_init, | ||
917 | .offset = versatile_gettimeoffset, | ||
918 | }; | ||
diff --git a/arch/arm/mach-versatile/core.h b/arch/arm/mach-versatile/core.h new file mode 100644 index 000000000000..588c20669d5d --- /dev/null +++ b/arch/arm/mach-versatile/core.h | |||
@@ -0,0 +1,50 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-versatile/core.h | ||
3 | * | ||
4 | * Copyright (C) 2004 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 | #ifndef __ASM_ARCH_VERSATILE_H | ||
23 | #define __ASM_ARCH_VERSATILE_H | ||
24 | |||
25 | #include <asm/hardware/amba.h> | ||
26 | |||
27 | extern void __init versatile_init(void); | ||
28 | extern void __init versatile_init_irq(void); | ||
29 | extern void __init versatile_map_io(void); | ||
30 | extern struct sys_timer versatile_timer; | ||
31 | extern unsigned int mmc_status(struct device *dev); | ||
32 | |||
33 | #define AMBA_DEVICE(name,busid,base,plat) \ | ||
34 | static struct amba_device name##_device = { \ | ||
35 | .dev = { \ | ||
36 | .coherent_dma_mask = ~0, \ | ||
37 | .bus_id = busid, \ | ||
38 | .platform_data = plat, \ | ||
39 | }, \ | ||
40 | .res = { \ | ||
41 | .start = VERSATILE_##base##_BASE, \ | ||
42 | .end = (VERSATILE_##base##_BASE) + SZ_4K - 1,\ | ||
43 | .flags = IORESOURCE_MEM, \ | ||
44 | }, \ | ||
45 | .dma_mask = ~0, \ | ||
46 | .irq = base##_IRQ, \ | ||
47 | /* .dma = base##_DMA,*/ \ | ||
48 | } | ||
49 | |||
50 | #endif | ||
diff --git a/arch/arm/mach-versatile/versatile_ab.c b/arch/arm/mach-versatile/versatile_ab.c new file mode 100644 index 000000000000..d332084586cf --- /dev/null +++ b/arch/arm/mach-versatile/versatile_ab.c | |||
@@ -0,0 +1,45 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-versatile/versatile_ab.c | ||
3 | * | ||
4 | * Copyright (C) 2004 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 | #include <linux/config.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/device.h> | ||
25 | #include <linux/sysdev.h> | ||
26 | |||
27 | #include <asm/hardware.h> | ||
28 | #include <asm/io.h> | ||
29 | #include <asm/irq.h> | ||
30 | #include <asm/mach-types.h> | ||
31 | #include <asm/hardware/amba.h> | ||
32 | |||
33 | #include <asm/mach/arch.h> | ||
34 | |||
35 | #include "core.h" | ||
36 | |||
37 | MACHINE_START(VERSATILE_AB, "ARM-Versatile AB") | ||
38 | MAINTAINER("ARM Ltd/Deep Blue Solutions Ltd") | ||
39 | BOOT_MEM(0x00000000, 0x101f1000, 0xf11f1000) | ||
40 | BOOT_PARAMS(0x00000100) | ||
41 | MAPIO(versatile_map_io) | ||
42 | INITIRQ(versatile_init_irq) | ||
43 | .timer = &versatile_timer, | ||
44 | INIT_MACHINE(versatile_init) | ||
45 | MACHINE_END | ||
diff --git a/arch/arm/mach-versatile/versatile_pb.c b/arch/arm/mach-versatile/versatile_pb.c new file mode 100644 index 000000000000..2702099a68f3 --- /dev/null +++ b/arch/arm/mach-versatile/versatile_pb.c | |||
@@ -0,0 +1,109 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-versatile/versatile_pb.c | ||
3 | * | ||
4 | * Copyright (C) 2004 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 | #include <linux/config.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/device.h> | ||
25 | #include <linux/sysdev.h> | ||
26 | |||
27 | #include <asm/hardware.h> | ||
28 | #include <asm/io.h> | ||
29 | #include <asm/irq.h> | ||
30 | #include <asm/mach-types.h> | ||
31 | #include <asm/hardware/amba.h> | ||
32 | |||
33 | #include <asm/mach/arch.h> | ||
34 | #include <asm/mach/mmc.h> | ||
35 | |||
36 | #include "core.h" | ||
37 | |||
38 | #if 1 | ||
39 | #define IRQ_MMCI1A IRQ_VICSOURCE23 | ||
40 | #else | ||
41 | #define IRQ_MMCI1A IRQ_SIC_MMCI1A | ||
42 | #endif | ||
43 | |||
44 | static struct mmc_platform_data mmc1_plat_data = { | ||
45 | .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, | ||
46 | .status = mmc_status, | ||
47 | }; | ||
48 | |||
49 | #define UART3_IRQ { IRQ_SIC_UART3, NO_IRQ } | ||
50 | #define UART3_DMA { 0x86, 0x87 } | ||
51 | #define SCI1_IRQ { IRQ_SIC_SCI3, NO_IRQ } | ||
52 | #define SCI1_DMA { 0x88, 0x89 } | ||
53 | #define MMCI1_IRQ { IRQ_MMCI1A, IRQ_SIC_MMCI1B } | ||
54 | #define MMCI1_DMA { 0x85, 0 } | ||
55 | |||
56 | /* | ||
57 | * These devices are connected via the core APB bridge | ||
58 | */ | ||
59 | #define GPIO2_IRQ { IRQ_GPIOINT2, NO_IRQ } | ||
60 | #define GPIO2_DMA { 0, 0 } | ||
61 | #define GPIO3_IRQ { IRQ_GPIOINT3, NO_IRQ } | ||
62 | #define GPIO3_DMA { 0, 0 } | ||
63 | |||
64 | /* | ||
65 | * These devices are connected via the DMA APB bridge | ||
66 | */ | ||
67 | |||
68 | /* FPGA Primecells */ | ||
69 | AMBA_DEVICE(uart3, "fpga:09", UART3, NULL); | ||
70 | AMBA_DEVICE(sci1, "fpga:0a", SCI1, NULL); | ||
71 | AMBA_DEVICE(mmc1, "fpga:0b", MMCI1, &mmc1_plat_data); | ||
72 | |||
73 | /* DevChip Primecells */ | ||
74 | AMBA_DEVICE(gpio2, "dev:e6", GPIO2, NULL); | ||
75 | AMBA_DEVICE(gpio3, "dev:e7", GPIO3, NULL); | ||
76 | |||
77 | static struct amba_device *amba_devs[] __initdata = { | ||
78 | &uart3_device, | ||
79 | &gpio2_device, | ||
80 | &gpio3_device, | ||
81 | &sci1_device, | ||
82 | &mmc1_device, | ||
83 | }; | ||
84 | |||
85 | static int __init versatile_pb_init(void) | ||
86 | { | ||
87 | int i; | ||
88 | |||
89 | if (machine_is_versatile_pb()) { | ||
90 | for (i = 0; i < ARRAY_SIZE(amba_devs); i++) { | ||
91 | struct amba_device *d = amba_devs[i]; | ||
92 | amba_device_register(d, &iomem_resource); | ||
93 | } | ||
94 | } | ||
95 | |||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | arch_initcall(versatile_pb_init); | ||
100 | |||
101 | MACHINE_START(VERSATILE_PB, "ARM-Versatile PB") | ||
102 | MAINTAINER("ARM Ltd/Deep Blue Solutions Ltd") | ||
103 | BOOT_MEM(0x00000000, 0x101f1000, 0xf11f1000) | ||
104 | BOOT_PARAMS(0x00000100) | ||
105 | MAPIO(versatile_map_io) | ||
106 | INITIRQ(versatile_init_irq) | ||
107 | .timer = &versatile_timer, | ||
108 | INIT_MACHINE(versatile_init) | ||
109 | MACHINE_END | ||