49c33202843b2fb1d47814d93fd2bc014fea9e99
[linux-2.6.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/i2c.h>
13 #include <linux/dma-mapping.h>
14 #include <linux/module.h>
15 #include <linux/platform_device.h>
16
17 #include <asm/octeon/octeon.h>
18 #include <asm/octeon/cvmx-rnm-defs.h>
19
20 static struct octeon_cf_data octeon_cf_data;
21
22 static int __init octeon_cf_device_init(void)
23 {
24         union cvmx_mio_boot_reg_cfgx mio_boot_reg_cfg;
25         unsigned long base_ptr, region_base, region_size;
26         struct platform_device *pd;
27         struct resource cf_resources[3];
28         unsigned int num_resources;
29         int i;
30         int ret = 0;
31
32         /* Setup octeon-cf platform device if present. */
33         base_ptr = 0;
34         if (octeon_bootinfo->major_version == 1
35                 && octeon_bootinfo->minor_version >= 1) {
36                 if (octeon_bootinfo->compact_flash_common_base_addr)
37                         base_ptr =
38                                 octeon_bootinfo->compact_flash_common_base_addr;
39         } else {
40                 base_ptr = 0x1d000800;
41         }
42
43         if (!base_ptr)
44                 return ret;
45
46         /* Find CS0 region. */
47         for (i = 0; i < 8; i++) {
48                 mio_boot_reg_cfg.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(i));
49                 region_base = mio_boot_reg_cfg.s.base << 16;
50                 region_size = (mio_boot_reg_cfg.s.size + 1) << 16;
51                 if (mio_boot_reg_cfg.s.en && base_ptr >= region_base
52                     && base_ptr < region_base + region_size)
53                         break;
54         }
55         if (i >= 7) {
56                 /* i and i + 1 are CS0 and CS1, both must be less than 8. */
57                 goto out;
58         }
59         octeon_cf_data.base_region = i;
60         octeon_cf_data.is16bit = mio_boot_reg_cfg.s.width;
61         octeon_cf_data.base_region_bias = base_ptr - region_base;
62         memset(cf_resources, 0, sizeof(cf_resources));
63         num_resources = 0;
64         cf_resources[num_resources].flags       = IORESOURCE_MEM;
65         cf_resources[num_resources].start       = region_base;
66         cf_resources[num_resources].end = region_base + region_size - 1;
67         num_resources++;
68
69
70         if (!(base_ptr & 0xfffful)) {
71                 /*
72                  * Boot loader signals availability of DMA (true_ide
73                  * mode) by setting low order bits of base_ptr to
74                  * zero.
75                  */
76
77                 /* Asume that CS1 immediately follows. */
78                 mio_boot_reg_cfg.u64 =
79                         cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(i + 1));
80                 region_base = mio_boot_reg_cfg.s.base << 16;
81                 region_size = (mio_boot_reg_cfg.s.size + 1) << 16;
82                 if (!mio_boot_reg_cfg.s.en)
83                         goto out;
84
85                 cf_resources[num_resources].flags       = IORESOURCE_MEM;
86                 cf_resources[num_resources].start       = region_base;
87                 cf_resources[num_resources].end = region_base + region_size - 1;
88                 num_resources++;
89
90                 octeon_cf_data.dma_engine = 0;
91                 cf_resources[num_resources].flags       = IORESOURCE_IRQ;
92                 cf_resources[num_resources].start       = OCTEON_IRQ_BOOTDMA;
93                 cf_resources[num_resources].end = OCTEON_IRQ_BOOTDMA;
94                 num_resources++;
95         } else {
96                 octeon_cf_data.dma_engine = -1;
97         }
98
99         pd = platform_device_alloc("pata_octeon_cf", -1);
100         if (!pd) {
101                 ret = -ENOMEM;
102                 goto out;
103         }
104         pd->dev.platform_data = &octeon_cf_data;
105
106         ret = platform_device_add_resources(pd, cf_resources, num_resources);
107         if (ret)
108                 goto fail;
109
110         ret = platform_device_add(pd);
111         if (ret)
112                 goto fail;
113
114         return ret;
115 fail:
116         platform_device_put(pd);
117 out:
118         return ret;
119 }
120 device_initcall(octeon_cf_device_init);
121
122 /* Octeon Random Number Generator.  */
123 static int __init octeon_rng_device_init(void)
124 {
125         struct platform_device *pd;
126         int ret = 0;
127
128         struct resource rng_resources[] = {
129                 {
130                         .flags  = IORESOURCE_MEM,
131                         .start  = XKPHYS_TO_PHYS(CVMX_RNM_CTL_STATUS),
132                         .end    = XKPHYS_TO_PHYS(CVMX_RNM_CTL_STATUS) + 0xf
133                 }, {
134                         .flags  = IORESOURCE_MEM,
135                         .start  = cvmx_build_io_address(8, 0),
136                         .end    = cvmx_build_io_address(8, 0) + 0x7
137                 }
138         };
139
140         pd = platform_device_alloc("octeon_rng", -1);
141         if (!pd) {
142                 ret = -ENOMEM;
143                 goto out;
144         }
145
146         ret = platform_device_add_resources(pd, rng_resources,
147                                             ARRAY_SIZE(rng_resources));
148         if (ret)
149                 goto fail;
150
151         ret = platform_device_add(pd);
152         if (ret)
153                 goto fail;
154
155         return ret;
156 fail:
157         platform_device_put(pd);
158
159 out:
160         return ret;
161 }
162 device_initcall(octeon_rng_device_init);
163
164 static struct i2c_board_info __initdata octeon_i2c_devices[] = {
165         {
166                 I2C_BOARD_INFO("ds1337", 0x68),
167         },
168 };
169
170 static int __init octeon_i2c_devices_init(void)
171 {
172         return i2c_register_board_info(0, octeon_i2c_devices,
173                                        ARRAY_SIZE(octeon_i2c_devices));
174 }
175 arch_initcall(octeon_i2c_devices_init);
176
177 #define OCTEON_I2C_IO_BASE 0x1180000001000ull
178 #define OCTEON_I2C_IO_UNIT_OFFSET 0x200
179
180 static struct octeon_i2c_data octeon_i2c_data[2];
181
182 static int __init octeon_i2c_device_init(void)
183 {
184         struct platform_device *pd;
185         int ret = 0;
186         int port, num_ports;
187
188         struct resource i2c_resources[] = {
189                 {
190                         .flags  = IORESOURCE_MEM,
191                 }, {
192                         .flags  = IORESOURCE_IRQ,
193                 }
194         };
195
196         if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN52XX))
197                 num_ports = 2;
198         else
199                 num_ports = 1;
200
201         for (port = 0; port < num_ports; port++) {
202                 octeon_i2c_data[port].sys_freq = octeon_get_io_clock_rate();
203                 /*FIXME: should be examined. At the moment is set for 100Khz */
204                 octeon_i2c_data[port].i2c_freq = 100000;
205
206                 pd = platform_device_alloc("i2c-octeon", port);
207                 if (!pd) {
208                         ret = -ENOMEM;
209                         goto out;
210                 }
211
212                 pd->dev.platform_data = octeon_i2c_data + port;
213
214                 i2c_resources[0].start =
215                         OCTEON_I2C_IO_BASE + (port * OCTEON_I2C_IO_UNIT_OFFSET);
216                 i2c_resources[0].end = i2c_resources[0].start + 0x1f;
217                 switch (port) {
218                 case 0:
219                         i2c_resources[1].start = OCTEON_IRQ_TWSI;
220                         i2c_resources[1].end = OCTEON_IRQ_TWSI;
221                         break;
222                 case 1:
223                         i2c_resources[1].start = OCTEON_IRQ_TWSI2;
224                         i2c_resources[1].end = OCTEON_IRQ_TWSI2;
225                         break;
226                 default:
227                         BUG();
228                 }
229
230                 ret = platform_device_add_resources(pd,
231                                                     i2c_resources,
232                                                     ARRAY_SIZE(i2c_resources));
233                 if (ret)
234                         goto fail;
235
236                 ret = platform_device_add(pd);
237                 if (ret)
238                         goto fail;
239         }
240         return ret;
241 fail:
242         platform_device_put(pd);
243 out:
244         return ret;
245 }
246 device_initcall(octeon_i2c_device_init);
247
248 /* Octeon SMI/MDIO interface.  */
249 static int __init octeon_mdiobus_device_init(void)
250 {
251         struct platform_device *pd;
252         int ret = 0;
253
254         if (octeon_is_simulation())
255                 return 0; /* No mdio in the simulator. */
256
257         /* The bus number is the platform_device id.  */
258         pd = platform_device_alloc("mdio-octeon", 0);
259         if (!pd) {
260                 ret = -ENOMEM;
261                 goto out;
262         }
263
264         ret = platform_device_add(pd);
265         if (ret)
266                 goto fail;
267
268         return ret;
269 fail:
270         platform_device_put(pd);
271
272 out:
273         return ret;
274
275 }
276 device_initcall(octeon_mdiobus_device_init);
277
278 /* Octeon mgmt port Ethernet interface.  */
279 static int __init octeon_mgmt_device_init(void)
280 {
281         struct platform_device *pd;
282         int ret = 0;
283         int port, num_ports;
284
285         struct resource mgmt_port_resource = {
286                 .flags  = IORESOURCE_IRQ,
287                 .start  = -1,
288                 .end    = -1
289         };
290
291         if (!OCTEON_IS_MODEL(OCTEON_CN56XX) && !OCTEON_IS_MODEL(OCTEON_CN52XX))
292                 return 0;
293
294         if (OCTEON_IS_MODEL(OCTEON_CN56XX))
295                 num_ports = 1;
296         else
297                 num_ports = 2;
298
299         for (port = 0; port < num_ports; port++) {
300                 pd = platform_device_alloc("octeon_mgmt", port);
301                 if (!pd) {
302                         ret = -ENOMEM;
303                         goto out;
304                 }
305                 /* No DMA restrictions */
306                 pd->dev.coherent_dma_mask = DMA_BIT_MASK(64);
307                 pd->dev.dma_mask = &pd->dev.coherent_dma_mask;
308
309                 switch (port) {
310                 case 0:
311                         mgmt_port_resource.start = OCTEON_IRQ_MII0;
312                         break;
313                 case 1:
314                         mgmt_port_resource.start = OCTEON_IRQ_MII1;
315                         break;
316                 default:
317                         BUG();
318                 }
319                 mgmt_port_resource.end = mgmt_port_resource.start;
320
321                 ret = platform_device_add_resources(pd, &mgmt_port_resource, 1);
322
323                 if (ret)
324                         goto fail;
325
326                 ret = platform_device_add(pd);
327                 if (ret)
328                         goto fail;
329         }
330         return ret;
331 fail:
332         platform_device_put(pd);
333
334 out:
335         return ret;
336
337 }
338 device_initcall(octeon_mgmt_device_init);
339
340 MODULE_AUTHOR("David Daney <ddaney@caviumnetworks.com>");
341 MODULE_LICENSE("GPL");
342 MODULE_DESCRIPTION("Platform driver for Octeon SOC");