diff options
Diffstat (limited to 'arch/arm/plat-versatile')
-rw-r--r-- | arch/arm/plat-versatile/Kconfig | 17 | ||||
-rw-r--r-- | arch/arm/plat-versatile/Makefile | 13 | ||||
-rw-r--r-- | arch/arm/plat-versatile/clcd.c | 182 | ||||
-rw-r--r-- | arch/arm/plat-versatile/fpga-irq.c | 72 | ||||
-rw-r--r-- | arch/arm/plat-versatile/headsmp.S | 40 | ||||
-rw-r--r-- | arch/arm/plat-versatile/include/plat/clcd.h | 9 | ||||
-rw-r--r-- | arch/arm/plat-versatile/include/plat/fpga-irq.h | 12 | ||||
-rw-r--r-- | arch/arm/plat-versatile/localtimer.c | 27 | ||||
-rw-r--r-- | arch/arm/plat-versatile/platsmp.c | 104 |
9 files changed, 469 insertions, 7 deletions
diff --git a/arch/arm/plat-versatile/Kconfig b/arch/arm/plat-versatile/Kconfig new file mode 100644 index 000000000000..52353beb369d --- /dev/null +++ b/arch/arm/plat-versatile/Kconfig | |||
@@ -0,0 +1,17 @@ | |||
1 | if PLAT_VERSATILE | ||
2 | |||
3 | config PLAT_VERSATILE_CLCD | ||
4 | bool | ||
5 | |||
6 | config PLAT_VERSATILE_FPGA_IRQ | ||
7 | bool | ||
8 | |||
9 | config PLAT_VERSATILE_LEDS | ||
10 | def_bool y if LEDS_CLASS | ||
11 | depends on ARCH_REALVIEW || ARCH_VERSATILE | ||
12 | |||
13 | config PLAT_VERSATILE_SCHED_CLOCK | ||
14 | def_bool y if !ARCH_INTEGRATOR_AP | ||
15 | select HAVE_SCHED_CLOCK | ||
16 | |||
17 | endif | ||
diff --git a/arch/arm/plat-versatile/Makefile b/arch/arm/plat-versatile/Makefile index 16dde0819934..69714db47c33 100644 --- a/arch/arm/plat-versatile/Makefile +++ b/arch/arm/plat-versatile/Makefile | |||
@@ -1,8 +1,7 @@ | |||
1 | obj-y := clock.o | 1 | obj-y := clock.o |
2 | ifneq ($(CONFIG_ARCH_INTEGRATOR),y) | 2 | obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o |
3 | obj-y += sched-clock.o | 3 | obj-$(CONFIG_PLAT_VERSATILE_CLCD) += clcd.o |
4 | endif | 4 | obj-$(CONFIG_PLAT_VERSATILE_FPGA_IRQ) += fpga-irq.o |
5 | ifeq ($(CONFIG_LEDS_CLASS),y) | 5 | obj-$(CONFIG_PLAT_VERSATILE_LEDS) += leds.o |
6 | obj-$(CONFIG_ARCH_REALVIEW) += leds.o | 6 | obj-$(CONFIG_PLAT_VERSATILE_SCHED_CLOCK) += sched-clock.o |
7 | obj-$(CONFIG_ARCH_VERSATILE) += leds.o | 7 | obj-$(CONFIG_SMP) += headsmp.o platsmp.o |
8 | endif | ||
diff --git a/arch/arm/plat-versatile/clcd.c b/arch/arm/plat-versatile/clcd.c new file mode 100644 index 000000000000..6628cc27efc5 --- /dev/null +++ b/arch/arm/plat-versatile/clcd.c | |||
@@ -0,0 +1,182 @@ | |||
1 | #include <linux/device.h> | ||
2 | #include <linux/dma-mapping.h> | ||
3 | #include <linux/amba/bus.h> | ||
4 | #include <linux/amba/clcd.h> | ||
5 | #include <plat/clcd.h> | ||
6 | |||
7 | static struct clcd_panel vga = { | ||
8 | .mode = { | ||
9 | .name = "VGA", | ||
10 | .refresh = 60, | ||
11 | .xres = 640, | ||
12 | .yres = 480, | ||
13 | .pixclock = 39721, | ||
14 | .left_margin = 40, | ||
15 | .right_margin = 24, | ||
16 | .upper_margin = 32, | ||
17 | .lower_margin = 11, | ||
18 | .hsync_len = 96, | ||
19 | .vsync_len = 2, | ||
20 | .sync = 0, | ||
21 | .vmode = FB_VMODE_NONINTERLACED, | ||
22 | }, | ||
23 | .width = -1, | ||
24 | .height = -1, | ||
25 | .tim2 = TIM2_BCD | TIM2_IPC, | ||
26 | .cntl = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1), | ||
27 | .caps = CLCD_CAP_5551 | CLCD_CAP_565 | CLCD_CAP_888, | ||
28 | .bpp = 16, | ||
29 | }; | ||
30 | |||
31 | static struct clcd_panel xvga = { | ||
32 | .mode = { | ||
33 | .name = "XVGA", | ||
34 | .refresh = 60, | ||
35 | .xres = 1024, | ||
36 | .yres = 768, | ||
37 | .pixclock = 15748, | ||
38 | .left_margin = 152, | ||
39 | .right_margin = 48, | ||
40 | .upper_margin = 23, | ||
41 | .lower_margin = 3, | ||
42 | .hsync_len = 104, | ||
43 | .vsync_len = 4, | ||
44 | .sync = 0, | ||
45 | .vmode = FB_VMODE_NONINTERLACED, | ||
46 | }, | ||
47 | .width = -1, | ||
48 | .height = -1, | ||
49 | .tim2 = TIM2_BCD | TIM2_IPC, | ||
50 | .cntl = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1), | ||
51 | .caps = CLCD_CAP_5551 | CLCD_CAP_565 | CLCD_CAP_888, | ||
52 | .bpp = 16, | ||
53 | }; | ||
54 | |||
55 | /* Sanyo TM38QV67A02A - 3.8 inch QVGA (320x240) Color TFT */ | ||
56 | static struct clcd_panel sanyo_tm38qv67a02a = { | ||
57 | .mode = { | ||
58 | .name = "Sanyo TM38QV67A02A", | ||
59 | .refresh = 116, | ||
60 | .xres = 320, | ||
61 | .yres = 240, | ||
62 | .pixclock = 100000, | ||
63 | .left_margin = 6, | ||
64 | .right_margin = 6, | ||
65 | .upper_margin = 5, | ||
66 | .lower_margin = 5, | ||
67 | .hsync_len = 6, | ||
68 | .vsync_len = 6, | ||
69 | .sync = 0, | ||
70 | .vmode = FB_VMODE_NONINTERLACED, | ||
71 | }, | ||
72 | .width = -1, | ||
73 | .height = -1, | ||
74 | .tim2 = TIM2_BCD, | ||
75 | .cntl = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1), | ||
76 | .caps = CLCD_CAP_5551, | ||
77 | .bpp = 16, | ||
78 | }; | ||
79 | |||
80 | static struct clcd_panel sanyo_2_5_in = { | ||
81 | .mode = { | ||
82 | .name = "Sanyo QVGA Portrait", | ||
83 | .refresh = 116, | ||
84 | .xres = 240, | ||
85 | .yres = 320, | ||
86 | .pixclock = 100000, | ||
87 | .left_margin = 20, | ||
88 | .right_margin = 10, | ||
89 | .upper_margin = 2, | ||
90 | .lower_margin = 2, | ||
91 | .hsync_len = 10, | ||
92 | .vsync_len = 2, | ||
93 | .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
94 | .vmode = FB_VMODE_NONINTERLACED, | ||
95 | }, | ||
96 | .width = -1, | ||
97 | .height = -1, | ||
98 | .tim2 = TIM2_IVS | TIM2_IHS | TIM2_IPC, | ||
99 | .cntl = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1), | ||
100 | .caps = CLCD_CAP_5551, | ||
101 | .bpp = 16, | ||
102 | }; | ||
103 | |||
104 | /* Epson L2F50113T00 - 2.2 inch 176x220 Color TFT */ | ||
105 | static struct clcd_panel epson_l2f50113t00 = { | ||
106 | .mode = { | ||
107 | .name = "Epson L2F50113T00", | ||
108 | .refresh = 390, | ||
109 | .xres = 176, | ||
110 | .yres = 220, | ||
111 | .pixclock = 62500, | ||
112 | .left_margin = 3, | ||
113 | .right_margin = 2, | ||
114 | .upper_margin = 1, | ||
115 | .lower_margin = 0, | ||
116 | .hsync_len = 3, | ||
117 | .vsync_len = 2, | ||
118 | .sync = 0, | ||
119 | .vmode = FB_VMODE_NONINTERLACED, | ||
120 | }, | ||
121 | .width = -1, | ||
122 | .height = -1, | ||
123 | .tim2 = TIM2_BCD | TIM2_IPC, | ||
124 | .cntl = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1), | ||
125 | .caps = CLCD_CAP_5551, | ||
126 | .bpp = 16, | ||
127 | }; | ||
128 | |||
129 | static struct clcd_panel *panels[] = { | ||
130 | &vga, | ||
131 | &xvga, | ||
132 | &sanyo_tm38qv67a02a, | ||
133 | &sanyo_2_5_in, | ||
134 | &epson_l2f50113t00, | ||
135 | }; | ||
136 | |||
137 | struct clcd_panel *versatile_clcd_get_panel(const char *name) | ||
138 | { | ||
139 | int i; | ||
140 | |||
141 | for (i = 0; i < ARRAY_SIZE(panels); i++) | ||
142 | if (strcmp(panels[i]->mode.name, name) == 0) | ||
143 | break; | ||
144 | |||
145 | if (i < ARRAY_SIZE(panels)) | ||
146 | return panels[i]; | ||
147 | |||
148 | pr_err("CLCD: couldn't get parameters for panel %s\n", name); | ||
149 | |||
150 | return NULL; | ||
151 | } | ||
152 | |||
153 | int versatile_clcd_setup_dma(struct clcd_fb *fb, unsigned long framesize) | ||
154 | { | ||
155 | dma_addr_t dma; | ||
156 | |||
157 | fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev, framesize, | ||
158 | &dma, GFP_KERNEL); | ||
159 | if (!fb->fb.screen_base) { | ||
160 | pr_err("CLCD: unable to map framebuffer\n"); | ||
161 | return -ENOMEM; | ||
162 | } | ||
163 | |||
164 | fb->fb.fix.smem_start = dma; | ||
165 | fb->fb.fix.smem_len = framesize; | ||
166 | |||
167 | return 0; | ||
168 | } | ||
169 | |||
170 | int versatile_clcd_mmap_dma(struct clcd_fb *fb, struct vm_area_struct *vma) | ||
171 | { | ||
172 | return dma_mmap_writecombine(&fb->dev->dev, vma, | ||
173 | fb->fb.screen_base, | ||
174 | fb->fb.fix.smem_start, | ||
175 | fb->fb.fix.smem_len); | ||
176 | } | ||
177 | |||
178 | void versatile_clcd_remove_dma(struct clcd_fb *fb) | ||
179 | { | ||
180 | dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len, | ||
181 | fb->fb.screen_base, fb->fb.fix.smem_start); | ||
182 | } | ||
diff --git a/arch/arm/plat-versatile/fpga-irq.c b/arch/arm/plat-versatile/fpga-irq.c new file mode 100644 index 000000000000..31d945d37e4f --- /dev/null +++ b/arch/arm/plat-versatile/fpga-irq.c | |||
@@ -0,0 +1,72 @@ | |||
1 | /* | ||
2 | * Support for Versatile FPGA-based IRQ controllers | ||
3 | */ | ||
4 | #include <linux/irq.h> | ||
5 | #include <linux/io.h> | ||
6 | |||
7 | #include <asm/mach/irq.h> | ||
8 | #include <plat/fpga-irq.h> | ||
9 | |||
10 | #define IRQ_STATUS 0x00 | ||
11 | #define IRQ_RAW_STATUS 0x04 | ||
12 | #define IRQ_ENABLE_SET 0x08 | ||
13 | #define IRQ_ENABLE_CLEAR 0x0c | ||
14 | |||
15 | static void fpga_irq_mask(struct irq_data *d) | ||
16 | { | ||
17 | struct fpga_irq_data *f = irq_data_get_irq_chip_data(d); | ||
18 | u32 mask = 1 << (d->irq - f->irq_start); | ||
19 | |||
20 | writel(mask, f->base + IRQ_ENABLE_CLEAR); | ||
21 | } | ||
22 | |||
23 | static void fpga_irq_unmask(struct irq_data *d) | ||
24 | { | ||
25 | struct fpga_irq_data *f = irq_data_get_irq_chip_data(d); | ||
26 | u32 mask = 1 << (d->irq - f->irq_start); | ||
27 | |||
28 | writel(mask, f->base + IRQ_ENABLE_SET); | ||
29 | } | ||
30 | |||
31 | static void fpga_irq_handle(unsigned int irq, struct irq_desc *desc) | ||
32 | { | ||
33 | struct fpga_irq_data *f = get_irq_desc_data(desc); | ||
34 | u32 status = readl(f->base + IRQ_STATUS); | ||
35 | |||
36 | if (status == 0) { | ||
37 | do_bad_IRQ(irq, desc); | ||
38 | return; | ||
39 | } | ||
40 | |||
41 | do { | ||
42 | irq = ffs(status) - 1; | ||
43 | status &= ~(1 << irq); | ||
44 | |||
45 | generic_handle_irq(irq + f->irq_start); | ||
46 | } while (status); | ||
47 | } | ||
48 | |||
49 | void __init fpga_irq_init(int parent_irq, u32 valid, struct fpga_irq_data *f) | ||
50 | { | ||
51 | unsigned int i; | ||
52 | |||
53 | f->chip.irq_ack = fpga_irq_mask; | ||
54 | f->chip.irq_mask = fpga_irq_mask; | ||
55 | f->chip.irq_unmask = fpga_irq_unmask; | ||
56 | |||
57 | if (parent_irq != -1) { | ||
58 | set_irq_data(parent_irq, f); | ||
59 | set_irq_chained_handler(parent_irq, fpga_irq_handle); | ||
60 | } | ||
61 | |||
62 | for (i = 0; i < 32; i++) { | ||
63 | if (valid & (1 << i)) { | ||
64 | unsigned int irq = f->irq_start + i; | ||
65 | |||
66 | set_irq_chip_data(irq, f); | ||
67 | set_irq_chip(irq, &f->chip); | ||
68 | set_irq_handler(irq, handle_level_irq); | ||
69 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | ||
70 | } | ||
71 | } | ||
72 | } | ||
diff --git a/arch/arm/plat-versatile/headsmp.S b/arch/arm/plat-versatile/headsmp.S new file mode 100644 index 000000000000..d397a1fb2f54 --- /dev/null +++ b/arch/arm/plat-versatile/headsmp.S | |||
@@ -0,0 +1,40 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/plat-versatile/headsmp.S | ||
3 | * | ||
4 | * Copyright (c) 2003 ARM Limited | ||
5 | * All Rights Reserved | ||
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/linkage.h> | ||
12 | #include <linux/init.h> | ||
13 | |||
14 | __INIT | ||
15 | |||
16 | /* | ||
17 | * Realview/Versatile Express specific entry point for secondary CPUs. | ||
18 | * This provides a "holding pen" into which all secondary cores are held | ||
19 | * until we're ready for them to initialise. | ||
20 | */ | ||
21 | ENTRY(versatile_secondary_startup) | ||
22 | mrc p15, 0, r0, c0, c0, 5 | ||
23 | and r0, r0, #15 | ||
24 | adr r4, 1f | ||
25 | ldmia r4, {r5, r6} | ||
26 | sub r4, r4, r5 | ||
27 | add r6, r6, r4 | ||
28 | pen: ldr r7, [r6] | ||
29 | cmp r7, r0 | ||
30 | bne pen | ||
31 | |||
32 | /* | ||
33 | * we've been released from the holding pen: secondary_stack | ||
34 | * should now contain the SVC stack for this core | ||
35 | */ | ||
36 | b secondary_startup | ||
37 | |||
38 | .align | ||
39 | 1: .long . | ||
40 | .long pen_release | ||
diff --git a/arch/arm/plat-versatile/include/plat/clcd.h b/arch/arm/plat-versatile/include/plat/clcd.h new file mode 100644 index 000000000000..6bb6a1d2019b --- /dev/null +++ b/arch/arm/plat-versatile/include/plat/clcd.h | |||
@@ -0,0 +1,9 @@ | |||
1 | #ifndef PLAT_CLCD_H | ||
2 | #define PLAT_CLCD_H | ||
3 | |||
4 | struct clcd_panel *versatile_clcd_get_panel(const char *); | ||
5 | int versatile_clcd_setup_dma(struct clcd_fb *, unsigned long); | ||
6 | int versatile_clcd_mmap_dma(struct clcd_fb *, struct vm_area_struct *); | ||
7 | void versatile_clcd_remove_dma(struct clcd_fb *); | ||
8 | |||
9 | #endif | ||
diff --git a/arch/arm/plat-versatile/include/plat/fpga-irq.h b/arch/arm/plat-versatile/include/plat/fpga-irq.h new file mode 100644 index 000000000000..627fafd1e595 --- /dev/null +++ b/arch/arm/plat-versatile/include/plat/fpga-irq.h | |||
@@ -0,0 +1,12 @@ | |||
1 | #ifndef PLAT_FPGA_IRQ_H | ||
2 | #define PLAT_FPGA_IRQ_H | ||
3 | |||
4 | struct fpga_irq_data { | ||
5 | void __iomem *base; | ||
6 | unsigned int irq_start; | ||
7 | struct irq_chip chip; | ||
8 | }; | ||
9 | |||
10 | void fpga_irq_init(int, u32, struct fpga_irq_data *); | ||
11 | |||
12 | #endif | ||
diff --git a/arch/arm/plat-versatile/localtimer.c b/arch/arm/plat-versatile/localtimer.c new file mode 100644 index 000000000000..0fb3961999b5 --- /dev/null +++ b/arch/arm/plat-versatile/localtimer.c | |||
@@ -0,0 +1,27 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/plat-versatile/localtimer.c | ||
3 | * | ||
4 | * Copyright (C) 2002 ARM Ltd. | ||
5 | * All Rights Reserved | ||
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/init.h> | ||
12 | #include <linux/smp.h> | ||
13 | #include <linux/clockchips.h> | ||
14 | |||
15 | #include <asm/smp_twd.h> | ||
16 | #include <asm/localtimer.h> | ||
17 | #include <mach/irqs.h> | ||
18 | |||
19 | /* | ||
20 | * Setup the local clock events for a CPU. | ||
21 | */ | ||
22 | int __cpuinit local_timer_setup(struct clock_event_device *evt) | ||
23 | { | ||
24 | evt->irq = IRQ_LOCALTIMER; | ||
25 | twd_timer_setup(evt); | ||
26 | return 0; | ||
27 | } | ||
diff --git a/arch/arm/plat-versatile/platsmp.c b/arch/arm/plat-versatile/platsmp.c new file mode 100644 index 000000000000..ba3d471d4bcf --- /dev/null +++ b/arch/arm/plat-versatile/platsmp.c | |||
@@ -0,0 +1,104 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/plat-versatile/platsmp.c | ||
3 | * | ||
4 | * Copyright (C) 2002 ARM Ltd. | ||
5 | * All Rights Reserved | ||
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/init.h> | ||
12 | #include <linux/errno.h> | ||
13 | #include <linux/delay.h> | ||
14 | #include <linux/device.h> | ||
15 | #include <linux/jiffies.h> | ||
16 | #include <linux/smp.h> | ||
17 | |||
18 | #include <asm/cacheflush.h> | ||
19 | |||
20 | /* | ||
21 | * control for which core is the next to come out of the secondary | ||
22 | * boot "holding pen" | ||
23 | */ | ||
24 | volatile int __cpuinitdata pen_release = -1; | ||
25 | |||
26 | /* | ||
27 | * Write pen_release in a way that is guaranteed to be visible to all | ||
28 | * observers, irrespective of whether they're taking part in coherency | ||
29 | * or not. This is necessary for the hotplug code to work reliably. | ||
30 | */ | ||
31 | static void __cpuinit write_pen_release(int val) | ||
32 | { | ||
33 | pen_release = val; | ||
34 | smp_wmb(); | ||
35 | __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release)); | ||
36 | outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1)); | ||
37 | } | ||
38 | |||
39 | static DEFINE_SPINLOCK(boot_lock); | ||
40 | |||
41 | void __cpuinit platform_secondary_init(unsigned int cpu) | ||
42 | { | ||
43 | /* | ||
44 | * if any interrupts are already enabled for the primary | ||
45 | * core (e.g. timer irq), then they will not have been enabled | ||
46 | * for us: do so | ||
47 | */ | ||
48 | gic_secondary_init(0); | ||
49 | |||
50 | /* | ||
51 | * let the primary processor know we're out of the | ||
52 | * pen, then head off into the C entry point | ||
53 | */ | ||
54 | write_pen_release(-1); | ||
55 | |||
56 | /* | ||
57 | * Synchronise with the boot thread. | ||
58 | */ | ||
59 | spin_lock(&boot_lock); | ||
60 | spin_unlock(&boot_lock); | ||
61 | } | ||
62 | |||
63 | int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) | ||
64 | { | ||
65 | unsigned long timeout; | ||
66 | |||
67 | /* | ||
68 | * Set synchronisation state between this boot processor | ||
69 | * and the secondary one | ||
70 | */ | ||
71 | spin_lock(&boot_lock); | ||
72 | |||
73 | /* | ||
74 | * This is really belt and braces; we hold unintended secondary | ||
75 | * CPUs in the holding pen until we're ready for them. However, | ||
76 | * since we haven't sent them a soft interrupt, they shouldn't | ||
77 | * be there. | ||
78 | */ | ||
79 | write_pen_release(cpu); | ||
80 | |||
81 | /* | ||
82 | * Send the secondary CPU a soft interrupt, thereby causing | ||
83 | * the boot monitor to read the system wide flags register, | ||
84 | * and branch to the address found there. | ||
85 | */ | ||
86 | smp_cross_call(cpumask_of(cpu), 1); | ||
87 | |||
88 | timeout = jiffies + (1 * HZ); | ||
89 | while (time_before(jiffies, timeout)) { | ||
90 | smp_rmb(); | ||
91 | if (pen_release == -1) | ||
92 | break; | ||
93 | |||
94 | udelay(10); | ||
95 | } | ||
96 | |||
97 | /* | ||
98 | * now the secondary core is starting up let it run its | ||
99 | * calibrations, then wait for it to finish | ||
100 | */ | ||
101 | spin_unlock(&boot_lock); | ||
102 | |||
103 | return pen_release != -1 ? -ENOSYS : 0; | ||
104 | } | ||