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 
octeon_cf_device_init(void)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 		/* Assume 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.  */
octeon_rng_device_init(void)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 
octeon_i2c_devices_init(void)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 
octeon_i2c_device_init(void)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.  */
octeon_mdiobus_device_init(void)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.  */
octeon_mgmt_device_init(void)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 
octeon_ehci_device_init(void)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 
octeon_ohci_device_init(void)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");
446