diff options
Diffstat (limited to 'arch/arm/mach-ns9xxx')
-rw-r--r-- | arch/arm/mach-ns9xxx/Kconfig | 21 | ||||
-rw-r--r-- | arch/arm/mach-ns9xxx/Makefile | 5 | ||||
-rw-r--r-- | arch/arm/mach-ns9xxx/Makefile.boot | 2 | ||||
-rw-r--r-- | arch/arm/mach-ns9xxx/board-a9m9750dev.c | 199 | ||||
-rw-r--r-- | arch/arm/mach-ns9xxx/board-a9m9750dev.h | 15 | ||||
-rw-r--r-- | arch/arm/mach-ns9xxx/generic.c | 42 | ||||
-rw-r--r-- | arch/arm/mach-ns9xxx/generic.h | 19 | ||||
-rw-r--r-- | arch/arm/mach-ns9xxx/irq.c | 94 | ||||
-rw-r--r-- | arch/arm/mach-ns9xxx/mach-cc9p9360dev.c | 41 | ||||
-rw-r--r-- | arch/arm/mach-ns9xxx/time.c | 88 |
10 files changed, 526 insertions, 0 deletions
diff --git a/arch/arm/mach-ns9xxx/Kconfig b/arch/arm/mach-ns9xxx/Kconfig new file mode 100644 index 000000000000..8175ba92a2fa --- /dev/null +++ b/arch/arm/mach-ns9xxx/Kconfig | |||
@@ -0,0 +1,21 @@ | |||
1 | if ARCH_NS9XXX | ||
2 | |||
3 | menu "NS9xxx Implementations" | ||
4 | |||
5 | config MACH_CC9P9360DEV | ||
6 | bool "Connect Core 9P 9360 on an A9M9750 Devboard" | ||
7 | select PROCESSOR_NS9360 | ||
8 | select BOARD_A9M9750DEV | ||
9 | help | ||
10 | Say Y here if you are using the Digi Connect Core 9P 9360 | ||
11 | on an A9M9750 Development Board. | ||
12 | |||
13 | config PROCESSOR_NS9360 | ||
14 | bool | ||
15 | |||
16 | config BOARD_A9M9750DEV | ||
17 | bool | ||
18 | |||
19 | endmenu | ||
20 | |||
21 | endif | ||
diff --git a/arch/arm/mach-ns9xxx/Makefile b/arch/arm/mach-ns9xxx/Makefile new file mode 100644 index 000000000000..91e945f5e16d --- /dev/null +++ b/arch/arm/mach-ns9xxx/Makefile | |||
@@ -0,0 +1,5 @@ | |||
1 | obj-y := irq.o time.o generic.o | ||
2 | |||
3 | obj-$(CONFIG_MACH_CC9P9360DEV) += mach-cc9p9360dev.o | ||
4 | |||
5 | obj-$(CONFIG_BOARD_A9M9750DEV) += board-a9m9750dev.o | ||
diff --git a/arch/arm/mach-ns9xxx/Makefile.boot b/arch/arm/mach-ns9xxx/Makefile.boot new file mode 100644 index 000000000000..75ed64e90fa4 --- /dev/null +++ b/arch/arm/mach-ns9xxx/Makefile.boot | |||
@@ -0,0 +1,2 @@ | |||
1 | zreladdr-y := 0x108000 | ||
2 | params_phys-y := 0x100 | ||
diff --git a/arch/arm/mach-ns9xxx/board-a9m9750dev.c b/arch/arm/mach-ns9xxx/board-a9m9750dev.c new file mode 100644 index 000000000000..25289884a607 --- /dev/null +++ b/arch/arm/mach-ns9xxx/board-a9m9750dev.c | |||
@@ -0,0 +1,199 @@ | |||
1 | /* | ||
2 | * arch/arm/mach-ns9xxx/board-a9m9750dev.c | ||
3 | * | ||
4 | * Copyright (C) 2006,2007 by Digi International Inc. | ||
5 | * All rights reserved. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License version 2 as published by | ||
9 | * the Free Software Foundation. | ||
10 | */ | ||
11 | #include <linux/platform_device.h> | ||
12 | #include <linux/serial_8250.h> | ||
13 | #include <linux/irq.h> | ||
14 | |||
15 | #include <asm/mach/map.h> | ||
16 | |||
17 | #include <asm/arch-ns9xxx/board.h> | ||
18 | #include <asm/arch-ns9xxx/regs-sys.h> | ||
19 | #include <asm/arch-ns9xxx/regs-mem.h> | ||
20 | #include <asm/arch-ns9xxx/regs-bbu.h> | ||
21 | #include <asm/arch-ns9xxx/regs-board-a9m9750dev.h> | ||
22 | |||
23 | #include "board-a9m9750dev.h" | ||
24 | |||
25 | static struct map_desc board_a9m9750dev_io_desc[] __initdata = { | ||
26 | { /* FPGA on CS0 */ | ||
27 | .virtual = io_p2v(NS9XXX_CSxSTAT_PHYS(0)), | ||
28 | .pfn = __phys_to_pfn(NS9XXX_CSxSTAT_PHYS(0)), | ||
29 | .length = NS9XXX_CS0STAT_LENGTH, | ||
30 | .type = MT_DEVICE, | ||
31 | }, | ||
32 | }; | ||
33 | |||
34 | void __init board_a9m9750dev_map_io(void) | ||
35 | { | ||
36 | iotable_init(board_a9m9750dev_io_desc, | ||
37 | ARRAY_SIZE(board_a9m9750dev_io_desc)); | ||
38 | } | ||
39 | |||
40 | static void a9m9750dev_fpga_ack_irq(unsigned int irq) | ||
41 | { | ||
42 | /* nothing */ | ||
43 | } | ||
44 | |||
45 | static void a9m9750dev_fpga_mask_irq(unsigned int irq) | ||
46 | { | ||
47 | FPGA_IER &= ~(1 << (irq - FPGA_IRQ(0))); | ||
48 | } | ||
49 | |||
50 | static void a9m9750dev_fpga_maskack_irq(unsigned int irq) | ||
51 | { | ||
52 | a9m9750dev_fpga_mask_irq(irq); | ||
53 | a9m9750dev_fpga_ack_irq(irq); | ||
54 | } | ||
55 | |||
56 | static void a9m9750dev_fpga_unmask_irq(unsigned int irq) | ||
57 | { | ||
58 | FPGA_IER |= 1 << (irq - FPGA_IRQ(0)); | ||
59 | } | ||
60 | |||
61 | static struct irq_chip a9m9750dev_fpga_chip = { | ||
62 | .ack = a9m9750dev_fpga_ack_irq, | ||
63 | .mask = a9m9750dev_fpga_mask_irq, | ||
64 | .mask_ack = a9m9750dev_fpga_maskack_irq, | ||
65 | .unmask = a9m9750dev_fpga_unmask_irq, | ||
66 | }; | ||
67 | |||
68 | static void a9m9750dev_fpga_demux_handler(unsigned int irq, | ||
69 | struct irq_desc *desc) | ||
70 | { | ||
71 | int stat = FPGA_ISR; | ||
72 | |||
73 | while (stat != 0) { | ||
74 | int irqno = fls(stat) - 1; | ||
75 | |||
76 | stat &= ~(1 << irqno); | ||
77 | |||
78 | desc = irq_desc + FPGA_IRQ(irqno); | ||
79 | |||
80 | desc_handle_irq(irqno, desc); | ||
81 | } | ||
82 | } | ||
83 | |||
84 | void __init board_a9m9750dev_init_irq(void) | ||
85 | { | ||
86 | u32 reg; | ||
87 | int i; | ||
88 | |||
89 | /* | ||
90 | * configure gpio for IRQ_EXT2 | ||
91 | * use GPIO 11, because GPIO 32 is used for the LCD | ||
92 | */ | ||
93 | /* XXX: proper GPIO handling */ | ||
94 | BBU_GC(2) &= ~0x2000; | ||
95 | |||
96 | for (i = FPGA_IRQ(0); i <= FPGA_IRQ(7); ++i) { | ||
97 | set_irq_chip(i, &a9m9750dev_fpga_chip); | ||
98 | set_irq_handler(i, handle_level_irq); | ||
99 | set_irq_flags(i, IRQF_VALID); | ||
100 | } | ||
101 | |||
102 | /* IRQ_EXT2: level sensitive + active low */ | ||
103 | reg = SYS_EIC(2); | ||
104 | REGSET(reg, SYS_EIC, PLTY, AL); | ||
105 | REGSET(reg, SYS_EIC, LVEDG, LEVEL); | ||
106 | SYS_EIC(2) = reg; | ||
107 | |||
108 | set_irq_chained_handler(IRQ_EXT2, | ||
109 | a9m9750dev_fpga_demux_handler); | ||
110 | } | ||
111 | |||
112 | static struct plat_serial8250_port board_a9m9750dev_serial8250_port[] = { | ||
113 | { | ||
114 | .iobase = FPGA_UARTA_BASE, | ||
115 | .membase = (unsigned char*)FPGA_UARTA_BASE, | ||
116 | .mapbase = FPGA_UARTA_BASE, | ||
117 | .irq = IRQ_FPGA_UARTA, | ||
118 | .iotype = UPIO_MEM, | ||
119 | .uartclk = 18432000, | ||
120 | .regshift = 0, | ||
121 | .flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ, | ||
122 | }, { | ||
123 | .iobase = FPGA_UARTB_BASE, | ||
124 | .membase = (unsigned char*)FPGA_UARTB_BASE, | ||
125 | .mapbase = FPGA_UARTB_BASE, | ||
126 | .irq = IRQ_FPGA_UARTB, | ||
127 | .iotype = UPIO_MEM, | ||
128 | .uartclk = 18432000, | ||
129 | .regshift = 0, | ||
130 | .flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ, | ||
131 | }, { | ||
132 | .iobase = FPGA_UARTC_BASE, | ||
133 | .membase = (unsigned char*)FPGA_UARTC_BASE, | ||
134 | .mapbase = FPGA_UARTC_BASE, | ||
135 | .irq = IRQ_FPGA_UARTC, | ||
136 | .iotype = UPIO_MEM, | ||
137 | .uartclk = 18432000, | ||
138 | .regshift = 0, | ||
139 | .flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ, | ||
140 | }, { | ||
141 | .iobase = FPGA_UARTD_BASE, | ||
142 | .membase = (unsigned char*)FPGA_UARTD_BASE, | ||
143 | .mapbase = FPGA_UARTD_BASE, | ||
144 | .irq = IRQ_FPGA_UARTD, | ||
145 | .iotype = UPIO_MEM, | ||
146 | .uartclk = 18432000, | ||
147 | .regshift = 0, | ||
148 | .flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ, | ||
149 | }, { | ||
150 | /* end marker */ | ||
151 | }, | ||
152 | }; | ||
153 | |||
154 | static struct platform_device board_a9m9750dev_serial_device = { | ||
155 | .name = "serial8250", | ||
156 | .dev = { | ||
157 | .platform_data = board_a9m9750dev_serial8250_port, | ||
158 | }, | ||
159 | }; | ||
160 | |||
161 | static struct platform_device *board_a9m9750dev_devices[] __initdata = { | ||
162 | &board_a9m9750dev_serial_device, | ||
163 | }; | ||
164 | |||
165 | void __init board_a9m9750dev_init_machine(void) | ||
166 | { | ||
167 | u32 reg; | ||
168 | |||
169 | /* setup static CS0: memory base ... */ | ||
170 | REGSETIM(SYS_SMCSSMB(0), SYS_SMCSSMB, CSxB, | ||
171 | NS9XXX_CSxSTAT_PHYS(0) >> 12); | ||
172 | |||
173 | /* ... and mask */ | ||
174 | reg = SYS_SMCSSMM(0); | ||
175 | REGSETIM(reg, SYS_SMCSSMM, CSxM, 0xfffff); | ||
176 | REGSET(reg, SYS_SMCSSMM, CSEx, EN); | ||
177 | SYS_SMCSSMM(0) = reg; | ||
178 | |||
179 | /* setup static CS0: memory configuration */ | ||
180 | reg = MEM_SMC(0); | ||
181 | REGSET(reg, MEM_SMC, WSMC, OFF); | ||
182 | REGSET(reg, MEM_SMC, BSMC, OFF); | ||
183 | REGSET(reg, MEM_SMC, EW, OFF); | ||
184 | REGSET(reg, MEM_SMC, PB, 1); | ||
185 | REGSET(reg, MEM_SMC, PC, AL); | ||
186 | REGSET(reg, MEM_SMC, PM, DIS); | ||
187 | REGSET(reg, MEM_SMC, MW, 8); | ||
188 | MEM_SMC(0) = reg; | ||
189 | |||
190 | /* setup static CS0: timing */ | ||
191 | MEM_SMWED(0) = 0x2; | ||
192 | MEM_SMOED(0) = 0x2; | ||
193 | MEM_SMRD(0) = 0x6; | ||
194 | MEM_SMWD(0) = 0x6; | ||
195 | |||
196 | platform_add_devices(board_a9m9750dev_devices, | ||
197 | ARRAY_SIZE(board_a9m9750dev_devices)); | ||
198 | } | ||
199 | |||
diff --git a/arch/arm/mach-ns9xxx/board-a9m9750dev.h b/arch/arm/mach-ns9xxx/board-a9m9750dev.h new file mode 100644 index 000000000000..edc75abbc5dd --- /dev/null +++ b/arch/arm/mach-ns9xxx/board-a9m9750dev.h | |||
@@ -0,0 +1,15 @@ | |||
1 | /* | ||
2 | * arch/arm/mach-ns9xxx/board-a9m9750dev.h | ||
3 | * | ||
4 | * Copyright (C) 2006 by Digi International Inc. | ||
5 | * All rights reserved. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License version 2 as published by | ||
9 | * the Free Software Foundation. | ||
10 | */ | ||
11 | #include <linux/init.h> | ||
12 | |||
13 | void __init board_a9m9750dev_map_io(void); | ||
14 | void __init board_a9m9750dev_init_machine(void); | ||
15 | void __init board_a9m9750dev_init_irq(void); | ||
diff --git a/arch/arm/mach-ns9xxx/generic.c b/arch/arm/mach-ns9xxx/generic.c new file mode 100644 index 000000000000..83e2b6532b22 --- /dev/null +++ b/arch/arm/mach-ns9xxx/generic.c | |||
@@ -0,0 +1,42 @@ | |||
1 | /* | ||
2 | * arch/arm/mach-ns9xxx/generic.c | ||
3 | * | ||
4 | * Copyright (C) 2006 by Digi International Inc. | ||
5 | * All rights reserved. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License version 2 as published by | ||
9 | * the Free Software Foundation. | ||
10 | */ | ||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/init.h> | ||
13 | #include <asm/memory.h> | ||
14 | #include <asm/page.h> | ||
15 | #include <asm/mach-types.h> | ||
16 | #include <asm/mach/map.h> | ||
17 | #include <asm/arch-ns9xxx/regs-sys.h> | ||
18 | #include <asm/arch-ns9xxx/regs-mem.h> | ||
19 | #include <asm/arch-ns9xxx/board.h> | ||
20 | |||
21 | static struct map_desc standard_io_desc[] __initdata = { | ||
22 | { /* BBus */ | ||
23 | .virtual = io_p2v(0x90000000), | ||
24 | .pfn = __phys_to_pfn(0x90000000), | ||
25 | .length = 0x00700000, | ||
26 | .type = MT_DEVICE, | ||
27 | }, { /* AHB */ | ||
28 | .virtual = io_p2v(0xa0100000), | ||
29 | .pfn = __phys_to_pfn(0xa0100000), | ||
30 | .length = 0x00900000, | ||
31 | .type = MT_DEVICE, | ||
32 | }, | ||
33 | }; | ||
34 | |||
35 | void __init ns9xxx_map_io(void) | ||
36 | { | ||
37 | iotable_init(standard_io_desc, ARRAY_SIZE(standard_io_desc)); | ||
38 | } | ||
39 | |||
40 | void __init ns9xxx_init_machine(void) | ||
41 | { | ||
42 | } | ||
diff --git a/arch/arm/mach-ns9xxx/generic.h b/arch/arm/mach-ns9xxx/generic.h new file mode 100644 index 000000000000..687e291773f4 --- /dev/null +++ b/arch/arm/mach-ns9xxx/generic.h | |||
@@ -0,0 +1,19 @@ | |||
1 | /* | ||
2 | * arch/arm/mach-ns9xxx/generic.h | ||
3 | * | ||
4 | * Copyright (C) 2006 by Digi International Inc. | ||
5 | * All rights reserved. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License version 2 as published by | ||
9 | * the Free Software Foundation. | ||
10 | */ | ||
11 | #include <linux/time.h> | ||
12 | #include <asm/mach/time.h> | ||
13 | #include <linux/init.h> | ||
14 | |||
15 | void __init ns9xxx_init_irq(void); | ||
16 | void __init ns9xxx_map_io(void); | ||
17 | void __init ns9xxx_init_machine(void); | ||
18 | |||
19 | extern struct sys_timer ns9xxx_timer; | ||
diff --git a/arch/arm/mach-ns9xxx/irq.c b/arch/arm/mach-ns9xxx/irq.c new file mode 100644 index 000000000000..83d92724a971 --- /dev/null +++ b/arch/arm/mach-ns9xxx/irq.c | |||
@@ -0,0 +1,94 @@ | |||
1 | /* | ||
2 | * arch/arm/mach-ns9xxx/irq.c | ||
3 | * | ||
4 | * Copyright (C) 2006,2007 by Digi International Inc. | ||
5 | * All rights reserved. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License version 2 as published by | ||
9 | * the Free Software Foundation. | ||
10 | */ | ||
11 | #include <linux/interrupt.h> | ||
12 | #include <asm/mach/irq.h> | ||
13 | #include <asm/mach-types.h> | ||
14 | #include <asm/arch-ns9xxx/regs-sys.h> | ||
15 | #include <asm/arch-ns9xxx/irqs.h> | ||
16 | #include <asm/arch-ns9xxx/board.h> | ||
17 | |||
18 | #include "generic.h" | ||
19 | |||
20 | static void ns9xxx_ack_irq_timer(unsigned int irq) | ||
21 | { | ||
22 | u32 tc = SYS_TC(irq - IRQ_TIMER0); | ||
23 | |||
24 | REGSET(tc, SYS_TCx, INTC, SET); | ||
25 | SYS_TC(irq - IRQ_TIMER0) = tc; | ||
26 | |||
27 | REGSET(tc, SYS_TCx, INTC, UNSET); | ||
28 | SYS_TC(irq - IRQ_TIMER0) = tc; | ||
29 | } | ||
30 | |||
31 | void (*ns9xxx_ack_irq_functions[NR_IRQS])(unsigned int) = { | ||
32 | [IRQ_TIMER0] = ns9xxx_ack_irq_timer, | ||
33 | [IRQ_TIMER1] = ns9xxx_ack_irq_timer, | ||
34 | [IRQ_TIMER2] = ns9xxx_ack_irq_timer, | ||
35 | [IRQ_TIMER3] = ns9xxx_ack_irq_timer, | ||
36 | }; | ||
37 | |||
38 | static void ns9xxx_mask_irq(unsigned int irq) | ||
39 | { | ||
40 | /* XXX: better use cpp symbols */ | ||
41 | SYS_IC(irq / 4) &= ~(1 << (7 + 8 * (3 - (irq & 3)))); | ||
42 | } | ||
43 | |||
44 | static void ns9xxx_ack_irq(unsigned int irq) | ||
45 | { | ||
46 | if (!ns9xxx_ack_irq_functions[irq]) { | ||
47 | printk(KERN_ERR "no ack function for irq %u\n", irq); | ||
48 | BUG(); | ||
49 | } | ||
50 | |||
51 | ns9xxx_ack_irq_functions[irq](irq); | ||
52 | SYS_ISRADDR = 0; | ||
53 | } | ||
54 | |||
55 | static void ns9xxx_maskack_irq(unsigned int irq) | ||
56 | { | ||
57 | ns9xxx_mask_irq(irq); | ||
58 | ns9xxx_ack_irq(irq); | ||
59 | } | ||
60 | |||
61 | static void ns9xxx_unmask_irq(unsigned int irq) | ||
62 | { | ||
63 | /* XXX: better use cpp symbols */ | ||
64 | SYS_IC(irq / 4) |= 1 << (7 + 8 * (3 - (irq & 3))); | ||
65 | } | ||
66 | |||
67 | static struct irq_chip ns9xxx_chip = { | ||
68 | .ack = ns9xxx_ack_irq, | ||
69 | .mask = ns9xxx_mask_irq, | ||
70 | .mask_ack = ns9xxx_maskack_irq, | ||
71 | .unmask = ns9xxx_unmask_irq, | ||
72 | }; | ||
73 | |||
74 | void __init ns9xxx_init_irq(void) | ||
75 | { | ||
76 | int i; | ||
77 | |||
78 | /* disable all IRQs */ | ||
79 | for (i = 0; i < 8; ++i) | ||
80 | SYS_IC(i) = (4 * i) << 24 | (4 * i + 1) << 16 | | ||
81 | (4 * i + 2) << 8 | (4 * i + 3); | ||
82 | |||
83 | /* simple interrupt prio table: | ||
84 | * prio(x) < prio(y) <=> x < y | ||
85 | */ | ||
86 | for (i = 0; i < 32; ++i) | ||
87 | SYS_IVA(i) = i; | ||
88 | |||
89 | for (i = IRQ_WATCHDOG; i <= IRQ_EXT3; ++i) { | ||
90 | set_irq_chip(i, &ns9xxx_chip); | ||
91 | set_irq_handler(i, handle_level_irq); | ||
92 | set_irq_flags(i, IRQF_VALID); | ||
93 | } | ||
94 | } | ||
diff --git a/arch/arm/mach-ns9xxx/mach-cc9p9360dev.c b/arch/arm/mach-ns9xxx/mach-cc9p9360dev.c new file mode 100644 index 000000000000..a193dd931512 --- /dev/null +++ b/arch/arm/mach-ns9xxx/mach-cc9p9360dev.c | |||
@@ -0,0 +1,41 @@ | |||
1 | /* | ||
2 | * arch/arm/mach-ns9xxx/mach-cc9p9360dev.c | ||
3 | * | ||
4 | * Copyright (C) 2006 by Digi International Inc. | ||
5 | * All rights reserved. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License version 2 as published by | ||
9 | * the Free Software Foundation. | ||
10 | */ | ||
11 | #include <asm/mach/arch.h> | ||
12 | #include <asm/mach-types.h> | ||
13 | |||
14 | #include "board-a9m9750dev.h" | ||
15 | #include "generic.h" | ||
16 | |||
17 | static void __init mach_cc9p9360dev_map_io(void) | ||
18 | { | ||
19 | ns9xxx_map_io(); | ||
20 | board_a9m9750dev_map_io(); | ||
21 | } | ||
22 | |||
23 | static void __init mach_cc9p9360dev_init_irq(void) | ||
24 | { | ||
25 | ns9xxx_init_irq(); | ||
26 | board_a9m9750dev_init_irq(); | ||
27 | } | ||
28 | |||
29 | static void __init mach_cc9p9360dev_init_machine(void) | ||
30 | { | ||
31 | ns9xxx_init_machine(); | ||
32 | board_a9m9750dev_init_machine(); | ||
33 | } | ||
34 | |||
35 | MACHINE_START(CC9P9360DEV, "Connect Core 9P 9360 on an A9M9750 Devboard") | ||
36 | .map_io = mach_cc9p9360dev_map_io, | ||
37 | .init_irq = mach_cc9p9360dev_init_irq, | ||
38 | .init_machine = mach_cc9p9360dev_init_machine, | ||
39 | .timer = &ns9xxx_timer, | ||
40 | .boot_params = 0x100, | ||
41 | MACHINE_END | ||
diff --git a/arch/arm/mach-ns9xxx/time.c b/arch/arm/mach-ns9xxx/time.c new file mode 100644 index 000000000000..eec05f18714a --- /dev/null +++ b/arch/arm/mach-ns9xxx/time.c | |||
@@ -0,0 +1,88 @@ | |||
1 | /* | ||
2 | * arch/arm/mach-ns9xxx/time.c | ||
3 | * | ||
4 | * Copyright (C) 2006 by Digi International Inc. | ||
5 | * All rights reserved. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License version 2 as published by | ||
9 | * the Free Software Foundation. | ||
10 | */ | ||
11 | #include <linux/jiffies.h> | ||
12 | #include <linux/interrupt.h> | ||
13 | #include <linux/irq.h> | ||
14 | #include <asm/arch-ns9xxx/regs-sys.h> | ||
15 | #include <asm/arch-ns9xxx/clock.h> | ||
16 | #include <asm/arch-ns9xxx/irqs.h> | ||
17 | #include <asm/arch/system.h> | ||
18 | #include "generic.h" | ||
19 | |||
20 | #define TIMERCLOCKSELECT 64 | ||
21 | |||
22 | static u32 usecs_per_tick; | ||
23 | |||
24 | static irqreturn_t | ||
25 | ns9xxx_timer_interrupt(int irq, void *dev_id) | ||
26 | { | ||
27 | write_seqlock(&xtime_lock); | ||
28 | timer_tick(); | ||
29 | write_sequnlock(&xtime_lock); | ||
30 | |||
31 | return IRQ_HANDLED; | ||
32 | } | ||
33 | |||
34 | static unsigned long ns9xxx_timer_gettimeoffset(void) | ||
35 | { | ||
36 | /* return the microseconds which have passed since the last interrupt | ||
37 | * was _serviced_. That is, if an interrupt is pending or the counter | ||
38 | * reloads, return one periode more. */ | ||
39 | |||
40 | u32 counter1 = SYS_TR(0); | ||
41 | int pending = SYS_ISR & (1 << IRQ_TIMER0); | ||
42 | u32 counter2 = SYS_TR(0); | ||
43 | u32 elapsed; | ||
44 | |||
45 | if (pending || counter2 > counter1) | ||
46 | elapsed = 2 * SYS_TRC(0) - counter2; | ||
47 | else | ||
48 | elapsed = SYS_TRC(0) - counter1; | ||
49 | |||
50 | return (elapsed * usecs_per_tick) >> 16; | ||
51 | |||
52 | } | ||
53 | |||
54 | static struct irqaction ns9xxx_timer_irq = { | ||
55 | .name = "NS9xxx Timer Tick", | ||
56 | .flags = IRQF_DISABLED | IRQF_TIMER, | ||
57 | .handler = ns9xxx_timer_interrupt, | ||
58 | }; | ||
59 | |||
60 | static void __init ns9xxx_timer_init(void) | ||
61 | { | ||
62 | int tc; | ||
63 | |||
64 | usecs_per_tick = | ||
65 | SH_DIV(1000000 * TIMERCLOCKSELECT, ns9xxx_cpuclock(), 16); | ||
66 | |||
67 | /* disable timer */ | ||
68 | if ((tc = SYS_TC(0)) & SYS_TCx_TEN) | ||
69 | SYS_TC(0) = tc & ~SYS_TCx_TEN; | ||
70 | |||
71 | SYS_TRC(0) = SH_DIV(ns9xxx_cpuclock(), (TIMERCLOCKSELECT * HZ), 0); | ||
72 | |||
73 | REGSET(tc, SYS_TCx, TEN, EN); | ||
74 | REGSET(tc, SYS_TCx, TLCS, DIV64); /* This must match TIMERCLOCKSELECT */ | ||
75 | REGSET(tc, SYS_TCx, INTS, EN); | ||
76 | REGSET(tc, SYS_TCx, UDS, DOWN); | ||
77 | REGSET(tc, SYS_TCx, TDBG, STOP); | ||
78 | REGSET(tc, SYS_TCx, TSZ, 32); | ||
79 | REGSET(tc, SYS_TCx, REN, EN); | ||
80 | SYS_TC(0) = tc; | ||
81 | |||
82 | setup_irq(IRQ_TIMER0, &ns9xxx_timer_irq); | ||
83 | } | ||
84 | |||
85 | struct sys_timer ns9xxx_timer = { | ||
86 | .init = ns9xxx_timer_init, | ||
87 | .offset = ns9xxx_timer_gettimeoffset, | ||
88 | }; | ||