[ARM] orion5x: ts78xx amend RTC registering to not depend on ifdef's
[deliverable/linux.git] / arch / arm / mach-orion5x / ts78xx-setup.c
CommitLineData
7171d867
AC
1/*
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>
39008f95 13#include <linux/sysfs.h>
7171d867 14#include <linux/platform_device.h>
7171d867
AC
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>
a09e64fb 21#include <mach/orion5x.h>
7171d867
AC
22#include "common.h"
23#include "mpp.h"
39008f95 24#include "ts78xx-fpga.h"
7171d867
AC
25
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
39008f95
AC
37static struct ts78xx_fpga_data ts78xx_fpga = {
38 .id = 0,
39 .state = 1,
40/* .supports = ... - populated by ts78xx_fpga_supports() */
41};
7171d867 42
7171d867
AC
43/*****************************************************************************
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
7171d867
AC
61/*****************************************************************************
62 * Ethernet
63 ****************************************************************************/
64static struct mv643xx_eth_platform_data ts78xx_eth_data = {
ac840605 65 .phy_addr = MV643XX_ETH_PHY_ADDR(0),
7171d867
AC
66};
67
39008f95
AC
68/*****************************************************************************
69 * SATA
70 ****************************************************************************/
71static struct mv_sata_platform_data ts78xx_sata_data = {
72 .n_ports = 2,
73};
74
7171d867
AC
75/*****************************************************************************
76 * RTC M48T86 - nicked^Wborrowed from arch/arm/mach-ep93xx/ts72xx.c
77 ****************************************************************************/
39008f95
AC
78#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)
7171d867 82{
39008f95
AC
83 writeb(addr, TS_RTC_CTRL);
84 return readb(TS_RTC_DATA);
7171d867
AC
85}
86
39008f95 87static void ts78xx_ts_rtc_writebyte(unsigned char value, unsigned long addr)
7171d867 88{
39008f95
AC
89 writeb(addr, TS_RTC_CTRL);
90 writeb(value, TS_RTC_DATA);
7171d867
AC
91}
92
39008f95
AC
93static struct m48t86_ops ts78xx_ts_rtc_ops = {
94 .readbyte = ts78xx_ts_rtc_readbyte,
95 .writebyte = ts78xx_ts_rtc_writebyte,
7171d867
AC
96};
97
39008f95 98static struct platform_device ts78xx_ts_rtc_device = {
7171d867
AC
99 .name = "rtc-m48t86",
100 .id = -1,
101 .dev = {
39008f95 102 .platform_data = &ts78xx_ts_rtc_ops,
7171d867
AC
103 },
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 */
39008f95 117static int ts78xx_ts_rtc_load(void)
7171d867 118{
f5273fa3 119 int rc;
7171d867
AC
120 unsigned char tmp_rtc0, tmp_rtc1;
121
39008f95
AC
122 tmp_rtc0 = ts78xx_ts_rtc_readbyte(126);
123 tmp_rtc1 = ts78xx_ts_rtc_readbyte(127);
124
125 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);
f5273fa3 133
39008f95 134 if (ts78xx_fpga.supports.ts_rtc.init == 0) {
f5273fa3
AC
135 rc = platform_device_register(&ts78xx_ts_rtc_device);
136 if (!rc)
137 ts78xx_fpga.supports.ts_rtc.init = 1;
39008f95 138 } else
f5273fa3
AC
139 rc = platform_device_add(&ts78xx_ts_rtc_device);
140
141 return rc;
7171d867
AC
142 }
143 }
144
39008f95 145 return -ENODEV;
7171d867 146};
39008f95
AC
147
148static void ts78xx_ts_rtc_unload(void)
149{
150 platform_device_del(&ts78xx_ts_rtc_device);
151}
7171d867
AC
152
153/*****************************************************************************
39008f95 154 * FPGA 'hotplug' support code
7171d867 155 ****************************************************************************/
39008f95
AC
156static void ts78xx_fpga_devices_zero_init(void)
157{
158 ts78xx_fpga.supports.ts_rtc.init = 0;
159}
160
161static 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();
f5273fa3 179 if (tmp) {
673492a8 180 printk(KERN_INFO "TS-78xx: RTC not registered\n");
f5273fa3
AC
181 ts78xx_fpga.supports.ts_rtc.present = 0;
182 }
39008f95
AC
183 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;
7171d867
AC
215};
216
39008f95
AC
217static 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;
7171d867
AC
245};
246
39008f95
AC
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
7171d867
AC
291/*****************************************************************************
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 },
f5412860
AC
315 /*
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 */
7171d867
AC
323 { -1 },
324};
325
326static void __init ts78xx_init(void)
327{
39008f95
AC
328 int ret;
329
7171d867
AC
330 /*
331 * Setup basic Orion functions. Need to be called early.
332 */
333 orion5x_init();
334
7171d867
AC
335 orion5x_mpp_conf(ts78xx_mpp_modes);
336
7171d867
AC
337 /*
338 * 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();
1d5a1a6e 346 orion5x_xor_init();
7171d867 347
39008f95
AC
348 /* 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);
7171d867
AC
354}
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
This page took 0.076775 seconds and 5 git commands to generate.