Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/mips/cavium-octeon/octeon-platform.c
10820 views
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
/* 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. */
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 <[email protected]>");
444
MODULE_LICENSE("GPL");
445
MODULE_DESCRIPTION("Platform driver for Octeon SOC");
446
447