blob: 640b44db5a3f17dff80180c0ecaff768712a3404 [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 ****************************************************************************/
Alexander Clouter39008f92009-02-06 22:16:55 +000078#define TS_RTC_CTRL (TS78XX_FPGA_REGS_VIRT_BASE | 0x808)
79#define TS_RTC_DATA (TS78XX_FPGA_REGS_VIRT_BASE | 0x80c)
80
81static unsigned char ts78xx_ts_rtc_readbyte(unsigned long addr)
Alexander Clouter7171d862008-05-31 22:32:37 +010082{
Alexander Clouter39008f92009-02-06 22:16:55 +000083 writeb(addr, TS_RTC_CTRL);
84 return readb(TS_RTC_DATA);
Alexander Clouter7171d862008-05-31 22:32:37 +010085}
86
Alexander Clouter39008f92009-02-06 22:16:55 +000087static void ts78xx_ts_rtc_writebyte(unsigned char value, unsigned long addr)
Alexander Clouter7171d862008-05-31 22:32:37 +010088{
Alexander Clouter39008f92009-02-06 22:16:55 +000089 writeb(addr, TS_RTC_CTRL);
90 writeb(value, TS_RTC_DATA);
Alexander Clouter7171d862008-05-31 22:32:37 +010091}
92
Alexander Clouter39008f92009-02-06 22:16:55 +000093static struct m48t86_ops ts78xx_ts_rtc_ops = {
94 .readbyte = ts78xx_ts_rtc_readbyte,
95 .writebyte = ts78xx_ts_rtc_writebyte,
Alexander Clouter7171d862008-05-31 22:32:37 +010096};
97
Alexander Clouter39008f92009-02-06 22:16:55 +000098static struct platform_device ts78xx_ts_rtc_device = {
Alexander Clouter7171d862008-05-31 22:32:37 +010099 .name = "rtc-m48t86",
100 .id = -1,
101 .dev = {
Alexander Clouter39008f92009-02-06 22:16:55 +0000102 .platform_data = &ts78xx_ts_rtc_ops,
Alexander Clouter7171d862008-05-31 22:32:37 +0100103 },
104 .num_resources = 0,
105};
106
107/*
108 * TS uses some of the user storage space on the RTC chip so see if it is
109 * present; as it's an optional feature at purchase time and not all boards
110 * will have it present
111 *
112 * I've used the method TS use in their rtc7800.c example for the detection
113 *
114 * TODO: track down a guinea pig without an RTC to see if we can work out a
115 * better RTC detection routine
116 */
Alexander Clouter39008f92009-02-06 22:16:55 +0000117static int ts78xx_ts_rtc_load(void)
Alexander Clouter7171d862008-05-31 22:32:37 +0100118{
Alexander Clouterf5273fa2009-02-23 22:37:36 +0000119 int rc;
Alexander Clouter7171d862008-05-31 22:32:37 +0100120 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);
Alexander Clouterf5273fa2009-02-23 22:37:36 +0000133
Alexander Clouter39008f92009-02-06 22:16:55 +0000134 if (ts78xx_fpga.supports.ts_rtc.init == 0) {
Alexander Clouterf5273fa2009-02-23 22:37:36 +0000135 rc = platform_device_register(&ts78xx_ts_rtc_device);
136 if (!rc)
137 ts78xx_fpga.supports.ts_rtc.init = 1;
Alexander Clouter39008f92009-02-06 22:16:55 +0000138 } else
Alexander Clouterf5273fa2009-02-23 22:37:36 +0000139 rc = platform_device_add(&ts78xx_ts_rtc_device);
140
141 return rc;
Alexander Clouter7171d862008-05-31 22:32:37 +0100142 }
143 }
144
Alexander Clouter39008f92009-02-06 22:16:55 +0000145 return -ENODEV;
Alexander Clouter7171d862008-05-31 22:32:37 +0100146};
Alexander Clouter39008f92009-02-06 22:16:55 +0000147
148static void ts78xx_ts_rtc_unload(void)
149{
150 platform_device_del(&ts78xx_ts_rtc_device);
151}
Alexander Clouter7171d862008-05-31 22:32:37 +0100152
153/*****************************************************************************
Alexander Clouter39008f92009-02-06 22:16:55 +0000154 * FPGA 'hotplug' support code
Alexander Clouter7171d862008-05-31 22:32:37 +0100155 ****************************************************************************/
Alexander Clouter39008f92009-02-06 22:16:55 +0000156static void ts78xx_fpga_devices_zero_init(void)
Alexander Clouter7171d862008-05-31 22:32:37 +0100157{
Alexander Clouter39008f92009-02-06 22:16:55 +0000158 ts78xx_fpga.supports.ts_rtc.init = 0;
159}
Alexander Clouter7171d862008-05-31 22:32:37 +0100160
Alexander Clouter39008f92009-02-06 22:16:55 +0000161static void ts78xx_fpga_supports(void)
162{
163 /* TODO: put this 'table' into ts78xx-fpga.h */
164 switch (ts78xx_fpga.id) {
165 case TS7800_REV_B:
166 ts78xx_fpga.supports.ts_rtc.present = 1;
167 break;
168 default:
169 ts78xx_fpga.supports.ts_rtc.present = 0;
170 }
171}
172
173static int ts78xx_fpga_load_devices(void)
174{
175 int tmp, ret = 0;
176
177 if (ts78xx_fpga.supports.ts_rtc.present == 1) {
178 tmp = ts78xx_ts_rtc_load();
Alexander Clouterf5273fa2009-02-23 22:37:36 +0000179 if (tmp) {
Alexander Clouter673492a2009-02-23 22:38:50 +0000180 printk(KERN_INFO "TS-78xx: RTC not registered\n");
Alexander Clouterf5273fa2009-02-23 22:37:36 +0000181 ts78xx_fpga.supports.ts_rtc.present = 0;
182 }
Alexander Clouter39008f92009-02-06 22:16:55 +0000183 ret |= tmp;
184 }
185
186 return ret;
187}
188
189static int ts78xx_fpga_unload_devices(void)
190{
191 int ret = 0;
192
193 if (ts78xx_fpga.supports.ts_rtc.present == 1)
194 ts78xx_ts_rtc_unload();
195
196 return ret;
197}
198
199static int ts78xx_fpga_load(void)
200{
201 ts78xx_fpga.id = readl(TS78XX_FPGA_REGS_VIRT_BASE);
202
203 printk(KERN_INFO "TS-78xx FPGA: magic=0x%.6x, rev=0x%.2x\n",
204 (ts78xx_fpga.id >> 8) & 0xffffff,
205 ts78xx_fpga.id & 0xff);
206
207 ts78xx_fpga_supports();
208
209 if (ts78xx_fpga_load_devices()) {
210 ts78xx_fpga.state = -1;
211 return -EBUSY;
212 }
213
214 return 0;
Alexander Clouter7171d862008-05-31 22:32:37 +0100215};
216
Alexander Clouter39008f92009-02-06 22:16:55 +0000217static int ts78xx_fpga_unload(void)
218{
219 unsigned int fpga_id;
220
221 fpga_id = readl(TS78XX_FPGA_REGS_VIRT_BASE);
222
223 /*
224 * There does not seem to be a feasible way to block access to the GPIO
225 * pins from userspace (/dev/mem). This if clause should hopefully warn
226 * those foolish enough not to follow 'policy' :)
227 *
228 * UrJTAG SVN since r1381 can be used to reprogram the FPGA
229 */
230 if (ts78xx_fpga.id != fpga_id) {
231 printk(KERN_ERR "TS-78xx FPGA: magic/rev mismatch\n"
232 "TS-78xx FPGA: was 0x%.6x/%.2x but now 0x%.6x/%.2x\n",
233 (ts78xx_fpga.id >> 8) & 0xffffff, ts78xx_fpga.id & 0xff,
234 (fpga_id >> 8) & 0xffffff, fpga_id & 0xff);
235 ts78xx_fpga.state = -1;
236 return -EBUSY;
237 }
238
239 if (ts78xx_fpga_unload_devices()) {
240 ts78xx_fpga.state = -1;
241 return -EBUSY;
242 }
243
244 return 0;
245};
246
247static ssize_t ts78xx_fpga_show(struct kobject *kobj,
248 struct kobj_attribute *attr, char *buf)
249{
250 if (ts78xx_fpga.state < 0)
251 return sprintf(buf, "borked\n");
252
253 return sprintf(buf, "%s\n", (ts78xx_fpga.state) ? "online" : "offline");
254}
255
256static ssize_t ts78xx_fpga_store(struct kobject *kobj,
257 struct kobj_attribute *attr, const char *buf, size_t n)
258{
259 int value, ret;
260
261 if (ts78xx_fpga.state < 0) {
262 printk(KERN_ERR "TS-78xx FPGA: borked, you must powercycle asap\n");
263 return -EBUSY;
264 }
265
266 if (strncmp(buf, "online", sizeof("online") - 1) == 0)
267 value = 1;
268 else if (strncmp(buf, "offline", sizeof("offline") - 1) == 0)
269 value = 0;
270 else {
271 printk(KERN_ERR "ts78xx_fpga_store: Invalid value\n");
272 return -EINVAL;
273 }
274
275 if (ts78xx_fpga.state == value)
276 return n;
277
278 ret = (ts78xx_fpga.state == 0)
279 ? ts78xx_fpga_load()
280 : ts78xx_fpga_unload();
281
282 if (!(ret < 0))
283 ts78xx_fpga.state = value;
284
285 return n;
286}
287
288static struct kobj_attribute ts78xx_fpga_attr =
289 __ATTR(ts78xx_fpga, 0644, ts78xx_fpga_show, ts78xx_fpga_store);
290
Alexander Clouter7171d862008-05-31 22:32:37 +0100291/*****************************************************************************
292 * General Setup
293 ****************************************************************************/
294static struct orion5x_mpp_mode ts78xx_mpp_modes[] __initdata = {
295 { 0, MPP_UNUSED },
296 { 1, MPP_GPIO }, /* JTAG Clock */
297 { 2, MPP_GPIO }, /* JTAG Data In */
298 { 3, MPP_GPIO }, /* Lat ECP2 256 FPGA - PB2B */
299 { 4, MPP_GPIO }, /* JTAG Data Out */
300 { 5, MPP_GPIO }, /* JTAG TMS */
301 { 6, MPP_GPIO }, /* Lat ECP2 256 FPGA - PB31A_CLK4+ */
302 { 7, MPP_GPIO }, /* Lat ECP2 256 FPGA - PB22B */
303 { 8, MPP_UNUSED },
304 { 9, MPP_UNUSED },
305 { 10, MPP_UNUSED },
306 { 11, MPP_UNUSED },
307 { 12, MPP_UNUSED },
308 { 13, MPP_UNUSED },
309 { 14, MPP_UNUSED },
310 { 15, MPP_UNUSED },
311 { 16, MPP_UART },
312 { 17, MPP_UART },
313 { 18, MPP_UART },
314 { 19, MPP_UART },
Alexander Clouterf5412862009-02-06 21:59:15 +0000315 /*
316 * MPP[20] PCI Clock Out 1
317 * MPP[21] PCI Clock Out 0
318 * MPP[22] Unused
319 * MPP[23] Unused
320 * MPP[24] Unused
321 * MPP[25] Unused
322 */
Alexander Clouter7171d862008-05-31 22:32:37 +0100323 { -1 },
324};
325
326static void __init ts78xx_init(void)
327{
Alexander Clouter39008f92009-02-06 22:16:55 +0000328 int ret;
329
Alexander Clouter7171d862008-05-31 22:32:37 +0100330 /*
331 * Setup basic Orion functions. Need to be called early.
332 */
333 orion5x_init();
334
Alexander Clouter7171d862008-05-31 22:32:37 +0100335 orion5x_mpp_conf(ts78xx_mpp_modes);
336
337 /*
Alexander Clouter7171d862008-05-31 22:32:37 +0100338 * Configure peripherals.
339 */
340 orion5x_ehci0_init();
341 orion5x_ehci1_init();
342 orion5x_eth_init(&ts78xx_eth_data);
343 orion5x_sata_init(&ts78xx_sata_data);
344 orion5x_uart0_init();
345 orion5x_uart1_init();
Saeed Bishara1d5a1a62008-06-16 23:25:12 -1100346 orion5x_xor_init();
Alexander Clouter7171d862008-05-31 22:32:37 +0100347
Alexander Clouter39008f92009-02-06 22:16:55 +0000348 /* FPGA init */
349 ts78xx_fpga_devices_zero_init();
350 ret = ts78xx_fpga_load();
351 ret = sysfs_create_file(power_kobj, &ts78xx_fpga_attr.attr);
352 if (ret)
353 printk(KERN_ERR "sysfs_create_file failed: %d\n", ret);
Alexander Clouter7171d862008-05-31 22:32:37 +0100354}
355
356MACHINE_START(TS78XX, "Technologic Systems TS-78xx SBC")
357 /* Maintainer: Alexander Clouter <alex@digriz.org.uk> */
358 .phys_io = ORION5X_REGS_PHYS_BASE,
359 .io_pg_offst = ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
360 .boot_params = 0x00000100,
361 .init_machine = ts78xx_init,
362 .map_io = ts78xx_map_io,
363 .init_irq = orion5x_init_irq,
364 .timer = &orion5x_timer,
365MACHINE_END