blob: 778b11860ee660fecd2f730db16e2835407dd2b5 [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{
Alexander Clouterf5273fa2009-02-23 22:37:36 +0000120 int rc;
Alexander Clouter7171d862008-05-31 22:32:37 +0100121 unsigned char tmp_rtc0, tmp_rtc1;
122
Alexander Clouter39008f92009-02-06 22:16:55 +0000123 tmp_rtc0 = ts78xx_ts_rtc_readbyte(126);
124 tmp_rtc1 = ts78xx_ts_rtc_readbyte(127);
Alexander Clouter7171d862008-05-31 22:32:37 +0100125
Alexander Clouter39008f92009-02-06 22:16:55 +0000126 ts78xx_ts_rtc_writebyte(0x00, 126);
127 ts78xx_ts_rtc_writebyte(0x55, 127);
128 if (ts78xx_ts_rtc_readbyte(127) == 0x55) {
129 ts78xx_ts_rtc_writebyte(0xaa, 127);
130 if (ts78xx_ts_rtc_readbyte(127) == 0xaa
131 && ts78xx_ts_rtc_readbyte(126) == 0x00) {
132 ts78xx_ts_rtc_writebyte(tmp_rtc0, 126);
133 ts78xx_ts_rtc_writebyte(tmp_rtc1, 127);
Alexander Clouterf5273fa2009-02-23 22:37:36 +0000134
Alexander Clouter39008f92009-02-06 22:16:55 +0000135 if (ts78xx_fpga.supports.ts_rtc.init == 0) {
Alexander Clouterf5273fa2009-02-23 22:37:36 +0000136 rc = platform_device_register(&ts78xx_ts_rtc_device);
137 if (!rc)
138 ts78xx_fpga.supports.ts_rtc.init = 1;
Alexander Clouter39008f92009-02-06 22:16:55 +0000139 } else
Alexander Clouterf5273fa2009-02-23 22:37:36 +0000140 rc = platform_device_add(&ts78xx_ts_rtc_device);
141
142 return rc;
Alexander Clouter7171d862008-05-31 22:32:37 +0100143 }
144 }
145
Alexander Clouter39008f92009-02-06 22:16:55 +0000146 return -ENODEV;
Alexander Clouter7171d862008-05-31 22:32:37 +0100147};
Alexander Clouter39008f92009-02-06 22:16:55 +0000148
149static void ts78xx_ts_rtc_unload(void)
150{
151 platform_device_del(&ts78xx_ts_rtc_device);
152}
Alexander Clouter7171d862008-05-31 22:32:37 +0100153#else
Alexander Clouter39008f92009-02-06 22:16:55 +0000154static int ts78xx_ts_rtc_load(void)
Alexander Clouter7171d862008-05-31 22:32:37 +0100155{
Alexander Clouterf5273fa2009-02-23 22:37:36 +0000156 return -ENODEV;
Alexander Clouter7171d862008-05-31 22:32:37 +0100157}
Alexander Clouter39008f92009-02-06 22:16:55 +0000158
159static void ts78xx_ts_rtc_unload(void)
160{
161}
Alexander Clouter7171d862008-05-31 22:32:37 +0100162#endif
163
164/*****************************************************************************
Alexander Clouter39008f92009-02-06 22:16:55 +0000165 * FPGA 'hotplug' support code
Alexander Clouter7171d862008-05-31 22:32:37 +0100166 ****************************************************************************/
Alexander Clouter39008f92009-02-06 22:16:55 +0000167static void ts78xx_fpga_devices_zero_init(void)
Alexander Clouter7171d862008-05-31 22:32:37 +0100168{
Alexander Clouter39008f92009-02-06 22:16:55 +0000169 ts78xx_fpga.supports.ts_rtc.init = 0;
170}
Alexander Clouter7171d862008-05-31 22:32:37 +0100171
Alexander Clouter39008f92009-02-06 22:16:55 +0000172static void ts78xx_fpga_supports(void)
173{
174 /* TODO: put this 'table' into ts78xx-fpga.h */
175 switch (ts78xx_fpga.id) {
176 case TS7800_REV_B:
177 ts78xx_fpga.supports.ts_rtc.present = 1;
178 break;
179 default:
180 ts78xx_fpga.supports.ts_rtc.present = 0;
181 }
182}
183
184static int ts78xx_fpga_load_devices(void)
185{
186 int tmp, ret = 0;
187
188 if (ts78xx_fpga.supports.ts_rtc.present == 1) {
189 tmp = ts78xx_ts_rtc_load();
Alexander Clouterf5273fa2009-02-23 22:37:36 +0000190 if (tmp) {
191 printk(KERN_INFO "TS-78xx RTC"
192 " not detected or enabled\n");
193 ts78xx_fpga.supports.ts_rtc.present = 0;
194 }
Alexander Clouter39008f92009-02-06 22:16:55 +0000195 ret |= tmp;
196 }
197
198 return ret;
199}
200
201static int ts78xx_fpga_unload_devices(void)
202{
203 int ret = 0;
204
205 if (ts78xx_fpga.supports.ts_rtc.present == 1)
206 ts78xx_ts_rtc_unload();
207
208 return ret;
209}
210
211static int ts78xx_fpga_load(void)
212{
213 ts78xx_fpga.id = readl(TS78XX_FPGA_REGS_VIRT_BASE);
214
215 printk(KERN_INFO "TS-78xx FPGA: magic=0x%.6x, rev=0x%.2x\n",
216 (ts78xx_fpga.id >> 8) & 0xffffff,
217 ts78xx_fpga.id & 0xff);
218
219 ts78xx_fpga_supports();
220
221 if (ts78xx_fpga_load_devices()) {
222 ts78xx_fpga.state = -1;
223 return -EBUSY;
224 }
225
226 return 0;
Alexander Clouter7171d862008-05-31 22:32:37 +0100227};
228
Alexander Clouter39008f92009-02-06 22:16:55 +0000229static int ts78xx_fpga_unload(void)
230{
231 unsigned int fpga_id;
232
233 fpga_id = readl(TS78XX_FPGA_REGS_VIRT_BASE);
234
235 /*
236 * There does not seem to be a feasible way to block access to the GPIO
237 * pins from userspace (/dev/mem). This if clause should hopefully warn
238 * those foolish enough not to follow 'policy' :)
239 *
240 * UrJTAG SVN since r1381 can be used to reprogram the FPGA
241 */
242 if (ts78xx_fpga.id != fpga_id) {
243 printk(KERN_ERR "TS-78xx FPGA: magic/rev mismatch\n"
244 "TS-78xx FPGA: was 0x%.6x/%.2x but now 0x%.6x/%.2x\n",
245 (ts78xx_fpga.id >> 8) & 0xffffff, ts78xx_fpga.id & 0xff,
246 (fpga_id >> 8) & 0xffffff, fpga_id & 0xff);
247 ts78xx_fpga.state = -1;
248 return -EBUSY;
249 }
250
251 if (ts78xx_fpga_unload_devices()) {
252 ts78xx_fpga.state = -1;
253 return -EBUSY;
254 }
255
256 return 0;
257};
258
259static ssize_t ts78xx_fpga_show(struct kobject *kobj,
260 struct kobj_attribute *attr, char *buf)
261{
262 if (ts78xx_fpga.state < 0)
263 return sprintf(buf, "borked\n");
264
265 return sprintf(buf, "%s\n", (ts78xx_fpga.state) ? "online" : "offline");
266}
267
268static ssize_t ts78xx_fpga_store(struct kobject *kobj,
269 struct kobj_attribute *attr, const char *buf, size_t n)
270{
271 int value, ret;
272
273 if (ts78xx_fpga.state < 0) {
274 printk(KERN_ERR "TS-78xx FPGA: borked, you must powercycle asap\n");
275 return -EBUSY;
276 }
277
278 if (strncmp(buf, "online", sizeof("online") - 1) == 0)
279 value = 1;
280 else if (strncmp(buf, "offline", sizeof("offline") - 1) == 0)
281 value = 0;
282 else {
283 printk(KERN_ERR "ts78xx_fpga_store: Invalid value\n");
284 return -EINVAL;
285 }
286
287 if (ts78xx_fpga.state == value)
288 return n;
289
290 ret = (ts78xx_fpga.state == 0)
291 ? ts78xx_fpga_load()
292 : ts78xx_fpga_unload();
293
294 if (!(ret < 0))
295 ts78xx_fpga.state = value;
296
297 return n;
298}
299
300static struct kobj_attribute ts78xx_fpga_attr =
301 __ATTR(ts78xx_fpga, 0644, ts78xx_fpga_show, ts78xx_fpga_store);
302
Alexander Clouter7171d862008-05-31 22:32:37 +0100303/*****************************************************************************
304 * General Setup
305 ****************************************************************************/
306static struct orion5x_mpp_mode ts78xx_mpp_modes[] __initdata = {
307 { 0, MPP_UNUSED },
308 { 1, MPP_GPIO }, /* JTAG Clock */
309 { 2, MPP_GPIO }, /* JTAG Data In */
310 { 3, MPP_GPIO }, /* Lat ECP2 256 FPGA - PB2B */
311 { 4, MPP_GPIO }, /* JTAG Data Out */
312 { 5, MPP_GPIO }, /* JTAG TMS */
313 { 6, MPP_GPIO }, /* Lat ECP2 256 FPGA - PB31A_CLK4+ */
314 { 7, MPP_GPIO }, /* Lat ECP2 256 FPGA - PB22B */
315 { 8, MPP_UNUSED },
316 { 9, MPP_UNUSED },
317 { 10, MPP_UNUSED },
318 { 11, MPP_UNUSED },
319 { 12, MPP_UNUSED },
320 { 13, MPP_UNUSED },
321 { 14, MPP_UNUSED },
322 { 15, MPP_UNUSED },
323 { 16, MPP_UART },
324 { 17, MPP_UART },
325 { 18, MPP_UART },
326 { 19, MPP_UART },
Alexander Clouterf5412862009-02-06 21:59:15 +0000327 /*
328 * MPP[20] PCI Clock Out 1
329 * MPP[21] PCI Clock Out 0
330 * MPP[22] Unused
331 * MPP[23] Unused
332 * MPP[24] Unused
333 * MPP[25] Unused
334 */
Alexander Clouter7171d862008-05-31 22:32:37 +0100335 { -1 },
336};
337
338static void __init ts78xx_init(void)
339{
Alexander Clouter39008f92009-02-06 22:16:55 +0000340 int ret;
341
Alexander Clouter7171d862008-05-31 22:32:37 +0100342 /*
343 * Setup basic Orion functions. Need to be called early.
344 */
345 orion5x_init();
346
Alexander Clouter7171d862008-05-31 22:32:37 +0100347 orion5x_mpp_conf(ts78xx_mpp_modes);
348
349 /*
Alexander Clouter7171d862008-05-31 22:32:37 +0100350 * Configure peripherals.
351 */
352 orion5x_ehci0_init();
353 orion5x_ehci1_init();
354 orion5x_eth_init(&ts78xx_eth_data);
355 orion5x_sata_init(&ts78xx_sata_data);
356 orion5x_uart0_init();
357 orion5x_uart1_init();
Saeed Bishara1d5a1a62008-06-16 23:25:12 -1100358 orion5x_xor_init();
Alexander Clouter7171d862008-05-31 22:32:37 +0100359
Alexander Clouter39008f92009-02-06 22:16:55 +0000360 /* FPGA init */
361 ts78xx_fpga_devices_zero_init();
362 ret = ts78xx_fpga_load();
363 ret = sysfs_create_file(power_kobj, &ts78xx_fpga_attr.attr);
364 if (ret)
365 printk(KERN_ERR "sysfs_create_file failed: %d\n", ret);
Alexander Clouter7171d862008-05-31 22:32:37 +0100366}
367
368MACHINE_START(TS78XX, "Technologic Systems TS-78xx SBC")
369 /* Maintainer: Alexander Clouter <alex@digriz.org.uk> */
370 .phys_io = ORION5X_REGS_PHYS_BASE,
371 .io_pg_offst = ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
372 .boot_params = 0x00000100,
373 .init_machine = ts78xx_init,
374 .map_io = ts78xx_map_io,
375 .init_irq = orion5x_init_irq,
376 .timer = &orion5x_timer,
377MACHINE_END