diff options
Diffstat (limited to 'arch/arm/mach-ns9xxx')
-rw-r--r-- | arch/arm/mach-ns9xxx/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/mach-ns9xxx/board-a9m9750dev.c | 70 | ||||
-rw-r--r-- | arch/arm/mach-ns9xxx/gpio.c | 190 | ||||
-rw-r--r-- | arch/arm/mach-ns9xxx/irq.c | 50 | ||||
-rw-r--r-- | arch/arm/mach-ns9xxx/time.c | 172 |
5 files changed, 380 insertions, 104 deletions
diff --git a/arch/arm/mach-ns9xxx/Makefile b/arch/arm/mach-ns9xxx/Makefile index 4476411b8140..6fb82b855a55 100644 --- a/arch/arm/mach-ns9xxx/Makefile +++ b/arch/arm/mach-ns9xxx/Makefile | |||
@@ -1,4 +1,4 @@ | |||
1 | obj-y := irq.o time.o generic.o | 1 | obj-y := irq.o time.o generic.o gpio.o |
2 | 2 | ||
3 | obj-$(CONFIG_MACH_CC9P9360DEV) += mach-cc9p9360dev.o | 3 | obj-$(CONFIG_MACH_CC9P9360DEV) += mach-cc9p9360dev.o |
4 | obj-$(CONFIG_MACH_CC9P9360JS) += mach-cc9p9360js.o | 4 | obj-$(CONFIG_MACH_CC9P9360JS) += mach-cc9p9360js.o |
diff --git a/arch/arm/mach-ns9xxx/board-a9m9750dev.c b/arch/arm/mach-ns9xxx/board-a9m9750dev.c index 925048e7adfe..0f65177f9e5f 100644 --- a/arch/arm/mach-ns9xxx/board-a9m9750dev.c +++ b/arch/arm/mach-ns9xxx/board-a9m9750dev.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/irq.h> | 13 | #include <linux/irq.h> |
14 | 14 | ||
15 | #include <asm/mach/map.h> | 15 | #include <asm/mach/map.h> |
16 | #include <asm/gpio.h> | ||
16 | 17 | ||
17 | #include <asm/arch-ns9xxx/board.h> | 18 | #include <asm/arch-ns9xxx/board.h> |
18 | #include <asm/arch-ns9xxx/regs-sys.h> | 19 | #include <asm/arch-ns9xxx/regs-sys.h> |
@@ -44,7 +45,13 @@ static void a9m9750dev_fpga_ack_irq(unsigned int irq) | |||
44 | 45 | ||
45 | static void a9m9750dev_fpga_mask_irq(unsigned int irq) | 46 | static void a9m9750dev_fpga_mask_irq(unsigned int irq) |
46 | { | 47 | { |
47 | FPGA_IER &= ~(1 << (irq - FPGA_IRQ(0))); | 48 | u8 ier; |
49 | |||
50 | ier = __raw_readb(FPGA_IER); | ||
51 | |||
52 | ier &= ~(1 << (irq - FPGA_IRQ(0))); | ||
53 | |||
54 | __raw_writeb(ier, FPGA_IER); | ||
48 | } | 55 | } |
49 | 56 | ||
50 | static void a9m9750dev_fpga_maskack_irq(unsigned int irq) | 57 | static void a9m9750dev_fpga_maskack_irq(unsigned int irq) |
@@ -55,7 +62,13 @@ static void a9m9750dev_fpga_maskack_irq(unsigned int irq) | |||
55 | 62 | ||
56 | static void a9m9750dev_fpga_unmask_irq(unsigned int irq) | 63 | static void a9m9750dev_fpga_unmask_irq(unsigned int irq) |
57 | { | 64 | { |
58 | FPGA_IER |= 1 << (irq - FPGA_IRQ(0)); | 65 | u8 ier; |
66 | |||
67 | ier = __raw_readb(FPGA_IER); | ||
68 | |||
69 | ier |= 1 << (irq - FPGA_IRQ(0)); | ||
70 | |||
71 | __raw_writeb(ier, FPGA_IER); | ||
59 | } | 72 | } |
60 | 73 | ||
61 | static struct irq_chip a9m9750dev_fpga_chip = { | 74 | static struct irq_chip a9m9750dev_fpga_chip = { |
@@ -68,30 +81,34 @@ static struct irq_chip a9m9750dev_fpga_chip = { | |||
68 | static void a9m9750dev_fpga_demux_handler(unsigned int irq, | 81 | static void a9m9750dev_fpga_demux_handler(unsigned int irq, |
69 | struct irq_desc *desc) | 82 | struct irq_desc *desc) |
70 | { | 83 | { |
71 | int stat = FPGA_ISR; | 84 | u8 stat = __raw_readb(FPGA_ISR); |
85 | |||
86 | desc->chip->mask_ack(irq); | ||
72 | 87 | ||
73 | while (stat != 0) { | 88 | while (stat != 0) { |
74 | int irqno = fls(stat) - 1; | 89 | int irqno = fls(stat) - 1; |
90 | struct irq_desc *fpgadesc; | ||
75 | 91 | ||
76 | stat &= ~(1 << irqno); | 92 | stat &= ~(1 << irqno); |
77 | 93 | ||
78 | desc = irq_desc + FPGA_IRQ(irqno); | 94 | fpgadesc = irq_desc + FPGA_IRQ(irqno); |
79 | 95 | ||
80 | desc_handle_irq(FPGA_IRQ(irqno), desc); | 96 | desc_handle_irq(FPGA_IRQ(irqno), fpgadesc); |
81 | } | 97 | } |
98 | |||
99 | desc->chip->unmask(irq); | ||
82 | } | 100 | } |
83 | 101 | ||
84 | void __init board_a9m9750dev_init_irq(void) | 102 | void __init board_a9m9750dev_init_irq(void) |
85 | { | 103 | { |
86 | u32 reg; | 104 | u32 eic; |
87 | int i; | 105 | int i; |
88 | 106 | ||
89 | /* | 107 | if (gpio_request(11, "board a9m9750dev extirq2") == 0) |
90 | * configure gpio for IRQ_EXT2 | 108 | ns9xxx_gpio_configure(11, 0, 1); |
91 | * use GPIO 11, because GPIO 32 is used for the LCD | 109 | else |
92 | */ | 110 | printk(KERN_ERR "%s: cannot get gpio 11 for IRQ_EXT2\n", |
93 | /* XXX: proper GPIO handling */ | 111 | __func__); |
94 | BBU_GCONFb1(1) &= ~0x2000; | ||
95 | 112 | ||
96 | for (i = FPGA_IRQ(0); i <= FPGA_IRQ(7); ++i) { | 113 | for (i = FPGA_IRQ(0); i <= FPGA_IRQ(7); ++i) { |
97 | set_irq_chip(i, &a9m9750dev_fpga_chip); | 114 | set_irq_chip(i, &a9m9750dev_fpga_chip); |
@@ -100,10 +117,10 @@ void __init board_a9m9750dev_init_irq(void) | |||
100 | } | 117 | } |
101 | 118 | ||
102 | /* IRQ_EXT2: level sensitive + active low */ | 119 | /* IRQ_EXT2: level sensitive + active low */ |
103 | reg = SYS_EIC(2); | 120 | eic = __raw_readl(SYS_EIC(2)); |
104 | REGSET(reg, SYS_EIC, PLTY, AL); | 121 | REGSET(eic, SYS_EIC, PLTY, AL); |
105 | REGSET(reg, SYS_EIC, LVEDG, LEVEL); | 122 | REGSET(eic, SYS_EIC, LVEDG, LEVEL); |
106 | SYS_EIC(2) = reg; | 123 | __raw_writel(eic, SYS_EIC(2)); |
107 | 124 | ||
108 | set_irq_chained_handler(IRQ_EXT2, | 125 | set_irq_chained_handler(IRQ_EXT2, |
109 | a9m9750dev_fpga_demux_handler); | 126 | a9m9750dev_fpga_demux_handler); |
@@ -167,17 +184,18 @@ void __init board_a9m9750dev_init_machine(void) | |||
167 | u32 reg; | 184 | u32 reg; |
168 | 185 | ||
169 | /* setup static CS0: memory base ... */ | 186 | /* setup static CS0: memory base ... */ |
170 | REGSETIM(SYS_SMCSSMB(0), SYS_SMCSSMB, CSxB, | 187 | reg = __raw_readl(SYS_SMCSSMB(0)); |
171 | NS9XXX_CSxSTAT_PHYS(0) >> 12); | 188 | REGSETIM(reg, SYS_SMCSSMB, CSxB, NS9XXX_CSxSTAT_PHYS(0) >> 12); |
189 | __raw_writel(reg, SYS_SMCSSMB(0)); | ||
172 | 190 | ||
173 | /* ... and mask */ | 191 | /* ... and mask */ |
174 | reg = SYS_SMCSSMM(0); | 192 | reg = __raw_readl(SYS_SMCSSMM(0)); |
175 | REGSETIM(reg, SYS_SMCSSMM, CSxM, 0xfffff); | 193 | REGSETIM(reg, SYS_SMCSSMM, CSxM, 0xfffff); |
176 | REGSET(reg, SYS_SMCSSMM, CSEx, EN); | 194 | REGSET(reg, SYS_SMCSSMM, CSEx, EN); |
177 | SYS_SMCSSMM(0) = reg; | 195 | __raw_writel(reg, SYS_SMCSSMM(0)); |
178 | 196 | ||
179 | /* setup static CS0: memory configuration */ | 197 | /* setup static CS0: memory configuration */ |
180 | reg = MEM_SMC(0); | 198 | reg = __raw_readl(MEM_SMC(0)); |
181 | REGSET(reg, MEM_SMC, PSMC, OFF); | 199 | REGSET(reg, MEM_SMC, PSMC, OFF); |
182 | REGSET(reg, MEM_SMC, BSMC, OFF); | 200 | REGSET(reg, MEM_SMC, BSMC, OFF); |
183 | REGSET(reg, MEM_SMC, EW, OFF); | 201 | REGSET(reg, MEM_SMC, EW, OFF); |
@@ -185,13 +203,13 @@ void __init board_a9m9750dev_init_machine(void) | |||
185 | REGSET(reg, MEM_SMC, PC, AL); | 203 | REGSET(reg, MEM_SMC, PC, AL); |
186 | REGSET(reg, MEM_SMC, PM, DIS); | 204 | REGSET(reg, MEM_SMC, PM, DIS); |
187 | REGSET(reg, MEM_SMC, MW, 8); | 205 | REGSET(reg, MEM_SMC, MW, 8); |
188 | MEM_SMC(0) = reg; | 206 | __raw_writel(reg, MEM_SMC(0)); |
189 | 207 | ||
190 | /* setup static CS0: timing */ | 208 | /* setup static CS0: timing */ |
191 | MEM_SMWED(0) = 0x2; | 209 | __raw_writel(0x2, MEM_SMWED(0)); |
192 | MEM_SMOED(0) = 0x2; | 210 | __raw_writel(0x2, MEM_SMOED(0)); |
193 | MEM_SMRD(0) = 0x6; | 211 | __raw_writel(0x6, MEM_SMRD(0)); |
194 | MEM_SMWD(0) = 0x6; | 212 | __raw_writel(0x6, MEM_SMWD(0)); |
195 | 213 | ||
196 | platform_add_devices(board_a9m9750dev_devices, | 214 | platform_add_devices(board_a9m9750dev_devices, |
197 | ARRAY_SIZE(board_a9m9750dev_devices)); | 215 | ARRAY_SIZE(board_a9m9750dev_devices)); |
diff --git a/arch/arm/mach-ns9xxx/gpio.c b/arch/arm/mach-ns9xxx/gpio.c new file mode 100644 index 000000000000..b2230213b983 --- /dev/null +++ b/arch/arm/mach-ns9xxx/gpio.c | |||
@@ -0,0 +1,190 @@ | |||
1 | /* | ||
2 | * arch/arm/mach-ns9xxx/gpio.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/compiler.h> | ||
12 | #include <linux/init.h> | ||
13 | #include <linux/spinlock.h> | ||
14 | #include <linux/module.h> | ||
15 | |||
16 | #include <asm/arch-ns9xxx/gpio.h> | ||
17 | #include <asm/arch-ns9xxx/processor.h> | ||
18 | #include <asm/arch-ns9xxx/regs-bbu.h> | ||
19 | #include <asm/io.h> | ||
20 | #include <asm/bug.h> | ||
21 | #include <asm/types.h> | ||
22 | #include <asm/bitops.h> | ||
23 | |||
24 | #if defined(CONFIG_PROCESSOR_NS9360) | ||
25 | #define GPIO_MAX 72 | ||
26 | #elif defined(CONFIG_PROCESSOR_NS9750) | ||
27 | #define GPIO_MAX 49 | ||
28 | #endif | ||
29 | |||
30 | /* protects BBU_GCONFx and BBU_GCTRLx */ | ||
31 | static spinlock_t gpio_lock = __SPIN_LOCK_UNLOCKED(gpio_lock); | ||
32 | |||
33 | /* only access gpiores with atomic ops */ | ||
34 | static DECLARE_BITMAP(gpiores, GPIO_MAX); | ||
35 | |||
36 | static inline int ns9xxx_valid_gpio(unsigned gpio) | ||
37 | { | ||
38 | #if defined(CONFIG_PROCESSOR_NS9360) | ||
39 | if (processor_is_ns9360()) | ||
40 | return gpio <= 72; | ||
41 | else | ||
42 | #endif | ||
43 | #if defined(CONFIG_PROCESSOR_NS9750) | ||
44 | if (processor_is_ns9750()) | ||
45 | return gpio <= 49; | ||
46 | else | ||
47 | #endif | ||
48 | BUG(); | ||
49 | } | ||
50 | |||
51 | static inline void __iomem *ns9xxx_gpio_get_gconfaddr(unsigned gpio) | ||
52 | { | ||
53 | if (gpio < 56) | ||
54 | return BBU_GCONFb1(gpio / 8); | ||
55 | else | ||
56 | /* | ||
57 | * this could be optimised away on | ||
58 | * ns9750 only builds, but it isn't ... | ||
59 | */ | ||
60 | return BBU_GCONFb2((gpio - 56) / 8); | ||
61 | } | ||
62 | |||
63 | static inline void __iomem *ns9xxx_gpio_get_gctrladdr(unsigned gpio) | ||
64 | { | ||
65 | if (gpio < 32) | ||
66 | return BBU_GCTRL1; | ||
67 | else if (gpio < 64) | ||
68 | return BBU_GCTRL2; | ||
69 | else | ||
70 | /* this could be optimised away on ns9750 only builds */ | ||
71 | return BBU_GCTRL3; | ||
72 | } | ||
73 | |||
74 | static inline void __iomem *ns9xxx_gpio_get_gstataddr(unsigned gpio) | ||
75 | { | ||
76 | if (gpio < 32) | ||
77 | return BBU_GSTAT1; | ||
78 | else if (gpio < 64) | ||
79 | return BBU_GSTAT2; | ||
80 | else | ||
81 | /* this could be optimised away on ns9750 only builds */ | ||
82 | return BBU_GSTAT3; | ||
83 | } | ||
84 | |||
85 | int gpio_request(unsigned gpio, const char *label) | ||
86 | { | ||
87 | if (likely(ns9xxx_valid_gpio(gpio))) | ||
88 | return test_and_set_bit(gpio, gpiores) ? -EBUSY : 0; | ||
89 | else | ||
90 | return -EINVAL; | ||
91 | } | ||
92 | EXPORT_SYMBOL(gpio_request); | ||
93 | |||
94 | void gpio_free(unsigned gpio) | ||
95 | { | ||
96 | clear_bit(gpio, gpiores); | ||
97 | return; | ||
98 | } | ||
99 | EXPORT_SYMBOL(gpio_free); | ||
100 | |||
101 | /* | ||
102 | * each gpio can serve for 4 different purposes [0..3]. These are called | ||
103 | * "functions" and passed in the parameter func. Functions 0-2 are always some | ||
104 | * special things, function 3 is GPIO. If func == 3 dir specifies input or | ||
105 | * output, and with inv you can enable an inverter (independent of func). | ||
106 | */ | ||
107 | static int __ns9xxx_gpio_configure(unsigned gpio, int dir, int inv, int func) | ||
108 | { | ||
109 | void __iomem *conf = ns9xxx_gpio_get_gconfaddr(gpio); | ||
110 | u32 confval; | ||
111 | unsigned long flags; | ||
112 | |||
113 | spin_lock_irqsave(&gpio_lock, flags); | ||
114 | |||
115 | confval = __raw_readl(conf); | ||
116 | REGSETIM_IDX(confval, BBU_GCONFx, DIR, gpio & 7, dir); | ||
117 | REGSETIM_IDX(confval, BBU_GCONFx, INV, gpio & 7, inv); | ||
118 | REGSETIM_IDX(confval, BBU_GCONFx, FUNC, gpio & 7, func); | ||
119 | __raw_writel(confval, conf); | ||
120 | |||
121 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
122 | |||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | int ns9xxx_gpio_configure(unsigned gpio, int inv, int func) | ||
127 | { | ||
128 | if (likely(ns9xxx_valid_gpio(gpio))) { | ||
129 | if (func == 3) { | ||
130 | printk(KERN_WARNING "use gpio_direction_input " | ||
131 | "or gpio_direction_output\n"); | ||
132 | return -EINVAL; | ||
133 | } else | ||
134 | return __ns9xxx_gpio_configure(gpio, 0, inv, func); | ||
135 | } else | ||
136 | return -EINVAL; | ||
137 | } | ||
138 | EXPORT_SYMBOL(ns9xxx_gpio_configure); | ||
139 | |||
140 | int gpio_direction_input(unsigned gpio) | ||
141 | { | ||
142 | if (likely(ns9xxx_valid_gpio(gpio))) { | ||
143 | return __ns9xxx_gpio_configure(gpio, 0, 0, 3); | ||
144 | } else | ||
145 | return -EINVAL; | ||
146 | } | ||
147 | EXPORT_SYMBOL(gpio_direction_input); | ||
148 | |||
149 | int gpio_direction_output(unsigned gpio, int value) | ||
150 | { | ||
151 | if (likely(ns9xxx_valid_gpio(gpio))) { | ||
152 | gpio_set_value(gpio, value); | ||
153 | |||
154 | return __ns9xxx_gpio_configure(gpio, 1, 0, 3); | ||
155 | } else | ||
156 | return -EINVAL; | ||
157 | } | ||
158 | EXPORT_SYMBOL(gpio_direction_output); | ||
159 | |||
160 | int gpio_get_value(unsigned gpio) | ||
161 | { | ||
162 | void __iomem *stat = ns9xxx_gpio_get_gstataddr(gpio); | ||
163 | int ret; | ||
164 | |||
165 | ret = 1 & (__raw_readl(stat) >> (gpio & 31)); | ||
166 | |||
167 | return ret; | ||
168 | } | ||
169 | EXPORT_SYMBOL(gpio_get_value); | ||
170 | |||
171 | void gpio_set_value(unsigned gpio, int value) | ||
172 | { | ||
173 | void __iomem *ctrl = ns9xxx_gpio_get_gctrladdr(gpio); | ||
174 | u32 ctrlval; | ||
175 | unsigned long flags; | ||
176 | |||
177 | spin_lock_irqsave(&gpio_lock, flags); | ||
178 | |||
179 | ctrlval = __raw_readl(ctrl); | ||
180 | |||
181 | if (value) | ||
182 | ctrlval |= 1 << (gpio & 31); | ||
183 | else | ||
184 | ctrlval &= ~(1 << (gpio & 31)); | ||
185 | |||
186 | __raw_writel(ctrlval, ctrl); | ||
187 | |||
188 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
189 | } | ||
190 | EXPORT_SYMBOL(gpio_set_value); | ||
diff --git a/arch/arm/mach-ns9xxx/irq.c b/arch/arm/mach-ns9xxx/irq.c index b8c7b00522e6..00001b874e97 100644 --- a/arch/arm/mach-ns9xxx/irq.c +++ b/arch/arm/mach-ns9xxx/irq.c | |||
@@ -9,6 +9,7 @@ | |||
9 | * the Free Software Foundation. | 9 | * the Free Software Foundation. |
10 | */ | 10 | */ |
11 | #include <linux/interrupt.h> | 11 | #include <linux/interrupt.h> |
12 | #include <asm/io.h> | ||
12 | #include <asm/mach/irq.h> | 13 | #include <asm/mach/irq.h> |
13 | #include <asm/mach-types.h> | 14 | #include <asm/mach-types.h> |
14 | #include <asm/arch-ns9xxx/regs-sys.h> | 15 | #include <asm/arch-ns9xxx/regs-sys.h> |
@@ -17,48 +18,17 @@ | |||
17 | 18 | ||
18 | #include "generic.h" | 19 | #include "generic.h" |
19 | 20 | ||
20 | static void ns9xxx_ack_irq_timer(unsigned int irq) | ||
21 | { | ||
22 | u32 tc = SYS_TC(irq - IRQ_TIMER0); | ||
23 | |||
24 | /* | ||
25 | * If the timer is programmed to halt on terminal count, the | ||
26 | * timer must be disabled before clearing the interrupt. | ||
27 | */ | ||
28 | if (REGGET(tc, SYS_TCx, REN) == 0) { | ||
29 | REGSET(tc, SYS_TCx, TEN, DIS); | ||
30 | SYS_TC(irq - IRQ_TIMER0) = tc; | ||
31 | } | ||
32 | |||
33 | REGSET(tc, SYS_TCx, INTC, SET); | ||
34 | SYS_TC(irq - IRQ_TIMER0) = tc; | ||
35 | |||
36 | REGSET(tc, SYS_TCx, INTC, UNSET); | ||
37 | SYS_TC(irq - IRQ_TIMER0) = tc; | ||
38 | } | ||
39 | |||
40 | static void (*ns9xxx_ack_irq_functions[NR_IRQS])(unsigned int) = { | ||
41 | [IRQ_TIMER0] = ns9xxx_ack_irq_timer, | ||
42 | [IRQ_TIMER1] = ns9xxx_ack_irq_timer, | ||
43 | [IRQ_TIMER2] = ns9xxx_ack_irq_timer, | ||
44 | [IRQ_TIMER3] = ns9xxx_ack_irq_timer, | ||
45 | }; | ||
46 | |||
47 | static void ns9xxx_mask_irq(unsigned int irq) | 21 | static void ns9xxx_mask_irq(unsigned int irq) |
48 | { | 22 | { |
49 | /* XXX: better use cpp symbols */ | 23 | /* XXX: better use cpp symbols */ |
50 | SYS_IC(irq / 4) &= ~(1 << (7 + 8 * (3 - (irq & 3)))); | 24 | u32 ic = __raw_readl(SYS_IC(irq / 4)); |
25 | ic &= ~(1 << (7 + 8 * (3 - (irq & 3)))); | ||
26 | __raw_writel(ic, SYS_IC(irq / 4)); | ||
51 | } | 27 | } |
52 | 28 | ||
53 | static void ns9xxx_ack_irq(unsigned int irq) | 29 | static void ns9xxx_ack_irq(unsigned int irq) |
54 | { | 30 | { |
55 | if (!ns9xxx_ack_irq_functions[irq]) { | 31 | __raw_writel(0, SYS_ISRADDR); |
56 | printk(KERN_ERR "no ack function for irq %u\n", irq); | ||
57 | BUG(); | ||
58 | } | ||
59 | |||
60 | ns9xxx_ack_irq_functions[irq](irq); | ||
61 | SYS_ISRADDR = 0; | ||
62 | } | 32 | } |
63 | 33 | ||
64 | static void ns9xxx_maskack_irq(unsigned int irq) | 34 | static void ns9xxx_maskack_irq(unsigned int irq) |
@@ -70,7 +40,9 @@ static void ns9xxx_maskack_irq(unsigned int irq) | |||
70 | static void ns9xxx_unmask_irq(unsigned int irq) | 40 | static void ns9xxx_unmask_irq(unsigned int irq) |
71 | { | 41 | { |
72 | /* XXX: better use cpp symbols */ | 42 | /* XXX: better use cpp symbols */ |
73 | SYS_IC(irq / 4) |= 1 << (7 + 8 * (3 - (irq & 3))); | 43 | u32 ic = __raw_readl(SYS_IC(irq / 4)); |
44 | ic |= 1 << (7 + 8 * (3 - (irq & 3))); | ||
45 | __raw_writel(ic, SYS_IC(irq / 4)); | ||
74 | } | 46 | } |
75 | 47 | ||
76 | static struct irq_chip ns9xxx_chip = { | 48 | static struct irq_chip ns9xxx_chip = { |
@@ -86,14 +58,14 @@ void __init ns9xxx_init_irq(void) | |||
86 | 58 | ||
87 | /* disable all IRQs */ | 59 | /* disable all IRQs */ |
88 | for (i = 0; i < 8; ++i) | 60 | for (i = 0; i < 8; ++i) |
89 | SYS_IC(i) = (4 * i) << 24 | (4 * i + 1) << 16 | | 61 | __raw_writel((4 * i) << 24 | (4 * i + 1) << 16 | |
90 | (4 * i + 2) << 8 | (4 * i + 3); | 62 | (4 * i + 2) << 8 | (4 * i + 3), SYS_IC(i)); |
91 | 63 | ||
92 | /* simple interrupt prio table: | 64 | /* simple interrupt prio table: |
93 | * prio(x) < prio(y) <=> x < y | 65 | * prio(x) < prio(y) <=> x < y |
94 | */ | 66 | */ |
95 | for (i = 0; i < 32; ++i) | 67 | for (i = 0; i < 32; ++i) |
96 | SYS_IVA(i) = i; | 68 | __raw_writel(i, SYS_IVA(i)); |
97 | 69 | ||
98 | for (i = IRQ_WATCHDOG; i <= IRQ_EXT3; ++i) { | 70 | for (i = IRQ_WATCHDOG; i <= IRQ_EXT3; ++i) { |
99 | set_irq_chip(i, &ns9xxx_chip); | 71 | set_irq_chip(i, &ns9xxx_chip); |
diff --git a/arch/arm/mach-ns9xxx/time.c b/arch/arm/mach-ns9xxx/time.c index b97d0c54a388..c3dd1f4acb99 100644 --- a/arch/arm/mach-ns9xxx/time.c +++ b/arch/arm/mach-ns9xxx/time.c | |||
@@ -11,78 +11,174 @@ | |||
11 | #include <linux/jiffies.h> | 11 | #include <linux/jiffies.h> |
12 | #include <linux/interrupt.h> | 12 | #include <linux/interrupt.h> |
13 | #include <linux/irq.h> | 13 | #include <linux/irq.h> |
14 | #include <linux/stringify.h> | ||
15 | #include <linux/clocksource.h> | ||
16 | #include <linux/clockchips.h> | ||
17 | |||
14 | #include <asm/arch-ns9xxx/regs-sys.h> | 18 | #include <asm/arch-ns9xxx/regs-sys.h> |
15 | #include <asm/arch-ns9xxx/clock.h> | 19 | #include <asm/arch-ns9xxx/clock.h> |
16 | #include <asm/arch-ns9xxx/irqs.h> | 20 | #include <asm/arch-ns9xxx/irqs.h> |
17 | #include <asm/arch/system.h> | 21 | #include <asm/arch/system.h> |
18 | #include "generic.h" | 22 | #include "generic.h" |
19 | 23 | ||
20 | #define TIMERCLOCKSELECT 64 | 24 | #define TIMER_CLOCKSOURCE 0 |
25 | #define TIMER_CLOCKEVENT 1 | ||
26 | static u32 latch; | ||
27 | |||
28 | static cycle_t ns9xxx_clocksource_read(void) | ||
29 | { | ||
30 | return __raw_readl(SYS_TR(TIMER_CLOCKSOURCE)); | ||
31 | } | ||
21 | 32 | ||
22 | static u32 usecs_per_tick; | 33 | static struct clocksource ns9xxx_clocksource = { |
34 | .name = "ns9xxx-timer" __stringify(TIMER_CLOCKSOURCE), | ||
35 | .rating = 300, | ||
36 | .read = ns9xxx_clocksource_read, | ||
37 | .mask = CLOCKSOURCE_MASK(32), | ||
38 | .shift = 20, | ||
39 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
40 | }; | ||
23 | 41 | ||
24 | static irqreturn_t | 42 | static void ns9xxx_clockevent_setmode(enum clock_event_mode mode, |
25 | ns9xxx_timer_interrupt(int irq, void *dev_id) | 43 | struct clock_event_device *clk) |
26 | { | 44 | { |
27 | write_seqlock(&xtime_lock); | 45 | u32 tc = __raw_readl(SYS_TC(TIMER_CLOCKEVENT)); |
28 | timer_tick(); | 46 | |
29 | write_sequnlock(&xtime_lock); | 47 | switch(mode) { |
48 | case CLOCK_EVT_MODE_PERIODIC: | ||
49 | __raw_writel(latch, SYS_TRC(TIMER_CLOCKEVENT)); | ||
50 | REGSET(tc, SYS_TCx, REN, EN); | ||
51 | REGSET(tc, SYS_TCx, INTS, EN); | ||
52 | REGSET(tc, SYS_TCx, TEN, EN); | ||
53 | break; | ||
54 | |||
55 | case CLOCK_EVT_MODE_ONESHOT: | ||
56 | REGSET(tc, SYS_TCx, REN, DIS); | ||
57 | REGSET(tc, SYS_TCx, INTS, EN); | ||
58 | |||
59 | /* fall through */ | ||
60 | |||
61 | case CLOCK_EVT_MODE_UNUSED: | ||
62 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
63 | case CLOCK_EVT_MODE_RESUME: | ||
64 | default: | ||
65 | REGSET(tc, SYS_TCx, TEN, DIS); | ||
66 | break; | ||
67 | } | ||
68 | |||
69 | __raw_writel(tc, SYS_TC(TIMER_CLOCKEVENT)); | ||
70 | } | ||
30 | 71 | ||
31 | return IRQ_HANDLED; | 72 | static int ns9xxx_clockevent_setnextevent(unsigned long evt, |
73 | struct clock_event_device *clk) | ||
74 | { | ||
75 | u32 tc = __raw_readl(SYS_TC(TIMER_CLOCKEVENT)); | ||
76 | |||
77 | if (REGGET(tc, SYS_TCx, TEN)) { | ||
78 | REGSET(tc, SYS_TCx, TEN, DIS); | ||
79 | __raw_writel(tc, SYS_TC(TIMER_CLOCKEVENT)); | ||
80 | } | ||
81 | |||
82 | REGSET(tc, SYS_TCx, TEN, EN); | ||
83 | |||
84 | __raw_writel(evt, SYS_TRC(TIMER_CLOCKEVENT)); | ||
85 | |||
86 | __raw_writel(tc, SYS_TC(TIMER_CLOCKEVENT)); | ||
87 | |||
88 | return 0; | ||
32 | } | 89 | } |
33 | 90 | ||
34 | static unsigned long ns9xxx_timer_gettimeoffset(void) | 91 | static struct clock_event_device ns9xxx_clockevent_device = { |
92 | .name = "ns9xxx-timer" __stringify(TIMER_CLOCKEVENT), | ||
93 | .shift = 20, | ||
94 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, | ||
95 | .set_mode = ns9xxx_clockevent_setmode, | ||
96 | .set_next_event = ns9xxx_clockevent_setnextevent, | ||
97 | }; | ||
98 | |||
99 | static irqreturn_t ns9xxx_clockevent_handler(int irq, void *dev_id) | ||
35 | { | 100 | { |
36 | /* return the microseconds which have passed since the last interrupt | 101 | int timerno = irq - IRQ_TIMER0; |
37 | * was _serviced_. That is, if an interrupt is pending or the counter | 102 | u32 tc; |
38 | * reloads, return one period more. */ | ||
39 | 103 | ||
40 | u32 counter1 = SYS_TR(0); | 104 | struct clock_event_device *evt = &ns9xxx_clockevent_device; |
41 | int pending = SYS_ISR & (1 << IRQ_TIMER0); | ||
42 | u32 counter2 = SYS_TR(0); | ||
43 | u32 elapsed; | ||
44 | 105 | ||
45 | if (pending || counter2 > counter1) | 106 | /* clear irq */ |
46 | elapsed = 2 * SYS_TRC(0) - counter2; | 107 | tc = __raw_readl(SYS_TC(timerno)); |
47 | else | 108 | if (REGGET(tc, SYS_TCx, REN) == SYS_TCx_REN_DIS) { |
48 | elapsed = SYS_TRC(0) - counter1; | 109 | REGSET(tc, SYS_TCx, TEN, DIS); |
110 | __raw_writel(tc, SYS_TC(timerno)); | ||
111 | } | ||
112 | REGSET(tc, SYS_TCx, INTC, SET); | ||
113 | __raw_writel(tc, SYS_TC(timerno)); | ||
114 | REGSET(tc, SYS_TCx, INTC, UNSET); | ||
115 | __raw_writel(tc, SYS_TC(timerno)); | ||
49 | 116 | ||
50 | return (elapsed * usecs_per_tick) >> 16; | 117 | evt->event_handler(evt); |
51 | 118 | ||
119 | return IRQ_HANDLED; | ||
52 | } | 120 | } |
53 | 121 | ||
54 | static struct irqaction ns9xxx_timer_irq = { | 122 | static struct irqaction ns9xxx_clockevent_action = { |
55 | .name = "NS9xxx Timer Tick", | 123 | .name = "ns9xxx-timer" __stringify(TIMER_CLOCKEVENT), |
56 | .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, | 124 | .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, |
57 | .handler = ns9xxx_timer_interrupt, | 125 | .handler = ns9xxx_clockevent_handler, |
58 | }; | 126 | }; |
59 | 127 | ||
60 | static void __init ns9xxx_timer_init(void) | 128 | static void __init ns9xxx_timer_init(void) |
61 | { | 129 | { |
62 | int tc; | 130 | int tc; |
63 | 131 | ||
64 | usecs_per_tick = | 132 | tc = __raw_readl(SYS_TC(TIMER_CLOCKSOURCE)); |
65 | SH_DIV(1000000 * TIMERCLOCKSELECT, ns9xxx_cpuclock(), 16); | 133 | if (REGGET(tc, SYS_TCx, TEN)) { |
134 | REGSET(tc, SYS_TCx, TEN, DIS); | ||
135 | __raw_writel(tc, SYS_TC(TIMER_CLOCKSOURCE)); | ||
136 | } | ||
66 | 137 | ||
67 | /* disable timer */ | 138 | __raw_writel(0, SYS_TRC(TIMER_CLOCKSOURCE)); |
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 | 139 | ||
73 | REGSET(tc, SYS_TCx, TEN, EN); | 140 | 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); | 141 | REGSET(tc, SYS_TCx, TDBG, STOP); |
142 | REGSET(tc, SYS_TCx, TLCS, CPU); | ||
143 | REGSET(tc, SYS_TCx, TM, IEE); | ||
144 | REGSET(tc, SYS_TCx, INTS, DIS); | ||
145 | REGSET(tc, SYS_TCx, UDS, UP); | ||
78 | REGSET(tc, SYS_TCx, TSZ, 32); | 146 | REGSET(tc, SYS_TCx, TSZ, 32); |
79 | REGSET(tc, SYS_TCx, REN, EN); | 147 | REGSET(tc, SYS_TCx, REN, EN); |
80 | SYS_TC(0) = tc; | ||
81 | 148 | ||
82 | setup_irq(IRQ_TIMER0, &ns9xxx_timer_irq); | 149 | __raw_writel(tc, SYS_TC(TIMER_CLOCKSOURCE)); |
150 | |||
151 | ns9xxx_clocksource.mult = clocksource_hz2mult(ns9xxx_cpuclock(), | ||
152 | ns9xxx_clocksource.shift); | ||
153 | |||
154 | clocksource_register(&ns9xxx_clocksource); | ||
155 | |||
156 | latch = SH_DIV(ns9xxx_cpuclock(), HZ, 0); | ||
157 | |||
158 | tc = __raw_readl(SYS_TC(TIMER_CLOCKEVENT)); | ||
159 | REGSET(tc, SYS_TCx, TEN, DIS); | ||
160 | REGSET(tc, SYS_TCx, TDBG, STOP); | ||
161 | REGSET(tc, SYS_TCx, TLCS, CPU); | ||
162 | REGSET(tc, SYS_TCx, TM, IEE); | ||
163 | REGSET(tc, SYS_TCx, INTS, DIS); | ||
164 | REGSET(tc, SYS_TCx, UDS, DOWN); | ||
165 | REGSET(tc, SYS_TCx, TSZ, 32); | ||
166 | REGSET(tc, SYS_TCx, REN, EN); | ||
167 | __raw_writel(tc, SYS_TC(TIMER_CLOCKEVENT)); | ||
168 | |||
169 | ns9xxx_clockevent_device.mult = div_sc(ns9xxx_cpuclock(), | ||
170 | NSEC_PER_SEC, ns9xxx_clockevent_device.shift); | ||
171 | ns9xxx_clockevent_device.max_delta_ns = | ||
172 | clockevent_delta2ns(-1, &ns9xxx_clockevent_device); | ||
173 | ns9xxx_clockevent_device.min_delta_ns = | ||
174 | clockevent_delta2ns(1, &ns9xxx_clockevent_device); | ||
175 | |||
176 | ns9xxx_clockevent_device.cpumask = cpumask_of_cpu(0); | ||
177 | clockevents_register_device(&ns9xxx_clockevent_device); | ||
178 | |||
179 | setup_irq(IRQ_TIMER0 + TIMER_CLOCKEVENT, &ns9xxx_clockevent_action); | ||
83 | } | 180 | } |
84 | 181 | ||
85 | struct sys_timer ns9xxx_timer = { | 182 | struct sys_timer ns9xxx_timer = { |
86 | .init = ns9xxx_timer_init, | 183 | .init = ns9xxx_timer_init, |
87 | .offset = ns9xxx_timer_gettimeoffset, | ||
88 | }; | 184 | }; |