]>
Commit | Line | Data |
---|---|---|
512254ba DD |
1 | /* |
2 | * This file is subject to the terms and conditions of the GNU General Public | |
3 | * License. See the file "COPYING" in the main directory of this archive | |
4 | * for more details. | |
5 | * | |
340fbb8b | 6 | * Copyright (C) 2004-2010 Cavium Networks |
512254ba DD |
7 | * Copyright (C) 2008 Wind River Systems |
8 | */ | |
9 | ||
10 | #include <linux/init.h> | |
11 | #include <linux/irq.h> | |
d9577054 | 12 | #include <linux/i2c.h> |
340fbb8b | 13 | #include <linux/usb.h> |
f1299072 | 14 | #include <linux/dma-mapping.h> |
512254ba DD |
15 | #include <linux/module.h> |
16 | #include <linux/platform_device.h> | |
17 | ||
18 | #include <asm/octeon/octeon.h> | |
19 | #include <asm/octeon/cvmx-rnm-defs.h> | |
20 | ||
21 | static struct octeon_cf_data octeon_cf_data; | |
22 | ||
23 | static int __init octeon_cf_device_init(void) | |
24 | { | |
25 | union cvmx_mio_boot_reg_cfgx mio_boot_reg_cfg; | |
26 | unsigned long base_ptr, region_base, region_size; | |
27 | struct platform_device *pd; | |
28 | struct resource cf_resources[3]; | |
29 | unsigned int num_resources; | |
30 | int i; | |
31 | int ret = 0; | |
32 | ||
33 | /* Setup octeon-cf platform device if present. */ | |
34 | base_ptr = 0; | |
35 | if (octeon_bootinfo->major_version == 1 | |
36 | && octeon_bootinfo->minor_version >= 1) { | |
37 | if (octeon_bootinfo->compact_flash_common_base_addr) | |
38 | base_ptr = | |
39 | octeon_bootinfo->compact_flash_common_base_addr; | |
40 | } else { | |
41 | base_ptr = 0x1d000800; | |
42 | } | |
43 | ||
44 | if (!base_ptr) | |
45 | return ret; | |
46 | ||
47 | /* Find CS0 region. */ | |
48 | for (i = 0; i < 8; i++) { | |
49 | mio_boot_reg_cfg.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(i)); | |
50 | region_base = mio_boot_reg_cfg.s.base << 16; | |
51 | region_size = (mio_boot_reg_cfg.s.size + 1) << 16; | |
52 | if (mio_boot_reg_cfg.s.en && base_ptr >= region_base | |
53 | && base_ptr < region_base + region_size) | |
54 | break; | |
55 | } | |
56 | if (i >= 7) { | |
57 | /* i and i + 1 are CS0 and CS1, both must be less than 8. */ | |
58 | goto out; | |
59 | } | |
60 | octeon_cf_data.base_region = i; | |
61 | octeon_cf_data.is16bit = mio_boot_reg_cfg.s.width; | |
62 | octeon_cf_data.base_region_bias = base_ptr - region_base; | |
63 | memset(cf_resources, 0, sizeof(cf_resources)); | |
64 | num_resources = 0; | |
65 | cf_resources[num_resources].flags = IORESOURCE_MEM; | |
66 | cf_resources[num_resources].start = region_base; | |
67 | cf_resources[num_resources].end = region_base + region_size - 1; | |
68 | num_resources++; | |
69 | ||
70 | ||
71 | if (!(base_ptr & 0xfffful)) { | |
72 | /* | |
73 | * Boot loader signals availability of DMA (true_ide | |
74 | * mode) by setting low order bits of base_ptr to | |
75 | * zero. | |
76 | */ | |
77 | ||
25985edc | 78 | /* Assume that CS1 immediately follows. */ |
512254ba DD |
79 | mio_boot_reg_cfg.u64 = |
80 | cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(i + 1)); | |
81 | region_base = mio_boot_reg_cfg.s.base << 16; | |
82 | region_size = (mio_boot_reg_cfg.s.size + 1) << 16; | |
83 | if (!mio_boot_reg_cfg.s.en) | |
84 | goto out; | |
85 | ||
86 | cf_resources[num_resources].flags = IORESOURCE_MEM; | |
87 | cf_resources[num_resources].start = region_base; | |
88 | cf_resources[num_resources].end = region_base + region_size - 1; | |
89 | num_resources++; | |
90 | ||
91 | octeon_cf_data.dma_engine = 0; | |
92 | cf_resources[num_resources].flags = IORESOURCE_IRQ; | |
93 | cf_resources[num_resources].start = OCTEON_IRQ_BOOTDMA; | |
94 | cf_resources[num_resources].end = OCTEON_IRQ_BOOTDMA; | |
95 | num_resources++; | |
96 | } else { | |
97 | octeon_cf_data.dma_engine = -1; | |
98 | } | |
99 | ||
100 | pd = platform_device_alloc("pata_octeon_cf", -1); | |
101 | if (!pd) { | |
102 | ret = -ENOMEM; | |
103 | goto out; | |
104 | } | |
105 | pd->dev.platform_data = &octeon_cf_data; | |
106 | ||
107 | ret = platform_device_add_resources(pd, cf_resources, num_resources); | |
108 | if (ret) | |
109 | goto fail; | |
110 | ||
111 | ret = platform_device_add(pd); | |
112 | if (ret) | |
113 | goto fail; | |
114 | ||
115 | return ret; | |
116 | fail: | |
117 | platform_device_put(pd); | |
118 | out: | |
119 | return ret; | |
120 | } | |
121 | device_initcall(octeon_cf_device_init); | |
122 | ||
123 | /* Octeon Random Number Generator. */ | |
124 | static int __init octeon_rng_device_init(void) | |
125 | { | |
126 | struct platform_device *pd; | |
127 | int ret = 0; | |
128 | ||
129 | struct resource rng_resources[] = { | |
130 | { | |
131 | .flags = IORESOURCE_MEM, | |
132 | .start = XKPHYS_TO_PHYS(CVMX_RNM_CTL_STATUS), | |
133 | .end = XKPHYS_TO_PHYS(CVMX_RNM_CTL_STATUS) + 0xf | |
134 | }, { | |
135 | .flags = IORESOURCE_MEM, | |
136 | .start = cvmx_build_io_address(8, 0), | |
137 | .end = cvmx_build_io_address(8, 0) + 0x7 | |
138 | } | |
139 | }; | |
140 | ||
141 | pd = platform_device_alloc("octeon_rng", -1); | |
142 | if (!pd) { | |
143 | ret = -ENOMEM; | |
144 | goto out; | |
145 | } | |
146 | ||
147 | ret = platform_device_add_resources(pd, rng_resources, | |
148 | ARRAY_SIZE(rng_resources)); | |
149 | if (ret) | |
150 | goto fail; | |
151 | ||
152 | ret = platform_device_add(pd); | |
153 | if (ret) | |
154 | goto fail; | |
155 | ||
156 | return ret; | |
157 | fail: | |
158 | platform_device_put(pd); | |
159 | ||
160 | out: | |
161 | return ret; | |
162 | } | |
163 | device_initcall(octeon_rng_device_init); | |
164 | ||
d9577054 DD |
165 | static struct i2c_board_info __initdata octeon_i2c_devices[] = { |
166 | { | |
167 | I2C_BOARD_INFO("ds1337", 0x68), | |
168 | }, | |
169 | }; | |
170 | ||
171 | static int __init octeon_i2c_devices_init(void) | |
172 | { | |
173 | return i2c_register_board_info(0, octeon_i2c_devices, | |
174 | ARRAY_SIZE(octeon_i2c_devices)); | |
175 | } | |
176 | arch_initcall(octeon_i2c_devices_init); | |
f41c3c1b DD |
177 | |
178 | #define OCTEON_I2C_IO_BASE 0x1180000001000ull | |
179 | #define OCTEON_I2C_IO_UNIT_OFFSET 0x200 | |
180 | ||
181 | static struct octeon_i2c_data octeon_i2c_data[2]; | |
182 | ||
183 | static int __init octeon_i2c_device_init(void) | |
184 | { | |
185 | struct platform_device *pd; | |
186 | int ret = 0; | |
187 | int port, num_ports; | |
188 | ||
189 | struct resource i2c_resources[] = { | |
190 | { | |
191 | .flags = IORESOURCE_MEM, | |
192 | }, { | |
193 | .flags = IORESOURCE_IRQ, | |
194 | } | |
195 | }; | |
196 | ||
197 | if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN52XX)) | |
198 | num_ports = 2; | |
199 | else | |
200 | num_ports = 1; | |
201 | ||
202 | for (port = 0; port < num_ports; port++) { | |
4b8bca70 | 203 | octeon_i2c_data[port].sys_freq = octeon_get_io_clock_rate(); |
f41c3c1b DD |
204 | /*FIXME: should be examined. At the moment is set for 100Khz */ |
205 | octeon_i2c_data[port].i2c_freq = 100000; | |
206 | ||
207 | pd = platform_device_alloc("i2c-octeon", port); | |
208 | if (!pd) { | |
209 | ret = -ENOMEM; | |
210 | goto out; | |
211 | } | |
212 | ||
213 | pd->dev.platform_data = octeon_i2c_data + port; | |
214 | ||
215 | i2c_resources[0].start = | |
216 | OCTEON_I2C_IO_BASE + (port * OCTEON_I2C_IO_UNIT_OFFSET); | |
217 | i2c_resources[0].end = i2c_resources[0].start + 0x1f; | |
218 | switch (port) { | |
219 | case 0: | |
220 | i2c_resources[1].start = OCTEON_IRQ_TWSI; | |
221 | i2c_resources[1].end = OCTEON_IRQ_TWSI; | |
222 | break; | |
223 | case 1: | |
224 | i2c_resources[1].start = OCTEON_IRQ_TWSI2; | |
225 | i2c_resources[1].end = OCTEON_IRQ_TWSI2; | |
226 | break; | |
227 | default: | |
228 | BUG(); | |
229 | } | |
230 | ||
231 | ret = platform_device_add_resources(pd, | |
232 | i2c_resources, | |
233 | ARRAY_SIZE(i2c_resources)); | |
234 | if (ret) | |
235 | goto fail; | |
236 | ||
237 | ret = platform_device_add(pd); | |
238 | if (ret) | |
239 | goto fail; | |
240 | } | |
241 | return ret; | |
242 | fail: | |
243 | platform_device_put(pd); | |
244 | out: | |
245 | return ret; | |
246 | } | |
247 | device_initcall(octeon_i2c_device_init); | |
248 | ||
0f7e64a3 DD |
249 | /* Octeon SMI/MDIO interface. */ |
250 | static int __init octeon_mdiobus_device_init(void) | |
251 | { | |
252 | struct platform_device *pd; | |
253 | int ret = 0; | |
254 | ||
255 | if (octeon_is_simulation()) | |
256 | return 0; /* No mdio in the simulator. */ | |
257 | ||
258 | /* The bus number is the platform_device id. */ | |
259 | pd = platform_device_alloc("mdio-octeon", 0); | |
260 | if (!pd) { | |
261 | ret = -ENOMEM; | |
262 | goto out; | |
263 | } | |
264 | ||
265 | ret = platform_device_add(pd); | |
266 | if (ret) | |
267 | goto fail; | |
268 | ||
269 | return ret; | |
270 | fail: | |
271 | platform_device_put(pd); | |
272 | ||
273 | out: | |
274 | return ret; | |
275 | ||
276 | } | |
277 | device_initcall(octeon_mdiobus_device_init); | |
278 | ||
24479d9f DD |
279 | /* Octeon mgmt port Ethernet interface. */ |
280 | static int __init octeon_mgmt_device_init(void) | |
281 | { | |
282 | struct platform_device *pd; | |
283 | int ret = 0; | |
284 | int port, num_ports; | |
285 | ||
286 | struct resource mgmt_port_resource = { | |
287 | .flags = IORESOURCE_IRQ, | |
288 | .start = -1, | |
289 | .end = -1 | |
290 | }; | |
291 | ||
292 | if (!OCTEON_IS_MODEL(OCTEON_CN56XX) && !OCTEON_IS_MODEL(OCTEON_CN52XX)) | |
293 | return 0; | |
294 | ||
295 | if (OCTEON_IS_MODEL(OCTEON_CN56XX)) | |
296 | num_ports = 1; | |
297 | else | |
298 | num_ports = 2; | |
299 | ||
300 | for (port = 0; port < num_ports; port++) { | |
301 | pd = platform_device_alloc("octeon_mgmt", port); | |
302 | if (!pd) { | |
303 | ret = -ENOMEM; | |
304 | goto out; | |
305 | } | |
f1299072 DD |
306 | /* No DMA restrictions */ |
307 | pd->dev.coherent_dma_mask = DMA_BIT_MASK(64); | |
308 | pd->dev.dma_mask = &pd->dev.coherent_dma_mask; | |
309 | ||
24479d9f DD |
310 | switch (port) { |
311 | case 0: | |
312 | mgmt_port_resource.start = OCTEON_IRQ_MII0; | |
313 | break; | |
314 | case 1: | |
315 | mgmt_port_resource.start = OCTEON_IRQ_MII1; | |
316 | break; | |
317 | default: | |
318 | BUG(); | |
319 | } | |
320 | mgmt_port_resource.end = mgmt_port_resource.start; | |
321 | ||
322 | ret = platform_device_add_resources(pd, &mgmt_port_resource, 1); | |
323 | ||
324 | if (ret) | |
325 | goto fail; | |
326 | ||
327 | ret = platform_device_add(pd); | |
328 | if (ret) | |
329 | goto fail; | |
330 | } | |
331 | return ret; | |
332 | fail: | |
333 | platform_device_put(pd); | |
334 | ||
335 | out: | |
336 | return ret; | |
337 | ||
338 | } | |
339 | device_initcall(octeon_mgmt_device_init); | |
340 | ||
340fbb8b DD |
341 | #ifdef CONFIG_USB |
342 | ||
343 | static int __init octeon_ehci_device_init(void) | |
344 | { | |
345 | struct platform_device *pd; | |
346 | int ret = 0; | |
347 | ||
348 | struct resource usb_resources[] = { | |
349 | { | |
350 | .flags = IORESOURCE_MEM, | |
351 | }, { | |
352 | .flags = IORESOURCE_IRQ, | |
353 | } | |
354 | }; | |
355 | ||
356 | /* Only Octeon2 has ehci/ohci */ | |
357 | if (!OCTEON_IS_MODEL(OCTEON_CN63XX)) | |
358 | return 0; | |
359 | ||
360 | if (octeon_is_simulation() || usb_disabled()) | |
361 | return 0; /* No USB in the simulator. */ | |
362 | ||
363 | pd = platform_device_alloc("octeon-ehci", 0); | |
364 | if (!pd) { | |
365 | ret = -ENOMEM; | |
366 | goto out; | |
367 | } | |
368 | ||
369 | usb_resources[0].start = 0x00016F0000000000ULL; | |
370 | usb_resources[0].end = usb_resources[0].start + 0x100; | |
371 | ||
372 | usb_resources[1].start = OCTEON_IRQ_USB0; | |
373 | usb_resources[1].end = OCTEON_IRQ_USB0; | |
374 | ||
375 | ret = platform_device_add_resources(pd, usb_resources, | |
376 | ARRAY_SIZE(usb_resources)); | |
377 | if (ret) | |
378 | goto fail; | |
379 | ||
380 | ret = platform_device_add(pd); | |
381 | if (ret) | |
382 | goto fail; | |
383 | ||
384 | return ret; | |
385 | fail: | |
386 | platform_device_put(pd); | |
387 | out: | |
388 | return ret; | |
389 | } | |
390 | device_initcall(octeon_ehci_device_init); | |
391 | ||
392 | static int __init octeon_ohci_device_init(void) | |
393 | { | |
394 | struct platform_device *pd; | |
395 | int ret = 0; | |
396 | ||
397 | struct resource usb_resources[] = { | |
398 | { | |
399 | .flags = IORESOURCE_MEM, | |
400 | }, { | |
401 | .flags = IORESOURCE_IRQ, | |
402 | } | |
403 | }; | |
404 | ||
405 | /* Only Octeon2 has ehci/ohci */ | |
406 | if (!OCTEON_IS_MODEL(OCTEON_CN63XX)) | |
407 | return 0; | |
408 | ||
409 | if (octeon_is_simulation() || usb_disabled()) | |
410 | return 0; /* No USB in the simulator. */ | |
411 | ||
412 | pd = platform_device_alloc("octeon-ohci", 0); | |
413 | if (!pd) { | |
414 | ret = -ENOMEM; | |
415 | goto out; | |
416 | } | |
417 | ||
418 | usb_resources[0].start = 0x00016F0000000400ULL; | |
419 | usb_resources[0].end = usb_resources[0].start + 0x100; | |
420 | ||
421 | usb_resources[1].start = OCTEON_IRQ_USB0; | |
422 | usb_resources[1].end = OCTEON_IRQ_USB0; | |
423 | ||
424 | ret = platform_device_add_resources(pd, usb_resources, | |
425 | ARRAY_SIZE(usb_resources)); | |
426 | if (ret) | |
427 | goto fail; | |
428 | ||
429 | ret = platform_device_add(pd); | |
430 | if (ret) | |
431 | goto fail; | |
432 | ||
433 | return ret; | |
434 | fail: | |
435 | platform_device_put(pd); | |
436 | out: | |
437 | return ret; | |
438 | } | |
439 | device_initcall(octeon_ohci_device_init); | |
440 | ||
441 | #endif /* CONFIG_USB */ | |
442 | ||
512254ba DD |
443 | MODULE_AUTHOR("David Daney <ddaney@caviumnetworks.com>"); |
444 | MODULE_LICENSE("GPL"); | |
445 | MODULE_DESCRIPTION("Platform driver for Octeon SOC"); |