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 | ||
3b9334ac PM |
131 | static struct clk_lookup osc1_lookup = { |
132 | .dev_id = "ct:clcd", | |
133 | }; | |
134 | ||
38669e04 PM |
135 | static struct platform_device osc1_device = { |
136 | .name = "vexpress-osc", | |
137 | .id = 1, | |
138 | .num_resources = 1, | |
139 | .resource = (struct resource []) { | |
140 | VEXPRESS_RES_FUNC(0xf, 1), | |
141 | }, | |
3b9334ac | 142 | .dev.platform_data = &osc1_lookup, |
38669e04 PM |
143 | }; |
144 | ||
cdaf9a2f | 145 | static void __init ct_ca9x4_init(void) |
fef88f10 RK |
146 | { |
147 | int i; | |
148 | ||
149 | #ifdef CONFIG_CACHE_L2X0 | |
98ed4ceb | 150 | void __iomem *l2x0_base = ioremap(CT_CA9X4_L2CC, SZ_4K); |
2de59fea WD |
151 | |
152 | /* set RAM latencies to 1 cycle for this core tile. */ | |
153 | writel(0, l2x0_base + L2X0_TAG_LATENCY_CTRL); | |
154 | writel(0, l2x0_base + L2X0_DATA_LATENCY_CTRL); | |
155 | ||
156 | l2x0_init(l2x0_base, 0x00400000, 0xfe0fffff); | |
fef88f10 RK |
157 | #endif |
158 | ||
fef88f10 RK |
159 | for (i = 0; i < ARRAY_SIZE(ct_ca9x4_amba_devs); i++) |
160 | amba_device_register(ct_ca9x4_amba_devs[i], &iomem_resource); | |
f417cbad WD |
161 | |
162 | platform_device_register(&pmu_device); | |
3b9334ac | 163 | vexpress_sysreg_config_device_register(&osc1_device); |
fef88f10 RK |
164 | } |
165 | ||
80b5efbd | 166 | #ifdef CONFIG_SMP |
98ed4ceb PM |
167 | static void *ct_ca9x4_scu_base __initdata; |
168 | ||
94ae0275 | 169 | static void __init ct_ca9x4_init_cpu_map(void) |
80b5efbd | 170 | { |
98ed4ceb PM |
171 | int i, ncores; |
172 | ||
173 | ct_ca9x4_scu_base = ioremap(A9_MPCORE_SCU, SZ_128); | |
174 | if (WARN_ON(!ct_ca9x4_scu_base)) | |
175 | return; | |
176 | ||
177 | ncores = scu_get_core_count(ct_ca9x4_scu_base); | |
80b5efbd | 178 | |
a06f916b RK |
179 | if (ncores > nr_cpu_ids) { |
180 | pr_warn("SMP: %u cores greater than maximum (%u), clipping\n", | |
181 | ncores, nr_cpu_ids); | |
182 | ncores = nr_cpu_ids; | |
183 | } | |
184 | ||
80b5efbd WD |
185 | for (i = 0; i < ncores; ++i) |
186 | set_cpu_possible(i, true); | |
187 | } | |
188 | ||
94ae0275 | 189 | static void __init ct_ca9x4_smp_enable(unsigned int max_cpus) |
80b5efbd | 190 | { |
98ed4ceb | 191 | scu_enable(ct_ca9x4_scu_base); |
80b5efbd WD |
192 | } |
193 | #endif | |
194 | ||
195 | struct ct_desc ct_ca9x4_desc __initdata = { | |
196 | .id = V2M_CT_ID_CA9, | |
197 | .name = "CA9x4", | |
fef88f10 | 198 | .map_io = ct_ca9x4_map_io, |
80b5efbd WD |
199 | .init_irq = ct_ca9x4_init_irq, |
200 | .init_tile = ct_ca9x4_init, | |
201 | #ifdef CONFIG_SMP | |
202 | .init_cpu_map = ct_ca9x4_init_cpu_map, | |
203 | .smp_enable = ct_ca9x4_smp_enable, | |
fef88f10 | 204 | #endif |
80b5efbd | 205 | }; |