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)); |
fef88f10 RK |
45 | } |
46 | ||
7c380f27 MZ |
47 | #ifdef CONFIG_HAVE_ARM_TWD |
48 | static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, A9_MPCORE_TWD, IRQ_LOCALTIMER); | |
49 | ||
50 | static void __init ca9x4_twd_init(void) | |
51 | { | |
52 | int err = twd_local_timer_register(&twd_local_timer); | |
53 | if (err) | |
54 | pr_err("twd_local_timer_register failed %d\n", err); | |
55 | } | |
56 | #else | |
57 | #define ca9x4_twd_init() do {} while(0) | |
58 | #endif | |
59 | ||
fef88f10 RK |
60 | static void __init ct_ca9x4_init_irq(void) |
61 | { | |
98ed4ceb PM |
62 | gic_init(0, 29, ioremap(A9_MPCORE_GIC_DIST, SZ_4K), |
63 | ioremap(A9_MPCORE_GIC_CPU, SZ_256)); | |
7c380f27 | 64 | ca9x4_twd_init(); |
fef88f10 RK |
65 | } |
66 | ||
fef88f10 RK |
67 | static void ct_ca9x4_clcd_enable(struct clcd_fb *fb) |
68 | { | |
d927daf5 PM |
69 | u32 site = v2m_get_master_site(); |
70 | ||
71 | /* | |
72 | * Old firmware was using the "site" component of the command | |
73 | * to control the DVI muxer (while it should be always 0 ie. MB). | |
74 | * Newer firmware uses the data register. Keep both for compatibility. | |
75 | */ | |
76 | v2m_cfg_write(SYS_CFG_MUXFPGA | SYS_CFG_SITE(site), site); | |
77 | v2m_cfg_write(SYS_CFG_DVIMODE | SYS_CFG_SITE(SYS_CFG_SITE_MB), 2); | |
fef88f10 RK |
78 | } |
79 | ||
80 | static int ct_ca9x4_clcd_setup(struct clcd_fb *fb) | |
81 | { | |
82 | unsigned long framesize = 1024 * 768 * 2; | |
fef88f10 | 83 | |
0fb44b91 RK |
84 | fb->panel = versatile_clcd_get_panel("XVGA"); |
85 | if (!fb->panel) | |
86 | return -EINVAL; | |
fef88f10 | 87 | |
0fb44b91 | 88 | return versatile_clcd_setup_dma(fb, framesize); |
fef88f10 RK |
89 | } |
90 | ||
91 | static struct clcd_board ct_ca9x4_clcd_data = { | |
92 | .name = "CT-CA9X4", | |
0fb44b91 | 93 | .caps = CLCD_CAP_5551 | CLCD_CAP_565, |
fef88f10 RK |
94 | .check = clcdfb_check, |
95 | .decode = clcdfb_decode, | |
96 | .enable = ct_ca9x4_clcd_enable, | |
97 | .setup = ct_ca9x4_clcd_setup, | |
0fb44b91 RK |
98 | .mmap = versatile_clcd_mmap_dma, |
99 | .remove = versatile_clcd_remove_dma, | |
fef88f10 RK |
100 | }; |
101 | ||
cdd4e1a7 RK |
102 | static AMBA_AHB_DEVICE(clcd, "ct:clcd", 0, CT_CA9X4_CLCDC, IRQ_CT_CA9X4_CLCDC, &ct_ca9x4_clcd_data); |
103 | static AMBA_APB_DEVICE(dmc, "ct:dmc", 0, CT_CA9X4_DMC, IRQ_CT_CA9X4_DMC, NULL); | |
104 | static AMBA_APB_DEVICE(smc, "ct:smc", 0, CT_CA9X4_SMC, IRQ_CT_CA9X4_SMC, NULL); | |
105 | static AMBA_APB_DEVICE(gpio, "ct:gpio", 0, CT_CA9X4_GPIO, IRQ_CT_CA9X4_GPIO, NULL); | |
fef88f10 RK |
106 | |
107 | static struct amba_device *ct_ca9x4_amba_devs[] __initdata = { | |
108 | &clcd_device, | |
109 | &dmc_device, | |
110 | &smc_device, | |
111 | &gpio_device, | |
112 | }; | |
113 | ||
114 | ||
d1b8a775 PM |
115 | static struct v2m_osc ct_osc1 = { |
116 | .osc = 1, | |
117 | .rate_min = 10000000, | |
118 | .rate_max = 80000000, | |
119 | .rate_default = 23750000, | |
fef88f10 RK |
120 | }; |
121 | ||
f417cbad WD |
122 | static struct resource pmu_resources[] = { |
123 | [0] = { | |
124 | .start = IRQ_CT_CA9X4_PMU_CPU0, | |
125 | .end = IRQ_CT_CA9X4_PMU_CPU0, | |
126 | .flags = IORESOURCE_IRQ, | |
127 | }, | |
128 | [1] = { | |
129 | .start = IRQ_CT_CA9X4_PMU_CPU1, | |
130 | .end = IRQ_CT_CA9X4_PMU_CPU1, | |
131 | .flags = IORESOURCE_IRQ, | |
132 | }, | |
133 | [2] = { | |
134 | .start = IRQ_CT_CA9X4_PMU_CPU2, | |
135 | .end = IRQ_CT_CA9X4_PMU_CPU2, | |
136 | .flags = IORESOURCE_IRQ, | |
137 | }, | |
138 | [3] = { | |
139 | .start = IRQ_CT_CA9X4_PMU_CPU3, | |
140 | .end = IRQ_CT_CA9X4_PMU_CPU3, | |
141 | .flags = IORESOURCE_IRQ, | |
142 | }, | |
143 | }; | |
144 | ||
145 | static struct platform_device pmu_device = { | |
146 | .name = "arm-pmu", | |
147 | .id = ARM_PMU_DEVICE_CPU, | |
148 | .num_resources = ARRAY_SIZE(pmu_resources), | |
149 | .resource = pmu_resources, | |
150 | }; | |
151 | ||
cdaf9a2f | 152 | static void __init ct_ca9x4_init(void) |
fef88f10 RK |
153 | { |
154 | int i; | |
d1b8a775 | 155 | struct clk *clk; |
fef88f10 RK |
156 | |
157 | #ifdef CONFIG_CACHE_L2X0 | |
98ed4ceb | 158 | void __iomem *l2x0_base = ioremap(CT_CA9X4_L2CC, SZ_4K); |
2de59fea WD |
159 | |
160 | /* set RAM latencies to 1 cycle for this core tile. */ | |
161 | writel(0, l2x0_base + L2X0_TAG_LATENCY_CTRL); | |
162 | writel(0, l2x0_base + L2X0_DATA_LATENCY_CTRL); | |
163 | ||
164 | l2x0_init(l2x0_base, 0x00400000, 0xfe0fffff); | |
fef88f10 RK |
165 | #endif |
166 | ||
d1b8a775 PM |
167 | ct_osc1.site = v2m_get_master_site(); |
168 | clk = v2m_osc_register("ct:osc1", &ct_osc1); | |
169 | clk_register_clkdev(clk, NULL, "ct:clcd"); | |
170 | ||
fef88f10 RK |
171 | for (i = 0; i < ARRAY_SIZE(ct_ca9x4_amba_devs); i++) |
172 | amba_device_register(ct_ca9x4_amba_devs[i], &iomem_resource); | |
f417cbad WD |
173 | |
174 | platform_device_register(&pmu_device); | |
fef88f10 RK |
175 | } |
176 | ||
80b5efbd | 177 | #ifdef CONFIG_SMP |
98ed4ceb PM |
178 | static void *ct_ca9x4_scu_base __initdata; |
179 | ||
94ae0275 | 180 | static void __init ct_ca9x4_init_cpu_map(void) |
80b5efbd | 181 | { |
98ed4ceb PM |
182 | int i, ncores; |
183 | ||
184 | ct_ca9x4_scu_base = ioremap(A9_MPCORE_SCU, SZ_128); | |
185 | if (WARN_ON(!ct_ca9x4_scu_base)) | |
186 | return; | |
187 | ||
188 | ncores = scu_get_core_count(ct_ca9x4_scu_base); | |
80b5efbd | 189 | |
a06f916b RK |
190 | if (ncores > nr_cpu_ids) { |
191 | pr_warn("SMP: %u cores greater than maximum (%u), clipping\n", | |
192 | ncores, nr_cpu_ids); | |
193 | ncores = nr_cpu_ids; | |
194 | } | |
195 | ||
80b5efbd WD |
196 | for (i = 0; i < ncores; ++i) |
197 | set_cpu_possible(i, true); | |
0f7b332f RK |
198 | |
199 | set_smp_cross_call(gic_raise_softirq); | |
80b5efbd WD |
200 | } |
201 | ||
94ae0275 | 202 | static void __init ct_ca9x4_smp_enable(unsigned int max_cpus) |
80b5efbd | 203 | { |
98ed4ceb | 204 | scu_enable(ct_ca9x4_scu_base); |
80b5efbd WD |
205 | } |
206 | #endif | |
207 | ||
208 | struct ct_desc ct_ca9x4_desc __initdata = { | |
209 | .id = V2M_CT_ID_CA9, | |
210 | .name = "CA9x4", | |
fef88f10 | 211 | .map_io = ct_ca9x4_map_io, |
80b5efbd WD |
212 | .init_irq = ct_ca9x4_init_irq, |
213 | .init_tile = ct_ca9x4_init, | |
214 | #ifdef CONFIG_SMP | |
215 | .init_cpu_map = ct_ca9x4_init_cpu_map, | |
216 | .smp_enable = ct_ca9x4_smp_enable, | |
fef88f10 | 217 | #endif |
80b5efbd | 218 | }; |