Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/arm/mach-orion5x/ts78xx-setup.c
10817 views
1
/*
2
* arch/arm/mach-orion5x/ts78xx-setup.c
3
*
4
* Maintainer: Alexander Clouter <[email protected]>
5
*
6
* This file is licensed under the terms of the GNU General Public
7
* License version 2. This program is licensed "as is" without any
8
* warranty of any kind, whether express or implied.
9
*/
10
11
#include <linux/kernel.h>
12
#include <linux/init.h>
13
#include <linux/sysfs.h>
14
#include <linux/platform_device.h>
15
#include <linux/mv643xx_eth.h>
16
#include <linux/ata_platform.h>
17
#include <linux/m48t86.h>
18
#include <linux/mtd/nand.h>
19
#include <linux/mtd/partitions.h>
20
#include <linux/timeriomem-rng.h>
21
#include <asm/mach-types.h>
22
#include <asm/mach/arch.h>
23
#include <asm/mach/map.h>
24
#include <mach/orion5x.h>
25
#include "common.h"
26
#include "mpp.h"
27
#include "ts78xx-fpga.h"
28
29
/*****************************************************************************
30
* TS-78xx Info
31
****************************************************************************/
32
33
/*
34
* FPGA - lives where the PCI bus would be at ORION5X_PCI_MEM_PHYS_BASE
35
*/
36
#define TS78XX_FPGA_REGS_PHYS_BASE 0xe8000000
37
#define TS78XX_FPGA_REGS_VIRT_BASE 0xff900000
38
#define TS78XX_FPGA_REGS_SIZE SZ_1M
39
40
static struct ts78xx_fpga_data ts78xx_fpga = {
41
.id = 0,
42
.state = 1,
43
/* .supports = ... - populated by ts78xx_fpga_supports() */
44
};
45
46
/*****************************************************************************
47
* I/O Address Mapping
48
****************************************************************************/
49
static struct map_desc ts78xx_io_desc[] __initdata = {
50
{
51
.virtual = TS78XX_FPGA_REGS_VIRT_BASE,
52
.pfn = __phys_to_pfn(TS78XX_FPGA_REGS_PHYS_BASE),
53
.length = TS78XX_FPGA_REGS_SIZE,
54
.type = MT_DEVICE,
55
},
56
};
57
58
void __init ts78xx_map_io(void)
59
{
60
orion5x_map_io();
61
iotable_init(ts78xx_io_desc, ARRAY_SIZE(ts78xx_io_desc));
62
}
63
64
/*****************************************************************************
65
* Ethernet
66
****************************************************************************/
67
static struct mv643xx_eth_platform_data ts78xx_eth_data = {
68
.phy_addr = MV643XX_ETH_PHY_ADDR(0),
69
};
70
71
/*****************************************************************************
72
* SATA
73
****************************************************************************/
74
static struct mv_sata_platform_data ts78xx_sata_data = {
75
.n_ports = 2,
76
};
77
78
/*****************************************************************************
79
* RTC M48T86 - nicked^Wborrowed from arch/arm/mach-ep93xx/ts72xx.c
80
****************************************************************************/
81
#define TS_RTC_CTRL (TS78XX_FPGA_REGS_VIRT_BASE | 0x808)
82
#define TS_RTC_DATA (TS78XX_FPGA_REGS_VIRT_BASE | 0x80c)
83
84
static unsigned char ts78xx_ts_rtc_readbyte(unsigned long addr)
85
{
86
writeb(addr, TS_RTC_CTRL);
87
return readb(TS_RTC_DATA);
88
}
89
90
static void ts78xx_ts_rtc_writebyte(unsigned char value, unsigned long addr)
91
{
92
writeb(addr, TS_RTC_CTRL);
93
writeb(value, TS_RTC_DATA);
94
}
95
96
static struct m48t86_ops ts78xx_ts_rtc_ops = {
97
.readbyte = ts78xx_ts_rtc_readbyte,
98
.writebyte = ts78xx_ts_rtc_writebyte,
99
};
100
101
static struct platform_device ts78xx_ts_rtc_device = {
102
.name = "rtc-m48t86",
103
.id = -1,
104
.dev = {
105
.platform_data = &ts78xx_ts_rtc_ops,
106
},
107
.num_resources = 0,
108
};
109
110
/*
111
* TS uses some of the user storage space on the RTC chip so see if it is
112
* present; as it's an optional feature at purchase time and not all boards
113
* will have it present
114
*
115
* I've used the method TS use in their rtc7800.c example for the detection
116
*
117
* TODO: track down a guinea pig without an RTC to see if we can work out a
118
* better RTC detection routine
119
*/
120
static int ts78xx_ts_rtc_load(void)
121
{
122
int rc;
123
unsigned char tmp_rtc0, tmp_rtc1;
124
125
tmp_rtc0 = ts78xx_ts_rtc_readbyte(126);
126
tmp_rtc1 = ts78xx_ts_rtc_readbyte(127);
127
128
ts78xx_ts_rtc_writebyte(0x00, 126);
129
ts78xx_ts_rtc_writebyte(0x55, 127);
130
if (ts78xx_ts_rtc_readbyte(127) == 0x55) {
131
ts78xx_ts_rtc_writebyte(0xaa, 127);
132
if (ts78xx_ts_rtc_readbyte(127) == 0xaa
133
&& ts78xx_ts_rtc_readbyte(126) == 0x00) {
134
ts78xx_ts_rtc_writebyte(tmp_rtc0, 126);
135
ts78xx_ts_rtc_writebyte(tmp_rtc1, 127);
136
137
if (ts78xx_fpga.supports.ts_rtc.init == 0) {
138
rc = platform_device_register(&ts78xx_ts_rtc_device);
139
if (!rc)
140
ts78xx_fpga.supports.ts_rtc.init = 1;
141
} else
142
rc = platform_device_add(&ts78xx_ts_rtc_device);
143
144
return rc;
145
}
146
}
147
148
return -ENODEV;
149
};
150
151
static void ts78xx_ts_rtc_unload(void)
152
{
153
platform_device_del(&ts78xx_ts_rtc_device);
154
}
155
156
/*****************************************************************************
157
* NAND Flash
158
****************************************************************************/
159
#define TS_NAND_CTRL (TS78XX_FPGA_REGS_VIRT_BASE | 0x800) /* VIRT */
160
#define TS_NAND_DATA (TS78XX_FPGA_REGS_PHYS_BASE | 0x804) /* PHYS */
161
162
/*
163
* hardware specific access to control-lines
164
*
165
* ctrl:
166
* NAND_NCE: bit 0 -> bit 2
167
* NAND_CLE: bit 1 -> bit 1
168
* NAND_ALE: bit 2 -> bit 0
169
*/
170
static void ts78xx_ts_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
171
unsigned int ctrl)
172
{
173
struct nand_chip *this = mtd->priv;
174
175
if (ctrl & NAND_CTRL_CHANGE) {
176
unsigned char bits;
177
178
bits = (ctrl & NAND_NCE) << 2;
179
bits |= ctrl & NAND_CLE;
180
bits |= (ctrl & NAND_ALE) >> 2;
181
182
writeb((readb(TS_NAND_CTRL) & ~0x7) | bits, TS_NAND_CTRL);
183
}
184
185
if (cmd != NAND_CMD_NONE)
186
writeb(cmd, this->IO_ADDR_W);
187
}
188
189
static int ts78xx_ts_nand_dev_ready(struct mtd_info *mtd)
190
{
191
return readb(TS_NAND_CTRL) & 0x20;
192
}
193
194
static void ts78xx_ts_nand_write_buf(struct mtd_info *mtd,
195
const uint8_t *buf, int len)
196
{
197
struct nand_chip *chip = mtd->priv;
198
void __iomem *io_base = chip->IO_ADDR_W;
199
unsigned long off = ((unsigned long)buf & 3);
200
int sz;
201
202
if (off) {
203
sz = min_t(int, 4 - off, len);
204
writesb(io_base, buf, sz);
205
buf += sz;
206
len -= sz;
207
}
208
209
sz = len >> 2;
210
if (sz) {
211
u32 *buf32 = (u32 *)buf;
212
writesl(io_base, buf32, sz);
213
buf += sz << 2;
214
len -= sz << 2;
215
}
216
217
if (len)
218
writesb(io_base, buf, len);
219
}
220
221
static void ts78xx_ts_nand_read_buf(struct mtd_info *mtd,
222
uint8_t *buf, int len)
223
{
224
struct nand_chip *chip = mtd->priv;
225
void __iomem *io_base = chip->IO_ADDR_R;
226
unsigned long off = ((unsigned long)buf & 3);
227
int sz;
228
229
if (off) {
230
sz = min_t(int, 4 - off, len);
231
readsb(io_base, buf, sz);
232
buf += sz;
233
len -= sz;
234
}
235
236
sz = len >> 2;
237
if (sz) {
238
u32 *buf32 = (u32 *)buf;
239
readsl(io_base, buf32, sz);
240
buf += sz << 2;
241
len -= sz << 2;
242
}
243
244
if (len)
245
readsb(io_base, buf, len);
246
}
247
248
const char *ts_nand_part_probes[] = { "cmdlinepart", NULL };
249
250
static struct mtd_partition ts78xx_ts_nand_parts[] = {
251
{
252
.name = "mbr",
253
.offset = 0,
254
.size = SZ_128K,
255
.mask_flags = MTD_WRITEABLE,
256
}, {
257
.name = "kernel",
258
.offset = MTDPART_OFS_APPEND,
259
.size = SZ_4M,
260
}, {
261
.name = "initrd",
262
.offset = MTDPART_OFS_APPEND,
263
.size = SZ_4M,
264
}, {
265
.name = "rootfs",
266
.offset = MTDPART_OFS_APPEND,
267
.size = MTDPART_SIZ_FULL,
268
}
269
};
270
271
static struct platform_nand_data ts78xx_ts_nand_data = {
272
.chip = {
273
.nr_chips = 1,
274
.part_probe_types = ts_nand_part_probes,
275
.partitions = ts78xx_ts_nand_parts,
276
.nr_partitions = ARRAY_SIZE(ts78xx_ts_nand_parts),
277
.chip_delay = 15,
278
.options = NAND_USE_FLASH_BBT,
279
},
280
.ctrl = {
281
/*
282
* The HW ECC offloading functions, used to give about a 9%
283
* performance increase for 'dd if=/dev/mtdblockX' and 5% for
284
* nanddump. This all however was changed by git commit
285
* e6cf5df1838c28bb060ac45b5585e48e71bbc740 so now there is
286
* no performance advantage to be had so we no longer bother
287
*/
288
.cmd_ctrl = ts78xx_ts_nand_cmd_ctrl,
289
.dev_ready = ts78xx_ts_nand_dev_ready,
290
.write_buf = ts78xx_ts_nand_write_buf,
291
.read_buf = ts78xx_ts_nand_read_buf,
292
},
293
};
294
295
static struct resource ts78xx_ts_nand_resources = {
296
.start = TS_NAND_DATA,
297
.end = TS_NAND_DATA + 4,
298
.flags = IORESOURCE_MEM,
299
};
300
301
static struct platform_device ts78xx_ts_nand_device = {
302
.name = "gen_nand",
303
.id = -1,
304
.dev = {
305
.platform_data = &ts78xx_ts_nand_data,
306
},
307
.resource = &ts78xx_ts_nand_resources,
308
.num_resources = 1,
309
};
310
311
static int ts78xx_ts_nand_load(void)
312
{
313
int rc;
314
315
if (ts78xx_fpga.supports.ts_nand.init == 0) {
316
rc = platform_device_register(&ts78xx_ts_nand_device);
317
if (!rc)
318
ts78xx_fpga.supports.ts_nand.init = 1;
319
} else
320
rc = platform_device_add(&ts78xx_ts_nand_device);
321
322
return rc;
323
};
324
325
static void ts78xx_ts_nand_unload(void)
326
{
327
platform_device_del(&ts78xx_ts_nand_device);
328
}
329
330
/*****************************************************************************
331
* HW RNG
332
****************************************************************************/
333
#define TS_RNG_DATA (TS78XX_FPGA_REGS_PHYS_BASE | 0x044)
334
335
static struct resource ts78xx_ts_rng_resource = {
336
.flags = IORESOURCE_MEM,
337
.start = TS_RNG_DATA,
338
.end = TS_RNG_DATA + 4 - 1,
339
};
340
341
static struct timeriomem_rng_data ts78xx_ts_rng_data = {
342
.period = 1000000, /* one second */
343
};
344
345
static struct platform_device ts78xx_ts_rng_device = {
346
.name = "timeriomem_rng",
347
.id = -1,
348
.dev = {
349
.platform_data = &ts78xx_ts_rng_data,
350
},
351
.resource = &ts78xx_ts_rng_resource,
352
.num_resources = 1,
353
};
354
355
static int ts78xx_ts_rng_load(void)
356
{
357
int rc;
358
359
if (ts78xx_fpga.supports.ts_rng.init == 0) {
360
rc = platform_device_register(&ts78xx_ts_rng_device);
361
if (!rc)
362
ts78xx_fpga.supports.ts_rng.init = 1;
363
} else
364
rc = platform_device_add(&ts78xx_ts_rng_device);
365
366
return rc;
367
};
368
369
static void ts78xx_ts_rng_unload(void)
370
{
371
platform_device_del(&ts78xx_ts_rng_device);
372
}
373
374
/*****************************************************************************
375
* FPGA 'hotplug' support code
376
****************************************************************************/
377
static void ts78xx_fpga_devices_zero_init(void)
378
{
379
ts78xx_fpga.supports.ts_rtc.init = 0;
380
ts78xx_fpga.supports.ts_nand.init = 0;
381
ts78xx_fpga.supports.ts_rng.init = 0;
382
}
383
384
static void ts78xx_fpga_supports(void)
385
{
386
/* TODO: put this 'table' into ts78xx-fpga.h */
387
switch (ts78xx_fpga.id) {
388
case TS7800_REV_1:
389
case TS7800_REV_2:
390
case TS7800_REV_3:
391
case TS7800_REV_4:
392
case TS7800_REV_5:
393
case TS7800_REV_6:
394
case TS7800_REV_7:
395
case TS7800_REV_8:
396
case TS7800_REV_9:
397
ts78xx_fpga.supports.ts_rtc.present = 1;
398
ts78xx_fpga.supports.ts_nand.present = 1;
399
ts78xx_fpga.supports.ts_rng.present = 1;
400
break;
401
default:
402
/* enable devices if magic matches */
403
switch ((ts78xx_fpga.id >> 8) & 0xffffff) {
404
case TS7800_FPGA_MAGIC:
405
pr_warning("TS-7800 FPGA: unrecognized revision 0x%.2x\n",
406
ts78xx_fpga.id & 0xff);
407
ts78xx_fpga.supports.ts_rtc.present = 1;
408
ts78xx_fpga.supports.ts_nand.present = 1;
409
ts78xx_fpga.supports.ts_rng.present = 1;
410
break;
411
default:
412
ts78xx_fpga.supports.ts_rtc.present = 0;
413
ts78xx_fpga.supports.ts_nand.present = 0;
414
ts78xx_fpga.supports.ts_rng.present = 0;
415
}
416
}
417
}
418
419
static int ts78xx_fpga_load_devices(void)
420
{
421
int tmp, ret = 0;
422
423
if (ts78xx_fpga.supports.ts_rtc.present == 1) {
424
tmp = ts78xx_ts_rtc_load();
425
if (tmp) {
426
pr_info("TS-78xx: RTC not registered\n");
427
ts78xx_fpga.supports.ts_rtc.present = 0;
428
}
429
ret |= tmp;
430
}
431
if (ts78xx_fpga.supports.ts_nand.present == 1) {
432
tmp = ts78xx_ts_nand_load();
433
if (tmp) {
434
pr_info("TS-78xx: NAND not registered\n");
435
ts78xx_fpga.supports.ts_nand.present = 0;
436
}
437
ret |= tmp;
438
}
439
if (ts78xx_fpga.supports.ts_rng.present == 1) {
440
tmp = ts78xx_ts_rng_load();
441
if (tmp) {
442
pr_info("TS-78xx: RNG not registered\n");
443
ts78xx_fpga.supports.ts_rng.present = 0;
444
}
445
ret |= tmp;
446
}
447
448
return ret;
449
}
450
451
static int ts78xx_fpga_unload_devices(void)
452
{
453
int ret = 0;
454
455
if (ts78xx_fpga.supports.ts_rtc.present == 1)
456
ts78xx_ts_rtc_unload();
457
if (ts78xx_fpga.supports.ts_nand.present == 1)
458
ts78xx_ts_nand_unload();
459
if (ts78xx_fpga.supports.ts_rng.present == 1)
460
ts78xx_ts_rng_unload();
461
462
return ret;
463
}
464
465
static int ts78xx_fpga_load(void)
466
{
467
ts78xx_fpga.id = readl(TS78XX_FPGA_REGS_VIRT_BASE);
468
469
pr_info("TS-78xx FPGA: magic=0x%.6x, rev=0x%.2x\n",
470
(ts78xx_fpga.id >> 8) & 0xffffff,
471
ts78xx_fpga.id & 0xff);
472
473
ts78xx_fpga_supports();
474
475
if (ts78xx_fpga_load_devices()) {
476
ts78xx_fpga.state = -1;
477
return -EBUSY;
478
}
479
480
return 0;
481
};
482
483
static int ts78xx_fpga_unload(void)
484
{
485
unsigned int fpga_id;
486
487
fpga_id = readl(TS78XX_FPGA_REGS_VIRT_BASE);
488
489
/*
490
* There does not seem to be a feasible way to block access to the GPIO
491
* pins from userspace (/dev/mem). This if clause should hopefully warn
492
* those foolish enough not to follow 'policy' :)
493
*
494
* UrJTAG SVN since r1381 can be used to reprogram the FPGA
495
*/
496
if (ts78xx_fpga.id != fpga_id) {
497
pr_err("TS-78xx FPGA: magic/rev mismatch\n"
498
"TS-78xx FPGA: was 0x%.6x/%.2x but now 0x%.6x/%.2x\n",
499
(ts78xx_fpga.id >> 8) & 0xffffff, ts78xx_fpga.id & 0xff,
500
(fpga_id >> 8) & 0xffffff, fpga_id & 0xff);
501
ts78xx_fpga.state = -1;
502
return -EBUSY;
503
}
504
505
if (ts78xx_fpga_unload_devices()) {
506
ts78xx_fpga.state = -1;
507
return -EBUSY;
508
}
509
510
return 0;
511
};
512
513
static ssize_t ts78xx_fpga_show(struct kobject *kobj,
514
struct kobj_attribute *attr, char *buf)
515
{
516
if (ts78xx_fpga.state < 0)
517
return sprintf(buf, "borked\n");
518
519
return sprintf(buf, "%s\n", (ts78xx_fpga.state) ? "online" : "offline");
520
}
521
522
static ssize_t ts78xx_fpga_store(struct kobject *kobj,
523
struct kobj_attribute *attr, const char *buf, size_t n)
524
{
525
int value, ret;
526
527
if (ts78xx_fpga.state < 0) {
528
pr_err("TS-78xx FPGA: borked, you must powercycle asap\n");
529
return -EBUSY;
530
}
531
532
if (strncmp(buf, "online", sizeof("online") - 1) == 0)
533
value = 1;
534
else if (strncmp(buf, "offline", sizeof("offline") - 1) == 0)
535
value = 0;
536
else {
537
pr_err("ts78xx_fpga_store: Invalid value\n");
538
return -EINVAL;
539
}
540
541
if (ts78xx_fpga.state == value)
542
return n;
543
544
ret = (ts78xx_fpga.state == 0)
545
? ts78xx_fpga_load()
546
: ts78xx_fpga_unload();
547
548
if (!(ret < 0))
549
ts78xx_fpga.state = value;
550
551
return n;
552
}
553
554
static struct kobj_attribute ts78xx_fpga_attr =
555
__ATTR(ts78xx_fpga, 0644, ts78xx_fpga_show, ts78xx_fpga_store);
556
557
/*****************************************************************************
558
* General Setup
559
****************************************************************************/
560
static unsigned int ts78xx_mpp_modes[] __initdata = {
561
MPP0_UNUSED,
562
MPP1_GPIO, /* JTAG Clock */
563
MPP2_GPIO, /* JTAG Data In */
564
MPP3_GPIO, /* Lat ECP2 256 FPGA - PB2B */
565
MPP4_GPIO, /* JTAG Data Out */
566
MPP5_GPIO, /* JTAG TMS */
567
MPP6_GPIO, /* Lat ECP2 256 FPGA - PB31A_CLK4+ */
568
MPP7_GPIO, /* Lat ECP2 256 FPGA - PB22B */
569
MPP8_UNUSED,
570
MPP9_UNUSED,
571
MPP10_UNUSED,
572
MPP11_UNUSED,
573
MPP12_UNUSED,
574
MPP13_UNUSED,
575
MPP14_UNUSED,
576
MPP15_UNUSED,
577
MPP16_UART,
578
MPP17_UART,
579
MPP18_UART,
580
MPP19_UART,
581
/*
582
* MPP[20] PCI Clock Out 1
583
* MPP[21] PCI Clock Out 0
584
* MPP[22] Unused
585
* MPP[23] Unused
586
* MPP[24] Unused
587
* MPP[25] Unused
588
*/
589
0,
590
};
591
592
static void __init ts78xx_init(void)
593
{
594
int ret;
595
596
/*
597
* Setup basic Orion functions. Need to be called early.
598
*/
599
orion5x_init();
600
601
orion5x_mpp_conf(ts78xx_mpp_modes);
602
603
/*
604
* Configure peripherals.
605
*/
606
orion5x_ehci0_init();
607
orion5x_ehci1_init();
608
orion5x_eth_init(&ts78xx_eth_data);
609
orion5x_sata_init(&ts78xx_sata_data);
610
orion5x_uart0_init();
611
orion5x_uart1_init();
612
orion5x_xor_init();
613
614
/* FPGA init */
615
ts78xx_fpga_devices_zero_init();
616
ret = ts78xx_fpga_load();
617
ret = sysfs_create_file(power_kobj, &ts78xx_fpga_attr.attr);
618
if (ret)
619
pr_err("sysfs_create_file failed: %d\n", ret);
620
}
621
622
MACHINE_START(TS78XX, "Technologic Systems TS-78xx SBC")
623
/* Maintainer: Alexander Clouter <[email protected]> */
624
.boot_params = 0x00000100,
625
.init_machine = ts78xx_init,
626
.map_io = ts78xx_map_io,
627
.init_early = orion5x_init_early,
628
.init_irq = orion5x_init_irq,
629
.timer = &orion5x_timer,
630
MACHINE_END
631
632