Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/teigland/dlm
[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-2009 Cavium Networks
7  * Copyright (C) 2008 Wind River Systems
8  */
9
10 #include <linux/init.h>
11 #include <linux/irq.h>
12 #include <linux/module.h>
13 #include <linux/platform_device.h>
14
15 #include <asm/octeon/octeon.h>
16 #include <asm/octeon/cvmx-rnm-defs.h>
17
18 static struct octeon_cf_data octeon_cf_data;
19
20 static int __init octeon_cf_device_init(void)
21 {
22         union cvmx_mio_boot_reg_cfgx mio_boot_reg_cfg;
23         unsigned long base_ptr, region_base, region_size;
24         struct platform_device *pd;
25         struct resource cf_resources[3];
26         unsigned int num_resources;
27         int i;
28         int ret = 0;
29
30         /* Setup octeon-cf platform device if present. */
31         base_ptr = 0;
32         if (octeon_bootinfo->major_version == 1
33                 && octeon_bootinfo->minor_version >= 1) {
34                 if (octeon_bootinfo->compact_flash_common_base_addr)
35                         base_ptr =
36                                 octeon_bootinfo->compact_flash_common_base_addr;
37         } else {
38                 base_ptr = 0x1d000800;
39         }
40
41         if (!base_ptr)
42                 return ret;
43
44         /* Find CS0 region. */
45         for (i = 0; i < 8; i++) {
46                 mio_boot_reg_cfg.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(i));
47                 region_base = mio_boot_reg_cfg.s.base << 16;
48                 region_size = (mio_boot_reg_cfg.s.size + 1) << 16;
49                 if (mio_boot_reg_cfg.s.en && base_ptr >= region_base
50                     && base_ptr < region_base + region_size)
51                         break;
52         }
53         if (i >= 7) {
54                 /* i and i + 1 are CS0 and CS1, both must be less than 8. */
55                 goto out;
56         }
57         octeon_cf_data.base_region = i;
58         octeon_cf_data.is16bit = mio_boot_reg_cfg.s.width;
59         octeon_cf_data.base_region_bias = base_ptr - region_base;
60         memset(cf_resources, 0, sizeof(cf_resources));
61         num_resources = 0;
62         cf_resources[num_resources].flags       = IORESOURCE_MEM;
63         cf_resources[num_resources].start       = region_base;
64         cf_resources[num_resources].end = region_base + region_size - 1;
65         num_resources++;
66
67
68         if (!(base_ptr & 0xfffful)) {
69                 /*
70                  * Boot loader signals availability of DMA (true_ide
71                  * mode) by setting low order bits of base_ptr to
72                  * zero.
73                  */
74
75                 /* Asume that CS1 immediately follows. */
76                 mio_boot_reg_cfg.u64 =
77                         cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(i + 1));
78                 region_base = mio_boot_reg_cfg.s.base << 16;
79                 region_size = (mio_boot_reg_cfg.s.size + 1) << 16;
80                 if (!mio_boot_reg_cfg.s.en)
81                         goto out;
82
83                 cf_resources[num_resources].flags       = IORESOURCE_MEM;
84                 cf_resources[num_resources].start       = region_base;
85                 cf_resources[num_resources].end = region_base + region_size - 1;
86                 num_resources++;
87
88                 octeon_cf_data.dma_engine = 0;
89                 cf_resources[num_resources].flags       = IORESOURCE_IRQ;
90                 cf_resources[num_resources].start       = OCTEON_IRQ_BOOTDMA;
91                 cf_resources[num_resources].end = OCTEON_IRQ_BOOTDMA;
92                 num_resources++;
93         } else {
94                 octeon_cf_data.dma_engine = -1;
95         }
96
97         pd = platform_device_alloc("pata_octeon_cf", -1);
98         if (!pd) {
99                 ret = -ENOMEM;
100                 goto out;
101         }
102         pd->dev.platform_data = &octeon_cf_data;
103
104         ret = platform_device_add_resources(pd, cf_resources, num_resources);
105         if (ret)
106                 goto fail;
107
108         ret = platform_device_add(pd);
109         if (ret)
110                 goto fail;
111
112         return ret;
113 fail:
114         platform_device_put(pd);
115 out:
116         return ret;
117 }
118 device_initcall(octeon_cf_device_init);
119
120 /* Octeon Random Number Generator.  */
121 static int __init octeon_rng_device_init(void)
122 {
123         struct platform_device *pd;
124         int ret = 0;
125
126         struct resource rng_resources[] = {
127                 {
128                         .flags  = IORESOURCE_MEM,
129                         .start  = XKPHYS_TO_PHYS(CVMX_RNM_CTL_STATUS),
130                         .end    = XKPHYS_TO_PHYS(CVMX_RNM_CTL_STATUS) + 0xf
131                 }, {
132                         .flags  = IORESOURCE_MEM,
133                         .start  = cvmx_build_io_address(8, 0),
134                         .end    = cvmx_build_io_address(8, 0) + 0x7
135                 }
136         };
137
138         pd = platform_device_alloc("octeon_rng", -1);
139         if (!pd) {
140                 ret = -ENOMEM;
141                 goto out;
142         }
143
144         ret = platform_device_add_resources(pd, rng_resources,
145                                             ARRAY_SIZE(rng_resources));
146         if (ret)
147                 goto fail;
148
149         ret = platform_device_add(pd);
150         if (ret)
151                 goto fail;
152
153         return ret;
154 fail:
155         platform_device_put(pd);
156
157 out:
158         return ret;
159 }
160 device_initcall(octeon_rng_device_init);
161
162 MODULE_AUTHOR("David Daney <ddaney@caviumnetworks.com>");
163 MODULE_LICENSE("GPL");
164 MODULE_DESCRIPTION("Platform driver for Octeon SOC");