aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorAlexander Clouter <alex@digriz.org.uk>2009-02-06 17:16:55 -0500
committerAlexander Clouter <alex@digriz.org.uk>2009-02-06 17:16:55 -0500
commit39008f959f4f3b60eecc5cec0ca077146c1f366b (patch)
tree35d9aaf4c722f0b9c9f8f2e7ef33a60a4ab28fff /arch
parentf54128609c4e7792fb52b03c3db0da78627ce607 (diff)
[ARM] orion5x: TS-78xx support for 'hotplug' of FPGA devices
the FPGA on the TS-7800 provides access to a number of devices and so we have to be careful when reprogramming it. As we are effectively turning a bus off/on we have to inform the kernel that it should stop using anything provided by the FPGA (currently only the RTC however the NAND, LCD, etc is to come) before it's reprogrammed. Once reprogramed, we can tell the kernel to (re)enable things by checking the FPGA ID against a lookup table for what a particular FPGA bitstream can provide. Signed-off-by: Alexander Clouter <alex@digriz.org.uk>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-orion5x/Kconfig1
-rw-r--r--arch/arm/mach-orion5x/ts78xx-fpga.h27
-rw-r--r--arch/arm/mach-orion5x/ts78xx-setup.c251
3 files changed, 224 insertions, 55 deletions
diff --git a/arch/arm/mach-orion5x/Kconfig b/arch/arm/mach-orion5x/Kconfig
index f59a8d0e0824..2c7035d8dcbf 100644
--- a/arch/arm/mach-orion5x/Kconfig
+++ b/arch/arm/mach-orion5x/Kconfig
@@ -71,6 +71,7 @@ config MACH_WRT350N_V2
71 71
72config MACH_TS78XX 72config MACH_TS78XX
73 bool "Technologic Systems TS-78xx" 73 bool "Technologic Systems TS-78xx"
74 select PM
74 help 75 help
75 Say 'Y' here if you want your kernel to support the 76 Say 'Y' here if you want your kernel to support the
76 Technologic Systems TS-78xx platform. 77 Technologic Systems TS-78xx platform.
diff --git a/arch/arm/mach-orion5x/ts78xx-fpga.h b/arch/arm/mach-orion5x/ts78xx-fpga.h
new file mode 100644
index 000000000000..0b8e30faff14
--- /dev/null
+++ b/arch/arm/mach-orion5x/ts78xx-fpga.h
@@ -0,0 +1,27 @@
1#define FPGAID(_magic, _rev) ((_magic << 8) + _rev)
2
3/*
4 * get yer id's from http://ts78xx.digriz.org.uk/
5 * do *not* make up your own or 'borrow' any!
6 */
7enum fpga_ids {
8 /* Technologic Systems */
9 TS7800_REV_B = FPGAID(0x00b480, 0x03),
10};
11
12struct fpga_device {
13 unsigned present:1;
14 unsigned init:1;
15};
16
17struct fpga_devices {
18 /* Technologic Systems */
19 struct fpga_device ts_rtc;
20};
21
22struct ts78xx_fpga_data {
23 unsigned int id;
24 int state;
25
26 struct fpga_devices supports;
27};
diff --git a/arch/arm/mach-orion5x/ts78xx-setup.c b/arch/arm/mach-orion5x/ts78xx-setup.c
index b194956518a2..baa25d0fd5c9 100644
--- a/arch/arm/mach-orion5x/ts78xx-setup.c
+++ b/arch/arm/mach-orion5x/ts78xx-setup.c
@@ -10,6 +10,7 @@
10 10
11#include <linux/kernel.h> 11#include <linux/kernel.h>
12#include <linux/init.h> 12#include <linux/init.h>
13#include <linux/sysfs.h>
13#include <linux/platform_device.h> 14#include <linux/platform_device.h>
14#include <linux/mv643xx_eth.h> 15#include <linux/mv643xx_eth.h>
15#include <linux/ata_platform.h> 16#include <linux/ata_platform.h>
@@ -20,6 +21,7 @@
20#include <mach/orion5x.h> 21#include <mach/orion5x.h>
21#include "common.h" 22#include "common.h"
22#include "mpp.h" 23#include "mpp.h"
24#include "ts78xx-fpga.h"
23 25
24/***************************************************************************** 26/*****************************************************************************
25 * TS-78xx Info 27 * TS-78xx Info
@@ -32,12 +34,11 @@
32#define TS78XX_FPGA_REGS_VIRT_BASE 0xff900000 34#define TS78XX_FPGA_REGS_VIRT_BASE 0xff900000
33#define TS78XX_FPGA_REGS_SIZE SZ_1M 35#define TS78XX_FPGA_REGS_SIZE SZ_1M
34 36
35#define TS78XX_FPGA_REGS_SYSCON_ID (TS78XX_FPGA_REGS_VIRT_BASE | 0x000) 37static struct ts78xx_fpga_data ts78xx_fpga = {
36#define TS78XX_FPGA_REGS_SYSCON_LCDI (TS78XX_FPGA_REGS_VIRT_BASE | 0x004) 38 .id = 0,
37#define TS78XX_FPGA_REGS_SYSCON_LCDO (TS78XX_FPGA_REGS_VIRT_BASE | 0x008) 39 .state = 1,
38 40/* .supports = ... - populated by ts78xx_fpga_supports() */
39#define TS78XX_FPGA_REGS_RTC_CTRL (TS78XX_FPGA_REGS_VIRT_BASE | 0x808) 41};
40#define TS78XX_FPGA_REGS_RTC_DATA (TS78XX_FPGA_REGS_VIRT_BASE | 0x80c)
41 42
42/***************************************************************************** 43/*****************************************************************************
43 * I/O Address Mapping 44 * I/O Address Mapping
@@ -65,31 +66,41 @@ static struct mv643xx_eth_platform_data ts78xx_eth_data = {
65}; 66};
66 67
67/***************************************************************************** 68/*****************************************************************************
69 * SATA
70 ****************************************************************************/
71static struct mv_sata_platform_data ts78xx_sata_data = {
72 .n_ports = 2,
73};
74
75/*****************************************************************************
68 * RTC M48T86 - nicked^Wborrowed from arch/arm/mach-ep93xx/ts72xx.c 76 * RTC M48T86 - nicked^Wborrowed from arch/arm/mach-ep93xx/ts72xx.c
69 ****************************************************************************/ 77 ****************************************************************************/
70#ifdef CONFIG_RTC_DRV_M48T86 78#ifdef CONFIG_RTC_DRV_M48T86
71static unsigned char ts78xx_rtc_readbyte(unsigned long addr) 79#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)
72{ 83{
73 writeb(addr, TS78XX_FPGA_REGS_RTC_CTRL); 84 writeb(addr, TS_RTC_CTRL);
74 return readb(TS78XX_FPGA_REGS_RTC_DATA); 85 return readb(TS_RTC_DATA);
75} 86}
76 87
77static void ts78xx_rtc_writebyte(unsigned char value, unsigned long addr) 88static void ts78xx_ts_rtc_writebyte(unsigned char value, unsigned long addr)
78{ 89{
79 writeb(addr, TS78XX_FPGA_REGS_RTC_CTRL); 90 writeb(addr, TS_RTC_CTRL);
80 writeb(value, TS78XX_FPGA_REGS_RTC_DATA); 91 writeb(value, TS_RTC_DATA);
81} 92}
82 93
83static struct m48t86_ops ts78xx_rtc_ops = { 94static struct m48t86_ops ts78xx_ts_rtc_ops = {
84 .readbyte = ts78xx_rtc_readbyte, 95 .readbyte = ts78xx_ts_rtc_readbyte,
85 .writebyte = ts78xx_rtc_writebyte, 96 .writebyte = ts78xx_ts_rtc_writebyte,
86}; 97};
87 98
88static struct platform_device ts78xx_rtc_device = { 99static struct platform_device ts78xx_ts_rtc_device = {
89 .name = "rtc-m48t86", 100 .name = "rtc-m48t86",
90 .id = -1, 101 .id = -1,
91 .dev = { 102 .dev = {
92 .platform_data = &ts78xx_rtc_ops, 103 .platform_data = &ts78xx_ts_rtc_ops,
93 }, 104 },
94 .num_resources = 0, 105 .num_resources = 0,
95}; 106};
@@ -104,59 +115,185 @@ static struct platform_device ts78xx_rtc_device = {
104 * TODO: track down a guinea pig without an RTC to see if we can work out a 115 * TODO: track down a guinea pig without an RTC to see if we can work out a
105 * better RTC detection routine 116 * better RTC detection routine
106 */ 117 */
107static int __init ts78xx_rtc_init(void) 118static int ts78xx_ts_rtc_load(void)
108{ 119{
109 unsigned char tmp_rtc0, tmp_rtc1; 120 unsigned char tmp_rtc0, tmp_rtc1;
110 121
111 tmp_rtc0 = ts78xx_rtc_readbyte(126); 122 tmp_rtc0 = ts78xx_ts_rtc_readbyte(126);
112 tmp_rtc1 = ts78xx_rtc_readbyte(127); 123 tmp_rtc1 = ts78xx_ts_rtc_readbyte(127);
113 124
114 ts78xx_rtc_writebyte(0x00, 126); 125 ts78xx_ts_rtc_writebyte(0x00, 126);
115 ts78xx_rtc_writebyte(0x55, 127); 126 ts78xx_ts_rtc_writebyte(0x55, 127);
116 if (ts78xx_rtc_readbyte(127) == 0x55) { 127 if (ts78xx_ts_rtc_readbyte(127) == 0x55) {
117 ts78xx_rtc_writebyte(0xaa, 127); 128 ts78xx_ts_rtc_writebyte(0xaa, 127);
118 if (ts78xx_rtc_readbyte(127) == 0xaa 129 if (ts78xx_ts_rtc_readbyte(127) == 0xaa
119 && ts78xx_rtc_readbyte(126) == 0x00) { 130 && ts78xx_ts_rtc_readbyte(126) == 0x00) {
120 ts78xx_rtc_writebyte(tmp_rtc0, 126); 131 ts78xx_ts_rtc_writebyte(tmp_rtc0, 126);
121 ts78xx_rtc_writebyte(tmp_rtc1, 127); 132 ts78xx_ts_rtc_writebyte(tmp_rtc1, 127);
122 platform_device_register(&ts78xx_rtc_device); 133 if (ts78xx_fpga.supports.ts_rtc.init == 0) {
123 return 1; 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;
124 } 139 }
125 } 140 }
126 141
127 return 0; 142 ts78xx_fpga.supports.ts_rtc.present = 0;
143 return -ENODEV;
128}; 144};
145
146static void ts78xx_ts_rtc_unload(void)
147{
148 platform_device_del(&ts78xx_ts_rtc_device);
149}
129#else 150#else
130static int __init ts78xx_rtc_init(void) 151static int ts78xx_ts_rtc_load(void)
131{ 152{
132 return 0; 153 return 0;
133} 154}
155
156static void ts78xx_ts_rtc_unload(void)
157{
158}
134#endif 159#endif
135 160
136/***************************************************************************** 161/*****************************************************************************
137 * SATA 162 * FPGA 'hotplug' support code
138 ****************************************************************************/ 163 ****************************************************************************/
139static struct mv_sata_platform_data ts78xx_sata_data = { 164static void ts78xx_fpga_devices_zero_init(void)
140 .n_ports = 2, 165{
166 ts78xx_fpga.supports.ts_rtc.init = 0;
167}
168
169static 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;
141}; 221};
142 222
143/***************************************************************************** 223static int ts78xx_fpga_unload(void)
144 * print some information regarding the board 224{
145 ****************************************************************************/ 225 unsigned int fpga_id;
146static void __init ts78xx_print_board_id(void) 226
147{ 227 fpga_id = readl(TS78XX_FPGA_REGS_VIRT_BASE);
148 unsigned int board_info; 228
149 229 /*
150 board_info = readl(TS78XX_FPGA_REGS_SYSCON_ID); 230 * There does not seem to be a feasible way to block access to the GPIO
151 printk(KERN_INFO "TS-78xx Info: FPGA rev=%.2x, Board Magic=%.6x, ", 231 * pins from userspace (/dev/mem). This if clause should hopefully warn
152 board_info & 0xff, 232 * those foolish enough not to follow 'policy' :)
153 (board_info >> 8) & 0xffffff); 233 *
154 board_info = readl(TS78XX_FPGA_REGS_SYSCON_LCDI); 234 * UrJTAG SVN since r1381 can be used to reprogram the FPGA
155 printk("JP1=%d, JP2=%d\n", 235 */
156 (board_info >> 30) & 0x1, 236 if (ts78xx_fpga.id != fpga_id) {
157 (board_info >> 31) & 0x1); 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;
158}; 251};
159 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
160/***************************************************************************** 297/*****************************************************************************
161 * General Setup 298 * General Setup
162 ****************************************************************************/ 299 ****************************************************************************/
@@ -194,13 +331,13 @@ static struct orion5x_mpp_mode ts78xx_mpp_modes[] __initdata = {
194 331
195static void __init ts78xx_init(void) 332static void __init ts78xx_init(void)
196{ 333{
334 int ret;
335
197 /* 336 /*
198 * Setup basic Orion functions. Need to be called early. 337 * Setup basic Orion functions. Need to be called early.
199 */ 338 */
200 orion5x_init(); 339 orion5x_init();
201 340
202 ts78xx_print_board_id();
203
204 orion5x_mpp_conf(ts78xx_mpp_modes); 341 orion5x_mpp_conf(ts78xx_mpp_modes);
205 342
206 /* 343 /*
@@ -214,8 +351,12 @@ static void __init ts78xx_init(void)
214 orion5x_uart1_init(); 351 orion5x_uart1_init();
215 orion5x_xor_init(); 352 orion5x_xor_init();
216 353
217 if (!ts78xx_rtc_init()) 354 /* FPGA init */
218 printk(KERN_INFO "TS-78xx RTC not detected or enabled\n"); 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);
219} 360}
220 361
221MACHINE_START(TS78XX, "Technologic Systems TS-78xx SBC") 362MACHINE_START(TS78XX, "Technologic Systems TS-78xx SBC")