blob: c3468bf2841e6a53305ab6dc4732a0b7ea595748 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include <linux/init.h>
22#include <linux/device.h>
23#include <linux/dma-mapping.h>
Russell Kingd052d1b2005-10-29 19:07:23 +010024#include <linux/platform_device.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070025#include <linux/sysdev.h>
26#include <linux/interrupt.h>
Russell Kinga62c80e2006-01-07 13:52:45 +000027#include <linux/amba/bus.h>
28#include <linux/amba/clcd.h>
Kevin Hilmanb49c87c2007-03-08 20:25:13 +010029#include <linux/clocksource.h>
Kevin Hilman89df1272007-03-08 20:30:38 +010030#include <linux/clockchips.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031
Nicolas Pitre752bee12006-12-04 20:29:21 +010032#include <asm/cnt32_to_63.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <asm/system.h>
Russell Kinga09e64f2008-08-05 16:14:15 +010034#include <mach/hardware.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <asm/io.h>
36#include <asm/irq.h>
37#include <asm/leds.h>
Russell Kingb720f732005-06-29 15:15:54 +010038#include <asm/hardware/arm_timer.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include <asm/hardware/icst307.h>
Russell Kingfa0fe482006-01-13 21:30:48 +000040#include <asm/hardware/vic.h>
Russell Kingdc5bc8f2006-07-10 16:33:54 +010041#include <asm/mach-types.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070042
43#include <asm/mach/arch.h>
44#include <asm/mach/flash.h>
45#include <asm/mach/irq.h>
46#include <asm/mach/time.h>
47#include <asm/mach/map.h>
48#include <asm/mach/mmc.h>
49
50#include "core.h"
51#include "clock.h"
52
53/*
54 * All IO addresses are mapped onto VA 0xFFFx.xxxx, where x.xxxx
55 * is the (PA >> 12).
56 *
57 * Setup a VA for the Versatile Vectored Interrupt Controller.
58 */
Al Viro2ad4f862005-09-29 00:09:02 +010059#define __io_address(n) __io(IO_ADDRESS(n))
60#define VA_VIC_BASE __io_address(VERSATILE_VIC_BASE)
61#define VA_SIC_BASE __io_address(VERSATILE_SIC_BASE)
Linus Torvalds1da177e2005-04-16 15:20:36 -070062
Linus Torvalds1da177e2005-04-16 15:20:36 -070063static void sic_mask_irq(unsigned int irq)
64{
65 irq -= IRQ_SIC_START;
66 writel(1 << irq, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR);
67}
68
69static void sic_unmask_irq(unsigned int irq)
70{
71 irq -= IRQ_SIC_START;
72 writel(1 << irq, VA_SIC_BASE + SIC_IRQ_ENABLE_SET);
73}
74
David Brownell38c677c2006-08-01 22:26:25 +010075static struct irq_chip sic_chip = {
76 .name = "SIC",
Linus Torvalds1da177e2005-04-16 15:20:36 -070077 .ack = sic_mask_irq,
78 .mask = sic_mask_irq,
79 .unmask = sic_unmask_irq,
80};
81
82static void
Russell King10dd5ce2006-11-23 11:41:32 +000083sic_handle_irq(unsigned int irq, struct irq_desc *desc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070084{
85 unsigned long status = readl(VA_SIC_BASE + SIC_IRQ_STATUS);
86
87 if (status == 0) {
Linus Torvalds0cd61b62006-10-06 10:53:39 -070088 do_bad_IRQ(irq, desc);
Linus Torvalds1da177e2005-04-16 15:20:36 -070089 return;
90 }
91
92 do {
93 irq = ffs(status) - 1;
94 status &= ~(1 << irq);
95
96 irq += IRQ_SIC_START;
97
Dmitry Baryshkovd8aa0252008-10-09 13:36:24 +010098 generic_handle_irq(irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 } while (status);
100}
101
102#if 1
103#define IRQ_MMCI0A IRQ_VICSOURCE22
104#define IRQ_AACI IRQ_VICSOURCE24
105#define IRQ_ETH IRQ_VICSOURCE25
106#define PIC_MASK 0xFFD00000
107#else
108#define IRQ_MMCI0A IRQ_SIC_MMCI0A
109#define IRQ_AACI IRQ_SIC_AACI
110#define IRQ_ETH IRQ_SIC_ETH
111#define PIC_MASK 0
112#endif
113
114void __init versatile_init_irq(void)
115{
Russell Kingfa0fe482006-01-13 21:30:48 +0000116 unsigned int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117
Russell King56f1319e2006-06-10 12:42:12 +0100118 vic_init(VA_VIC_BASE, IRQ_VIC_START, ~0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119
Russell King56f1319e2006-06-10 12:42:12 +0100120 set_irq_chained_handler(IRQ_VICSOURCE31, sic_handle_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121
122 /* Do second interrupt controller */
123 writel(~0, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR);
124
125 for (i = IRQ_SIC_START; i <= IRQ_SIC_END; i++) {
126 if ((PIC_MASK & (1 << (i - IRQ_SIC_START))) == 0) {
127 set_irq_chip(i, &sic_chip);
Russell King10dd5ce2006-11-23 11:41:32 +0000128 set_irq_handler(i, handle_level_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
130 }
131 }
132
133 /*
134 * Interrupts on secondary controller from 0 to 8 are routed to
135 * source 31 on PIC.
136 * Interrupts from 21 to 31 are routed directly to the VIC on
137 * the corresponding number on primary controller. This is controlled
138 * by setting PIC_ENABLEx.
139 */
140 writel(PIC_MASK, VA_SIC_BASE + SIC_INT_PIC_ENABLE);
141}
142
143static struct map_desc versatile_io_desc[] __initdata = {
Deepak Saxena13115212005-10-28 15:19:06 +0100144 {
145 .virtual = IO_ADDRESS(VERSATILE_SYS_BASE),
146 .pfn = __phys_to_pfn(VERSATILE_SYS_BASE),
147 .length = SZ_4K,
148 .type = MT_DEVICE
149 }, {
150 .virtual = IO_ADDRESS(VERSATILE_SIC_BASE),
151 .pfn = __phys_to_pfn(VERSATILE_SIC_BASE),
152 .length = SZ_4K,
153 .type = MT_DEVICE
154 }, {
155 .virtual = IO_ADDRESS(VERSATILE_VIC_BASE),
156 .pfn = __phys_to_pfn(VERSATILE_VIC_BASE),
157 .length = SZ_4K,
158 .type = MT_DEVICE
159 }, {
160 .virtual = IO_ADDRESS(VERSATILE_SCTL_BASE),
161 .pfn = __phys_to_pfn(VERSATILE_SCTL_BASE),
162 .length = SZ_4K * 9,
163 .type = MT_DEVICE
164 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165#ifdef CONFIG_MACH_VERSATILE_AB
Deepak Saxena13115212005-10-28 15:19:06 +0100166 {
167 .virtual = IO_ADDRESS(VERSATILE_GPIO0_BASE),
168 .pfn = __phys_to_pfn(VERSATILE_GPIO0_BASE),
169 .length = SZ_4K,
170 .type = MT_DEVICE
171 }, {
172 .virtual = IO_ADDRESS(VERSATILE_IB2_BASE),
173 .pfn = __phys_to_pfn(VERSATILE_IB2_BASE),
174 .length = SZ_64M,
175 .type = MT_DEVICE
176 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177#endif
178#ifdef CONFIG_DEBUG_LL
Deepak Saxena13115212005-10-28 15:19:06 +0100179 {
180 .virtual = IO_ADDRESS(VERSATILE_UART0_BASE),
181 .pfn = __phys_to_pfn(VERSATILE_UART0_BASE),
182 .length = SZ_4K,
183 .type = MT_DEVICE
184 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185#endif
Catalin Marinasc0da0852005-06-20 18:51:06 +0100186#ifdef CONFIG_PCI
Deepak Saxena13115212005-10-28 15:19:06 +0100187 {
188 .virtual = IO_ADDRESS(VERSATILE_PCI_CORE_BASE),
189 .pfn = __phys_to_pfn(VERSATILE_PCI_CORE_BASE),
190 .length = SZ_4K,
191 .type = MT_DEVICE
192 }, {
Al Viro399ad772006-10-11 17:22:34 +0100193 .virtual = (unsigned long)VERSATILE_PCI_VIRT_BASE,
Deepak Saxena13115212005-10-28 15:19:06 +0100194 .pfn = __phys_to_pfn(VERSATILE_PCI_BASE),
195 .length = VERSATILE_PCI_BASE_SIZE,
196 .type = MT_DEVICE
197 }, {
Al Viro399ad772006-10-11 17:22:34 +0100198 .virtual = (unsigned long)VERSATILE_PCI_CFG_VIRT_BASE,
Deepak Saxena13115212005-10-28 15:19:06 +0100199 .pfn = __phys_to_pfn(VERSATILE_PCI_CFG_BASE),
200 .length = VERSATILE_PCI_CFG_BASE_SIZE,
201 .type = MT_DEVICE
202 },
Catalin Marinasc0da0852005-06-20 18:51:06 +0100203#if 0
Deepak Saxena13115212005-10-28 15:19:06 +0100204 {
205 .virtual = VERSATILE_PCI_VIRT_MEM_BASE0,
206 .pfn = __phys_to_pfn(VERSATILE_PCI_MEM_BASE0),
207 .length = SZ_16M,
208 .type = MT_DEVICE
209 }, {
210 .virtual = VERSATILE_PCI_VIRT_MEM_BASE1,
211 .pfn = __phys_to_pfn(VERSATILE_PCI_MEM_BASE1),
212 .length = SZ_16M,
213 .type = MT_DEVICE
214 }, {
215 .virtual = VERSATILE_PCI_VIRT_MEM_BASE2,
216 .pfn = __phys_to_pfn(VERSATILE_PCI_MEM_BASE2),
217 .length = SZ_16M,
218 .type = MT_DEVICE
219 },
Catalin Marinasc0da0852005-06-20 18:51:06 +0100220#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221#endif
222};
223
224void __init versatile_map_io(void)
225{
226 iotable_init(versatile_io_desc, ARRAY_SIZE(versatile_io_desc));
227}
228
Al Viro2ad4f862005-09-29 00:09:02 +0100229#define VERSATILE_REFCOUNTER (__io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_24MHz_OFFSET)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230
231/*
232 * This is the Versatile sched_clock implementation. This has
Nicolas Pitre752bee12006-12-04 20:29:21 +0100233 * a resolution of 41.7ns, and a maximum value of about 35583 days.
234 *
235 * The return value is guaranteed to be monotonic in that range as
236 * long as there is always less than 89 seconds between successive
237 * calls to this function.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 */
239unsigned long long sched_clock(void)
240{
Nicolas Pitre752bee12006-12-04 20:29:21 +0100241 unsigned long long v = cnt32_to_63(readl(VERSATILE_REFCOUNTER));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242
Nicolas Pitre752bee12006-12-04 20:29:21 +0100243 /* the <<1 gets rid of the cnt_32_to_63 top bit saving on a bic insn */
244 v *= 125<<1;
245 do_div(v, 3<<1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246
247 return v;
248}
249
250
Al Viro2ad4f862005-09-29 00:09:02 +0100251#define VERSATILE_FLASHCTRL (__io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_FLASH_OFFSET)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252
253static int versatile_flash_init(void)
254{
255 u32 val;
256
257 val = __raw_readl(VERSATILE_FLASHCTRL);
258 val &= ~VERSATILE_FLASHPROG_FLVPPEN;
259 __raw_writel(val, VERSATILE_FLASHCTRL);
260
261 return 0;
262}
263
264static void versatile_flash_exit(void)
265{
266 u32 val;
267
268 val = __raw_readl(VERSATILE_FLASHCTRL);
269 val &= ~VERSATILE_FLASHPROG_FLVPPEN;
270 __raw_writel(val, VERSATILE_FLASHCTRL);
271}
272
273static void versatile_flash_set_vpp(int on)
274{
275 u32 val;
276
277 val = __raw_readl(VERSATILE_FLASHCTRL);
278 if (on)
279 val |= VERSATILE_FLASHPROG_FLVPPEN;
280 else
281 val &= ~VERSATILE_FLASHPROG_FLVPPEN;
282 __raw_writel(val, VERSATILE_FLASHCTRL);
283}
284
285static struct flash_platform_data versatile_flash_data = {
286 .map_name = "cfi_probe",
287 .width = 4,
288 .init = versatile_flash_init,
289 .exit = versatile_flash_exit,
290 .set_vpp = versatile_flash_set_vpp,
291};
292
293static struct resource versatile_flash_resource = {
294 .start = VERSATILE_FLASH_BASE,
Yoav Steinberga0c5a642006-08-13 14:17:12 +0100295 .end = VERSATILE_FLASH_BASE + VERSATILE_FLASH_SIZE - 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 .flags = IORESOURCE_MEM,
297};
298
299static struct platform_device versatile_flash_device = {
300 .name = "armflash",
301 .id = 0,
302 .dev = {
303 .platform_data = &versatile_flash_data,
304 },
305 .num_resources = 1,
306 .resource = &versatile_flash_resource,
307};
308
309static struct resource smc91x_resources[] = {
310 [0] = {
311 .start = VERSATILE_ETH_BASE,
312 .end = VERSATILE_ETH_BASE + SZ_64K - 1,
313 .flags = IORESOURCE_MEM,
314 },
315 [1] = {
316 .start = IRQ_ETH,
317 .end = IRQ_ETH,
318 .flags = IORESOURCE_IRQ,
319 },
320};
321
322static struct platform_device smc91x_device = {
323 .name = "smc91x",
324 .id = 0,
325 .num_resources = ARRAY_SIZE(smc91x_resources),
326 .resource = smc91x_resources,
327};
328
Russell King6b65cd72006-12-10 21:21:32 +0100329static struct resource versatile_i2c_resource = {
330 .start = VERSATILE_I2C_BASE,
331 .end = VERSATILE_I2C_BASE + SZ_4K - 1,
332 .flags = IORESOURCE_MEM,
333};
334
335static struct platform_device versatile_i2c_device = {
336 .name = "versatile-i2c",
337 .id = -1,
338 .num_resources = 1,
339 .resource = &versatile_i2c_resource,
340};
341
Al Viro2ad4f862005-09-29 00:09:02 +0100342#define VERSATILE_SYSMCI (__io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_MCI_OFFSET)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343
344unsigned int mmc_status(struct device *dev)
345{
346 struct amba_device *adev = container_of(dev, struct amba_device, dev);
347 u32 mask;
348
349 if (adev->res.start == VERSATILE_MMCI0_BASE)
350 mask = 1;
351 else
352 mask = 2;
353
354 return readl(VERSATILE_SYSMCI) & mask;
355}
356
357static struct mmc_platform_data mmc0_plat_data = {
358 .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
359 .status = mmc_status,
360};
361
362/*
363 * Clock handling
364 */
365static const struct icst307_params versatile_oscvco_params = {
366 .ref = 24000,
367 .vco_max = 200000,
368 .vd_min = 4 + 8,
369 .vd_max = 511 + 8,
370 .rd_min = 1 + 2,
371 .rd_max = 127 + 2,
372};
373
374static void versatile_oscvco_set(struct clk *clk, struct icst307_vco vco)
375{
Al Viro2ad4f862005-09-29 00:09:02 +0100376 void __iomem *sys_lock = __io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_LOCK_OFFSET;
Russell Kingdc5bc8f2006-07-10 16:33:54 +0100377 void __iomem *sys_osc = __io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_OSCCLCD_OFFSET;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 u32 val;
379
380 val = readl(sys_osc) & ~0x7ffff;
381 val |= vco.v | (vco.r << 9) | (vco.s << 16);
382
383 writel(0xa05f, sys_lock);
384 writel(val, sys_osc);
385 writel(0, sys_lock);
386}
387
388static struct clk versatile_clcd_clk = {
389 .name = "CLCDCLK",
390 .params = &versatile_oscvco_params,
391 .setvco = versatile_oscvco_set,
392};
393
394/*
395 * CLCD support.
396 */
397#define SYS_CLCD_MODE_MASK (3 << 0)
398#define SYS_CLCD_MODE_888 (0 << 0)
399#define SYS_CLCD_MODE_5551 (1 << 0)
400#define SYS_CLCD_MODE_565_RLSB (2 << 0)
401#define SYS_CLCD_MODE_565_BLSB (3 << 0)
402#define SYS_CLCD_NLCDIOON (1 << 2)
403#define SYS_CLCD_VDDPOSSWITCH (1 << 3)
404#define SYS_CLCD_PWR3V5SWITCH (1 << 4)
405#define SYS_CLCD_ID_MASK (0x1f << 8)
406#define SYS_CLCD_ID_SANYO_3_8 (0x00 << 8)
407#define SYS_CLCD_ID_UNKNOWN_8_4 (0x01 << 8)
408#define SYS_CLCD_ID_EPSON_2_2 (0x02 << 8)
409#define SYS_CLCD_ID_SANYO_2_5 (0x07 << 8)
410#define SYS_CLCD_ID_VGA (0x1f << 8)
411
412static struct clcd_panel vga = {
413 .mode = {
414 .name = "VGA",
415 .refresh = 60,
416 .xres = 640,
417 .yres = 480,
418 .pixclock = 39721,
419 .left_margin = 40,
420 .right_margin = 24,
421 .upper_margin = 32,
422 .lower_margin = 11,
423 .hsync_len = 96,
424 .vsync_len = 2,
425 .sync = 0,
426 .vmode = FB_VMODE_NONINTERLACED,
427 },
428 .width = -1,
429 .height = -1,
430 .tim2 = TIM2_BCD | TIM2_IPC,
431 .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1),
432 .bpp = 16,
433};
434
435static struct clcd_panel sanyo_3_8_in = {
436 .mode = {
437 .name = "Sanyo QVGA",
438 .refresh = 116,
439 .xres = 320,
440 .yres = 240,
441 .pixclock = 100000,
442 .left_margin = 6,
443 .right_margin = 6,
444 .upper_margin = 5,
445 .lower_margin = 5,
446 .hsync_len = 6,
447 .vsync_len = 6,
448 .sync = 0,
449 .vmode = FB_VMODE_NONINTERLACED,
450 },
451 .width = -1,
452 .height = -1,
453 .tim2 = TIM2_BCD,
454 .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1),
455 .bpp = 16,
456};
457
458static struct clcd_panel sanyo_2_5_in = {
459 .mode = {
460 .name = "Sanyo QVGA Portrait",
461 .refresh = 116,
462 .xres = 240,
463 .yres = 320,
464 .pixclock = 100000,
465 .left_margin = 20,
466 .right_margin = 10,
467 .upper_margin = 2,
468 .lower_margin = 2,
469 .hsync_len = 10,
470 .vsync_len = 2,
471 .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
472 .vmode = FB_VMODE_NONINTERLACED,
473 },
474 .width = -1,
475 .height = -1,
476 .tim2 = TIM2_IVS | TIM2_IHS | TIM2_IPC,
477 .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1),
478 .bpp = 16,
479};
480
481static struct clcd_panel epson_2_2_in = {
482 .mode = {
483 .name = "Epson QCIF",
484 .refresh = 390,
485 .xres = 176,
486 .yres = 220,
487 .pixclock = 62500,
488 .left_margin = 3,
489 .right_margin = 2,
490 .upper_margin = 1,
491 .lower_margin = 0,
492 .hsync_len = 3,
493 .vsync_len = 2,
494 .sync = 0,
495 .vmode = FB_VMODE_NONINTERLACED,
496 },
497 .width = -1,
498 .height = -1,
499 .tim2 = TIM2_BCD | TIM2_IPC,
500 .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1),
501 .bpp = 16,
502};
503
504/*
505 * Detect which LCD panel is connected, and return the appropriate
506 * clcd_panel structure. Note: we do not have any information on
507 * the required timings for the 8.4in panel, so we presently assume
508 * VGA timings.
509 */
510static struct clcd_panel *versatile_clcd_panel(void)
511{
Al Viro2ad4f862005-09-29 00:09:02 +0100512 void __iomem *sys_clcd = __io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_CLCD_OFFSET;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 struct clcd_panel *panel = &vga;
514 u32 val;
515
516 val = readl(sys_clcd) & SYS_CLCD_ID_MASK;
517 if (val == SYS_CLCD_ID_SANYO_3_8)
518 panel = &sanyo_3_8_in;
519 else if (val == SYS_CLCD_ID_SANYO_2_5)
520 panel = &sanyo_2_5_in;
521 else if (val == SYS_CLCD_ID_EPSON_2_2)
522 panel = &epson_2_2_in;
523 else if (val == SYS_CLCD_ID_VGA)
524 panel = &vga;
525 else {
526 printk(KERN_ERR "CLCD: unknown LCD panel ID 0x%08x, using VGA\n",
527 val);
528 panel = &vga;
529 }
530
531 return panel;
532}
533
534/*
535 * Disable all display connectors on the interface module.
536 */
537static void versatile_clcd_disable(struct clcd_fb *fb)
538{
Al Viro2ad4f862005-09-29 00:09:02 +0100539 void __iomem *sys_clcd = __io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_CLCD_OFFSET;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 u32 val;
541
542 val = readl(sys_clcd);
543 val &= ~SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH;
544 writel(val, sys_clcd);
545
546#ifdef CONFIG_MACH_VERSATILE_AB
547 /*
548 * If the LCD is Sanyo 2x5 in on the IB2 board, turn the back-light off
549 */
Russell Kingdc5bc8f2006-07-10 16:33:54 +0100550 if (machine_is_versatile_ab() && fb->panel == &sanyo_2_5_in) {
Al Viro2ad4f862005-09-29 00:09:02 +0100551 void __iomem *versatile_ib2_ctrl = __io_address(VERSATILE_IB2_CTRL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 unsigned long ctrl;
553
554 ctrl = readl(versatile_ib2_ctrl);
555 ctrl &= ~0x01;
556 writel(ctrl, versatile_ib2_ctrl);
557 }
558#endif
559}
560
561/*
562 * Enable the relevant connector on the interface module.
563 */
564static void versatile_clcd_enable(struct clcd_fb *fb)
565{
Al Viro2ad4f862005-09-29 00:09:02 +0100566 void __iomem *sys_clcd = __io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_CLCD_OFFSET;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 u32 val;
568
569 val = readl(sys_clcd);
570 val &= ~SYS_CLCD_MODE_MASK;
571
572 switch (fb->fb.var.green.length) {
573 case 5:
574 val |= SYS_CLCD_MODE_5551;
575 break;
576 case 6:
Catalin Marinas90ef7132005-06-16 18:01:11 +0100577 val |= SYS_CLCD_MODE_565_RLSB;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 break;
579 case 8:
580 val |= SYS_CLCD_MODE_888;
581 break;
582 }
583
584 /*
585 * Set the MUX
586 */
587 writel(val, sys_clcd);
588
589 /*
590 * And now enable the PSUs
591 */
592 val |= SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH;
593 writel(val, sys_clcd);
594
595#ifdef CONFIG_MACH_VERSATILE_AB
596 /*
597 * If the LCD is Sanyo 2x5 in on the IB2 board, turn the back-light on
598 */
Russell Kingdc5bc8f2006-07-10 16:33:54 +0100599 if (machine_is_versatile_ab() && fb->panel == &sanyo_2_5_in) {
Al Viro2ad4f862005-09-29 00:09:02 +0100600 void __iomem *versatile_ib2_ctrl = __io_address(VERSATILE_IB2_CTRL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 unsigned long ctrl;
602
603 ctrl = readl(versatile_ib2_ctrl);
604 ctrl |= 0x01;
605 writel(ctrl, versatile_ib2_ctrl);
606 }
607#endif
608}
609
610static unsigned long framesize = SZ_1M;
611
612static int versatile_clcd_setup(struct clcd_fb *fb)
613{
614 dma_addr_t dma;
615
616 fb->panel = versatile_clcd_panel();
617
618 fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev, framesize,
619 &dma, GFP_KERNEL);
620 if (!fb->fb.screen_base) {
621 printk(KERN_ERR "CLCD: unable to map framebuffer\n");
622 return -ENOMEM;
623 }
624
625 fb->fb.fix.smem_start = dma;
626 fb->fb.fix.smem_len = framesize;
627
628 return 0;
629}
630
631static int versatile_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
632{
633 return dma_mmap_writecombine(&fb->dev->dev, vma,
634 fb->fb.screen_base,
635 fb->fb.fix.smem_start,
636 fb->fb.fix.smem_len);
637}
638
639static void versatile_clcd_remove(struct clcd_fb *fb)
640{
641 dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len,
642 fb->fb.screen_base, fb->fb.fix.smem_start);
643}
644
645static struct clcd_board clcd_plat_data = {
646 .name = "Versatile",
647 .check = clcdfb_check,
648 .decode = clcdfb_decode,
649 .disable = versatile_clcd_disable,
650 .enable = versatile_clcd_enable,
651 .setup = versatile_clcd_setup,
652 .mmap = versatile_clcd_mmap,
653 .remove = versatile_clcd_remove,
654};
655
656#define AACI_IRQ { IRQ_AACI, NO_IRQ }
657#define AACI_DMA { 0x80, 0x81 }
658#define MMCI0_IRQ { IRQ_MMCI0A,IRQ_SIC_MMCI0B }
659#define MMCI0_DMA { 0x84, 0 }
660#define KMI0_IRQ { IRQ_SIC_KMI0, NO_IRQ }
661#define KMI0_DMA { 0, 0 }
662#define KMI1_IRQ { IRQ_SIC_KMI1, NO_IRQ }
663#define KMI1_DMA { 0, 0 }
664
665/*
666 * These devices are connected directly to the multi-layer AHB switch
667 */
668#define SMC_IRQ { NO_IRQ, NO_IRQ }
669#define SMC_DMA { 0, 0 }
670#define MPMC_IRQ { NO_IRQ, NO_IRQ }
671#define MPMC_DMA { 0, 0 }
672#define CLCD_IRQ { IRQ_CLCDINT, NO_IRQ }
673#define CLCD_DMA { 0, 0 }
674#define DMAC_IRQ { IRQ_DMAINT, NO_IRQ }
675#define DMAC_DMA { 0, 0 }
676
677/*
678 * These devices are connected via the core APB bridge
679 */
680#define SCTL_IRQ { NO_IRQ, NO_IRQ }
681#define SCTL_DMA { 0, 0 }
682#define WATCHDOG_IRQ { IRQ_WDOGINT, NO_IRQ }
683#define WATCHDOG_DMA { 0, 0 }
684#define GPIO0_IRQ { IRQ_GPIOINT0, NO_IRQ }
685#define GPIO0_DMA { 0, 0 }
686#define GPIO1_IRQ { IRQ_GPIOINT1, NO_IRQ }
687#define GPIO1_DMA { 0, 0 }
688#define RTC_IRQ { IRQ_RTCINT, NO_IRQ }
689#define RTC_DMA { 0, 0 }
690
691/*
692 * These devices are connected via the DMA APB bridge
693 */
694#define SCI_IRQ { IRQ_SCIINT, NO_IRQ }
695#define SCI_DMA { 7, 6 }
696#define UART0_IRQ { IRQ_UARTINT0, NO_IRQ }
697#define UART0_DMA { 15, 14 }
698#define UART1_IRQ { IRQ_UARTINT1, NO_IRQ }
699#define UART1_DMA { 13, 12 }
700#define UART2_IRQ { IRQ_UARTINT2, NO_IRQ }
701#define UART2_DMA { 11, 10 }
702#define SSP_IRQ { IRQ_SSPINT, NO_IRQ }
703#define SSP_DMA { 9, 8 }
704
705/* FPGA Primecells */
706AMBA_DEVICE(aaci, "fpga:04", AACI, NULL);
707AMBA_DEVICE(mmc0, "fpga:05", MMCI0, &mmc0_plat_data);
708AMBA_DEVICE(kmi0, "fpga:06", KMI0, NULL);
709AMBA_DEVICE(kmi1, "fpga:07", KMI1, NULL);
710
711/* DevChip Primecells */
712AMBA_DEVICE(smc, "dev:00", SMC, NULL);
713AMBA_DEVICE(mpmc, "dev:10", MPMC, NULL);
714AMBA_DEVICE(clcd, "dev:20", CLCD, &clcd_plat_data);
715AMBA_DEVICE(dmac, "dev:30", DMAC, NULL);
716AMBA_DEVICE(sctl, "dev:e0", SCTL, NULL);
717AMBA_DEVICE(wdog, "dev:e1", WATCHDOG, NULL);
718AMBA_DEVICE(gpio0, "dev:e4", GPIO0, NULL);
719AMBA_DEVICE(gpio1, "dev:e5", GPIO1, NULL);
720AMBA_DEVICE(rtc, "dev:e8", RTC, NULL);
721AMBA_DEVICE(sci0, "dev:f0", SCI, NULL);
722AMBA_DEVICE(uart0, "dev:f1", UART0, NULL);
723AMBA_DEVICE(uart1, "dev:f2", UART1, NULL);
724AMBA_DEVICE(uart2, "dev:f3", UART2, NULL);
725AMBA_DEVICE(ssp0, "dev:f4", SSP, NULL);
726
727static struct amba_device *amba_devs[] __initdata = {
728 &dmac_device,
729 &uart0_device,
730 &uart1_device,
731 &uart2_device,
732 &smc_device,
733 &mpmc_device,
734 &clcd_device,
735 &sctl_device,
736 &wdog_device,
737 &gpio0_device,
738 &gpio1_device,
739 &rtc_device,
740 &sci0_device,
741 &ssp0_device,
742 &aaci_device,
743 &mmc0_device,
744 &kmi0_device,
745 &kmi1_device,
746};
747
748#ifdef CONFIG_LEDS
Al Viro2ad4f862005-09-29 00:09:02 +0100749#define VA_LEDS_BASE (__io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_LED_OFFSET)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750
751static void versatile_leds_event(led_event_t ledevt)
752{
753 unsigned long flags;
754 u32 val;
755
756 local_irq_save(flags);
757 val = readl(VA_LEDS_BASE);
758
759 switch (ledevt) {
760 case led_idle_start:
761 val = val & ~VERSATILE_SYS_LED0;
762 break;
763
764 case led_idle_end:
765 val = val | VERSATILE_SYS_LED0;
766 break;
767
768 case led_timer:
769 val = val ^ VERSATILE_SYS_LED1;
770 break;
771
772 case led_halted:
773 val = 0;
774 break;
775
776 default:
777 break;
778 }
779
780 writel(val, VA_LEDS_BASE);
781 local_irq_restore(flags);
782}
783#endif /* CONFIG_LEDS */
784
785void __init versatile_init(void)
786{
787 int i;
788
789 clk_register(&versatile_clcd_clk);
790
791 platform_device_register(&versatile_flash_device);
Russell King6b65cd72006-12-10 21:21:32 +0100792 platform_device_register(&versatile_i2c_device);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 platform_device_register(&smc91x_device);
794
795 for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
796 struct amba_device *d = amba_devs[i];
797 amba_device_register(d, &iomem_resource);
798 }
799
800#ifdef CONFIG_LEDS
801 leds_event = versatile_leds_event;
802#endif
803}
804
805/*
806 * Where is the timer (VA)?
807 */
Al Viro2ad4f862005-09-29 00:09:02 +0100808#define TIMER0_VA_BASE __io_address(VERSATILE_TIMER0_1_BASE)
809#define TIMER1_VA_BASE (__io_address(VERSATILE_TIMER0_1_BASE) + 0x20)
810#define TIMER2_VA_BASE __io_address(VERSATILE_TIMER2_3_BASE)
811#define TIMER3_VA_BASE (__io_address(VERSATILE_TIMER2_3_BASE) + 0x20)
812#define VA_IC_BASE __io_address(VERSATILE_VIC_BASE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813
814/*
815 * How long is the timer interval?
816 */
817#define TIMER_INTERVAL (TICKS_PER_uSEC * mSEC_10)
818#if TIMER_INTERVAL >= 0x100000
Russell Kingb720f732005-06-29 15:15:54 +0100819#define TIMER_RELOAD (TIMER_INTERVAL >> 8)
820#define TIMER_DIVISOR (TIMER_CTRL_DIV256)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821#define TICKS2USECS(x) (256 * (x) / TICKS_PER_uSEC)
822#elif TIMER_INTERVAL >= 0x10000
823#define TIMER_RELOAD (TIMER_INTERVAL >> 4) /* Divide by 16 */
Russell Kingb720f732005-06-29 15:15:54 +0100824#define TIMER_DIVISOR (TIMER_CTRL_DIV16)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825#define TICKS2USECS(x) (16 * (x) / TICKS_PER_uSEC)
826#else
827#define TIMER_RELOAD (TIMER_INTERVAL)
Russell Kingb720f732005-06-29 15:15:54 +0100828#define TIMER_DIVISOR (TIMER_CTRL_DIV1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829#define TICKS2USECS(x) ((x) / TICKS_PER_uSEC)
830#endif
831
Kevin Hilman89df1272007-03-08 20:30:38 +0100832static void timer_set_mode(enum clock_event_mode mode,
833 struct clock_event_device *clk)
834{
835 unsigned long ctrl;
836
837 switch(mode) {
838 case CLOCK_EVT_MODE_PERIODIC:
839 writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_LOAD);
840
841 ctrl = TIMER_CTRL_PERIODIC;
842 ctrl |= TIMER_CTRL_32BIT | TIMER_CTRL_IE | TIMER_CTRL_ENABLE;
843 break;
844 case CLOCK_EVT_MODE_ONESHOT:
845 /* period set, and timer enabled in 'next_event' hook */
846 ctrl = TIMER_CTRL_ONESHOT;
847 ctrl |= TIMER_CTRL_32BIT | TIMER_CTRL_IE;
848 break;
849 case CLOCK_EVT_MODE_UNUSED:
850 case CLOCK_EVT_MODE_SHUTDOWN:
851 default:
852 ctrl = 0;
853 }
854
855 writel(ctrl, TIMER0_VA_BASE + TIMER_CTRL);
856}
857
858static int timer_set_next_event(unsigned long evt,
859 struct clock_event_device *unused)
860{
861 unsigned long ctrl = readl(TIMER0_VA_BASE + TIMER_CTRL);
862
863 writel(evt, TIMER0_VA_BASE + TIMER_LOAD);
864 writel(ctrl | TIMER_CTRL_ENABLE, TIMER0_VA_BASE + TIMER_CTRL);
865
866 return 0;
867}
868
869static struct clock_event_device timer0_clockevent = {
870 .name = "timer0",
871 .shift = 32,
872 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
873 .set_mode = timer_set_mode,
874 .set_next_event = timer_set_next_event,
875};
876
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 * IRQ handler for the timer
879 */
Linus Torvalds0cd61b62006-10-06 10:53:39 -0700880static irqreturn_t versatile_timer_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881{
Kevin Hilman89df1272007-03-08 20:30:38 +0100882 struct clock_event_device *evt = &timer0_clockevent;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883
Russell Kingb720f732005-06-29 15:15:54 +0100884 writel(1, TIMER0_VA_BASE + TIMER_INTCLR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885
Kevin Hilman89df1272007-03-08 20:30:38 +0100886 evt->event_handler(evt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887
888 return IRQ_HANDLED;
889}
890
891static struct irqaction versatile_timer_irq = {
892 .name = "Versatile Timer Tick",
Bernhard Walleb30faba2007-05-08 00:35:39 -0700893 .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
Russell King09b8b5f2005-06-26 17:06:36 +0100894 .handler = versatile_timer_interrupt,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895};
896
Kevin Hilmanb49c87c2007-03-08 20:25:13 +0100897static cycle_t versatile_get_cycles(void)
898{
899 return ~readl(TIMER3_VA_BASE + TIMER_VALUE);
900}
901
902static struct clocksource clocksource_versatile = {
903 .name = "timer3",
904 .rating = 200,
905 .read = versatile_get_cycles,
906 .mask = CLOCKSOURCE_MASK(32),
907 .shift = 20,
908 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
909};
910
911static int __init versatile_clocksource_init(void)
912{
913 /* setup timer3 as free-running clocksource */
914 writel(0, TIMER3_VA_BASE + TIMER_CTRL);
915 writel(0xffffffff, TIMER3_VA_BASE + TIMER_LOAD);
916 writel(0xffffffff, TIMER3_VA_BASE + TIMER_VALUE);
917 writel(TIMER_CTRL_32BIT | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC,
918 TIMER3_VA_BASE + TIMER_CTRL);
919
920 clocksource_versatile.mult =
921 clocksource_khz2mult(1000, clocksource_versatile.shift);
922 clocksource_register(&clocksource_versatile);
923
924 return 0;
925}
926
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927/*
928 * Set up timer interrupt, and return the current time in seconds.
929 */
930static void __init versatile_timer_init(void)
931{
Russell Kingb720f732005-06-29 15:15:54 +0100932 u32 val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933
934 /*
935 * set clock frequency:
936 * VERSATILE_REFCLK is 32KHz
937 * VERSATILE_TIMCLK is 1MHz
938 */
Al Viro2ad4f862005-09-29 00:09:02 +0100939 val = readl(__io_address(VERSATILE_SCTL_BASE));
Russell Kingb720f732005-06-29 15:15:54 +0100940 writel((VERSATILE_TIMCLK << VERSATILE_TIMER1_EnSel) |
941 (VERSATILE_TIMCLK << VERSATILE_TIMER2_EnSel) |
942 (VERSATILE_TIMCLK << VERSATILE_TIMER3_EnSel) |
943 (VERSATILE_TIMCLK << VERSATILE_TIMER4_EnSel) | val,
Al Viro2ad4f862005-09-29 00:09:02 +0100944 __io_address(VERSATILE_SCTL_BASE));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945
946 /*
947 * Initialise to a known state (all timers off)
948 */
Russell Kingb720f732005-06-29 15:15:54 +0100949 writel(0, TIMER0_VA_BASE + TIMER_CTRL);
950 writel(0, TIMER1_VA_BASE + TIMER_CTRL);
951 writel(0, TIMER2_VA_BASE + TIMER_CTRL);
952 writel(0, TIMER3_VA_BASE + TIMER_CTRL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 /*
955 * Make irqs happen for the system timer
956 */
957 setup_irq(IRQ_TIMERINT0_1, &versatile_timer_irq);
Kevin Hilmanb49c87c2007-03-08 20:25:13 +0100958
959 versatile_clocksource_init();
Kevin Hilman89df1272007-03-08 20:30:38 +0100960
961 timer0_clockevent.mult =
962 div_sc(1000000, NSEC_PER_SEC, timer0_clockevent.shift);
963 timer0_clockevent.max_delta_ns =
964 clockevent_delta2ns(0xffffffff, &timer0_clockevent);
965 timer0_clockevent.min_delta_ns =
966 clockevent_delta2ns(0xf, &timer0_clockevent);
967
968 timer0_clockevent.cpumask = cpumask_of_cpu(0);
969 clockevents_register_device(&timer0_clockevent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970}
971
972struct sys_timer versatile_timer = {
973 .init = versatile_timer_init,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974};
Kevin Hilmanb49c87c2007-03-08 20:25:13 +0100975