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> |
fef88f10 | 12 | |
fef88f10 RK |
13 | #include <asm/hardware/arm_timer.h> |
14 | #include <asm/hardware/cache-l2x0.h> | |
15 | #include <asm/hardware/gic.h> | |
f417cbad | 16 | #include <asm/pmu.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> | |
30 | ||
0fb44b91 RK |
31 | #include <plat/clcd.h> |
32 | ||
fef88f10 RK |
33 | static struct map_desc ct_ca9x4_io_desc[] __initdata = { |
34 | { | |
98ed4ceb PM |
35 | .virtual = V2T_PERIPH, |
36 | .pfn = __phys_to_pfn(CT_CA9X4_MPIC), | |
37 | .length = SZ_8K, | |
38 | .type = MT_DEVICE, | |
fef88f10 RK |
39 | }, |
40 | }; | |
41 | ||
42 | static void __init ct_ca9x4_map_io(void) | |
43 | { | |
98ed4ceb | 44 | iotable_init(ct_ca9x4_io_desc, ARRAY_SIZE(ct_ca9x4_io_desc)); |
e56c010f | 45 | #ifdef CONFIG_LOCAL_TIMERS |
98ed4ceb | 46 | twd_base = ioremap(A9_MPCORE_TWD, SZ_32); |
e56c010f | 47 | #endif |
fef88f10 RK |
48 | } |
49 | ||
fef88f10 RK |
50 | static void __init ct_ca9x4_init_irq(void) |
51 | { | |
98ed4ceb PM |
52 | gic_init(0, 29, ioremap(A9_MPCORE_GIC_DIST, SZ_4K), |
53 | ioremap(A9_MPCORE_GIC_CPU, SZ_256)); | |
fef88f10 RK |
54 | } |
55 | ||
fef88f10 RK |
56 | static void ct_ca9x4_clcd_enable(struct clcd_fb *fb) |
57 | { | |
58 | v2m_cfg_write(SYS_CFG_MUXFPGA | SYS_CFG_SITE_DB1, 0); | |
59 | v2m_cfg_write(SYS_CFG_DVIMODE | SYS_CFG_SITE_DB1, 2); | |
60 | } | |
61 | ||
62 | static int ct_ca9x4_clcd_setup(struct clcd_fb *fb) | |
63 | { | |
64 | unsigned long framesize = 1024 * 768 * 2; | |
fef88f10 | 65 | |
0fb44b91 RK |
66 | fb->panel = versatile_clcd_get_panel("XVGA"); |
67 | if (!fb->panel) | |
68 | return -EINVAL; | |
fef88f10 | 69 | |
0fb44b91 | 70 | return versatile_clcd_setup_dma(fb, framesize); |
fef88f10 RK |
71 | } |
72 | ||
73 | static struct clcd_board ct_ca9x4_clcd_data = { | |
74 | .name = "CT-CA9X4", | |
0fb44b91 | 75 | .caps = CLCD_CAP_5551 | CLCD_CAP_565, |
fef88f10 RK |
76 | .check = clcdfb_check, |
77 | .decode = clcdfb_decode, | |
78 | .enable = ct_ca9x4_clcd_enable, | |
79 | .setup = ct_ca9x4_clcd_setup, | |
0fb44b91 RK |
80 | .mmap = versatile_clcd_mmap_dma, |
81 | .remove = versatile_clcd_remove_dma, | |
fef88f10 RK |
82 | }; |
83 | ||
84 | static AMBA_DEVICE(clcd, "ct:clcd", CT_CA9X4_CLCDC, &ct_ca9x4_clcd_data); | |
85 | static AMBA_DEVICE(dmc, "ct:dmc", CT_CA9X4_DMC, NULL); | |
86 | static AMBA_DEVICE(smc, "ct:smc", CT_CA9X4_SMC, NULL); | |
87 | static AMBA_DEVICE(gpio, "ct:gpio", CT_CA9X4_GPIO, NULL); | |
88 | ||
89 | static struct amba_device *ct_ca9x4_amba_devs[] __initdata = { | |
90 | &clcd_device, | |
91 | &dmc_device, | |
92 | &smc_device, | |
93 | &gpio_device, | |
94 | }; | |
95 | ||
96 | ||
97 | static long ct_round(struct clk *clk, unsigned long rate) | |
98 | { | |
99 | return rate; | |
100 | } | |
101 | ||
102 | static int ct_set(struct clk *clk, unsigned long rate) | |
103 | { | |
104 | return v2m_cfg_write(SYS_CFG_OSC | SYS_CFG_SITE_DB1 | 1, rate); | |
105 | } | |
106 | ||
107 | static const struct clk_ops osc1_clk_ops = { | |
108 | .round = ct_round, | |
109 | .set = ct_set, | |
110 | }; | |
111 | ||
112 | static struct clk osc1_clk = { | |
113 | .ops = &osc1_clk_ops, | |
114 | .rate = 24000000, | |
115 | }; | |
116 | ||
7ff550de RK |
117 | static struct clk ct_sp804_clk = { |
118 | .rate = 1000000, | |
119 | }; | |
120 | ||
fef88f10 RK |
121 | static struct clk_lookup lookups[] = { |
122 | { /* CLCD */ | |
123 | .dev_id = "ct:clcd", | |
124 | .clk = &osc1_clk, | |
23828a7a RK |
125 | }, { /* SP804 timers */ |
126 | .dev_id = "sp804", | |
127 | .con_id = "ct-timer0", | |
128 | .clk = &ct_sp804_clk, | |
7ff550de RK |
129 | }, { /* SP804 timers */ |
130 | .dev_id = "sp804", | |
131 | .con_id = "ct-timer1", | |
132 | .clk = &ct_sp804_clk, | |
fef88f10 RK |
133 | }, |
134 | }; | |
135 | ||
f417cbad WD |
136 | static struct resource pmu_resources[] = { |
137 | [0] = { | |
138 | .start = IRQ_CT_CA9X4_PMU_CPU0, | |
139 | .end = IRQ_CT_CA9X4_PMU_CPU0, | |
140 | .flags = IORESOURCE_IRQ, | |
141 | }, | |
142 | [1] = { | |
143 | .start = IRQ_CT_CA9X4_PMU_CPU1, | |
144 | .end = IRQ_CT_CA9X4_PMU_CPU1, | |
145 | .flags = IORESOURCE_IRQ, | |
146 | }, | |
147 | [2] = { | |
148 | .start = IRQ_CT_CA9X4_PMU_CPU2, | |
149 | .end = IRQ_CT_CA9X4_PMU_CPU2, | |
150 | .flags = IORESOURCE_IRQ, | |
151 | }, | |
152 | [3] = { | |
153 | .start = IRQ_CT_CA9X4_PMU_CPU3, | |
154 | .end = IRQ_CT_CA9X4_PMU_CPU3, | |
155 | .flags = IORESOURCE_IRQ, | |
156 | }, | |
157 | }; | |
158 | ||
159 | static struct platform_device pmu_device = { | |
160 | .name = "arm-pmu", | |
161 | .id = ARM_PMU_DEVICE_CPU, | |
162 | .num_resources = ARRAY_SIZE(pmu_resources), | |
163 | .resource = pmu_resources, | |
164 | }; | |
165 | ||
493a451b RK |
166 | static void __init ct_ca9x4_init_early(void) |
167 | { | |
168 | clkdev_add_table(lookups, ARRAY_SIZE(lookups)); | |
493a451b RK |
169 | } |
170 | ||
cdaf9a2f | 171 | static void __init ct_ca9x4_init(void) |
fef88f10 RK |
172 | { |
173 | int i; | |
174 | ||
175 | #ifdef CONFIG_CACHE_L2X0 | |
98ed4ceb | 176 | void __iomem *l2x0_base = ioremap(CT_CA9X4_L2CC, SZ_4K); |
2de59fea WD |
177 | |
178 | /* set RAM latencies to 1 cycle for this core tile. */ | |
179 | writel(0, l2x0_base + L2X0_TAG_LATENCY_CTRL); | |
180 | writel(0, l2x0_base + L2X0_DATA_LATENCY_CTRL); | |
181 | ||
182 | l2x0_init(l2x0_base, 0x00400000, 0xfe0fffff); | |
fef88f10 RK |
183 | #endif |
184 | ||
fef88f10 RK |
185 | for (i = 0; i < ARRAY_SIZE(ct_ca9x4_amba_devs); i++) |
186 | amba_device_register(ct_ca9x4_amba_devs[i], &iomem_resource); | |
f417cbad WD |
187 | |
188 | platform_device_register(&pmu_device); | |
fef88f10 RK |
189 | } |
190 | ||
80b5efbd | 191 | #ifdef CONFIG_SMP |
98ed4ceb PM |
192 | static void *ct_ca9x4_scu_base __initdata; |
193 | ||
94ae0275 | 194 | static void __init ct_ca9x4_init_cpu_map(void) |
80b5efbd | 195 | { |
98ed4ceb PM |
196 | int i, ncores; |
197 | ||
198 | ct_ca9x4_scu_base = ioremap(A9_MPCORE_SCU, SZ_128); | |
199 | if (WARN_ON(!ct_ca9x4_scu_base)) | |
200 | return; | |
201 | ||
202 | ncores = scu_get_core_count(ct_ca9x4_scu_base); | |
80b5efbd | 203 | |
a06f916b RK |
204 | if (ncores > nr_cpu_ids) { |
205 | pr_warn("SMP: %u cores greater than maximum (%u), clipping\n", | |
206 | ncores, nr_cpu_ids); | |
207 | ncores = nr_cpu_ids; | |
208 | } | |
209 | ||
80b5efbd WD |
210 | for (i = 0; i < ncores; ++i) |
211 | set_cpu_possible(i, true); | |
0f7b332f RK |
212 | |
213 | set_smp_cross_call(gic_raise_softirq); | |
80b5efbd WD |
214 | } |
215 | ||
94ae0275 | 216 | static void __init ct_ca9x4_smp_enable(unsigned int max_cpus) |
80b5efbd | 217 | { |
98ed4ceb | 218 | scu_enable(ct_ca9x4_scu_base); |
80b5efbd WD |
219 | } |
220 | #endif | |
221 | ||
222 | struct ct_desc ct_ca9x4_desc __initdata = { | |
223 | .id = V2M_CT_ID_CA9, | |
224 | .name = "CA9x4", | |
fef88f10 | 225 | .map_io = ct_ca9x4_map_io, |
493a451b | 226 | .init_early = ct_ca9x4_init_early, |
80b5efbd WD |
227 | .init_irq = ct_ca9x4_init_irq, |
228 | .init_tile = ct_ca9x4_init, | |
229 | #ifdef CONFIG_SMP | |
230 | .init_cpu_map = ct_ca9x4_init_cpu_map, | |
231 | .smp_enable = ct_ca9x4_smp_enable, | |
fef88f10 | 232 | #endif |
80b5efbd | 233 | }; |