Commit | Line | Data |
---|---|---|
fef88f10 RK |
1 | /* |
2 | * Versatile Express Core Tile Cortex A9x4 Support | |
3 | */ | |
4 | #include <linux/init.h> | |
68aaae9e | 5 | #include <linux/gfp.h> |
fef88f10 RK |
6 | #include <linux/device.h> |
7 | #include <linux/dma-mapping.h> | |
f417cbad | 8 | #include <linux/platform_device.h> |
fef88f10 RK |
9 | #include <linux/amba/bus.h> |
10 | #include <linux/amba/clcd.h> | |
6d803ba7 | 11 | #include <linux/clkdev.h> |
38669e04 | 12 | #include <linux/vexpress.h> |
520f7bd7 | 13 | #include <linux/irqchip/arm-gic.h> |
fef88f10 | 14 | |
fef88f10 RK |
15 | #include <asm/hardware/arm_timer.h> |
16 | #include <asm/hardware/cache-l2x0.h> | |
80b5efbd | 17 | #include <asm/smp_scu.h> |
bde28b84 | 18 | #include <asm/smp_twd.h> |
fef88f10 | 19 | |
fef88f10 RK |
20 | #include <mach/ct-ca9x4.h> |
21 | ||
8a9618f5 | 22 | #include <asm/hardware/timer-sp.h> |
fef88f10 | 23 | |
fef88f10 RK |
24 | #include <asm/mach/map.h> |
25 | #include <asm/mach/time.h> | |
26 | ||
27 | #include "core.h" | |
28 | ||
29 | #include <mach/motherboard.h> | |
db6b672f | 30 | #include <mach/irqs.h> |
fef88f10 | 31 | |
0fb44b91 RK |
32 | #include <plat/clcd.h> |
33 | ||
fef88f10 RK |
34 | static struct map_desc ct_ca9x4_io_desc[] __initdata = { |
35 | { | |
98ed4ceb PM |
36 | .virtual = V2T_PERIPH, |
37 | .pfn = __phys_to_pfn(CT_CA9X4_MPIC), | |
38 | .length = SZ_8K, | |
39 | .type = MT_DEVICE, | |
fef88f10 RK |
40 | }, |
41 | }; | |
42 | ||
43 | static void __init ct_ca9x4_map_io(void) | |
44 | { | |
98ed4ceb | 45 | iotable_init(ct_ca9x4_io_desc, ARRAY_SIZE(ct_ca9x4_io_desc)); |
fef88f10 RK |
46 | } |
47 | ||
7c380f27 MZ |
48 | #ifdef CONFIG_HAVE_ARM_TWD |
49 | static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, A9_MPCORE_TWD, IRQ_LOCALTIMER); | |
50 | ||
51 | static void __init ca9x4_twd_init(void) | |
52 | { | |
53 | int err = twd_local_timer_register(&twd_local_timer); | |
54 | if (err) | |
55 | pr_err("twd_local_timer_register failed %d\n", err); | |
56 | } | |
57 | #else | |
58 | #define ca9x4_twd_init() do {} while(0) | |
59 | #endif | |
60 | ||
fef88f10 RK |
61 | static void __init ct_ca9x4_init_irq(void) |
62 | { | |
98ed4ceb PM |
63 | gic_init(0, 29, ioremap(A9_MPCORE_GIC_DIST, SZ_4K), |
64 | ioremap(A9_MPCORE_GIC_CPU, SZ_256)); | |
7c380f27 | 65 | ca9x4_twd_init(); |
fef88f10 RK |
66 | } |
67 | ||
fef88f10 RK |
68 | static int ct_ca9x4_clcd_setup(struct clcd_fb *fb) |
69 | { | |
70 | unsigned long framesize = 1024 * 768 * 2; | |
fef88f10 | 71 | |
0fb44b91 RK |
72 | fb->panel = versatile_clcd_get_panel("XVGA"); |
73 | if (!fb->panel) | |
74 | return -EINVAL; | |
fef88f10 | 75 | |
0fb44b91 | 76 | return versatile_clcd_setup_dma(fb, framesize); |
fef88f10 RK |
77 | } |
78 | ||
79 | static struct clcd_board ct_ca9x4_clcd_data = { | |
80 | .name = "CT-CA9X4", | |
0fb44b91 | 81 | .caps = CLCD_CAP_5551 | CLCD_CAP_565, |
fef88f10 RK |
82 | .check = clcdfb_check, |
83 | .decode = clcdfb_decode, | |
fef88f10 | 84 | .setup = ct_ca9x4_clcd_setup, |
0fb44b91 RK |
85 | .mmap = versatile_clcd_mmap_dma, |
86 | .remove = versatile_clcd_remove_dma, | |
fef88f10 RK |
87 | }; |
88 | ||
cdd4e1a7 RK |
89 | static AMBA_AHB_DEVICE(clcd, "ct:clcd", 0, CT_CA9X4_CLCDC, IRQ_CT_CA9X4_CLCDC, &ct_ca9x4_clcd_data); |
90 | static AMBA_APB_DEVICE(dmc, "ct:dmc", 0, CT_CA9X4_DMC, IRQ_CT_CA9X4_DMC, NULL); | |
91 | static AMBA_APB_DEVICE(smc, "ct:smc", 0, CT_CA9X4_SMC, IRQ_CT_CA9X4_SMC, NULL); | |
92 | static AMBA_APB_DEVICE(gpio, "ct:gpio", 0, CT_CA9X4_GPIO, IRQ_CT_CA9X4_GPIO, NULL); | |
fef88f10 RK |
93 | |
94 | static struct amba_device *ct_ca9x4_amba_devs[] __initdata = { | |
95 | &clcd_device, | |
96 | &dmc_device, | |
97 | &smc_device, | |
98 | &gpio_device, | |
99 | }; | |
100 | ||
f417cbad WD |
101 | static struct resource pmu_resources[] = { |
102 | [0] = { | |
103 | .start = IRQ_CT_CA9X4_PMU_CPU0, | |
104 | .end = IRQ_CT_CA9X4_PMU_CPU0, | |
105 | .flags = IORESOURCE_IRQ, | |
106 | }, | |
107 | [1] = { | |
108 | .start = IRQ_CT_CA9X4_PMU_CPU1, | |
109 | .end = IRQ_CT_CA9X4_PMU_CPU1, | |
110 | .flags = IORESOURCE_IRQ, | |
111 | }, | |
112 | [2] = { | |
113 | .start = IRQ_CT_CA9X4_PMU_CPU2, | |
114 | .end = IRQ_CT_CA9X4_PMU_CPU2, | |
115 | .flags = IORESOURCE_IRQ, | |
116 | }, | |
117 | [3] = { | |
118 | .start = IRQ_CT_CA9X4_PMU_CPU3, | |
119 | .end = IRQ_CT_CA9X4_PMU_CPU3, | |
120 | .flags = IORESOURCE_IRQ, | |
121 | }, | |
122 | }; | |
123 | ||
124 | static struct platform_device pmu_device = { | |
125 | .name = "arm-pmu", | |
df3d17e0 | 126 | .id = -1, |
f417cbad WD |
127 | .num_resources = ARRAY_SIZE(pmu_resources), |
128 | .resource = pmu_resources, | |
129 | }; | |
130 | ||
38669e04 PM |
131 | static struct platform_device osc1_device = { |
132 | .name = "vexpress-osc", | |
133 | .id = 1, | |
134 | .num_resources = 1, | |
135 | .resource = (struct resource []) { | |
136 | VEXPRESS_RES_FUNC(0xf, 1), | |
137 | }, | |
138 | }; | |
139 | ||
cdaf9a2f | 140 | static void __init ct_ca9x4_init(void) |
fef88f10 RK |
141 | { |
142 | int i; | |
143 | ||
144 | #ifdef CONFIG_CACHE_L2X0 | |
98ed4ceb | 145 | void __iomem *l2x0_base = ioremap(CT_CA9X4_L2CC, SZ_4K); |
2de59fea WD |
146 | |
147 | /* set RAM latencies to 1 cycle for this core tile. */ | |
148 | writel(0, l2x0_base + L2X0_TAG_LATENCY_CTRL); | |
149 | writel(0, l2x0_base + L2X0_DATA_LATENCY_CTRL); | |
150 | ||
151 | l2x0_init(l2x0_base, 0x00400000, 0xfe0fffff); | |
fef88f10 RK |
152 | #endif |
153 | ||
fef88f10 RK |
154 | for (i = 0; i < ARRAY_SIZE(ct_ca9x4_amba_devs); i++) |
155 | amba_device_register(ct_ca9x4_amba_devs[i], &iomem_resource); | |
f417cbad WD |
156 | |
157 | platform_device_register(&pmu_device); | |
38669e04 PM |
158 | platform_device_register(&osc1_device); |
159 | ||
160 | WARN_ON(clk_register_clkdev(vexpress_osc_setup(&osc1_device.dev), | |
161 | NULL, "ct:clcd")); | |
fef88f10 RK |
162 | } |
163 | ||
80b5efbd | 164 | #ifdef CONFIG_SMP |
98ed4ceb PM |
165 | static void *ct_ca9x4_scu_base __initdata; |
166 | ||
94ae0275 | 167 | static void __init ct_ca9x4_init_cpu_map(void) |
80b5efbd | 168 | { |
98ed4ceb PM |
169 | int i, ncores; |
170 | ||
171 | ct_ca9x4_scu_base = ioremap(A9_MPCORE_SCU, SZ_128); | |
172 | if (WARN_ON(!ct_ca9x4_scu_base)) | |
173 | return; | |
174 | ||
175 | ncores = scu_get_core_count(ct_ca9x4_scu_base); | |
80b5efbd | 176 | |
a06f916b RK |
177 | if (ncores > nr_cpu_ids) { |
178 | pr_warn("SMP: %u cores greater than maximum (%u), clipping\n", | |
179 | ncores, nr_cpu_ids); | |
180 | ncores = nr_cpu_ids; | |
181 | } | |
182 | ||
80b5efbd WD |
183 | for (i = 0; i < ncores; ++i) |
184 | set_cpu_possible(i, true); | |
185 | } | |
186 | ||
94ae0275 | 187 | static void __init ct_ca9x4_smp_enable(unsigned int max_cpus) |
80b5efbd | 188 | { |
98ed4ceb | 189 | scu_enable(ct_ca9x4_scu_base); |
80b5efbd WD |
190 | } |
191 | #endif | |
192 | ||
193 | struct ct_desc ct_ca9x4_desc __initdata = { | |
194 | .id = V2M_CT_ID_CA9, | |
195 | .name = "CA9x4", | |
fef88f10 | 196 | .map_io = ct_ca9x4_map_io, |
80b5efbd WD |
197 | .init_irq = ct_ca9x4_init_irq, |
198 | .init_tile = ct_ca9x4_init, | |
199 | #ifdef CONFIG_SMP | |
200 | .init_cpu_map = ct_ca9x4_init_cpu_map, | |
201 | .smp_enable = ct_ca9x4_smp_enable, | |
fef88f10 | 202 | #endif |
80b5efbd | 203 | }; |