blob: baa25d0fd5c948f492718f9121bc1274e0280d47 [file] [log] [blame]
Alexander Clouter7171d862008-05-31 22:32:37 +01001/*
2 * arch/arm/mach-orion5x/ts78xx-setup.c
3 *
4 * Maintainer: Alexander Clouter <alex@digriz.org.uk>
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>
Alexander Clouter39008f92009-02-06 22:16:55 +000013#include <linux/sysfs.h>
Alexander Clouter7171d862008-05-31 22:32:37 +010014#include <linux/platform_device.h>
Alexander Clouter7171d862008-05-31 22:32:37 +010015#include <linux/mv643xx_eth.h>
16#include <linux/ata_platform.h>
17#include <linux/m48t86.h>
18#include <asm/mach-types.h>
19#include <asm/mach/arch.h>
20#include <asm/mach/map.h>
Russell Kinga09e64f2008-08-05 16:14:15 +010021#include <mach/orion5x.h>
Alexander Clouter7171d862008-05-31 22:32:37 +010022#include "common.h"
23#include "mpp.h"
Alexander Clouter39008f92009-02-06 22:16:55 +000024#include "ts78xx-fpga.h"
Alexander Clouter7171d862008-05-31 22:32:37 +010025
26/*****************************************************************************
27 * TS-78xx Info
28 ****************************************************************************/
29
30/*
31 * FPGA - lives where the PCI bus would be at ORION5X_PCI_MEM_PHYS_BASE
32 */
33#define TS78XX_FPGA_REGS_PHYS_BASE 0xe8000000
34#define TS78XX_FPGA_REGS_VIRT_BASE 0xff900000
35#define TS78XX_FPGA_REGS_SIZE SZ_1M
36
Alexander Clouter39008f92009-02-06 22:16:55 +000037static struct ts78xx_fpga_data ts78xx_fpga = {
38 .id = 0,
39 .state = 1,
40/* .supports = ... - populated by ts78xx_fpga_supports() */
41};
Alexander Clouter7171d862008-05-31 22:32:37 +010042
Alexander Clouter7171d862008-05-31 22:32:37 +010043/*****************************************************************************
44 * I/O Address Mapping
45 ****************************************************************************/
46static struct map_desc ts78xx_io_desc[] __initdata = {
47 {
48 .virtual = TS78XX_FPGA_REGS_VIRT_BASE,
49 .pfn = __phys_to_pfn(TS78XX_FPGA_REGS_PHYS_BASE),
50 .length = TS78XX_FPGA_REGS_SIZE,
51 .type = MT_DEVICE,
52 },
53};
54
55void __init ts78xx_map_io(void)
56{
57 orion5x_map_io();
58 iotable_init(ts78xx_io_desc, ARRAY_SIZE(ts78xx_io_desc));
59}
60
61/*****************************************************************************
Alexander Clouter7171d862008-05-31 22:32:37 +010062 * Ethernet
63 ****************************************************************************/
64static struct mv643xx_eth_platform_data ts78xx_eth_data = {
Lennert Buytenhekac8406052008-08-26 14:06:47 +020065 .phy_addr = MV643XX_ETH_PHY_ADDR(0),
Alexander Clouter7171d862008-05-31 22:32:37 +010066};
67
68/*****************************************************************************
Alexander Clouter39008f92009-02-06 22:16:55 +000069 * SATA
70 ****************************************************************************/
71static struct mv_sata_platform_data ts78xx_sata_data = {
72 .n_ports = 2,
73};
74
75/*****************************************************************************
Alexander Clouter7171d862008-05-31 22:32:37 +010076 * RTC M48T86 - nicked^Wborrowed from arch/arm/mach-ep93xx/ts72xx.c
77 ****************************************************************************/
78#ifdef CONFIG_RTC_DRV_M48T86
Alexander Clouter39008f92009-02-06 22:16:55 +000079#define TS_RTC_CTRL (TS78XX_FPGA_REGS_VIRT_BASE | 0x808)
80#define TS_RTC_DATA (TS78XX_FPGA_REGS_VIRT_BASE | 0x80c)
81
82static unsigned char ts78xx_ts_rtc_readbyte(unsigned long addr)
Alexander Clouter7171d862008-05-31 22:32:37 +010083{
Alexander Clouter39008f92009-02-06 22:16:55 +000084 writeb(addr, TS_RTC_CTRL);
85 return readb(TS_RTC_DATA);
Alexander Clouter7171d862008-05-31 22:32:37 +010086}
87
Alexander Clouter39008f92009-02-06 22:16:55 +000088static void ts78xx_ts_rtc_writebyte(unsigned char value, unsigned long addr)
Alexander Clouter7171d862008-05-31 22:32:37 +010089{
Alexander Clouter39008f92009-02-06 22:16:55 +000090 writeb(addr, TS_RTC_CTRL);
91 writeb(value, TS_RTC_DATA);
Alexander Clouter7171d862008-05-31 22:32:37 +010092}
93
Alexander Clouter39008f92009-02-06 22:16:55 +000094static struct m48t86_ops ts78xx_ts_rtc_ops = {
95 .readbyte = ts78xx_ts_rtc_readbyte,
96 .writebyte = ts78xx_ts_rtc_writebyte,
Alexander Clouter7171d862008-05-31 22:32:37 +010097};
98
Alexander Clouter39008f92009-02-06 22:16:55 +000099static struct platform_device ts78xx_ts_rtc_device = {
Alexander Clouter7171d862008-05-31 22:32:37 +0100100 .name = "rtc-m48t86",
101 .id = -1,
102 .dev = {
Alexander Clouter39008f92009-02-06 22:16:55 +0000103 .platform_data = &ts78xx_ts_rtc_ops,
Alexander Clouter7171d862008-05-31 22:32:37 +0100104 },
105 .num_resources = 0,
106};
107
108/*
109 * TS uses some of the user storage space on the RTC chip so see if it is
110 * present; as it's an optional feature at purchase time and not all boards
111 * will have it present
112 *
113 * I've used the method TS use in their rtc7800.c example for the detection
114 *
115 * TODO: track down a guinea pig without an RTC to see if we can work out a
116 * better RTC detection routine
117 */
Alexander Clouter39008f92009-02-06 22:16:55 +0000118static int ts78xx_ts_rtc_load(void)
Alexander Clouter7171d862008-05-31 22:32:37 +0100119{
120 unsigned char tmp_rtc0, tmp_rtc1;
121
Alexander Clouter39008f92009-02-06 22:16:55 +0000122 tmp_rtc0 = ts78xx_ts_rtc_readbyte(126);
123 tmp_rtc1 = ts78xx_ts_rtc_readbyte(127);
Alexander Clouter7171d862008-05-31 22:32:37 +0100124
Alexander Clouter39008f92009-02-06 22:16:55 +0000125 ts78xx_ts_rtc_writebyte(0x00, 126);
126 ts78xx_ts_rtc_writebyte(0x55, 127);
127 if (ts78xx_ts_rtc_readbyte(127) == 0x55) {
128 ts78xx_ts_rtc_writebyte(0xaa, 127);
129 if (ts78xx_ts_rtc_readbyte(127) == 0xaa
130 && ts78xx_ts_rtc_readbyte(126) == 0x00) {
131 ts78xx_ts_rtc_writebyte(tmp_rtc0, 126);
132 ts78xx_ts_rtc_writebyte(tmp_rtc1, 127);
133 if (ts78xx_fpga.supports.ts_rtc.init == 0) {
134 ts78xx_fpga.supports.ts_rtc.init = 1;
135 platform_device_register(&ts78xx_ts_rtc_device);
136 } else
137 platform_device_add(&ts78xx_ts_rtc_device);
138 return 0;
Alexander Clouter7171d862008-05-31 22:32:37 +0100139 }
140 }
141
Alexander Clouter39008f92009-02-06 22:16:55 +0000142 ts78xx_fpga.supports.ts_rtc.present = 0;
143 return -ENODEV;
Alexander Clouter7171d862008-05-31 22:32:37 +0100144};
Alexander Clouter39008f92009-02-06 22:16:55 +0000145
146static void ts78xx_ts_rtc_unload(void)
147{
148 platform_device_del(&ts78xx_ts_rtc_device);
149}
Alexander Clouter7171d862008-05-31 22:32:37 +0100150#else
Alexander Clouter39008f92009-02-06 22:16:55 +0000151static int ts78xx_ts_rtc_load(void)
Alexander Clouter7171d862008-05-31 22:32:37 +0100152{
153 return 0;
154}
Alexander Clouter39008f92009-02-06 22:16:55 +0000155
156static void ts78xx_ts_rtc_unload(void)
157{
158}
Alexander Clouter7171d862008-05-31 22:32:37 +0100159#endif
160
161/*****************************************************************************
Alexander Clouter39008f92009-02-06 22:16:55 +0000162 * FPGA 'hotplug' support code
Alexander Clouter7171d862008-05-31 22:32:37 +0100163 ****************************************************************************/
Alexander Clouter39008f92009-02-06 22:16:55 +0000164static void ts78xx_fpga_devices_zero_init(void)
Alexander Clouter7171d862008-05-31 22:32:37 +0100165{
Alexander Clouter39008f92009-02-06 22:16:55 +0000166 ts78xx_fpga.supports.ts_rtc.init = 0;
167}
Alexander Clouter7171d862008-05-31 22:32:37 +0100168
Alexander Clouter39008f92009-02-06 22:16:55 +0000169static void ts78xx_fpga_supports(void)
170{
171 /* TODO: put this 'table' into ts78xx-fpga.h */
172 switch (ts78xx_fpga.id) {
173 case TS7800_REV_B:
174 ts78xx_fpga.supports.ts_rtc.present = 1;
175 break;
176 default:
177 ts78xx_fpga.supports.ts_rtc.present = 0;
178 }
179}
180
181static int ts78xx_fpga_load_devices(void)
182{
183 int tmp, ret = 0;
184
185 if (ts78xx_fpga.supports.ts_rtc.present == 1) {
186 tmp = ts78xx_ts_rtc_load();
187 if (tmp)
188 printk(KERN_INFO "TS-78xx RTC not detected or enabled\n");
189 ret |= tmp;
190 }
191
192 return ret;
193}
194
195static int ts78xx_fpga_unload_devices(void)
196{
197 int ret = 0;
198
199 if (ts78xx_fpga.supports.ts_rtc.present == 1)
200 ts78xx_ts_rtc_unload();
201
202 return ret;
203}
204
205static int ts78xx_fpga_load(void)
206{
207 ts78xx_fpga.id = readl(TS78XX_FPGA_REGS_VIRT_BASE);
208
209 printk(KERN_INFO "TS-78xx FPGA: magic=0x%.6x, rev=0x%.2x\n",
210 (ts78xx_fpga.id >> 8) & 0xffffff,
211 ts78xx_fpga.id & 0xff);
212
213 ts78xx_fpga_supports();
214
215 if (ts78xx_fpga_load_devices()) {
216 ts78xx_fpga.state = -1;
217 return -EBUSY;
218 }
219
220 return 0;
Alexander Clouter7171d862008-05-31 22:32:37 +0100221};
222
Alexander Clouter39008f92009-02-06 22:16:55 +0000223static int ts78xx_fpga_unload(void)
224{
225 unsigned int fpga_id;
226
227 fpga_id = readl(TS78XX_FPGA_REGS_VIRT_BASE);
228
229 /*
230 * There does not seem to be a feasible way to block access to the GPIO
231 * pins from userspace (/dev/mem). This if clause should hopefully warn
232 * those foolish enough not to follow 'policy' :)
233 *
234 * UrJTAG SVN since r1381 can be used to reprogram the FPGA
235 */
236 if (ts78xx_fpga.id != fpga_id) {
237 printk(KERN_ERR "TS-78xx FPGA: magic/rev mismatch\n"
238 "TS-78xx FPGA: was 0x%.6x/%.2x but now 0x%.6x/%.2x\n",
239 (ts78xx_fpga.id >> 8) & 0xffffff, ts78xx_fpga.id & 0xff,
240 (fpga_id >> 8) & 0xffffff, fpga_id & 0xff);
241 ts78xx_fpga.state = -1;
242 return -EBUSY;
243 }
244
245 if (ts78xx_fpga_unload_devices()) {
246 ts78xx_fpga.state = -1;
247 return -EBUSY;
248 }
249
250 return 0;
251};
252
253static ssize_t ts78xx_fpga_show(struct kobject *kobj,
254 struct kobj_attribute *attr, char *buf)
255{
256 if (ts78xx_fpga.state < 0)
257 return sprintf(buf, "borked\n");
258
259 return sprintf(buf, "%s\n", (ts78xx_fpga.state) ? "online" : "offline");
260}
261
262static ssize_t ts78xx_fpga_store(struct kobject *kobj,
263 struct kobj_attribute *attr, const char *buf, size_t n)
264{
265 int value, ret;
266
267 if (ts78xx_fpga.state < 0) {
268 printk(KERN_ERR "TS-78xx FPGA: borked, you must powercycle asap\n");
269 return -EBUSY;
270 }
271
272 if (strncmp(buf, "online", sizeof("online") - 1) == 0)
273 value = 1;
274 else if (strncmp(buf, "offline", sizeof("offline") - 1) == 0)
275 value = 0;
276 else {
277 printk(KERN_ERR "ts78xx_fpga_store: Invalid value\n");
278 return -EINVAL;
279 }
280
281 if (ts78xx_fpga.state == value)
282 return n;
283
284 ret = (ts78xx_fpga.state == 0)
285 ? ts78xx_fpga_load()
286 : ts78xx_fpga_unload();
287
288 if (!(ret < 0))
289 ts78xx_fpga.state = value;
290
291 return n;
292}
293
294static struct kobj_attribute ts78xx_fpga_attr =
295 __ATTR(ts78xx_fpga, 0644, ts78xx_fpga_show, ts78xx_fpga_store);
296
Alexander Clouter7171d862008-05-31 22:32:37 +0100297/*****************************************************************************
298 * General Setup
299 ****************************************************************************/
300static struct orion5x_mpp_mode ts78xx_mpp_modes[] __initdata = {
301 { 0, MPP_UNUSED },
302 { 1, MPP_GPIO }, /* JTAG Clock */
303 { 2, MPP_GPIO }, /* JTAG Data In */
304 { 3, MPP_GPIO }, /* Lat ECP2 256 FPGA - PB2B */
305 { 4, MPP_GPIO }, /* JTAG Data Out */
306 { 5, MPP_GPIO }, /* JTAG TMS */
307 { 6, MPP_GPIO }, /* Lat ECP2 256 FPGA - PB31A_CLK4+ */
308 { 7, MPP_GPIO }, /* Lat ECP2 256 FPGA - PB22B */
309 { 8, MPP_UNUSED },
310 { 9, MPP_UNUSED },
311 { 10, MPP_UNUSED },
312 { 11, MPP_UNUSED },
313 { 12, MPP_UNUSED },
314 { 13, MPP_UNUSED },
315 { 14, MPP_UNUSED },
316 { 15, MPP_UNUSED },
317 { 16, MPP_UART },
318 { 17, MPP_UART },
319 { 18, MPP_UART },
320 { 19, MPP_UART },
Alexander Clouterf5412862009-02-06 21:59:15 +0000321 /*
322 * MPP[20] PCI Clock Out 1
323 * MPP[21] PCI Clock Out 0
324 * MPP[22] Unused
325 * MPP[23] Unused
326 * MPP[24] Unused
327 * MPP[25] Unused
328 */
Alexander Clouter7171d862008-05-31 22:32:37 +0100329 { -1 },
330};
331
332static void __init ts78xx_init(void)
333{
Alexander Clouter39008f92009-02-06 22:16:55 +0000334 int ret;
335
Alexander Clouter7171d862008-05-31 22:32:37 +0100336 /*
337 * Setup basic Orion functions. Need to be called early.
338 */
339 orion5x_init();
340
Alexander Clouter7171d862008-05-31 22:32:37 +0100341 orion5x_mpp_conf(ts78xx_mpp_modes);
342
343 /*
Alexander Clouter7171d862008-05-31 22:32:37 +0100344 * Configure peripherals.
345 */
346 orion5x_ehci0_init();
347 orion5x_ehci1_init();
348 orion5x_eth_init(&ts78xx_eth_data);
349 orion5x_sata_init(&ts78xx_sata_data);
350 orion5x_uart0_init();
351 orion5x_uart1_init();
Saeed Bishara1d5a1a62008-06-16 23:25:12 -1100352 orion5x_xor_init();
Alexander Clouter7171d862008-05-31 22:32:37 +0100353
Alexander Clouter39008f92009-02-06 22:16:55 +0000354 /* FPGA init */
355 ts78xx_fpga_devices_zero_init();
356 ret = ts78xx_fpga_load();
357 ret = sysfs_create_file(power_kobj, &ts78xx_fpga_attr.attr);
358 if (ret)
359 printk(KERN_ERR "sysfs_create_file failed: %d\n", ret);
Alexander Clouter7171d862008-05-31 22:32:37 +0100360}
361
362MACHINE_START(TS78XX, "Technologic Systems TS-78xx SBC")
363 /* Maintainer: Alexander Clouter <alex@digriz.org.uk> */
364 .phys_io = ORION5X_REGS_PHYS_BASE,
365 .io_pg_offst = ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
366 .boot_params = 0x00000100,
367 .init_machine = ts78xx_init,
368 .map_io = ts78xx_map_io,
369 .init_irq = orion5x_init_irq,
370 .timer = &orion5x_timer,
371MACHINE_END