Merge branch 'imx-for-2.6.38' of git://git.pengutronix.de/git/ukl/linux-2.6 into...
[pandora-kernel.git] / arch / mips / cavium-octeon / octeon-platform.c
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  *
6  * Copyright (C) 2004-2010 Cavium Networks
7  * Copyright (C) 2008 Wind River Systems
8  */
9
10 #include <linux/init.h>
11 #include <linux/irq.h>
12 #include <linux/i2c.h>
13 #include <linux/usb.h>
14 #include <linux/dma-mapping.h>
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
78                 /* Asume that CS1 immediately follows. */
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
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);
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++) {
203                 octeon_i2c_data[port].sys_freq = octeon_get_io_clock_rate();
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
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
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                 }
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
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
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
443 MODULE_AUTHOR("David Daney <ddaney@caviumnetworks.com>");
444 MODULE_LICENSE("GPL");
445 MODULE_DESCRIPTION("Platform driver for Octeon SOC");