2 * arch/arm/mach-orion5x/ts78xx-setup.c
4 * Maintainer: Alexander Clouter <alex@digriz.org.uk>
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.
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 <asm/mach-types.h>
19 #include <asm/mach/arch.h>
20 #include <asm/mach/map.h>
21 #include <mach/orion5x.h>
24 #include "ts78xx-fpga.h"
26 /*****************************************************************************
28 ****************************************************************************/
31 * FPGA - lives where the PCI bus would be at ORION5X_PCI_MEM_PHYS_BASE
33 #define TS78XX_FPGA_REGS_PHYS_BASE 0xe8000000
34 #define TS78XX_FPGA_REGS_VIRT_BASE 0xff900000
35 #define TS78XX_FPGA_REGS_SIZE SZ_1M
37 static struct ts78xx_fpga_data ts78xx_fpga = {
40 /* .supports = ... - populated by ts78xx_fpga_supports() */
43 /*****************************************************************************
45 ****************************************************************************/
46 static struct map_desc ts78xx_io_desc[] __initdata = {
48 .virtual = TS78XX_FPGA_REGS_VIRT_BASE,
49 .pfn = __phys_to_pfn(TS78XX_FPGA_REGS_PHYS_BASE),
50 .length = TS78XX_FPGA_REGS_SIZE,
55 void __init ts78xx_map_io(void)
58 iotable_init(ts78xx_io_desc, ARRAY_SIZE(ts78xx_io_desc));
61 /*****************************************************************************
63 ****************************************************************************/
64 static struct mv643xx_eth_platform_data ts78xx_eth_data = {
65 .phy_addr = MV643XX_ETH_PHY_ADDR(0),
68 /*****************************************************************************
70 ****************************************************************************/
71 static struct mv_sata_platform_data ts78xx_sata_data = {
75 /*****************************************************************************
76 * RTC M48T86 - nicked^Wborrowed from arch/arm/mach-ep93xx/ts72xx.c
77 ****************************************************************************/
78 #ifdef CONFIG_RTC_DRV_M48T86
79 #define TS_RTC_CTRL (TS78XX_FPGA_REGS_VIRT_BASE | 0x808)
80 #define TS_RTC_DATA (TS78XX_FPGA_REGS_VIRT_BASE | 0x80c)
82 static unsigned char ts78xx_ts_rtc_readbyte(unsigned long addr)
84 writeb(addr, TS_RTC_CTRL);
85 return readb(TS_RTC_DATA);
88 static void ts78xx_ts_rtc_writebyte(unsigned char value, unsigned long addr)
90 writeb(addr, TS_RTC_CTRL);
91 writeb(value, TS_RTC_DATA);
94 static struct m48t86_ops ts78xx_ts_rtc_ops = {
95 .readbyte = ts78xx_ts_rtc_readbyte,
96 .writebyte = ts78xx_ts_rtc_writebyte,
99 static struct platform_device ts78xx_ts_rtc_device = {
100 .name = "rtc-m48t86",
103 .platform_data = &ts78xx_ts_rtc_ops,
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
113 * I've used the method TS use in their rtc7800.c example for the detection
115 * TODO: track down a guinea pig without an RTC to see if we can work out a
116 * better RTC detection routine
118 static int ts78xx_ts_rtc_load(void)
121 unsigned char tmp_rtc0, tmp_rtc1;
123 tmp_rtc0 = ts78xx_ts_rtc_readbyte(126);
124 tmp_rtc1 = ts78xx_ts_rtc_readbyte(127);
126 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);
135 if (ts78xx_fpga.supports.ts_rtc.init == 0) {
136 rc = platform_device_register(&ts78xx_ts_rtc_device);
138 ts78xx_fpga.supports.ts_rtc.init = 1;
140 rc = platform_device_add(&ts78xx_ts_rtc_device);
149 static void ts78xx_ts_rtc_unload(void)
151 platform_device_del(&ts78xx_ts_rtc_device);
154 static int ts78xx_ts_rtc_load(void)
159 static void ts78xx_ts_rtc_unload(void)
164 /*****************************************************************************
165 * FPGA 'hotplug' support code
166 ****************************************************************************/
167 static void ts78xx_fpga_devices_zero_init(void)
169 ts78xx_fpga.supports.ts_rtc.init = 0;
172 static void ts78xx_fpga_supports(void)
174 /* TODO: put this 'table' into ts78xx-fpga.h */
175 switch (ts78xx_fpga.id) {
177 ts78xx_fpga.supports.ts_rtc.present = 1;
180 ts78xx_fpga.supports.ts_rtc.present = 0;
184 static int ts78xx_fpga_load_devices(void)
188 if (ts78xx_fpga.supports.ts_rtc.present == 1) {
189 tmp = ts78xx_ts_rtc_load();
191 printk(KERN_INFO "TS-78xx RTC"
192 " not detected or enabled\n");
193 ts78xx_fpga.supports.ts_rtc.present = 0;
201 static int ts78xx_fpga_unload_devices(void)
205 if (ts78xx_fpga.supports.ts_rtc.present == 1)
206 ts78xx_ts_rtc_unload();
211 static int ts78xx_fpga_load(void)
213 ts78xx_fpga.id = readl(TS78XX_FPGA_REGS_VIRT_BASE);
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);
219 ts78xx_fpga_supports();
221 if (ts78xx_fpga_load_devices()) {
222 ts78xx_fpga.state = -1;
229 static int ts78xx_fpga_unload(void)
231 unsigned int fpga_id;
233 fpga_id = readl(TS78XX_FPGA_REGS_VIRT_BASE);
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' :)
240 * UrJTAG SVN since r1381 can be used to reprogram the FPGA
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;
251 if (ts78xx_fpga_unload_devices()) {
252 ts78xx_fpga.state = -1;
259 static ssize_t ts78xx_fpga_show(struct kobject *kobj,
260 struct kobj_attribute *attr, char *buf)
262 if (ts78xx_fpga.state < 0)
263 return sprintf(buf, "borked\n");
265 return sprintf(buf, "%s\n", (ts78xx_fpga.state) ? "online" : "offline");
268 static ssize_t ts78xx_fpga_store(struct kobject *kobj,
269 struct kobj_attribute *attr, const char *buf, size_t n)
273 if (ts78xx_fpga.state < 0) {
274 printk(KERN_ERR "TS-78xx FPGA: borked, you must powercycle asap\n");
278 if (strncmp(buf, "online", sizeof("online") - 1) == 0)
280 else if (strncmp(buf, "offline", sizeof("offline") - 1) == 0)
283 printk(KERN_ERR "ts78xx_fpga_store: Invalid value\n");
287 if (ts78xx_fpga.state == value)
290 ret = (ts78xx_fpga.state == 0)
292 : ts78xx_fpga_unload();
295 ts78xx_fpga.state = value;
300 static struct kobj_attribute ts78xx_fpga_attr =
301 __ATTR(ts78xx_fpga, 0644, ts78xx_fpga_show, ts78xx_fpga_store);
303 /*****************************************************************************
305 ****************************************************************************/
306 static struct orion5x_mpp_mode ts78xx_mpp_modes[] __initdata = {
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 */
328 * MPP[20] PCI Clock Out 1
329 * MPP[21] PCI Clock Out 0
338 static void __init ts78xx_init(void)
343 * Setup basic Orion functions. Need to be called early.
347 orion5x_mpp_conf(ts78xx_mpp_modes);
350 * Configure peripherals.
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();
361 ts78xx_fpga_devices_zero_init();
362 ret = ts78xx_fpga_load();
363 ret = sysfs_create_file(power_kobj, &ts78xx_fpga_attr.attr);
365 printk(KERN_ERR "sysfs_create_file failed: %d\n", ret);
368 MACHINE_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,