]> git.karo-electronics.de Git - karo-tx-linux.git/blob - arch/arm/mach-clps711x/common.c
47fb496ceae75b82b788e5806f1d1146195bb614
[karo-tx-linux.git] / arch / arm / mach-clps711x / common.c
1 /*
2  *  linux/arch/arm/mach-clps711x/core.c
3  *
4  *  Core support for the CLPS711x-based machines.
5  *
6  *  Copyright (C) 2001,2011 Deep Blue Solutions Ltd
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22 #include <linux/io.h>
23 #include <linux/init.h>
24 #include <linux/sizes.h>
25 #include <linux/interrupt.h>
26 #include <linux/irq.h>
27 #include <linux/clk.h>
28 #include <linux/clkdev.h>
29 #include <linux/clockchips.h>
30 #include <linux/clk-provider.h>
31
32 #include <asm/mach/map.h>
33 #include <asm/mach/time.h>
34 #include <asm/system_misc.h>
35
36 #include <mach/hardware.h>
37
38 static struct clk *clk_pll, *clk_bus, *clk_uart, *clk_timerl, *clk_timerh,
39                   *clk_tint, *clk_spi;
40
41 /*
42  * This maps the generic CLPS711x registers
43  */
44 static struct map_desc clps711x_io_desc[] __initdata = {
45         {
46                 .virtual        = (unsigned long)CLPS711X_VIRT_BASE,
47                 .pfn            = __phys_to_pfn(CLPS711X_PHYS_BASE),
48                 .length         = SZ_1M,
49                 .type           = MT_DEVICE
50         }
51 };
52
53 void __init clps711x_map_io(void)
54 {
55         iotable_init(clps711x_io_desc, ARRAY_SIZE(clps711x_io_desc));
56 }
57
58 static void int1_mask(struct irq_data *d)
59 {
60         u32 intmr1;
61
62         intmr1 = clps_readl(INTMR1);
63         intmr1 &= ~(1 << d->irq);
64         clps_writel(intmr1, INTMR1);
65 }
66
67 static void int1_ack(struct irq_data *d)
68 {
69 }
70
71 static void int1_eoi(struct irq_data *d)
72 {
73         switch (d->irq) {
74         case IRQ_CSINT:  clps_writel(0, COEOI);  break;
75         case IRQ_TC1OI:  clps_writel(0, TC1EOI); break;
76         case IRQ_TC2OI:  clps_writel(0, TC2EOI); break;
77         case IRQ_RTCMI:  clps_writel(0, RTCEOI); break;
78         case IRQ_TINT:   clps_writel(0, TEOI);   break;
79         case IRQ_UMSINT: clps_writel(0, UMSEOI); break;
80         }
81 }
82
83 static void int1_unmask(struct irq_data *d)
84 {
85         u32 intmr1;
86
87         intmr1 = clps_readl(INTMR1);
88         intmr1 |= 1 << d->irq;
89         clps_writel(intmr1, INTMR1);
90 }
91
92 static struct irq_chip int1_chip = {
93         .name           = "Interrupt Vector 1  ",
94         .irq_ack        = int1_ack,
95         .irq_eoi        = int1_eoi,
96         .irq_mask       = int1_mask,
97         .irq_unmask     = int1_unmask,
98 };
99
100 static void int2_mask(struct irq_data *d)
101 {
102         u32 intmr2;
103
104         intmr2 = clps_readl(INTMR2);
105         intmr2 &= ~(1 << (d->irq - 16));
106         clps_writel(intmr2, INTMR2);
107 }
108
109 static void int2_ack(struct irq_data *d)
110 {
111 }
112
113 static void int2_eoi(struct irq_data *d)
114 {
115         switch (d->irq) {
116         case IRQ_KBDINT: clps_writel(0, KBDEOI); break;
117         }
118 }
119
120 static void int2_unmask(struct irq_data *d)
121 {
122         u32 intmr2;
123
124         intmr2 = clps_readl(INTMR2);
125         intmr2 |= 1 << (d->irq - 16);
126         clps_writel(intmr2, INTMR2);
127 }
128
129 static struct irq_chip int2_chip = {
130         .name           = "Interrupt Vector 2  ",
131         .irq_ack        = int2_ack,
132         .irq_eoi        = int2_eoi,
133         .irq_mask       = int2_mask,
134         .irq_unmask     = int2_unmask,
135 };
136
137 struct clps711x_irqdesc {
138         int                     nr;
139         struct irq_chip         *chip;
140         irq_flow_handler_t      handle;
141 };
142
143 static struct clps711x_irqdesc clps711x_irqdescs[] __initdata = {
144         { IRQ_CSINT,    &int1_chip,     handle_fasteoi_irq,     },
145         { IRQ_EINT1,    &int1_chip,     handle_level_irq,       },
146         { IRQ_EINT2,    &int1_chip,     handle_level_irq,       },
147         { IRQ_EINT3,    &int1_chip,     handle_level_irq,       },
148         { IRQ_TC1OI,    &int1_chip,     handle_fasteoi_irq,     },
149         { IRQ_TC2OI,    &int1_chip,     handle_fasteoi_irq,     },
150         { IRQ_RTCMI,    &int1_chip,     handle_fasteoi_irq,     },
151         { IRQ_TINT,     &int1_chip,     handle_fasteoi_irq,     },
152         { IRQ_UTXINT1,  &int1_chip,     handle_level_irq,       },
153         { IRQ_URXINT1,  &int1_chip,     handle_level_irq,       },
154         { IRQ_UMSINT,   &int1_chip,     handle_fasteoi_irq,     },
155         { IRQ_SSEOTI,   &int1_chip,     handle_level_irq,       },
156         { IRQ_KBDINT,   &int2_chip,     handle_fasteoi_irq,     },
157         { IRQ_SS2RX,    &int2_chip,     handle_level_irq,       },
158         { IRQ_SS2TX,    &int2_chip,     handle_level_irq,       },
159         { IRQ_UTXINT2,  &int2_chip,     handle_level_irq,       },
160         { IRQ_URXINT2,  &int2_chip,     handle_level_irq,       },
161 };
162
163 void __init clps711x_init_irq(void)
164 {
165         unsigned int i;
166
167         /* Disable interrupts */
168         clps_writel(0, INTMR1);
169         clps_writel(0, INTMR2);
170         clps_writel(0, INTMR3);
171
172         /* Clear down any pending interrupts */
173         clps_writel(0, BLEOI);
174         clps_writel(0, MCEOI);
175         clps_writel(0, COEOI);
176         clps_writel(0, TC1EOI);
177         clps_writel(0, TC2EOI);
178         clps_writel(0, RTCEOI);
179         clps_writel(0, TEOI);
180         clps_writel(0, UMSEOI);
181         clps_writel(0, KBDEOI);
182         clps_writel(0, SRXEOF);
183         clps_writel(0xffffffff, DAISR);
184
185         for (i = 0; i < ARRAY_SIZE(clps711x_irqdescs); i++) {
186                 irq_set_chip_and_handler(clps711x_irqdescs[i].nr,
187                                          clps711x_irqdescs[i].chip,
188                                          clps711x_irqdescs[i].handle);
189                 set_irq_flags(clps711x_irqdescs[i].nr,
190                               IRQF_VALID | IRQF_PROBE);
191         }
192 }
193
194 static void clps711x_clockevent_set_mode(enum clock_event_mode mode,
195                                          struct clock_event_device *evt)
196 {
197 }
198
199 static struct clock_event_device clockevent_clps711x = {
200         .name           = "CLPS711x Clockevents",
201         .rating         = 300,
202         .features       = CLOCK_EVT_FEAT_PERIODIC,
203         .set_mode       = clps711x_clockevent_set_mode,
204 };
205
206 static irqreturn_t clps711x_timer_interrupt(int irq, void *dev_id)
207 {
208         clockevent_clps711x.event_handler(&clockevent_clps711x);
209
210         return IRQ_HANDLED;
211 }
212
213 static struct irqaction clps711x_timer_irq = {
214         .name           = "CLPS711x Timer Tick",
215         .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
216         .handler        = clps711x_timer_interrupt,
217 };
218
219 static void add_fixed_clk(struct clk *clk, const char *name, int rate)
220 {
221         clk = clk_register_fixed_rate(NULL, name, NULL, CLK_IS_ROOT, rate);
222         clk_register_clkdev(clk, name, NULL);
223 }
224
225 static void __init clps711x_timer_init(void)
226 {
227         int osc, ext, pll, cpu, bus, timl, timh, uart, spi;
228         u32 tmp;
229
230         osc = 3686400;
231         ext = 13000000;
232
233         tmp = clps_readl(PLLR) >> 24;
234         if (tmp)
235                 pll = (osc * tmp) / 2;
236         else
237                 pll = 73728000; /* Default value */
238
239         tmp = clps_readl(SYSFLG2);
240         if (tmp & SYSFLG2_CKMODE) {
241                 cpu = ext;
242                 bus = cpu;
243                 spi = 135400;
244         } else {
245                 cpu = pll;
246                 if (cpu >= 36864000)
247                         bus = cpu / 2;
248                 else
249                         bus = 36864000 / 2;
250                 spi = cpu / 576;
251         }
252
253         uart = bus / 10;
254
255         if (tmp & SYSFLG2_CKMODE) {
256                 tmp = clps_readl(SYSCON2);
257                 if (tmp & SYSCON2_OSTB)
258                         timh = ext / 26;
259                 else
260                         timh = 541440;
261         } else
262                 timh = cpu / 144;
263
264         timl = timh / 256;
265
266         /* All clocks are fixed */
267         add_fixed_clk(clk_pll, "pll", pll);
268         add_fixed_clk(clk_bus, "bus", bus);
269         add_fixed_clk(clk_uart, "uart", uart);
270         add_fixed_clk(clk_timerl, "timer_lf", timl);
271         add_fixed_clk(clk_timerh, "timer_hf", timh);
272         add_fixed_clk(clk_tint, "tint", 64);
273         add_fixed_clk(clk_spi, "spi", spi);
274
275         pr_info("CPU frequency set at %i Hz.\n", cpu);
276
277         clps_writew(DIV_ROUND_CLOSEST(timh, HZ), TC2D);
278
279         tmp = clps_readl(SYSCON1);
280         tmp |= SYSCON1_TC2S | SYSCON1_TC2M;
281         clps_writel(tmp, SYSCON1);
282
283         clockevents_config_and_register(&clockevent_clps711x, timh, 1, 0xffff);
284
285         setup_irq(IRQ_TC2OI, &clps711x_timer_irq);
286 }
287
288 struct sys_timer clps711x_timer = {
289         .init           = clps711x_timer_init,
290 };
291
292 void clps711x_restart(char mode, const char *cmd)
293 {
294         soft_restart(0);
295 }
296
297 static void clps711x_idle(void)
298 {
299         clps_writel(1, HALT);
300         __asm__ __volatile__(
301         "mov    r0, r0\n\
302         mov     r0, r0");
303 }
304
305 static int __init clps711x_idle_init(void)
306 {
307         arm_pm_idle = clps711x_idle;
308         return 0;
309 }
310
311 arch_initcall(clps711x_idle_init);