This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / arch / arm / mach-s3c2410 / s3c2440.c
1 /* linux/arch/arm/mach-s3c2410/s3c2440.c
2  *
3  * Copyright (c) 2004 Simtec Electronics
4  *   Ben Dooks <ben@simtec.co.uk>
5  *
6  * Samsung S3C2440 Mobile CPU support
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 version 2 as
10  * published by the Free Software Foundation.
11  *
12  * Modifications:
13  *     24-Aug-2004 BJD  Start of s3c2440 support
14 */
15
16 #include <linux/kernel.h>
17 #include <linux/types.h>
18 #include <linux/interrupt.h>
19 #include <linux/list.h>
20 #include <linux/timer.h>
21 #include <linux/init.h>
22 #include <linux/device.h>
23
24 #include <asm/mach/arch.h>
25 #include <asm/mach/map.h>
26 #include <asm/mach/irq.h>
27
28 #include <asm/hardware.h>
29 #include <asm/io.h>
30 #include <asm/irq.h>
31
32 #include <asm/arch/regs-clock.h>
33 #include <asm/arch/regs-serial.h>
34
35 #include "s3c2440.h"
36 #include "cpu.h"
37
38 int s3c2440_clock_tick_rate = 12*1000*1000;  /* current timers at 12MHz */
39
40 /* clock info */
41
42 unsigned long s3c2440_baseclk = 12*1000*1000;  /* assume base is 12MHz */
43 unsigned long s3c2440_hdiv;
44
45 unsigned long s3c2440_fclk;
46 unsigned long s3c2440_hclk;
47 unsigned long s3c2440_pclk;
48
49 static struct map_desc s3c2440_iodesc[] __initdata = {
50         IODESC_ENT(USBHOST),
51         IODESC_ENT(CLKPWR),
52         IODESC_ENT(LCD),
53         IODESC_ENT(TIMER),
54         IODESC_ENT(ADC),
55 };
56
57 static struct resource s3c_uart0_resource[] = {
58         [0] = {
59                 .start = S3C2410_PA_UART0,
60                 .end   = S3C2410_PA_UART0 + 0x3fff,
61                 .flags = IORESOURCE_MEM,
62         },
63         [1] = {
64                 .start = IRQ_S3CUART_RX0,
65                 .end   = IRQ_S3CUART_ERR0,
66                 .flags = IORESOURCE_IRQ,
67         }
68
69 };
70
71 static struct resource s3c_uart1_resource[] = {
72         [0] = {
73                 .start = S3C2410_PA_UART1,
74                 .end   = S3C2410_PA_UART1 + 0x3fff,
75                 .flags = IORESOURCE_MEM,
76         },
77         [1] = {
78                 .start = IRQ_S3CUART_RX1,
79                 .end   = IRQ_S3CUART_ERR1,
80                 .flags = IORESOURCE_IRQ,
81         }
82 };
83
84 static struct resource s3c_uart2_resource[] = {
85         [0] = {
86                 .start = S3C2410_PA_UART2,
87                 .end   = S3C2410_PA_UART2 + 0x3fff,
88                 .flags = IORESOURCE_MEM,
89         },
90         [1] = {
91                 .start = IRQ_S3CUART_RX2,
92                 .end   = IRQ_S3CUART_ERR2,
93                 .flags = IORESOURCE_IRQ,
94         }
95 };
96
97 /* our uart devices */
98
99 static struct platform_device s3c_uart0 = {
100         .name             = "s3c2440-uart",
101         .id               = 0,
102         .num_resources    = ARRAY_SIZE(s3c_uart0_resource),
103         .resource         = s3c_uart0_resource,
104 };
105
106
107 static struct platform_device s3c_uart1 = {
108         .name             = "s3c2440-uart",
109         .id               = 1,
110         .num_resources    = ARRAY_SIZE(s3c_uart1_resource),
111         .resource         = s3c_uart1_resource,
112 };
113
114 static struct platform_device s3c_uart2 = {
115         .name             = "s3c2440-uart",
116         .id               = 2,
117         .num_resources    = ARRAY_SIZE(s3c_uart2_resource),
118         .resource         = s3c_uart2_resource,
119 };
120
121 static struct platform_device *uart_devices[] __initdata = {
122         &s3c_uart0,
123         &s3c_uart1,
124         &s3c_uart2
125 };
126
127 void __init s3c2440_map_io(struct map_desc *mach_desc, int size)
128 {
129         unsigned long tmp;
130         unsigned long camdiv;
131
132         /* register our io-tables */
133
134         iotable_init(s3c2440_iodesc, ARRAY_SIZE(s3c2440_iodesc));
135         iotable_init(mach_desc, size);
136
137         /* now we've got our machine bits initialised, work out what
138          * clocks we've got */
139
140         s3c2440_fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON),
141                                        s3c2440_baseclk);
142
143         tmp = __raw_readl(S3C2410_CLKDIVN);
144         camdiv = __raw_readl(S3C2440_CAMDIVN);
145
146         /* work out clock scalings */
147
148         switch (tmp & S3C2440_CLKDIVN_HDIVN_MASK) {
149         case S3C2440_CLKDIVN_HDIVN_1:
150                 s3c2440_hdiv = 1;
151                 break;
152
153         case S3C2440_CLKDIVN_HDIVN_2:
154                 s3c2440_hdiv = 1;
155                 break;
156
157         case S3C2440_CLKDIVN_HDIVN_4_8:
158                 s3c2440_hdiv = (camdiv & S3C2440_CAMDIVN_HCLK4_HALF) ? 8 : 4;
159                 break;
160
161         case S3C2440_CLKDIVN_HDIVN_3_6:
162                 s3c2440_hdiv = (camdiv & S3C2440_CAMDIVN_HCLK4_HALF) ? 6 : 3;
163                 break;
164         }
165
166         s3c2440_hclk = s3c2440_fclk / s3c2440_hdiv;
167         s3c2440_pclk = s3c2440_hclk / ((tmp & S3C2440_CLKDIVN_PDIVN) ? 2 : 1);
168
169         /* print brieft summary of clocks, etc */
170
171         printk("S3C2440: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n",
172                print_mhz(s3c2440_fclk), print_mhz(s3c2440_hclk),
173                print_mhz(s3c2440_pclk));
174 }
175
176
177
178 int __init s3c2440_init(void)
179 {
180         int ret;
181
182         printk("S3C2440: Initialising architecture\n");
183
184         ret = platform_add_devices(uart_devices, ARRAY_SIZE(uart_devices));
185         if (ret)
186                 return ret;
187
188         // todo: board specific inits?
189
190         return ret;
191 }
192