diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/mach-orion5x/Kconfig | 1 | ||||
-rw-r--r-- | arch/arm/mach-orion5x/ts78xx-fpga.h | 27 | ||||
-rw-r--r-- | arch/arm/mach-orion5x/ts78xx-setup.c | 251 |
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 | ||
72 | config MACH_TS78XX | 72 | config 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 | */ | ||
7 | enum fpga_ids { | ||
8 | /* Technologic Systems */ | ||
9 | TS7800_REV_B = FPGAID(0x00b480, 0x03), | ||
10 | }; | ||
11 | |||
12 | struct fpga_device { | ||
13 | unsigned present:1; | ||
14 | unsigned init:1; | ||
15 | }; | ||
16 | |||
17 | struct fpga_devices { | ||
18 | /* Technologic Systems */ | ||
19 | struct fpga_device ts_rtc; | ||
20 | }; | ||
21 | |||
22 | struct 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) | 37 | static 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 | ****************************************************************************/ | ||
71 | static 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 |
71 | static 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 | |||
82 | static 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 | ||
77 | static void ts78xx_rtc_writebyte(unsigned char value, unsigned long addr) | 88 | static 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 | ||
83 | static struct m48t86_ops ts78xx_rtc_ops = { | 94 | static 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 | ||
88 | static struct platform_device ts78xx_rtc_device = { | 99 | static 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 | */ |
107 | static int __init ts78xx_rtc_init(void) | 118 | static 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 | |||
146 | static void ts78xx_ts_rtc_unload(void) | ||
147 | { | ||
148 | platform_device_del(&ts78xx_ts_rtc_device); | ||
149 | } | ||
129 | #else | 150 | #else |
130 | static int __init ts78xx_rtc_init(void) | 151 | static int ts78xx_ts_rtc_load(void) |
131 | { | 152 | { |
132 | return 0; | 153 | return 0; |
133 | } | 154 | } |
155 | |||
156 | static 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 | ****************************************************************************/ |
139 | static struct mv_sata_platform_data ts78xx_sata_data = { | 164 | static void ts78xx_fpga_devices_zero_init(void) |
140 | .n_ports = 2, | 165 | { |
166 | ts78xx_fpga.supports.ts_rtc.init = 0; | ||
167 | } | ||
168 | |||
169 | static 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 | |||
181 | static 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 | |||
195 | static 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 | |||
205 | static 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 | /***************************************************************************** | 223 | static int ts78xx_fpga_unload(void) |
144 | * print some information regarding the board | 224 | { |
145 | ****************************************************************************/ | 225 | unsigned int fpga_id; |
146 | static 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 | ||
253 | static 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 | |||
262 | static 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 | |||
294 | static 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 | ||
195 | static void __init ts78xx_init(void) | 332 | static 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 | ||
221 | MACHINE_START(TS78XX, "Technologic Systems TS-78xx SBC") | 362 | MACHINE_START(TS78XX, "Technologic Systems TS-78xx SBC") |