aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-sa1100
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/arm/mach-sa1100
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'arch/arm/mach-sa1100')
-rw-r--r--arch/arm/mach-sa1100/Kconfig162
-rw-r--r--arch/arm/mach-sa1100/Makefile53
-rw-r--r--arch/arm/mach-sa1100/Makefile.boot7
-rw-r--r--arch/arm/mach-sa1100/assabet.c441
-rw-r--r--arch/arm/mach-sa1100/badge4.c293
-rw-r--r--arch/arm/mach-sa1100/cerf.c132
-rw-r--r--arch/arm/mach-sa1100/collie.c192
-rw-r--r--arch/arm/mach-sa1100/cpu-sa1100.c249
-rw-r--r--arch/arm/mach-sa1100/cpu-sa1110.c367
-rw-r--r--arch/arm/mach-sa1100/dma.c348
-rw-r--r--arch/arm/mach-sa1100/generic.c419
-rw-r--r--arch/arm/mach-sa1100/generic.h38
-rw-r--r--arch/arm/mach-sa1100/h3600.c892
-rw-r--r--arch/arm/mach-sa1100/hackkit.c200
-rw-r--r--arch/arm/mach-sa1100/irq.c332
-rw-r--r--arch/arm/mach-sa1100/jornada720.c105
-rw-r--r--arch/arm/mach-sa1100/lart.c49
-rw-r--r--arch/arm/mach-sa1100/leds-assabet.c115
-rw-r--r--arch/arm/mach-sa1100/leds-badge4.c112
-rw-r--r--arch/arm/mach-sa1100/leds-cerf.c111
-rw-r--r--arch/arm/mach-sa1100/leds-hackkit.c113
-rw-r--r--arch/arm/mach-sa1100/leds-lart.c102
-rw-r--r--arch/arm/mach-sa1100/leds-simpad.c101
-rw-r--r--arch/arm/mach-sa1100/leds.c52
-rw-r--r--arch/arm/mach-sa1100/leds.h14
-rw-r--r--arch/arm/mach-sa1100/neponset.c342
-rw-r--r--arch/arm/mach-sa1100/pleb.c154
-rw-r--r--arch/arm/mach-sa1100/pm.c167
-rw-r--r--arch/arm/mach-sa1100/shannon.c85
-rw-r--r--arch/arm/mach-sa1100/simpad.c224
-rw-r--r--arch/arm/mach-sa1100/sleep.S215
-rw-r--r--arch/arm/mach-sa1100/ssp.c214
-rw-r--r--arch/arm/mach-sa1100/time.c159
33 files changed, 6559 insertions, 0 deletions
diff --git a/arch/arm/mach-sa1100/Kconfig b/arch/arm/mach-sa1100/Kconfig
new file mode 100644
index 000000000000..50cde576dadf
--- /dev/null
+++ b/arch/arm/mach-sa1100/Kconfig
@@ -0,0 +1,162 @@
1if ARCH_SA1100
2
3menu "SA11x0 Implementations"
4
5config SA1100_ASSABET
6 bool "Assabet"
7 help
8 Say Y here if you are using the Intel(R) StrongARM(R) SA-1110
9 Microprocessor Development Board (also known as the Assabet).
10
11config ASSABET_NEPONSET
12 bool "Include support for Neponset"
13 depends on SA1100_ASSABET
14 select SA1111
15 help
16 Say Y here if you are using the Intel(R) StrongARM(R) SA-1110
17 Microprocessor Development Board (Assabet) with the SA-1111
18 Development Board (Nepon).
19
20config SA1100_CERF
21 bool "CerfBoard"
22 help
23 The Intrinsyc CerfBoard is based on the StrongARM 1110 (Discontinued).
24 More information is available at:
25 <http://www.intrinsyc.com/products/cerfboard/>.
26
27 Say Y if configuring for an Intrinsyc CerfBoard.
28 Say N otherwise.
29
30choice
31 prompt "Cerf Flash available"
32 depends on SA1100_CERF
33 default SA1100_CERF_FLASH_8MB
34
35config SA1100_CERF_FLASH_8MB
36 bool "8MB"
37
38config SA1100_CERF_FLASH_16MB
39 bool "16MB"
40
41config SA1100_CERF_FLASH_32MB
42 bool "32MB"
43
44endchoice
45
46config SA1100_COLLIE
47 bool "Sharp Zaurus SL5500"
48 select SHARP_LOCOMO
49 select SHARP_SCOOP
50 select SHARP_PARAM
51 help
52 Say Y here to support the Sharp Zaurus SL5500 PDAs.
53
54config SA1100_H3100
55 bool "Compaq iPAQ H3100"
56 help
57 Say Y here if you intend to run this kernel on the Compaq iPAQ
58 H3100 handheld computer. Information about this machine and the
59 Linux port to this machine can be found at:
60
61 <http://www.handhelds.org/Compaq/index.html#iPAQ_H3100>
62 <http://www.compaq.com/products/handhelds/pocketpc/>
63
64config SA1100_H3600
65 bool "Compaq iPAQ H3600/H3700"
66 help
67 Say Y here if you intend to run this kernel on the Compaq iPAQ
68 H3600 handheld computer. Information about this machine and the
69 Linux port to this machine can be found at:
70
71 <http://www.handhelds.org/Compaq/index.html#iPAQ_H3600>
72 <http://www.compaq.com/products/handhelds/pocketpc/>
73
74config SA1100_H3800
75 bool "Compaq iPAQ H3800"
76 help
77 Say Y here if you intend to run this kernel on the Compaq iPAQ H3800
78 series handheld computer. Information about this machine and the
79 Linux port to this machine can be found at:
80
81 <http://www.handhelds.org/Compaq/index.html#iPAQ_H3800>
82 <http://www.compaq.com/products/handhelds/pocketpc/>
83
84config SA1100_H3XXX
85 bool
86 depends on SA1100_H3100 || SA1100_H3600 || SA1100_H3800
87 default y
88
89config SA1100_BADGE4
90 bool "HP Labs BadgePAD 4"
91 select SA1111
92 help
93 Say Y here if you want to build a kernel for the HP Laboratories
94 BadgePAD 4.
95
96config SA1100_JORNADA720
97 bool "HP Jornada 720"
98 select SA1111
99 help
100 Say Y here if you want to build a kernel for the HP Jornada 720
101 handheld computer. See <http://www.hp.com/jornada/products/720>
102 for details.
103
104config SA1100_HACKKIT
105 bool "HackKit Core CPU Board"
106 help
107 Say Y here to support the HackKit Core CPU Board
108 <http://hackkit.eletztrick.de>;
109
110config SA1100_LART
111 bool "LART"
112 help
113 Say Y here if you are using the Linux Advanced Radio Terminal
114 (also known as the LART). See <http://www.lart.tudelft.nl/> for
115 information on the LART.
116
117config SA1100_PLEB
118 bool "PLEB"
119 help
120 Say Y here if you are using version 1 of the Portable Linux
121 Embedded Board (also known as PLEB).
122 See <http://www.disy.cse.unsw.edu.au/Hardware/PLEB/>
123 for more information.
124
125config SA1100_SHANNON
126 bool "Shannon"
127 help
128 The Shannon (also known as a Tuxscreen, and also as a IS2630) was a
129 limited edition webphone produced by Philips. The Shannon is a SA1100
130 platform with a 640x480 LCD, touchscreen, CIR keyboard, PCMCIA slots,
131 and a telco interface.
132
133config SA1100_SIMPAD
134 bool "Simpad"
135 help
136 The SIEMENS webpad SIMpad is based on the StrongARM 1110. There
137 are two different versions CL4 and SL4. CL4 has 32MB RAM and 16MB
138 FLASH. The SL4 version got 64 MB RAM and 32 MB FLASH and a
139 PCMCIA-Slot. The version for the Germany Telecom (DTAG) is the same
140 like CL4 in additional it has a PCMCIA-Slot. For more information
141 visit <http://www.my-siemens.com/> or <http://www.siemens.ch/>.
142
143config SA1100_SSP
144 tristate "Generic PIO SSP"
145 help
146 Say Y here to enable support for the generic PIO SSP driver.
147 This isn't for audio support, but for attached sensors and
148 other devices, eg for BadgePAD 4 sensor support, or Jornada
149 720 touchscreen support.
150
151config H3600_SLEEVE
152 tristate "Compaq iPAQ Handheld sleeve support"
153 depends on SA1100_H3600
154 help
155 Choose this option to enable support for extension packs (sleeves)
156 for the Compaq iPAQ H3XXX series of handheld computers. This option
157 is required for the CF, PCMCIA, Bluetooth and GSM/GPRS extension
158 packs.
159
160endmenu
161
162endif
diff --git a/arch/arm/mach-sa1100/Makefile b/arch/arm/mach-sa1100/Makefile
new file mode 100644
index 000000000000..e4a4a3e8aa8f
--- /dev/null
+++ b/arch/arm/mach-sa1100/Makefile
@@ -0,0 +1,53 @@
1#
2# Makefile for the linux kernel.
3#
4
5# Common support
6obj-y := generic.o irq.o dma.o time.o
7obj-m :=
8obj-n :=
9obj- :=
10led-y := leds.o
11
12obj-$(CONFIG_CPU_FREQ_SA1100) += cpu-sa1100.o
13obj-$(CONFIG_CPU_FREQ_SA1110) += cpu-sa1110.o
14
15# Specific board support
16obj-$(CONFIG_SA1100_ASSABET) += assabet.o
17led-$(CONFIG_SA1100_ASSABET) += leds-assabet.o
18obj-$(CONFIG_ASSABET_NEPONSET) += neponset.o
19
20obj-$(CONFIG_SA1100_BADGE4) += badge4.o
21led-$(CONFIG_SA1100_BADGE4) += leds-badge4.o
22
23obj-$(CONFIG_SA1100_CERF) += cerf.o
24led-$(CONFIG_SA1100_CERF) += leds-cerf.o
25
26obj-$(CONFIG_SA1100_COLLIE) += collie.o
27
28obj-$(CONFIG_SA1100_H3600) += h3600.o
29
30obj-$(CONFIG_SA1100_HACKKIT) += hackkit.o
31led-$(CONFIG_SA1100_HACKKIT) += leds-hackkit.o
32
33obj-$(CONFIG_SA1100_JORNADA720) += jornada720.o
34
35obj-$(CONFIG_SA1100_LART) += lart.o
36led-$(CONFIG_SA1100_LART) += leds-lart.o
37
38obj-$(CONFIG_SA1100_PLEB) += pleb.o
39
40obj-$(CONFIG_SA1100_SHANNON) += shannon.o
41
42obj-$(CONFIG_SA1100_SIMPAD) += simpad.o
43led-$(CONFIG_SA1100_SIMPAD) += leds-simpad.o
44
45# LEDs support
46obj-$(CONFIG_LEDS) += $(led-y)
47
48# SA1110 USB client support
49#obj-$(CONFIG_SA1100_USB) += usb/
50
51# Miscelaneous functions
52obj-$(CONFIG_PM) += pm.o sleep.o
53obj-$(CONFIG_SA1100_SSP) += ssp.o
diff --git a/arch/arm/mach-sa1100/Makefile.boot b/arch/arm/mach-sa1100/Makefile.boot
new file mode 100644
index 000000000000..a56ad0417cf2
--- /dev/null
+++ b/arch/arm/mach-sa1100/Makefile.boot
@@ -0,0 +1,7 @@
1 zreladdr-y := 0xc0008000
2ifeq ($(CONFIG_ARCH_SA1100),y)
3 zreladdr-$(CONFIG_SA1111) := 0xc0208000
4endif
5params_phys-y := 0xc0000100
6initrd_phys-y := 0xc0800000
7
diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c
new file mode 100644
index 000000000000..bedf88fafe08
--- /dev/null
+++ b/arch/arm/mach-sa1100/assabet.c
@@ -0,0 +1,441 @@
1/*
2 * linux/arch/arm/mach-sa1100/assabet.c
3 *
4 * Author: Nicolas Pitre
5 *
6 * This file contains all Assabet-specific tweaks.
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#include <linux/config.h>
13#include <linux/init.h>
14#include <linux/kernel.h>
15#include <linux/module.h>
16#include <linux/errno.h>
17#include <linux/ioport.h>
18#include <linux/serial_core.h>
19#include <linux/mtd/mtd.h>
20#include <linux/mtd/partitions.h>
21#include <linux/delay.h>
22#include <linux/mm.h>
23
24#include <asm/hardware.h>
25#include <asm/mach-types.h>
26#include <asm/irq.h>
27#include <asm/setup.h>
28#include <asm/page.h>
29#include <asm/pgtable.h>
30#include <asm/tlbflush.h>
31
32#include <asm/mach/arch.h>
33#include <asm/mach/flash.h>
34#include <asm/mach/irda.h>
35#include <asm/mach/map.h>
36#include <asm/mach/serial_sa1100.h>
37#include <asm/arch/assabet.h>
38
39#include "generic.h"
40
41#define ASSABET_BCR_DB1110 \
42 (ASSABET_BCR_SPK_OFF | ASSABET_BCR_QMUTE | \
43 ASSABET_BCR_LED_GREEN | ASSABET_BCR_LED_RED | \
44 ASSABET_BCR_RS232EN | ASSABET_BCR_LCD_12RGB | \
45 ASSABET_BCR_IRDA_MD0)
46
47#define ASSABET_BCR_DB1111 \
48 (ASSABET_BCR_SPK_OFF | ASSABET_BCR_QMUTE | \
49 ASSABET_BCR_LED_GREEN | ASSABET_BCR_LED_RED | \
50 ASSABET_BCR_RS232EN | ASSABET_BCR_LCD_12RGB | \
51 ASSABET_BCR_CF_BUS_OFF | ASSABET_BCR_STEREO_LB | \
52 ASSABET_BCR_IRDA_MD0 | ASSABET_BCR_CF_RST)
53
54unsigned long SCR_value = ASSABET_SCR_INIT;
55EXPORT_SYMBOL(SCR_value);
56
57static unsigned long BCR_value = ASSABET_BCR_DB1110;
58
59void ASSABET_BCR_frob(unsigned int mask, unsigned int val)
60{
61 unsigned long flags;
62
63 local_irq_save(flags);
64 BCR_value = (BCR_value & ~mask) | val;
65 ASSABET_BCR = BCR_value;
66 local_irq_restore(flags);
67}
68
69EXPORT_SYMBOL(ASSABET_BCR_frob);
70
71static void assabet_backlight_power(int on)
72{
73#ifndef ASSABET_PAL_VIDEO
74 if (on)
75 ASSABET_BCR_set(ASSABET_BCR_LIGHT_ON);
76 else
77#endif
78 ASSABET_BCR_clear(ASSABET_BCR_LIGHT_ON);
79}
80
81/*
82 * Turn on/off the backlight. When turning the backlight on,
83 * we wait 500us after turning it on so we don't cause the
84 * supplies to droop when we enable the LCD controller (and
85 * cause a hard reset.)
86 */
87static void assabet_lcd_power(int on)
88{
89#ifndef ASSABET_PAL_VIDEO
90 if (on) {
91 ASSABET_BCR_set(ASSABET_BCR_LCD_ON);
92 udelay(500);
93 } else
94#endif
95 ASSABET_BCR_clear(ASSABET_BCR_LCD_ON);
96}
97
98
99/*
100 * Assabet flash support code.
101 */
102
103#ifdef ASSABET_REV_4
104/*
105 * Phase 4 Assabet has two 28F160B3 flash parts in bank 0:
106 */
107static struct mtd_partition assabet_partitions[] = {
108 {
109 .name = "bootloader",
110 .size = 0x00020000,
111 .offset = 0,
112 .mask_flags = MTD_WRITEABLE,
113 }, {
114 .name = "bootloader params",
115 .size = 0x00020000,
116 .offset = MTDPART_OFS_APPEND,
117 .mask_flags = MTD_WRITEABLE,
118 }, {
119 .name = "jffs",
120 .size = MTDPART_SIZ_FULL,
121 .offset = MTDPART_OFS_APPEND,
122 }
123};
124#else
125/*
126 * Phase 5 Assabet has two 28F128J3A flash parts in bank 0:
127 */
128static struct mtd_partition assabet_partitions[] = {
129 {
130 .name = "bootloader",
131 .size = 0x00040000,
132 .offset = 0,
133 .mask_flags = MTD_WRITEABLE,
134 }, {
135 .name = "bootloader params",
136 .size = 0x00040000,
137 .offset = MTDPART_OFS_APPEND,
138 .mask_flags = MTD_WRITEABLE,
139 }, {
140 .name = "jffs",
141 .size = MTDPART_SIZ_FULL,
142 .offset = MTDPART_OFS_APPEND,
143 }
144};
145#endif
146
147static struct flash_platform_data assabet_flash_data = {
148 .map_name = "cfi_probe",
149 .parts = assabet_partitions,
150 .nr_parts = ARRAY_SIZE(assabet_partitions),
151};
152
153static struct resource assabet_flash_resources[] = {
154 {
155 .start = SA1100_CS0_PHYS,
156 .end = SA1100_CS0_PHYS + SZ_32M - 1,
157 .flags = IORESOURCE_MEM,
158 }, {
159 .start = SA1100_CS1_PHYS,
160 .end = SA1100_CS1_PHYS + SZ_32M - 1,
161 .flags = IORESOURCE_MEM,
162 }
163};
164
165
166/*
167 * Assabet IrDA support code.
168 */
169
170static int assabet_irda_set_power(struct device *dev, unsigned int state)
171{
172 static unsigned int bcr_state[4] = {
173 ASSABET_BCR_IRDA_MD0,
174 ASSABET_BCR_IRDA_MD1|ASSABET_BCR_IRDA_MD0,
175 ASSABET_BCR_IRDA_MD1,
176 0
177 };
178
179 if (state < 4) {
180 state = bcr_state[state];
181 ASSABET_BCR_clear(state ^ (ASSABET_BCR_IRDA_MD1|
182 ASSABET_BCR_IRDA_MD0));
183 ASSABET_BCR_set(state);
184 }
185 return 0;
186}
187
188static void assabet_irda_set_speed(struct device *dev, unsigned int speed)
189{
190 if (speed < 4000000)
191 ASSABET_BCR_clear(ASSABET_BCR_IRDA_FSEL);
192 else
193 ASSABET_BCR_set(ASSABET_BCR_IRDA_FSEL);
194}
195
196static struct irda_platform_data assabet_irda_data = {
197 .set_power = assabet_irda_set_power,
198 .set_speed = assabet_irda_set_speed,
199};
200
201static void __init assabet_init(void)
202{
203 /*
204 * Ensure that the power supply is in "high power" mode.
205 */
206 GPDR |= GPIO_GPIO16;
207 GPSR = GPIO_GPIO16;
208
209 /*
210 * Ensure that these pins are set as outputs and are driving
211 * logic 0. This ensures that we won't inadvertently toggle
212 * the WS latch in the CPLD, and we don't float causing
213 * excessive power drain. --rmk
214 */
215 GPDR |= GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM;
216 GPCR = GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM;
217
218 /*
219 * Set up registers for sleep mode.
220 */
221 PWER = PWER_GPIO0;
222 PGSR = 0;
223 PCFR = 0;
224 PSDR = 0;
225 PPDR |= PPC_TXD3 | PPC_TXD1;
226 PPSR |= PPC_TXD3 | PPC_TXD1;
227
228 sa1100fb_lcd_power = assabet_lcd_power;
229 sa1100fb_backlight_power = assabet_backlight_power;
230
231 if (machine_has_neponset()) {
232 /*
233 * Angel sets this, but other bootloaders may not.
234 *
235 * This must precede any driver calls to BCR_set()
236 * or BCR_clear().
237 */
238 ASSABET_BCR = BCR_value = ASSABET_BCR_DB1111;
239
240#ifndef CONFIG_ASSABET_NEPONSET
241 printk( "Warning: Neponset detected but full support "
242 "hasn't been configured in the kernel\n" );
243#endif
244 }
245
246 sa11x0_set_flash_data(&assabet_flash_data, assabet_flash_resources,
247 ARRAY_SIZE(assabet_flash_resources));
248 sa11x0_set_irda_data(&assabet_irda_data);
249}
250
251/*
252 * On Assabet, we must probe for the Neponset board _before_
253 * paging_init() has occurred to actually determine the amount
254 * of RAM available. To do so, we map the appropriate IO section
255 * in the page table here in order to access GPIO registers.
256 */
257static void __init map_sa1100_gpio_regs( void )
258{
259 unsigned long phys = __PREG(GPLR) & PMD_MASK;
260 unsigned long virt = io_p2v(phys);
261 int prot = PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_DOMAIN(DOMAIN_IO);
262 pmd_t *pmd;
263
264 pmd = pmd_offset(pgd_offset_k(virt), virt);
265 *pmd = __pmd(phys | prot);
266 flush_pmd_entry(pmd);
267}
268
269/*
270 * Read System Configuration "Register"
271 * (taken from "Intel StrongARM SA-1110 Microprocessor Development Board
272 * User's Guide", section 4.4.1)
273 *
274 * This same scan is performed in arch/arm/boot/compressed/head-sa1100.S
275 * to set up the serial port for decompression status messages. We
276 * repeat it here because the kernel may not be loaded as a zImage, and
277 * also because it's a hassle to communicate the SCR value to the kernel
278 * from the decompressor.
279 *
280 * Note that IRQs are guaranteed to be disabled.
281 */
282static void __init get_assabet_scr(void)
283{
284 unsigned long scr, i;
285
286 GPDR |= 0x3fc; /* Configure GPIO 9:2 as outputs */
287 GPSR = 0x3fc; /* Write 0xFF to GPIO 9:2 */
288 GPDR &= ~(0x3fc); /* Configure GPIO 9:2 as inputs */
289 for(i = 100; i--; scr = GPLR); /* Read GPIO 9:2 */
290 GPDR |= 0x3fc; /* restore correct pin direction */
291 scr &= 0x3fc; /* save as system configuration byte. */
292 SCR_value = scr;
293}
294
295static void __init
296fixup_assabet(struct machine_desc *desc, struct tag *tags,
297 char **cmdline, struct meminfo *mi)
298{
299 /* This must be done before any call to machine_has_neponset() */
300 map_sa1100_gpio_regs();
301 get_assabet_scr();
302
303 if (machine_has_neponset())
304 printk("Neponset expansion board detected\n");
305}
306
307
308static void assabet_uart_pm(struct uart_port *port, u_int state, u_int oldstate)
309{
310 if (port->mapbase == _Ser1UTCR0) {
311 if (state)
312 ASSABET_BCR_clear(ASSABET_BCR_RS232EN |
313 ASSABET_BCR_COM_RTS |
314 ASSABET_BCR_COM_DTR);
315 else
316 ASSABET_BCR_set(ASSABET_BCR_RS232EN |
317 ASSABET_BCR_COM_RTS |
318 ASSABET_BCR_COM_DTR);
319 }
320}
321
322/*
323 * Assabet uses COM_RTS and COM_DTR for both UART1 (com port)
324 * and UART3 (radio module). We only handle them for UART1 here.
325 */
326static void assabet_set_mctrl(struct uart_port *port, u_int mctrl)
327{
328 if (port->mapbase == _Ser1UTCR0) {
329 u_int set = 0, clear = 0;
330
331 if (mctrl & TIOCM_RTS)
332 clear |= ASSABET_BCR_COM_RTS;
333 else
334 set |= ASSABET_BCR_COM_RTS;
335
336 if (mctrl & TIOCM_DTR)
337 clear |= ASSABET_BCR_COM_DTR;
338 else
339 set |= ASSABET_BCR_COM_DTR;
340
341 ASSABET_BCR_clear(clear);
342 ASSABET_BCR_set(set);
343 }
344}
345
346static u_int assabet_get_mctrl(struct uart_port *port)
347{
348 u_int ret = 0;
349 u_int bsr = ASSABET_BSR;
350
351 /* need 2 reads to read current value */
352 bsr = ASSABET_BSR;
353
354 if (port->mapbase == _Ser1UTCR0) {
355 if (bsr & ASSABET_BSR_COM_DCD)
356 ret |= TIOCM_CD;
357 if (bsr & ASSABET_BSR_COM_CTS)
358 ret |= TIOCM_CTS;
359 if (bsr & ASSABET_BSR_COM_DSR)
360 ret |= TIOCM_DSR;
361 } else if (port->mapbase == _Ser3UTCR0) {
362 if (bsr & ASSABET_BSR_RAD_DCD)
363 ret |= TIOCM_CD;
364 if (bsr & ASSABET_BSR_RAD_CTS)
365 ret |= TIOCM_CTS;
366 if (bsr & ASSABET_BSR_RAD_DSR)
367 ret |= TIOCM_DSR;
368 if (bsr & ASSABET_BSR_RAD_RI)
369 ret |= TIOCM_RI;
370 } else {
371 ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR;
372 }
373
374 return ret;
375}
376
377static struct sa1100_port_fns assabet_port_fns __initdata = {
378 .set_mctrl = assabet_set_mctrl,
379 .get_mctrl = assabet_get_mctrl,
380 .pm = assabet_uart_pm,
381};
382
383static struct map_desc assabet_io_desc[] __initdata = {
384 /* virtual physical length type */
385 { 0xf1000000, 0x12000000, 0x00100000, MT_DEVICE }, /* Board Control Register */
386 { 0xf2800000, 0x4b800000, 0x00800000, MT_DEVICE } /* MQ200 */
387};
388
389static void __init assabet_map_io(void)
390{
391 sa1100_map_io();
392 iotable_init(assabet_io_desc, ARRAY_SIZE(assabet_io_desc));
393
394 /*
395 * Set SUS bit in SDCR0 so serial port 1 functions.
396 * Its called GPCLKR0 in my SA1110 manual.
397 */
398 Ser1SDCR0 |= SDCR0_SUS;
399
400 if (machine_has_neponset()) {
401#ifdef CONFIG_ASSABET_NEPONSET
402 extern void neponset_map_io(void);
403
404 /*
405 * We map Neponset registers even if it isn't present since
406 * many drivers will try to probe their stuff (and fail).
407 * This is still more friendly than a kernel paging request
408 * crash.
409 */
410 neponset_map_io();
411#endif
412 } else {
413 sa1100_register_uart_fns(&assabet_port_fns);
414 }
415
416 /*
417 * When Neponset is attached, the first UART should be
418 * UART3. That's what Angel is doing and many documents
419 * are stating this.
420 *
421 * We do the Neponset mapping even if Neponset support
422 * isn't compiled in so the user will still get something on
423 * the expected physical serial port.
424 *
425 * We no longer do this; not all boot loaders support it,
426 * and UART3 appears to be somewhat unreliable with blob.
427 */
428 sa1100_register_uart(0, 1);
429 sa1100_register_uart(2, 3);
430}
431
432
433MACHINE_START(ASSABET, "Intel-Assabet")
434 BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
435 BOOT_PARAMS(0xc0000100)
436 FIXUP(fixup_assabet)
437 MAPIO(assabet_map_io)
438 INITIRQ(sa1100_init_irq)
439 .timer = &sa1100_timer,
440 .init_machine = assabet_init,
441MACHINE_END
diff --git a/arch/arm/mach-sa1100/badge4.c b/arch/arm/mach-sa1100/badge4.c
new file mode 100644
index 000000000000..6a60b497ab42
--- /dev/null
+++ b/arch/arm/mach-sa1100/badge4.c
@@ -0,0 +1,293 @@
1/*
2 * linux/arch/arm/mach-sa1100/badge4.c
3 *
4 * BadgePAD 4 specific initialization
5 *
6 * Tim Connors <connors@hpl.hp.com>
7 * Christopher Hoover <ch@hpl.hp.com>
8 *
9 * Copyright (C) 2002 Hewlett-Packard Company
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
14 *
15 */
16#include <linux/module.h>
17#include <linux/init.h>
18#include <linux/kernel.h>
19#include <linux/device.h>
20#include <linux/delay.h>
21#include <linux/tty.h>
22#include <linux/mtd/mtd.h>
23#include <linux/mtd/partitions.h>
24#include <linux/errno.h>
25
26#include <asm/hardware.h>
27#include <asm/mach-types.h>
28#include <asm/setup.h>
29#include <asm/arch/irqs.h>
30
31#include <asm/mach/arch.h>
32#include <asm/mach/flash.h>
33#include <asm/mach/map.h>
34#include <asm/hardware/sa1111.h>
35#include <asm/mach/serial_sa1100.h>
36
37#include <asm/arch/badge4.h>
38
39#include "generic.h"
40
41static struct resource sa1111_resources[] = {
42 [0] = {
43 .start = BADGE4_SA1111_BASE,
44 .end = BADGE4_SA1111_BASE + 0x00001fff,
45 .flags = IORESOURCE_MEM,
46 },
47 [1] = {
48 .start = BADGE4_IRQ_GPIO_SA1111,
49 .end = BADGE4_IRQ_GPIO_SA1111,
50 .flags = IORESOURCE_IRQ,
51 },
52};
53
54static u64 sa1111_dmamask = 0xffffffffUL;
55
56static struct platform_device sa1111_device = {
57 .name = "sa1111",
58 .id = 0,
59 .dev = {
60 .dma_mask = &sa1111_dmamask,
61 .coherent_dma_mask = 0xffffffff,
62 },
63 .num_resources = ARRAY_SIZE(sa1111_resources),
64 .resource = sa1111_resources,
65};
66
67static struct platform_device *devices[] __initdata = {
68 &sa1111_device,
69};
70
71static int __init badge4_sa1111_init(void)
72{
73 /*
74 * Ensure that the memory bus request/grant signals are setup,
75 * and the grant is held in its inactive state
76 */
77 sa1110_mb_disable();
78
79 /*
80 * Probe for SA1111.
81 */
82 return platform_add_devices(devices, ARRAY_SIZE(devices));
83}
84
85
86/*
87 * 1 x Intel 28F320C3 Advanced+ Boot Block Flash (32 Mi bit)
88 * Eight 4 KiW Parameter Bottom Blocks (64 KiB)
89 * Sixty-three 32 KiW Main Blocks (4032 Ki b)
90 *
91 * <or>
92 *
93 * 1 x Intel 28F640C3 Advanced+ Boot Block Flash (64 Mi bit)
94 * Eight 4 KiW Parameter Bottom Blocks (64 KiB)
95 * One-hundred-twenty-seven 32 KiW Main Blocks (8128 Ki b)
96 */
97static struct mtd_partition badge4_partitions[] = {
98 {
99 .name = "BLOB boot loader",
100 .offset = 0,
101 .size = 0x0000A000
102 }, {
103 .name = "params",
104 .offset = MTDPART_OFS_APPEND,
105 .size = 0x00006000
106 }, {
107 .name = "root",
108 .offset = MTDPART_OFS_APPEND,
109 .size = MTDPART_SIZ_FULL
110 }
111};
112
113static struct flash_platform_data badge4_flash_data = {
114 .map_name = "cfi_probe",
115 .parts = badge4_partitions,
116 .nr_parts = ARRAY_SIZE(badge4_partitions),
117};
118
119static struct resource badge4_flash_resource = {
120 .start = SA1100_CS0_PHYS,
121 .end = SA1100_CS0_PHYS + SZ_64M - 1,
122 .flags = IORESOURCE_MEM,
123};
124
125static int five_v_on __initdata = 0;
126
127static int __init five_v_on_setup(char *ignore)
128{
129 five_v_on = 1;
130 return 1;
131}
132__setup("five_v_on", five_v_on_setup);
133
134
135static int __init badge4_init(void)
136{
137 int ret;
138
139 if (!machine_is_badge4())
140 return -ENODEV;
141
142 /* LCD */
143 GPCR = (BADGE4_GPIO_LGP2 | BADGE4_GPIO_LGP3 |
144 BADGE4_GPIO_LGP4 | BADGE4_GPIO_LGP5 |
145 BADGE4_GPIO_LGP6 | BADGE4_GPIO_LGP7 |
146 BADGE4_GPIO_LGP8 | BADGE4_GPIO_LGP9 |
147 BADGE4_GPIO_GPA_VID | BADGE4_GPIO_GPB_VID |
148 BADGE4_GPIO_GPC_VID);
149 GPDR &= ~BADGE4_GPIO_INT_VID;
150 GPDR |= (BADGE4_GPIO_LGP2 | BADGE4_GPIO_LGP3 |
151 BADGE4_GPIO_LGP4 | BADGE4_GPIO_LGP5 |
152 BADGE4_GPIO_LGP6 | BADGE4_GPIO_LGP7 |
153 BADGE4_GPIO_LGP8 | BADGE4_GPIO_LGP9 |
154 BADGE4_GPIO_GPA_VID | BADGE4_GPIO_GPB_VID |
155 BADGE4_GPIO_GPC_VID);
156
157 /* SDRAM SPD i2c */
158 GPCR = (BADGE4_GPIO_SDSDA | BADGE4_GPIO_SDSCL);
159 GPDR |= (BADGE4_GPIO_SDSDA | BADGE4_GPIO_SDSCL);
160
161 /* uart */
162 GPCR = (BADGE4_GPIO_UART_HS1 | BADGE4_GPIO_UART_HS2);
163 GPDR |= (BADGE4_GPIO_UART_HS1 | BADGE4_GPIO_UART_HS2);
164
165 /* CPLD muxsel0 input for mux/adc chip select */
166 GPCR = BADGE4_GPIO_MUXSEL0;
167 GPDR |= BADGE4_GPIO_MUXSEL0;
168
169 /* test points: J5, J6 as inputs, J7 outputs */
170 GPDR &= ~(BADGE4_GPIO_TESTPT_J5 | BADGE4_GPIO_TESTPT_J6);
171 GPCR = BADGE4_GPIO_TESTPT_J7;
172 GPDR |= BADGE4_GPIO_TESTPT_J7;
173
174 /* 5V supply rail. */
175 GPCR = BADGE4_GPIO_PCMEN5V; /* initially off */
176 GPDR |= BADGE4_GPIO_PCMEN5V;
177
178 /* CPLD sdram type inputs; set up by blob */
179 //GPDR |= (BADGE4_GPIO_SDTYP1 | BADGE4_GPIO_SDTYP0);
180 printk(KERN_DEBUG __FILE__ ": SDRAM CPLD typ1=%d typ0=%d\n",
181 !!(GPLR & BADGE4_GPIO_SDTYP1),
182 !!(GPLR & BADGE4_GPIO_SDTYP0));
183
184 /* SA1111 reset pin; set up by blob */
185 //GPSR = BADGE4_GPIO_SA1111_NRST;
186 //GPDR |= BADGE4_GPIO_SA1111_NRST;
187
188
189 /* power management cruft */
190 PGSR = 0;
191 PWER = 0;
192 PCFR = 0;
193 PSDR = 0;
194
195 PWER |= PWER_GPIO26; /* wake up on an edge from TESTPT_J5 */
196 PWER |= PWER_RTC; /* wake up if rtc fires */
197
198 /* drive sa1111_nrst during sleep */
199 PGSR |= BADGE4_GPIO_SA1111_NRST;
200 /* drive CPLD as is during sleep */
201 PGSR |= (GPLR & (BADGE4_GPIO_SDTYP0|BADGE4_GPIO_SDTYP1));
202
203
204 /* Now bring up the SA-1111. */
205 ret = badge4_sa1111_init();
206 if (ret < 0)
207 printk(KERN_ERR
208 "%s: SA-1111 initialization failed (%d)\n",
209 __FUNCTION__, ret);
210
211
212 /* maybe turn on 5v0 from the start */
213 badge4_set_5V(BADGE4_5V_INITIALLY, five_v_on);
214
215 sa11x0_set_flash_data(&badge4_flash_data, &badge4_flash_resource, 1);
216
217 return 0;
218}
219
220arch_initcall(badge4_init);
221
222
223static unsigned badge4_5V_bitmap = 0;
224
225void badge4_set_5V(unsigned subsystem, int on)
226{
227 unsigned long flags;
228 unsigned old_5V_bitmap;
229
230 local_irq_save(flags);
231
232 old_5V_bitmap = badge4_5V_bitmap;
233
234 if (on) {
235 badge4_5V_bitmap |= subsystem;
236 } else {
237 badge4_5V_bitmap &= ~subsystem;
238 }
239
240 /* detect on->off and off->on transitions */
241 if ((!old_5V_bitmap) && (badge4_5V_bitmap)) {
242 /* was off, now on */
243 printk(KERN_INFO "%s: enabling 5V supply rail\n", __FUNCTION__);
244 GPSR = BADGE4_GPIO_PCMEN5V;
245 } else if ((old_5V_bitmap) && (!badge4_5V_bitmap)) {
246 /* was on, now off */
247 printk(KERN_INFO "%s: disabling 5V supply rail\n", __FUNCTION__);
248 GPCR = BADGE4_GPIO_PCMEN5V;
249 }
250
251 local_irq_restore(flags);
252}
253EXPORT_SYMBOL(badge4_set_5V);
254
255
256static struct map_desc badge4_io_desc[] __initdata = {
257 /* virtual physical length type */
258 {0xf1000000, 0x08000000, 0x00100000, MT_DEVICE },/* SRAM bank 1 */
259 {0xf2000000, 0x10000000, 0x00100000, MT_DEVICE },/* SRAM bank 2 */
260 {0xf4000000, 0x48000000, 0x00100000, MT_DEVICE } /* SA-1111 */
261};
262
263static void
264badge4_uart_pm(struct uart_port *port, u_int state, u_int oldstate)
265{
266 if (!state) {
267 Ser1SDCR0 |= SDCR0_UART;
268 }
269}
270
271static struct sa1100_port_fns badge4_port_fns __initdata = {
272 //.get_mctrl = badge4_get_mctrl,
273 //.set_mctrl = badge4_set_mctrl,
274 .pm = badge4_uart_pm,
275};
276
277static void __init badge4_map_io(void)
278{
279 sa1100_map_io();
280 iotable_init(badge4_io_desc, ARRAY_SIZE(badge4_io_desc));
281
282 sa1100_register_uart_fns(&badge4_port_fns);
283 sa1100_register_uart(0, 3);
284 sa1100_register_uart(1, 1);
285}
286
287MACHINE_START(BADGE4, "Hewlett-Packard Laboratories BadgePAD 4")
288 BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
289 BOOT_PARAMS(0xc0000100)
290 MAPIO(badge4_map_io)
291 INITIRQ(sa1100_init_irq)
292 .timer = &sa1100_timer,
293MACHINE_END
diff --git a/arch/arm/mach-sa1100/cerf.c b/arch/arm/mach-sa1100/cerf.c
new file mode 100644
index 000000000000..f8edde5e7cbf
--- /dev/null
+++ b/arch/arm/mach-sa1100/cerf.c
@@ -0,0 +1,132 @@
1/*
2 * linux/arch/arm/mach-sa1100/cerf.c
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * Apr-2003 : Removed some old PDA crud [FB]
9 * Oct-2003 : Added uart2 resource [FB]
10 * Jan-2004 : Removed io map for flash [FB]
11 */
12
13#include <linux/config.h>
14#include <linux/init.h>
15#include <linux/kernel.h>
16#include <linux/tty.h>
17#include <linux/device.h>
18#include <linux/mtd/mtd.h>
19#include <linux/mtd/partitions.h>
20
21#include <asm/irq.h>
22#include <asm/hardware.h>
23#include <asm/setup.h>
24
25#include <asm/mach-types.h>
26#include <asm/mach/arch.h>
27#include <asm/mach/flash.h>
28#include <asm/mach/map.h>
29#include <asm/mach/serial_sa1100.h>
30
31#include <asm/arch/cerf.h>
32#include "generic.h"
33
34static struct resource cerfuart2_resources[] = {
35 [0] = {
36 .start = 0x80030000,
37 .end = 0x8003ffff,
38 .flags = IORESOURCE_MEM,
39 },
40};
41
42static struct platform_device cerfuart2_device = {
43 .name = "sa11x0-uart",
44 .id = 2,
45 .num_resources = ARRAY_SIZE(cerfuart2_resources),
46 .resource = cerfuart2_resources,
47};
48
49static struct platform_device *cerf_devices[] __initdata = {
50 &cerfuart2_device,
51};
52
53#ifdef CONFIG_SA1100_CERF_FLASH_32MB
54# define CERF_FLASH_SIZE 0x02000000
55#elif defined CONFIG_SA1100_CERF_FLASH_16MB
56# define CERF_FLASH_SIZE 0x01000000
57#elif defined CONFIG_SA1100_CERF_FLASH_8MB
58# define CERF_FLASH_SIZE 0x00800000
59#else
60# error "Undefined flash size for CERF"
61#endif
62
63static struct mtd_partition cerf_partitions[] = {
64 {
65 .name = "Bootloader",
66 .size = 0x00020000,
67 .offset = 0x00000000,
68 }, {
69 .name = "Params",
70 .size = 0x00040000,
71 .offset = 0x00020000,
72 }, {
73 .name = "Kernel",
74 .size = 0x00100000,
75 .offset = 0x00060000,
76 }, {
77 .name = "Filesystem",
78 .size = CERF_FLASH_SIZE-0x00160000,
79 .offset = 0x00160000,
80 }
81};
82
83static struct flash_platform_data cerf_flash_data = {
84 .map_name = "cfi_probe",
85 .parts = cerf_partitions,
86 .nr_parts = ARRAY_SIZE(cerf_partitions),
87};
88
89static struct resource cerf_flash_resource = {
90 .start = SA1100_CS0_PHYS,
91 .end = SA1100_CS0_PHYS + SZ_32M - 1,
92 .flags = IORESOURCE_MEM,
93};
94
95static void __init cerf_init_irq(void)
96{
97 sa1100_init_irq();
98 set_irq_type(CERF_ETH_IRQ, IRQT_RISING);
99}
100
101static struct map_desc cerf_io_desc[] __initdata = {
102 /* virtual physical length type */
103 { 0xf0000000, 0x08000000, 0x00100000, MT_DEVICE } /* Crystal Ethernet Chip */
104};
105
106static void __init cerf_map_io(void)
107{
108 sa1100_map_io();
109 iotable_init(cerf_io_desc, ARRAY_SIZE(cerf_io_desc));
110
111 sa1100_register_uart(0, 3);
112 sa1100_register_uart(1, 2); /* disable this and the uart2 device for sa1100_fir */
113 sa1100_register_uart(2, 1);
114
115 /* set some GPDR bits here while it's safe */
116 GPDR |= CERF_GPIO_CF_RESET;
117}
118
119static void __init cerf_init(void)
120{
121 platform_add_devices(cerf_devices, ARRAY_SIZE(cerf_devices));
122 sa11x0_set_flash_data(&cerf_flash_data, &cerf_flash_resource, 1);
123}
124
125MACHINE_START(CERF, "Intrinsyc CerfBoard/CerfCube")
126 MAINTAINER("support@intrinsyc.com")
127 BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
128 MAPIO(cerf_map_io)
129 INITIRQ(cerf_init_irq)
130 .timer = &sa1100_timer,
131 .init_machine = cerf_init,
132MACHINE_END
diff --git a/arch/arm/mach-sa1100/collie.c b/arch/arm/mach-sa1100/collie.c
new file mode 100644
index 000000000000..99287890d396
--- /dev/null
+++ b/arch/arm/mach-sa1100/collie.c
@@ -0,0 +1,192 @@
1/*
2 * linux/arch/arm/mach-sa1100/collie.c
3 *
4 * May be copied or modified under the terms of the GNU General Public
5 * License. See linux/COPYING for more information.
6 *
7 * This file contains all Collie-specific tweaks.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 *
13 * ChangeLog:
14 * 03-06-2004 John Lenz <jelenz@wisc.edu>
15 * 06-04-2002 Chris Larson <kergoth@digitalnemesis.net>
16 * 04-16-2001 Lineo Japan,Inc. ...
17 */
18
19#include <linux/config.h>
20#include <linux/init.h>
21#include <linux/kernel.h>
22#include <linux/tty.h>
23#include <linux/delay.h>
24#include <linux/device.h>
25#include <linux/mtd/mtd.h>
26#include <linux/mtd/partitions.h>
27#include <linux/timer.h>
28
29#include <asm/hardware.h>
30#include <asm/mach-types.h>
31#include <asm/irq.h>
32#include <asm/setup.h>
33#include <asm/arch/collie.h>
34
35#include <asm/mach/arch.h>
36#include <asm/mach/flash.h>
37#include <asm/mach/map.h>
38#include <asm/mach/serial_sa1100.h>
39
40#include <asm/hardware/scoop.h>
41#include <asm/mach/sharpsl_param.h>
42#include <asm/hardware/locomo.h>
43
44#include "generic.h"
45
46static struct resource collie_scoop_resources[] = {
47 [0] = {
48 .start = 0x40800000,
49 .end = 0x40800fff,
50 .flags = IORESOURCE_MEM,
51 },
52};
53
54static struct scoop_config collie_scoop_setup = {
55 .io_dir = COLLIE_SCOOP_IO_DIR,
56 .io_out = COLLIE_SCOOP_IO_OUT,
57};
58
59struct platform_device colliescoop_device = {
60 .name = "sharp-scoop",
61 .id = -1,
62 .dev = {
63 .platform_data = &collie_scoop_setup,
64 },
65 .num_resources = ARRAY_SIZE(collie_scoop_resources),
66 .resource = collie_scoop_resources,
67};
68
69
70static struct resource locomo_resources[] = {
71 [0] = {
72 .start = 0x40000000,
73 .end = 0x40001fff,
74 .flags = IORESOURCE_MEM,
75 },
76 [1] = {
77 .start = IRQ_GPIO25,
78 .end = IRQ_GPIO25,
79 .flags = IORESOURCE_IRQ,
80 },
81};
82
83static struct platform_device locomo_device = {
84 .name = "locomo",
85 .id = 0,
86 .num_resources = ARRAY_SIZE(locomo_resources),
87 .resource = locomo_resources,
88};
89
90static struct platform_device *devices[] __initdata = {
91 &locomo_device,
92 &colliescoop_device,
93};
94
95static struct mtd_partition collie_partitions[] = {
96 {
97 .name = "bootloader",
98 .offset = 0,
99 .size = 0x000C0000,
100 .mask_flags = MTD_WRITEABLE
101 }, {
102 .name = "kernel",
103 .offset = MTDPART_OFS_APPEND,
104 .size = 0x00100000,
105 }, {
106 .name = "rootfs",
107 .offset = MTDPART_OFS_APPEND,
108 .size = 0x00e20000,
109 }
110};
111
112static void collie_set_vpp(int vpp)
113{
114 write_scoop_reg(SCOOP_GPCR, read_scoop_reg(SCOOP_GPCR) | COLLIE_SCP_VPEN);
115 if (vpp) {
116 write_scoop_reg(SCOOP_GPWR, read_scoop_reg(SCOOP_GPWR) | COLLIE_SCP_VPEN);
117 } else {
118 write_scoop_reg(SCOOP_GPWR, read_scoop_reg(SCOOP_GPWR) & ~COLLIE_SCP_VPEN);
119 }
120}
121
122static struct flash_platform_data collie_flash_data = {
123 .map_name = "cfi_probe",
124 .set_vpp = collie_set_vpp,
125 .parts = collie_partitions,
126 .nr_parts = ARRAY_SIZE(collie_partitions),
127};
128
129static struct resource collie_flash_resources[] = {
130 {
131 .start = SA1100_CS0_PHYS,
132 .end = SA1100_CS0_PHYS + SZ_32M - 1,
133 .flags = IORESOURCE_MEM,
134 }
135};
136
137static void __init collie_init(void)
138{
139 int ret = 0;
140
141 /* cpu initialize */
142 GAFR = ( GPIO_SSP_TXD | \
143 GPIO_SSP_SCLK | GPIO_SSP_SFRM | GPIO_SSP_CLK | GPIO_TIC_ACK | \
144 GPIO_32_768kHz );
145
146 GPDR = ( GPIO_LDD8 | GPIO_LDD9 | GPIO_LDD10 | GPIO_LDD11 | GPIO_LDD12 | \
147 GPIO_LDD13 | GPIO_LDD14 | GPIO_LDD15 | GPIO_SSP_TXD | \
148 GPIO_SSP_SCLK | GPIO_SSP_SFRM | GPIO_SDLC_SCLK | \
149 GPIO_SDLC_AAF | GPIO_UART_SCLK1 | GPIO_32_768kHz );
150 GPLR = GPIO_GPIO18;
151
152 // PPC pin setting
153 PPDR = ( PPC_LDD0 | PPC_LDD1 | PPC_LDD2 | PPC_LDD3 | PPC_LDD4 | PPC_LDD5 | \
154 PPC_LDD6 | PPC_LDD7 | PPC_L_PCLK | PPC_L_LCLK | PPC_L_FCLK | PPC_L_BIAS | \
155 PPC_TXD1 | PPC_TXD2 | PPC_RXD2 | PPC_TXD3 | PPC_TXD4 | PPC_SCLK | PPC_SFRM );
156
157 PSDR = ( PPC_RXD1 | PPC_RXD2 | PPC_RXD3 | PPC_RXD4 );
158
159 GAFR |= GPIO_32_768kHz;
160 GPDR |= GPIO_32_768kHz;
161 TUCR = TUCR_32_768kHz;
162
163 ret = platform_add_devices(devices, ARRAY_SIZE(devices));
164 if (ret) {
165 printk(KERN_WARNING "collie: Unable to register LoCoMo device\n");
166 }
167
168 sa11x0_set_flash_data(&collie_flash_data, collie_flash_resources,
169 ARRAY_SIZE(collie_flash_resources));
170
171 sharpsl_save_param();
172}
173
174static struct map_desc collie_io_desc[] __initdata = {
175 /* virtual physical length type */
176 {0xe8000000, 0x00000000, 0x02000000, MT_DEVICE}, /* 32M main flash (cs0) */
177 {0xea000000, 0x08000000, 0x02000000, MT_DEVICE}, /* 32M boot flash (cs1) */
178};
179
180static void __init collie_map_io(void)
181{
182 sa1100_map_io();
183 iotable_init(collie_io_desc, ARRAY_SIZE(collie_io_desc));
184}
185
186MACHINE_START(COLLIE, "Sharp-Collie")
187 BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
188 MAPIO(collie_map_io)
189 INITIRQ(sa1100_init_irq)
190 .timer = &sa1100_timer,
191 .init_machine = collie_init,
192MACHINE_END
diff --git a/arch/arm/mach-sa1100/cpu-sa1100.c b/arch/arm/mach-sa1100/cpu-sa1100.c
new file mode 100644
index 000000000000..6435b2e48ffa
--- /dev/null
+++ b/arch/arm/mach-sa1100/cpu-sa1100.c
@@ -0,0 +1,249 @@
1/*
2 * cpu-sa1100.c: clock scaling for the SA1100
3 *
4 * Copyright (C) 2000 2001, The Delft University of Technology
5 *
6 * Authors:
7 * - Johan Pouwelse (J.A.Pouwelse@its.tudelft.nl): initial version
8 * - Erik Mouw (J.A.K.Mouw@its.tudelft.nl):
9 * - major rewrite for linux-2.3.99
10 * - rewritten for the more generic power management scheme in
11 * linux-2.4.5-rmk1
12 *
13 * This software has been developed while working on the LART
14 * computing board (http://www.lart.tudelft.nl/), which is
15 * sponsored by the Mobile Multi-media Communications
16 * (http://www.mmc.tudelft.nl/) and Ubiquitous Communications
17 * (http://www.ubicom.tudelft.nl/) projects.
18 *
19 * The authors can be reached at:
20 *
21 * Erik Mouw
22 * Information and Communication Theory Group
23 * Faculty of Information Technology and Systems
24 * Delft University of Technology
25 * P.O. Box 5031
26 * 2600 GA Delft
27 * The Netherlands
28 *
29 *
30 * This program is free software; you can redistribute it and/or modify
31 * it under the terms of the GNU General Public License as published by
32 * the Free Software Foundation; either version 2 of the License, or
33 * (at your option) any later version.
34 *
35 * This program is distributed in the hope that it will be useful,
36 * but WITHOUT ANY WARRANTY; without even the implied warranty of
37 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
38 * GNU General Public License for more details.
39 *
40 * You should have received a copy of the GNU General Public License
41 * along with this program; if not, write to the Free Software
42 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
43 *
44 *
45 * Theory of operations
46 * ====================
47 *
48 * Clock scaling can be used to lower the power consumption of the CPU
49 * core. This will give you a somewhat longer running time.
50 *
51 * The SA-1100 has a single register to change the core clock speed:
52 *
53 * PPCR 0x90020014 PLL config
54 *
55 * However, the DRAM timings are closely related to the core clock
56 * speed, so we need to change these, too. The used registers are:
57 *
58 * MDCNFG 0xA0000000 DRAM config
59 * MDCAS0 0xA0000004 Access waveform
60 * MDCAS1 0xA0000008 Access waveform
61 * MDCAS2 0xA000000C Access waveform
62 *
63 * Care must be taken to change the DRAM parameters the correct way,
64 * because otherwise the DRAM becomes unusable and the kernel will
65 * crash.
66 *
67 * The simple solution to avoid a kernel crash is to put the actual
68 * clock change in ROM and jump to that code from the kernel. The main
69 * disadvantage is that the ROM has to be modified, which is not
70 * possible on all SA-1100 platforms. Another disadvantage is that
71 * jumping to ROM makes clock switching unecessary complicated.
72 *
73 * The idea behind this driver is that the memory configuration can be
74 * changed while running from DRAM (even with interrupts turned on!)
75 * as long as all re-configuration steps yield a valid DRAM
76 * configuration. The advantages are clear: it will run on all SA-1100
77 * platforms, and the code is very simple.
78 *
79 * If you really want to understand what is going on in
80 * sa1100_update_dram_timings(), you'll have to read sections 8.2,
81 * 9.5.7.3, and 10.2 from the "Intel StrongARM SA-1100 Microprocessor
82 * Developers Manual" (available for free from Intel).
83 *
84 */
85
86#include <linux/kernel.h>
87#include <linux/types.h>
88#include <linux/init.h>
89#include <linux/cpufreq.h>
90
91#include <asm/hardware.h>
92
93#include "generic.h"
94
95typedef struct {
96 int speed;
97 u32 mdcnfg;
98 u32 mdcas0;
99 u32 mdcas1;
100 u32 mdcas2;
101} sa1100_dram_regs_t;
102
103
104static struct cpufreq_driver sa1100_driver;
105
106static sa1100_dram_regs_t sa1100_dram_settings[] =
107{
108 /* speed, mdcnfg, mdcas0, mdcas1, mdcas2 clock frequency */
109 { 59000, 0x00dc88a3, 0xcccccccf, 0xfffffffc, 0xffffffff }, /* 59.0 MHz */
110 { 73700, 0x011490a3, 0xcccccccf, 0xfffffffc, 0xffffffff }, /* 73.7 MHz */
111 { 88500, 0x014e90a3, 0xcccccccf, 0xfffffffc, 0xffffffff }, /* 88.5 MHz */
112 { 103200, 0x01889923, 0xcccccccf, 0xfffffffc, 0xffffffff }, /* 103.2 MHz */
113 { 118000, 0x01c29923, 0x9999998f, 0xfffffff9, 0xffffffff }, /* 118.0 MHz */
114 { 132700, 0x01fb2123, 0x9999998f, 0xfffffff9, 0xffffffff }, /* 132.7 MHz */
115 { 147500, 0x02352123, 0x3333330f, 0xfffffff3, 0xffffffff }, /* 147.5 MHz */
116 { 162200, 0x026b29a3, 0x38e38e1f, 0xfff8e38e, 0xffffffff }, /* 162.2 MHz */
117 { 176900, 0x02a329a3, 0x71c71c1f, 0xfff1c71c, 0xffffffff }, /* 176.9 MHz */
118 { 191700, 0x02dd31a3, 0xe38e383f, 0xffe38e38, 0xffffffff }, /* 191.7 MHz */
119 { 206400, 0x03153223, 0xc71c703f, 0xffc71c71, 0xffffffff }, /* 206.4 MHz */
120 { 221200, 0x034fba23, 0xc71c703f, 0xffc71c71, 0xffffffff }, /* 221.2 MHz */
121 { 235900, 0x03853a23, 0xe1e1e07f, 0xe1e1e1e1, 0xffffffe1 }, /* 235.9 MHz */
122 { 250700, 0x03bf3aa3, 0xc3c3c07f, 0xc3c3c3c3, 0xffffffc3 }, /* 250.7 MHz */
123 { 265400, 0x03f7c2a3, 0xc3c3c07f, 0xc3c3c3c3, 0xffffffc3 }, /* 265.4 MHz */
124 { 280200, 0x0431c2a3, 0x878780ff, 0x87878787, 0xffffff87 }, /* 280.2 MHz */
125 { 0, 0, 0, 0, 0 } /* last entry */
126};
127
128static void sa1100_update_dram_timings(int current_speed, int new_speed)
129{
130 sa1100_dram_regs_t *settings = sa1100_dram_settings;
131
132 /* find speed */
133 while (settings->speed != 0) {
134 if(new_speed == settings->speed)
135 break;
136
137 settings++;
138 }
139
140 if (settings->speed == 0) {
141 panic("%s: couldn't find dram setting for speed %d\n",
142 __FUNCTION__, new_speed);
143 }
144
145 /* No risk, no fun: run with interrupts on! */
146 if (new_speed > current_speed) {
147 /* We're going FASTER, so first relax the memory
148 * timings before changing the core frequency
149 */
150
151 /* Half the memory access clock */
152 MDCNFG |= MDCNFG_CDB2;
153
154 /* The order of these statements IS important, keep 8
155 * pulses!!
156 */
157 MDCAS2 = settings->mdcas2;
158 MDCAS1 = settings->mdcas1;
159 MDCAS0 = settings->mdcas0;
160 MDCNFG = settings->mdcnfg;
161 } else {
162 /* We're going SLOWER: first decrease the core
163 * frequency and then tighten the memory settings.
164 */
165
166 /* Half the memory access clock */
167 MDCNFG |= MDCNFG_CDB2;
168
169 /* The order of these statements IS important, keep 8
170 * pulses!!
171 */
172 MDCAS0 = settings->mdcas0;
173 MDCAS1 = settings->mdcas1;
174 MDCAS2 = settings->mdcas2;
175 MDCNFG = settings->mdcnfg;
176 }
177}
178
179static int sa1100_target(struct cpufreq_policy *policy,
180 unsigned int target_freq,
181 unsigned int relation)
182{
183 unsigned int cur = sa11x0_getspeed(0);
184 unsigned int new_ppcr;
185
186 struct cpufreq_freqs freqs;
187 switch(relation){
188 case CPUFREQ_RELATION_L:
189 new_ppcr = sa11x0_freq_to_ppcr(target_freq);
190 if (sa11x0_ppcr_to_freq(new_ppcr) > policy->max)
191 new_ppcr--;
192 break;
193 case CPUFREQ_RELATION_H:
194 new_ppcr = sa11x0_freq_to_ppcr(target_freq);
195 if ((sa11x0_ppcr_to_freq(new_ppcr) > target_freq) &&
196 (sa11x0_ppcr_to_freq(new_ppcr - 1) >= policy->min))
197 new_ppcr--;
198 break;
199 }
200
201 freqs.old = cur;
202 freqs.new = sa11x0_ppcr_to_freq(new_ppcr);
203 freqs.cpu = 0;
204
205 cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
206
207 if (freqs.new > cur)
208 sa1100_update_dram_timings(cur, freqs.new);
209
210 PPCR = new_ppcr;
211
212 if (freqs.new < cur)
213 sa1100_update_dram_timings(cur, freqs.new);
214
215 cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
216
217 return 0;
218}
219
220static int __init sa1100_cpu_init(struct cpufreq_policy *policy)
221{
222 if (policy->cpu != 0)
223 return -EINVAL;
224 policy->cur = policy->min = policy->max = sa11x0_getspeed(0);
225 policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
226 policy->cpuinfo.min_freq = 59000;
227 policy->cpuinfo.max_freq = 287000;
228 policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
229 return 0;
230}
231
232static struct cpufreq_driver sa1100_driver = {
233 .flags = CPUFREQ_STICKY,
234 .verify = sa11x0_verify_speed,
235 .target = sa1100_target,
236 .get = sa11x0_getspeed,
237 .init = sa1100_cpu_init,
238 .name = "sa1100",
239};
240
241static int __init sa1100_dram_init(void)
242{
243 if ((processor_id & CPU_SA1100_MASK) == CPU_SA1100_ID)
244 return cpufreq_register_driver(&sa1100_driver);
245 else
246 return -ENODEV;
247}
248
249arch_initcall(sa1100_dram_init);
diff --git a/arch/arm/mach-sa1100/cpu-sa1110.c b/arch/arm/mach-sa1100/cpu-sa1110.c
new file mode 100644
index 000000000000..8d2a89a2ea01
--- /dev/null
+++ b/arch/arm/mach-sa1100/cpu-sa1110.c
@@ -0,0 +1,367 @@
1/*
2 * linux/arch/arm/mach-sa1100/cpu-sa1110.c
3 *
4 * Copyright (C) 2001 Russell King
5 *
6 * $Id: cpu-sa1110.c,v 1.9 2002/07/06 16:53:18 rmk Exp $
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 * Note: there are two erratas that apply to the SA1110 here:
13 * 7 - SDRAM auto-power-up failure (rev A0)
14 * 13 - Corruption of internal register reads/writes following
15 * SDRAM reads (rev A0, B0, B1)
16 *
17 * We ignore rev. A0 and B0 devices; I don't think they're worth supporting.
18 */
19#include <linux/types.h>
20#include <linux/kernel.h>
21#include <linux/sched.h>
22#include <linux/cpufreq.h>
23#include <linux/delay.h>
24#include <linux/init.h>
25
26#include <asm/hardware.h>
27#include <asm/mach-types.h>
28#include <asm/io.h>
29#include <asm/system.h>
30
31#include "generic.h"
32
33#undef DEBUG
34
35static struct cpufreq_driver sa1110_driver;
36
37struct sdram_params {
38 u_char rows; /* bits */
39 u_char cas_latency; /* cycles */
40 u_char tck; /* clock cycle time (ns) */
41 u_char trcd; /* activate to r/w (ns) */
42 u_char trp; /* precharge to activate (ns) */
43 u_char twr; /* write recovery time (ns) */
44 u_short refresh; /* refresh time for array (us) */
45};
46
47struct sdram_info {
48 u_int mdcnfg;
49 u_int mdrefr;
50 u_int mdcas[3];
51};
52
53static struct sdram_params tc59sm716_cl2_params __initdata = {
54 .rows = 12,
55 .tck = 10,
56 .trcd = 20,
57 .trp = 20,
58 .twr = 10,
59 .refresh = 64000,
60 .cas_latency = 2,
61};
62
63static struct sdram_params tc59sm716_cl3_params __initdata = {
64 .rows = 12,
65 .tck = 8,
66 .trcd = 20,
67 .trp = 20,
68 .twr = 8,
69 .refresh = 64000,
70 .cas_latency = 3,
71};
72
73static struct sdram_params samsung_k4s641632d_tc75 __initdata = {
74 .rows = 14,
75 .tck = 9,
76 .trcd = 27,
77 .trp = 20,
78 .twr = 9,
79 .refresh = 64000,
80 .cas_latency = 3,
81};
82
83static struct sdram_params samsung_km416s4030ct __initdata = {
84 .rows = 13,
85 .tck = 8,
86 .trcd = 24, /* 3 CLKs */
87 .trp = 24, /* 3 CLKs */
88 .twr = 16, /* Trdl: 2 CLKs */
89 .refresh = 64000,
90 .cas_latency = 3,
91};
92
93static struct sdram_params wbond_w982516ah75l_cl3_params __initdata = {
94 .rows = 16,
95 .tck = 8,
96 .trcd = 20,
97 .trp = 20,
98 .twr = 8,
99 .refresh = 64000,
100 .cas_latency = 3,
101};
102
103static struct sdram_params sdram_params;
104
105/*
106 * Given a period in ns and frequency in khz, calculate the number of
107 * cycles of frequency in period. Note that we round up to the next
108 * cycle, even if we are only slightly over.
109 */
110static inline u_int ns_to_cycles(u_int ns, u_int khz)
111{
112 return (ns * khz + 999999) / 1000000;
113}
114
115/*
116 * Create the MDCAS register bit pattern.
117 */
118static inline void set_mdcas(u_int *mdcas, int delayed, u_int rcd)
119{
120 u_int shift;
121
122 rcd = 2 * rcd - 1;
123 shift = delayed + 1 + rcd;
124
125 mdcas[0] = (1 << rcd) - 1;
126 mdcas[0] |= 0x55555555 << shift;
127 mdcas[1] = mdcas[2] = 0x55555555 << (shift & 1);
128}
129
130static void
131sdram_calculate_timing(struct sdram_info *sd, u_int cpu_khz,
132 struct sdram_params *sdram)
133{
134 u_int mem_khz, sd_khz, trp, twr;
135
136 mem_khz = cpu_khz / 2;
137 sd_khz = mem_khz;
138
139 /*
140 * If SDCLK would invalidate the SDRAM timings,
141 * run SDCLK at half speed.
142 *
143 * CPU steppings prior to B2 must either run the memory at
144 * half speed or use delayed read latching (errata 13).
145 */
146 if ((ns_to_cycles(sdram->tck, sd_khz) > 1) ||
147 (CPU_REVISION < CPU_SA1110_B2 && sd_khz < 62000))
148 sd_khz /= 2;
149
150 sd->mdcnfg = MDCNFG & 0x007f007f;
151
152 twr = ns_to_cycles(sdram->twr, mem_khz);
153
154 /* trp should always be >1 */
155 trp = ns_to_cycles(sdram->trp, mem_khz) - 1;
156 if (trp < 1)
157 trp = 1;
158
159 sd->mdcnfg |= trp << 8;
160 sd->mdcnfg |= trp << 24;
161 sd->mdcnfg |= sdram->cas_latency << 12;
162 sd->mdcnfg |= sdram->cas_latency << 28;
163 sd->mdcnfg |= twr << 14;
164 sd->mdcnfg |= twr << 30;
165
166 sd->mdrefr = MDREFR & 0xffbffff0;
167 sd->mdrefr |= 7;
168
169 if (sd_khz != mem_khz)
170 sd->mdrefr |= MDREFR_K1DB2;
171
172 /* initial number of '1's in MDCAS + 1 */
173 set_mdcas(sd->mdcas, sd_khz >= 62000, ns_to_cycles(sdram->trcd, mem_khz));
174
175#ifdef DEBUG
176 printk("MDCNFG: %08x MDREFR: %08x MDCAS0: %08x MDCAS1: %08x MDCAS2: %08x\n",
177 sd->mdcnfg, sd->mdrefr, sd->mdcas[0], sd->mdcas[1], sd->mdcas[2]);
178#endif
179}
180
181/*
182 * Set the SDRAM refresh rate.
183 */
184static inline void sdram_set_refresh(u_int dri)
185{
186 MDREFR = (MDREFR & 0xffff000f) | (dri << 4);
187 (void) MDREFR;
188}
189
190/*
191 * Update the refresh period. We do this such that we always refresh
192 * the SDRAMs within their permissible period. The refresh period is
193 * always a multiple of the memory clock (fixed at cpu_clock / 2).
194 *
195 * FIXME: we don't currently take account of burst accesses here,
196 * but neither do Intels DM nor Angel.
197 */
198static void
199sdram_update_refresh(u_int cpu_khz, struct sdram_params *sdram)
200{
201 u_int ns_row = (sdram->refresh * 1000) >> sdram->rows;
202 u_int dri = ns_to_cycles(ns_row, cpu_khz / 2) / 32;
203
204#ifdef DEBUG
205 mdelay(250);
206 printk("new dri value = %d\n", dri);
207#endif
208
209 sdram_set_refresh(dri);
210}
211
212/*
213 * Ok, set the CPU frequency.
214 */
215static int sa1110_target(struct cpufreq_policy *policy,
216 unsigned int target_freq,
217 unsigned int relation)
218{
219 struct sdram_params *sdram = &sdram_params;
220 struct cpufreq_freqs freqs;
221 struct sdram_info sd;
222 unsigned long flags;
223 unsigned int ppcr, unused;
224
225 switch(relation){
226 case CPUFREQ_RELATION_L:
227 ppcr = sa11x0_freq_to_ppcr(target_freq);
228 if (sa11x0_ppcr_to_freq(ppcr) > policy->max)
229 ppcr--;
230 break;
231 case CPUFREQ_RELATION_H:
232 ppcr = sa11x0_freq_to_ppcr(target_freq);
233 if (ppcr && (sa11x0_ppcr_to_freq(ppcr) > target_freq) &&
234 (sa11x0_ppcr_to_freq(ppcr-1) >= policy->min))
235 ppcr--;
236 break;
237 default:
238 return -EINVAL;
239 }
240
241 freqs.old = sa11x0_getspeed(0);
242 freqs.new = sa11x0_ppcr_to_freq(ppcr);
243 freqs.cpu = 0;
244
245 sdram_calculate_timing(&sd, freqs.new, sdram);
246
247#if 0
248 /*
249 * These values are wrong according to the SA1110 documentation
250 * and errata, but they seem to work. Need to get a storage
251 * scope on to the SDRAM signals to work out why.
252 */
253 if (policy->max < 147500) {
254 sd.mdrefr |= MDREFR_K1DB2;
255 sd.mdcas[0] = 0xaaaaaa7f;
256 } else {
257 sd.mdrefr &= ~MDREFR_K1DB2;
258 sd.mdcas[0] = 0xaaaaaa9f;
259 }
260 sd.mdcas[1] = 0xaaaaaaaa;
261 sd.mdcas[2] = 0xaaaaaaaa;
262#endif
263
264 cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
265
266 /*
267 * The clock could be going away for some time. Set the SDRAMs
268 * to refresh rapidly (every 64 memory clock cycles). To get
269 * through the whole array, we need to wait 262144 mclk cycles.
270 * We wait 20ms to be safe.
271 */
272 sdram_set_refresh(2);
273 if (!irqs_disabled()) {
274 set_current_state(TASK_UNINTERRUPTIBLE);
275 schedule_timeout(20 * HZ / 1000);
276 } else {
277 mdelay(20);
278 }
279
280 /*
281 * Reprogram the DRAM timings with interrupts disabled, and
282 * ensure that we are doing this within a complete cache line.
283 * This means that we won't access SDRAM for the duration of
284 * the programming.
285 */
286 local_irq_save(flags);
287 asm("mcr p15, 0, %0, c7, c10, 4" : : "r" (0));
288 udelay(10);
289 __asm__ __volatile__(" \n\
290 b 2f \n\
291 .align 5 \n\
2921: str %3, [%1, #0] @ MDCNFG \n\
293 str %4, [%1, #28] @ MDREFR \n\
294 str %5, [%1, #4] @ MDCAS0 \n\
295 str %6, [%1, #8] @ MDCAS1 \n\
296 str %7, [%1, #12] @ MDCAS2 \n\
297 str %8, [%2, #0] @ PPCR \n\
298 ldr %0, [%1, #0] \n\
299 b 3f \n\
3002: b 1b \n\
3013: nop \n\
302 nop"
303 : "=&r" (unused)
304 : "r" (&MDCNFG), "r" (&PPCR), "0" (sd.mdcnfg),
305 "r" (sd.mdrefr), "r" (sd.mdcas[0]),
306 "r" (sd.mdcas[1]), "r" (sd.mdcas[2]), "r" (ppcr));
307 local_irq_restore(flags);
308
309 /*
310 * Now, return the SDRAM refresh back to normal.
311 */
312 sdram_update_refresh(freqs.new, sdram);
313
314 cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
315
316 return 0;
317}
318
319static int __init sa1110_cpu_init(struct cpufreq_policy *policy)
320{
321 if (policy->cpu != 0)
322 return -EINVAL;
323 policy->cur = policy->min = policy->max = sa11x0_getspeed(0);
324 policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
325 policy->cpuinfo.min_freq = 59000;
326 policy->cpuinfo.max_freq = 287000;
327 policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
328 return 0;
329}
330
331static struct cpufreq_driver sa1110_driver = {
332 .flags = CPUFREQ_STICKY,
333 .verify = sa11x0_verify_speed,
334 .target = sa1110_target,
335 .get = sa11x0_getspeed,
336 .init = sa1110_cpu_init,
337 .name = "sa1110",
338};
339
340static int __init sa1110_clk_init(void)
341{
342 struct sdram_params *sdram = NULL;
343
344 if (machine_is_assabet())
345 sdram = &tc59sm716_cl3_params;
346
347 if (machine_is_pt_system3())
348 sdram = &samsung_k4s641632d_tc75;
349
350 if (machine_is_h3100())
351 sdram = &samsung_km416s4030ct;
352
353 if (sdram) {
354 printk(KERN_DEBUG "SDRAM: tck: %d trcd: %d trp: %d"
355 " twr: %d refresh: %d cas_latency: %d\n",
356 sdram->tck, sdram->trcd, sdram->trp,
357 sdram->twr, sdram->refresh, sdram->cas_latency);
358
359 memcpy(&sdram_params, sdram, sizeof(sdram_params));
360
361 return cpufreq_register_driver(&sa1110_driver);
362 }
363
364 return 0;
365}
366
367arch_initcall(sa1110_clk_init);
diff --git a/arch/arm/mach-sa1100/dma.c b/arch/arm/mach-sa1100/dma.c
new file mode 100644
index 000000000000..be0e4427bec7
--- /dev/null
+++ b/arch/arm/mach-sa1100/dma.c
@@ -0,0 +1,348 @@
1/*
2 * arch/arm/kernel/dma-sa1100.c
3 *
4 * Support functions for the SA11x0 internal DMA channels.
5 *
6 * Copyright (C) 2000, 2001 by Nicolas Pitre
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
13#include <linux/module.h>
14#include <linux/interrupt.h>
15#include <linux/init.h>
16#include <linux/spinlock.h>
17#include <linux/errno.h>
18
19#include <asm/system.h>
20#include <asm/irq.h>
21#include <asm/hardware.h>
22#include <asm/dma.h>
23
24
25#undef DEBUG
26#ifdef DEBUG
27#define DPRINTK( s, arg... ) printk( "dma<%p>: " s, regs , ##arg )
28#else
29#define DPRINTK( x... )
30#endif
31
32
33typedef struct {
34 const char *device_id; /* device name */
35 u_long device; /* this channel device, 0 if unused*/
36 dma_callback_t callback; /* to call when DMA completes */
37 void *data; /* ... with private data ptr */
38} sa1100_dma_t;
39
40static sa1100_dma_t dma_chan[SA1100_DMA_CHANNELS];
41
42static spinlock_t dma_list_lock;
43
44
45static irqreturn_t dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
46{
47 dma_regs_t *dma_regs = dev_id;
48 sa1100_dma_t *dma = dma_chan + (((u_int)dma_regs >> 5) & 7);
49 int status = dma_regs->RdDCSR;
50
51 if (status & (DCSR_ERROR)) {
52 printk(KERN_CRIT "DMA on \"%s\" caused an error\n", dma->device_id);
53 dma_regs->ClrDCSR = DCSR_ERROR;
54 }
55
56 dma_regs->ClrDCSR = status & (DCSR_DONEA | DCSR_DONEB);
57 if (dma->callback) {
58 if (status & DCSR_DONEA)
59 dma->callback(dma->data);
60 if (status & DCSR_DONEB)
61 dma->callback(dma->data);
62 }
63 return IRQ_HANDLED;
64}
65
66
67/**
68 * sa1100_request_dma - allocate one of the SA11x0's DMA chanels
69 * @device: The SA11x0 peripheral targeted by this request
70 * @device_id: An ascii name for the claiming device
71 * @callback: Function to be called when the DMA completes
72 * @data: A cookie passed back to the callback function
73 * @dma_regs: Pointer to the location of the allocated channel's identifier
74 *
75 * This function will search for a free DMA channel and returns the
76 * address of the hardware registers for that channel as the channel
77 * identifier. This identifier is written to the location pointed by
78 * @dma_regs. The list of possible values for @device are listed into
79 * linux/include/asm-arm/arch-sa1100/dma.h as a dma_device_t enum.
80 *
81 * Note that reading from a port and writing to the same port are
82 * actually considered as two different streams requiring separate
83 * DMA registrations.
84 *
85 * The @callback function is called from interrupt context when one
86 * of the two possible DMA buffers in flight has terminated. That
87 * function has to be small and efficient while posponing more complex
88 * processing to a lower priority execution context.
89 *
90 * If no channels are available, or if the desired @device is already in
91 * use by another DMA channel, then an error code is returned. This
92 * function must be called before any other DMA calls.
93 **/
94
95int sa1100_request_dma (dma_device_t device, const char *device_id,
96 dma_callback_t callback, void *data,
97 dma_regs_t **dma_regs)
98{
99 sa1100_dma_t *dma = NULL;
100 dma_regs_t *regs;
101 int i, err;
102
103 *dma_regs = NULL;
104
105 err = 0;
106 spin_lock(&dma_list_lock);
107 for (i = 0; i < SA1100_DMA_CHANNELS; i++) {
108 if (dma_chan[i].device == device) {
109 err = -EBUSY;
110 break;
111 } else if (!dma_chan[i].device && !dma) {
112 dma = &dma_chan[i];
113 }
114 }
115 if (!err) {
116 if (dma)
117 dma->device = device;
118 else
119 err = -ENOSR;
120 }
121 spin_unlock(&dma_list_lock);
122 if (err)
123 return err;
124
125 i = dma - dma_chan;
126 regs = (dma_regs_t *)&DDAR(i);
127 err = request_irq(IRQ_DMA0 + i, dma_irq_handler, SA_INTERRUPT,
128 device_id, regs);
129 if (err) {
130 printk(KERN_ERR
131 "%s: unable to request IRQ %d for %s\n",
132 __FUNCTION__, IRQ_DMA0 + i, device_id);
133 dma->device = 0;
134 return err;
135 }
136
137 *dma_regs = regs;
138 dma->device_id = device_id;
139 dma->callback = callback;
140 dma->data = data;
141
142 regs->ClrDCSR =
143 (DCSR_DONEA | DCSR_DONEB | DCSR_STRTA | DCSR_STRTB |
144 DCSR_IE | DCSR_ERROR | DCSR_RUN);
145 regs->DDAR = device;
146
147 return 0;
148}
149
150
151/**
152 * sa1100_free_dma - free a SA11x0 DMA channel
153 * @regs: identifier for the channel to free
154 *
155 * This clears all activities on a given DMA channel and releases it
156 * for future requests. The @regs identifier is provided by a
157 * successful call to sa1100_request_dma().
158 **/
159
160void sa1100_free_dma(dma_regs_t *regs)
161{
162 int i;
163
164 for (i = 0; i < SA1100_DMA_CHANNELS; i++)
165 if (regs == (dma_regs_t *)&DDAR(i))
166 break;
167 if (i >= SA1100_DMA_CHANNELS) {
168 printk(KERN_ERR "%s: bad DMA identifier\n", __FUNCTION__);
169 return;
170 }
171
172 if (!dma_chan[i].device) {
173 printk(KERN_ERR "%s: Trying to free free DMA\n", __FUNCTION__);
174 return;
175 }
176
177 regs->ClrDCSR =
178 (DCSR_DONEA | DCSR_DONEB | DCSR_STRTA | DCSR_STRTB |
179 DCSR_IE | DCSR_ERROR | DCSR_RUN);
180 free_irq(IRQ_DMA0 + i, regs);
181 dma_chan[i].device = 0;
182}
183
184
185/**
186 * sa1100_start_dma - submit a data buffer for DMA
187 * @regs: identifier for the channel to use
188 * @dma_ptr: buffer physical (or bus) start address
189 * @size: buffer size
190 *
191 * This function hands the given data buffer to the hardware for DMA
192 * access. If another buffer is already in flight then this buffer
193 * will be queued so the DMA engine will switch to it automatically
194 * when the previous one is done. The DMA engine is actually toggling
195 * between two buffers so at most 2 successful calls can be made before
196 * one of them terminates and the callback function is called.
197 *
198 * The @regs identifier is provided by a successful call to
199 * sa1100_request_dma().
200 *
201 * The @size must not be larger than %MAX_DMA_SIZE. If a given buffer
202 * is larger than that then it's the caller's responsibility to split
203 * it into smaller chunks and submit them separately. If this is the
204 * case then a @size of %CUT_DMA_SIZE is recommended to avoid ending
205 * up with too small chunks. The callback function can be used to chain
206 * submissions of buffer chunks.
207 *
208 * Error return values:
209 * %-EOVERFLOW: Given buffer size is too big.
210 * %-EBUSY: Both DMA buffers are already in use.
211 * %-EAGAIN: Both buffers were busy but one of them just completed
212 * but the interrupt handler has to execute first.
213 *
214 * This function returs 0 on success.
215 **/
216
217int sa1100_start_dma(dma_regs_t *regs, dma_addr_t dma_ptr, u_int size)
218{
219 unsigned long flags;
220 u_long status;
221 int ret;
222
223 if (dma_ptr & 3)
224 printk(KERN_WARNING "DMA: unaligned start address (0x%08lx)\n",
225 (unsigned long)dma_ptr);
226
227 if (size > MAX_DMA_SIZE)
228 return -EOVERFLOW;
229
230 local_irq_save(flags);
231 status = regs->RdDCSR;
232
233 /* If both DMA buffers are started, there's nothing else we can do. */
234 if ((status & (DCSR_STRTA | DCSR_STRTB)) == (DCSR_STRTA | DCSR_STRTB)) {
235 DPRINTK("start: st %#x busy\n", status);
236 ret = -EBUSY;
237 goto out;
238 }
239
240 if (((status & DCSR_BIU) && (status & DCSR_STRTB)) ||
241 (!(status & DCSR_BIU) && !(status & DCSR_STRTA))) {
242 if (status & DCSR_DONEA) {
243 /* give a chance for the interrupt to be processed */
244 ret = -EAGAIN;
245 goto out;
246 }
247 regs->DBSA = dma_ptr;
248 regs->DBTA = size;
249 regs->SetDCSR = DCSR_STRTA | DCSR_IE | DCSR_RUN;
250 DPRINTK("start a=%#x s=%d on A\n", dma_ptr, size);
251 } else {
252 if (status & DCSR_DONEB) {
253 /* give a chance for the interrupt to be processed */
254 ret = -EAGAIN;
255 goto out;
256 }
257 regs->DBSB = dma_ptr;
258 regs->DBTB = size;
259 regs->SetDCSR = DCSR_STRTB | DCSR_IE | DCSR_RUN;
260 DPRINTK("start a=%#x s=%d on B\n", dma_ptr, size);
261 }
262 ret = 0;
263
264out:
265 local_irq_restore(flags);
266 return ret;
267}
268
269
270/**
271 * sa1100_get_dma_pos - return current DMA position
272 * @regs: identifier for the channel to use
273 *
274 * This function returns the current physical (or bus) address for the
275 * given DMA channel. If the channel is running i.e. not in a stopped
276 * state then the caller must disable interrupts prior calling this
277 * function and process the returned value before re-enabling them to
278 * prevent races with the completion interrupt handler and the callback
279 * function. The validation of the returned value is the caller's
280 * responsibility as well -- the hardware seems to return out of range
281 * values when the DMA engine completes a buffer.
282 *
283 * The @regs identifier is provided by a successful call to
284 * sa1100_request_dma().
285 **/
286
287dma_addr_t sa1100_get_dma_pos(dma_regs_t *regs)
288{
289 int status;
290
291 /*
292 * We must determine whether buffer A or B is active.
293 * Two possibilities: either we are in the middle of
294 * a buffer, or the DMA controller just switched to the
295 * next toggle but the interrupt hasn't been serviced yet.
296 * The former case is straight forward. In the later case,
297 * we'll do like if DMA is just at the end of the previous
298 * toggle since all registers haven't been reset yet.
299 * This goes around the edge case and since we're always
300 * a little behind anyways it shouldn't make a big difference.
301 * If DMA has been stopped prior calling this then the
302 * position is exact.
303 */
304 status = regs->RdDCSR;
305 if ((!(status & DCSR_BIU) && (status & DCSR_STRTA)) ||
306 ( (status & DCSR_BIU) && !(status & DCSR_STRTB)))
307 return regs->DBSA;
308 else
309 return regs->DBSB;
310}
311
312
313/**
314 * sa1100_reset_dma - reset a DMA channel
315 * @regs: identifier for the channel to use
316 *
317 * This function resets and reconfigure the given DMA channel. This is
318 * particularly useful after a sleep/wakeup event.
319 *
320 * The @regs identifier is provided by a successful call to
321 * sa1100_request_dma().
322 **/
323
324void sa1100_reset_dma(dma_regs_t *regs)
325{
326 int i;
327
328 for (i = 0; i < SA1100_DMA_CHANNELS; i++)
329 if (regs == (dma_regs_t *)&DDAR(i))
330 break;
331 if (i >= SA1100_DMA_CHANNELS) {
332 printk(KERN_ERR "%s: bad DMA identifier\n", __FUNCTION__);
333 return;
334 }
335
336 regs->ClrDCSR =
337 (DCSR_DONEA | DCSR_DONEB | DCSR_STRTA | DCSR_STRTB |
338 DCSR_IE | DCSR_ERROR | DCSR_RUN);
339 regs->DDAR = dma_chan[i].device;
340}
341
342
343EXPORT_SYMBOL(sa1100_request_dma);
344EXPORT_SYMBOL(sa1100_free_dma);
345EXPORT_SYMBOL(sa1100_start_dma);
346EXPORT_SYMBOL(sa1100_get_dma_pos);
347EXPORT_SYMBOL(sa1100_reset_dma);
348
diff --git a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c
new file mode 100644
index 000000000000..95ae217be1bc
--- /dev/null
+++ b/arch/arm/mach-sa1100/generic.c
@@ -0,0 +1,419 @@
1/*
2 * linux/arch/arm/mach-sa1100/generic.c
3 *
4 * Author: Nicolas Pitre
5 *
6 * Code common to all SA11x0 machines.
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#include <linux/config.h>
13#include <linux/module.h>
14#include <linux/kernel.h>
15#include <linux/init.h>
16#include <linux/delay.h>
17#include <linux/pm.h>
18#include <linux/cpufreq.h>
19#include <linux/ioport.h>
20
21#include <asm/div64.h>
22#include <asm/hardware.h>
23#include <asm/system.h>
24#include <asm/pgtable.h>
25#include <asm/mach/map.h>
26#include <asm/irq.h>
27
28#include "generic.h"
29
30#define NR_FREQS 16
31
32/*
33 * This table is setup for a 3.6864MHz Crystal.
34 */
35static const unsigned short cclk_frequency_100khz[NR_FREQS] = {
36 590, /* 59.0 MHz */
37 737, /* 73.7 MHz */
38 885, /* 88.5 MHz */
39 1032, /* 103.2 MHz */
40 1180, /* 118.0 MHz */
41 1327, /* 132.7 MHz */
42 1475, /* 147.5 MHz */
43 1622, /* 162.2 MHz */
44 1769, /* 176.9 MHz */
45 1917, /* 191.7 MHz */
46 2064, /* 206.4 MHz */
47 2212, /* 221.2 MHz */
48 2359, /* 235.9 MHz */
49 2507, /* 250.7 MHz */
50 2654, /* 265.4 MHz */
51 2802 /* 280.2 MHz */
52};
53
54#if defined(CONFIG_CPU_FREQ_SA1100) || defined(CONFIG_CPU_FREQ_SA1110)
55/* rounds up(!) */
56unsigned int sa11x0_freq_to_ppcr(unsigned int khz)
57{
58 int i;
59
60 khz /= 100;
61
62 for (i = 0; i < NR_FREQS; i++)
63 if (cclk_frequency_100khz[i] >= khz)
64 break;
65
66 return i;
67}
68
69unsigned int sa11x0_ppcr_to_freq(unsigned int idx)
70{
71 unsigned int freq = 0;
72 if (idx < NR_FREQS)
73 freq = cclk_frequency_100khz[idx] * 100;
74 return freq;
75}
76
77
78/* make sure that only the "userspace" governor is run -- anything else wouldn't make sense on
79 * this platform, anyway.
80 */
81int sa11x0_verify_speed(struct cpufreq_policy *policy)
82{
83 unsigned int tmp;
84 if (policy->cpu)
85 return -EINVAL;
86
87 cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, policy->cpuinfo.max_freq);
88
89 /* make sure that at least one frequency is within the policy */
90 tmp = cclk_frequency_100khz[sa11x0_freq_to_ppcr(policy->min)] * 100;
91 if (tmp > policy->max)
92 policy->max = tmp;
93
94 cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, policy->cpuinfo.max_freq);
95
96 return 0;
97}
98
99unsigned int sa11x0_getspeed(unsigned int cpu)
100{
101 if (cpu)
102 return 0;
103 return cclk_frequency_100khz[PPCR & 0xf] * 100;
104}
105
106#else
107/*
108 * We still need to provide this so building without cpufreq works.
109 */
110unsigned int cpufreq_get(unsigned int cpu)
111{
112 return cclk_frequency_100khz[PPCR & 0xf] * 100;
113}
114EXPORT_SYMBOL(cpufreq_get);
115#endif
116
117/*
118 * This is the SA11x0 sched_clock implementation. This has
119 * a resolution of 271ns, and a maximum value of 1165s.
120 * ( * 1E9 / 3686400 => * 78125 / 288)
121 */
122unsigned long long sched_clock(void)
123{
124 unsigned long long v;
125
126 v = (unsigned long long)OSCR * 78125;
127 do_div(v, 288);
128
129 return v;
130}
131
132/*
133 * Default power-off for SA1100
134 */
135static void sa1100_power_off(void)
136{
137 mdelay(100);
138 local_irq_disable();
139 /* disable internal oscillator, float CS lines */
140 PCFR = (PCFR_OPDE | PCFR_FP | PCFR_FS);
141 /* enable wake-up on GPIO0 (Assabet...) */
142 PWER = GFER = GRER = 1;
143 /*
144 * set scratchpad to zero, just in case it is used as a
145 * restart address by the bootloader.
146 */
147 PSPR = 0;
148 /* enter sleep mode */
149 PMCR = PMCR_SF;
150}
151
152static struct resource sa11x0udc_resources[] = {
153 [0] = {
154 .start = 0x80000000,
155 .end = 0x8000ffff,
156 .flags = IORESOURCE_MEM,
157 },
158};
159
160static u64 sa11x0udc_dma_mask = 0xffffffffUL;
161
162static struct platform_device sa11x0udc_device = {
163 .name = "sa11x0-udc",
164 .id = -1,
165 .dev = {
166 .dma_mask = &sa11x0udc_dma_mask,
167 .coherent_dma_mask = 0xffffffff,
168 },
169 .num_resources = ARRAY_SIZE(sa11x0udc_resources),
170 .resource = sa11x0udc_resources,
171};
172
173static struct resource sa11x0uart1_resources[] = {
174 [0] = {
175 .start = 0x80010000,
176 .end = 0x8001ffff,
177 .flags = IORESOURCE_MEM,
178 },
179};
180
181static struct platform_device sa11x0uart1_device = {
182 .name = "sa11x0-uart",
183 .id = 1,
184 .num_resources = ARRAY_SIZE(sa11x0uart1_resources),
185 .resource = sa11x0uart1_resources,
186};
187
188static struct resource sa11x0uart3_resources[] = {
189 [0] = {
190 .start = 0x80050000,
191 .end = 0x8005ffff,
192 .flags = IORESOURCE_MEM,
193 },
194};
195
196static struct platform_device sa11x0uart3_device = {
197 .name = "sa11x0-uart",
198 .id = 3,
199 .num_resources = ARRAY_SIZE(sa11x0uart3_resources),
200 .resource = sa11x0uart3_resources,
201};
202
203static struct resource sa11x0mcp_resources[] = {
204 [0] = {
205 .start = 0x80060000,
206 .end = 0x8006ffff,
207 .flags = IORESOURCE_MEM,
208 },
209};
210
211static u64 sa11x0mcp_dma_mask = 0xffffffffUL;
212
213static struct platform_device sa11x0mcp_device = {
214 .name = "sa11x0-mcp",
215 .id = -1,
216 .dev = {
217 .dma_mask = &sa11x0mcp_dma_mask,
218 .coherent_dma_mask = 0xffffffff,
219 },
220 .num_resources = ARRAY_SIZE(sa11x0mcp_resources),
221 .resource = sa11x0mcp_resources,
222};
223
224static struct resource sa11x0ssp_resources[] = {
225 [0] = {
226 .start = 0x80070000,
227 .end = 0x8007ffff,
228 .flags = IORESOURCE_MEM,
229 },
230};
231
232static u64 sa11x0ssp_dma_mask = 0xffffffffUL;
233
234static struct platform_device sa11x0ssp_device = {
235 .name = "sa11x0-ssp",
236 .id = -1,
237 .dev = {
238 .dma_mask = &sa11x0ssp_dma_mask,
239 .coherent_dma_mask = 0xffffffff,
240 },
241 .num_resources = ARRAY_SIZE(sa11x0ssp_resources),
242 .resource = sa11x0ssp_resources,
243};
244
245static struct resource sa11x0fb_resources[] = {
246 [0] = {
247 .start = 0xb0100000,
248 .end = 0xb010ffff,
249 .flags = IORESOURCE_MEM,
250 },
251 [1] = {
252 .start = IRQ_LCD,
253 .end = IRQ_LCD,
254 .flags = IORESOURCE_IRQ,
255 },
256};
257
258static struct platform_device sa11x0fb_device = {
259 .name = "sa11x0-fb",
260 .id = -1,
261 .dev = {
262 .coherent_dma_mask = 0xffffffff,
263 },
264 .num_resources = ARRAY_SIZE(sa11x0fb_resources),
265 .resource = sa11x0fb_resources,
266};
267
268static struct platform_device sa11x0pcmcia_device = {
269 .name = "sa11x0-pcmcia",
270 .id = -1,
271};
272
273static struct platform_device sa11x0mtd_device = {
274 .name = "flash",
275 .id = -1,
276};
277
278void sa11x0_set_flash_data(struct flash_platform_data *flash,
279 struct resource *res, int nr)
280{
281 sa11x0mtd_device.dev.platform_data = flash;
282 sa11x0mtd_device.resource = res;
283 sa11x0mtd_device.num_resources = nr;
284}
285
286static struct resource sa11x0ir_resources[] = {
287 {
288 .start = __PREG(Ser2UTCR0),
289 .end = __PREG(Ser2UTCR0) + 0x24 - 1,
290 .flags = IORESOURCE_MEM,
291 }, {
292 .start = __PREG(Ser2HSCR0),
293 .end = __PREG(Ser2HSCR0) + 0x1c - 1,
294 .flags = IORESOURCE_MEM,
295 }, {
296 .start = __PREG(Ser2HSCR2),
297 .end = __PREG(Ser2HSCR2) + 0x04 - 1,
298 .flags = IORESOURCE_MEM,
299 }, {
300 .start = IRQ_Ser2ICP,
301 .end = IRQ_Ser2ICP,
302 .flags = IORESOURCE_IRQ,
303 }
304};
305
306static struct platform_device sa11x0ir_device = {
307 .name = "sa11x0-ir",
308 .id = -1,
309 .num_resources = ARRAY_SIZE(sa11x0ir_resources),
310 .resource = sa11x0ir_resources,
311};
312
313void sa11x0_set_irda_data(struct irda_platform_data *irda)
314{
315 sa11x0ir_device.dev.platform_data = irda;
316}
317
318static struct platform_device *sa11x0_devices[] __initdata = {
319 &sa11x0udc_device,
320 &sa11x0uart1_device,
321 &sa11x0uart3_device,
322 &sa11x0mcp_device,
323 &sa11x0ssp_device,
324 &sa11x0pcmcia_device,
325 &sa11x0fb_device,
326 &sa11x0mtd_device,
327};
328
329static int __init sa1100_init(void)
330{
331 pm_power_off = sa1100_power_off;
332
333 if (sa11x0ir_device.dev.platform_data)
334 platform_device_register(&sa11x0ir_device);
335
336 return platform_add_devices(sa11x0_devices, ARRAY_SIZE(sa11x0_devices));
337}
338
339arch_initcall(sa1100_init);
340
341void (*sa1100fb_backlight_power)(int on);
342void (*sa1100fb_lcd_power)(int on);
343
344EXPORT_SYMBOL(sa1100fb_backlight_power);
345EXPORT_SYMBOL(sa1100fb_lcd_power);
346
347
348/*
349 * Common I/O mapping:
350 *
351 * Typically, static virtual address mappings are as follow:
352 *
353 * 0xf0000000-0xf3ffffff: miscellaneous stuff (CPLDs, etc.)
354 * 0xf4000000-0xf4ffffff: SA-1111
355 * 0xf5000000-0xf5ffffff: reserved (used by cache flushing area)
356 * 0xf6000000-0xfffeffff: reserved (internal SA1100 IO defined above)
357 * 0xffff0000-0xffff0fff: SA1100 exception vectors
358 * 0xffff2000-0xffff2fff: Minicache copy_user_page area
359 *
360 * Below 0xe8000000 is reserved for vm allocation.
361 *
362 * The machine specific code must provide the extra mapping beside the
363 * default mapping provided here.
364 */
365
366static struct map_desc standard_io_desc[] __initdata = {
367 /* virtual physical length type */
368 { 0xf8000000, 0x80000000, 0x00100000, MT_DEVICE }, /* PCM */
369 { 0xfa000000, 0x90000000, 0x00100000, MT_DEVICE }, /* SCM */
370 { 0xfc000000, 0xa0000000, 0x00100000, MT_DEVICE }, /* MER */
371 { 0xfe000000, 0xb0000000, 0x00200000, MT_DEVICE } /* LCD + DMA */
372};
373
374void __init sa1100_map_io(void)
375{
376 iotable_init(standard_io_desc, ARRAY_SIZE(standard_io_desc));
377}
378
379/*
380 * Disable the memory bus request/grant signals on the SA1110 to
381 * ensure that we don't receive spurious memory requests. We set
382 * the MBGNT signal false to ensure the SA1111 doesn't own the
383 * SDRAM bus.
384 */
385void __init sa1110_mb_disable(void)
386{
387 unsigned long flags;
388
389 local_irq_save(flags);
390
391 PGSR &= ~GPIO_MBGNT;
392 GPCR = GPIO_MBGNT;
393 GPDR = (GPDR & ~GPIO_MBREQ) | GPIO_MBGNT;
394
395 GAFR &= ~(GPIO_MBGNT | GPIO_MBREQ);
396
397 local_irq_restore(flags);
398}
399
400/*
401 * If the system is going to use the SA-1111 DMA engines, set up
402 * the memory bus request/grant pins.
403 */
404void __init sa1110_mb_enable(void)
405{
406 unsigned long flags;
407
408 local_irq_save(flags);
409
410 PGSR &= ~GPIO_MBGNT;
411 GPCR = GPIO_MBGNT;
412 GPDR = (GPDR & ~GPIO_MBREQ) | GPIO_MBGNT;
413
414 GAFR |= (GPIO_MBGNT | GPIO_MBREQ);
415 TUCR |= TUCR_MR;
416
417 local_irq_restore(flags);
418}
419
diff --git a/arch/arm/mach-sa1100/generic.h b/arch/arm/mach-sa1100/generic.h
new file mode 100644
index 000000000000..bfe41da9923e
--- /dev/null
+++ b/arch/arm/mach-sa1100/generic.h
@@ -0,0 +1,38 @@
1/*
2 * linux/arch/arm/mach-sa1100/generic.h
3 *
4 * Author: Nicolas Pitre
5 */
6
7struct sys_timer;
8
9extern struct sys_timer sa1100_timer;
10extern void __init sa1100_map_io(void);
11extern void __init sa1100_init_irq(void);
12
13#define SET_BANK(__nr,__start,__size) \
14 mi->bank[__nr].start = (__start), \
15 mi->bank[__nr].size = (__size), \
16 mi->bank[__nr].node = (((unsigned)(__start) - PHYS_OFFSET) >> 27)
17
18extern void (*sa1100fb_backlight_power)(int on);
19extern void (*sa1100fb_lcd_power)(int on);
20
21extern void sa1110_mb_enable(void);
22extern void sa1110_mb_disable(void);
23
24struct cpufreq_policy;
25
26extern unsigned int sa11x0_freq_to_ppcr(unsigned int khz);
27extern int sa11x0_verify_speed(struct cpufreq_policy *policy);
28extern unsigned int sa11x0_getspeed(unsigned int cpu);
29extern unsigned int sa11x0_ppcr_to_freq(unsigned int idx);
30
31struct flash_platform_data;
32struct resource;
33
34extern void sa11x0_set_flash_data(struct flash_platform_data *flash,
35 struct resource *res, int nr);
36
37struct irda_platform_data;
38void sa11x0_set_irda_data(struct irda_platform_data *irda);
diff --git a/arch/arm/mach-sa1100/h3600.c b/arch/arm/mach-sa1100/h3600.c
new file mode 100644
index 000000000000..9788d3aefa73
--- /dev/null
+++ b/arch/arm/mach-sa1100/h3600.c
@@ -0,0 +1,892 @@
1/*
2 * Hardware definitions for Compaq iPAQ H3xxx Handheld Computers
3 *
4 * Copyright 2000,1 Compaq Computer Corporation.
5 *
6 * Use consistent with the GNU GPL is permitted,
7 * provided that this copyright notice is
8 * preserved in its entirety in all copies and derived works.
9 *
10 * COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
11 * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
12 * FITNESS FOR ANY PARTICULAR PURPOSE.
13 *
14 * Author: Jamey Hicks.
15 *
16 * History:
17 *
18 * 2001-10-?? Andrew Christian Added support for iPAQ H3800
19 * and abstracted EGPIO interface.
20 *
21 */
22#include <linux/config.h>
23#include <linux/module.h>
24#include <linux/init.h>
25#include <linux/kernel.h>
26#include <linux/tty.h>
27#include <linux/pm.h>
28#include <linux/device.h>
29#include <linux/mtd/mtd.h>
30#include <linux/mtd/partitions.h>
31#include <linux/serial_core.h>
32
33#include <asm/irq.h>
34#include <asm/hardware.h>
35#include <asm/mach-types.h>
36#include <asm/setup.h>
37
38#include <asm/mach/irq.h>
39#include <asm/mach/arch.h>
40#include <asm/mach/flash.h>
41#include <asm/mach/irda.h>
42#include <asm/mach/map.h>
43#include <asm/mach/serial_sa1100.h>
44
45#include <asm/arch/h3600.h>
46
47#if defined (CONFIG_SA1100_H3600) || defined (CONFIG_SA1100_H3100)
48#include <asm/arch/h3600_gpio.h>
49#endif
50
51#ifdef CONFIG_SA1100_H3800
52#include <asm/arch/h3600_asic.h>
53#endif
54
55#include "generic.h"
56
57struct ipaq_model_ops ipaq_model_ops;
58EXPORT_SYMBOL(ipaq_model_ops);
59
60static struct mtd_partition h3xxx_partitions[] = {
61 {
62 .name = "H3XXX boot firmware",
63 .size = 0x00040000,
64 .offset = 0,
65 .mask_flags = MTD_WRITEABLE, /* force read-only */
66 }, {
67#ifdef CONFIG_MTD_2PARTS_IPAQ
68 .name = "H3XXX root jffs2",
69 .size = MTDPART_SIZ_FULL,
70 .offset = 0x00040000,
71#else
72 .name = "H3XXX kernel",
73 .size = 0x00080000,
74 .offset = 0x00040000,
75 }, {
76 .name = "H3XXX params",
77 .size = 0x00040000,
78 .offset = 0x000C0000,
79 }, {
80#ifdef CONFIG_JFFS2_FS
81 .name = "H3XXX root jffs2",
82 .size = MTDPART_SIZ_FULL,
83 .offset = 0x00100000,
84#else
85 .name = "H3XXX initrd",
86 .size = 0x00100000,
87 .offset = 0x00100000,
88 }, {
89 .name = "H3XXX root cramfs",
90 .size = 0x00300000,
91 .offset = 0x00200000,
92 }, {
93 .name = "H3XXX usr cramfs",
94 .size = 0x00800000,
95 .offset = 0x00500000,
96 }, {
97 .name = "H3XXX usr local",
98 .size = MTDPART_SIZ_FULL,
99 .offset = 0x00d00000,
100#endif
101#endif
102 }
103};
104
105static void h3xxx_set_vpp(int vpp)
106{
107 assign_h3600_egpio(IPAQ_EGPIO_VPP_ON, vpp);
108}
109
110static struct flash_platform_data h3xxx_flash_data = {
111 .map_name = "cfi_probe",
112 .set_vpp = h3xxx_set_vpp,
113 .parts = h3xxx_partitions,
114 .nr_parts = ARRAY_SIZE(h3xxx_partitions),
115};
116
117static struct resource h3xxx_flash_resource = {
118 .start = SA1100_CS0_PHYS,
119 .end = SA1100_CS0_PHYS + SZ_32M - 1,
120 .flags = IORESOURCE_MEM,
121};
122
123/*
124 * This turns the IRDA power on or off on the Compaq H3600
125 */
126static int h3600_irda_set_power(struct device *dev, unsigned int state)
127{
128 assign_h3600_egpio( IPAQ_EGPIO_IR_ON, state );
129
130 return 0;
131}
132
133static void h3600_irda_set_speed(struct device *dev, int speed)
134{
135 if (speed < 4000000) {
136 clr_h3600_egpio(IPAQ_EGPIO_IR_FSEL);
137 } else {
138 set_h3600_egpio(IPAQ_EGPIO_IR_FSEL);
139 }
140}
141
142static struct irda_platform_data h3600_irda_data = {
143 .set_power = h3600_irda_set_power,
144 .set_speed = h3600_irda_set_speed,
145};
146
147static void h3xxx_mach_init(void)
148{
149 sa11x0_set_flash_data(&h3xxx_flash_data, &h3xxx_flash_resource, 1);
150 sa11x0_set_irda_data(&h3600_irda_data);
151}
152
153/*
154 * low-level UART features
155 */
156
157static void h3600_uart_set_mctrl(struct uart_port *port, u_int mctrl)
158{
159 if (port->mapbase == _Ser3UTCR0) {
160 if (mctrl & TIOCM_RTS)
161 GPCR = GPIO_H3600_COM_RTS;
162 else
163 GPSR = GPIO_H3600_COM_RTS;
164 }
165}
166
167static u_int h3600_uart_get_mctrl(struct uart_port *port)
168{
169 u_int ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR;
170
171 if (port->mapbase == _Ser3UTCR0) {
172 int gplr = GPLR;
173 /* DCD and CTS bits are inverted in GPLR by RS232 transceiver */
174 if (gplr & GPIO_H3600_COM_DCD)
175 ret &= ~TIOCM_CD;
176 if (gplr & GPIO_H3600_COM_CTS)
177 ret &= ~TIOCM_CTS;
178 }
179
180 return ret;
181}
182
183static void h3600_uart_pm(struct uart_port *port, u_int state, u_int oldstate)
184{
185 if (port->mapbase == _Ser2UTCR0) { /* TODO: REMOVE THIS */
186 assign_h3600_egpio(IPAQ_EGPIO_IR_ON, !state);
187 } else if (port->mapbase == _Ser3UTCR0) {
188 assign_h3600_egpio(IPAQ_EGPIO_RS232_ON, !state);
189 }
190}
191
192/*
193 * Enable/Disable wake up events for this serial port.
194 * Obviously, we only support this on the normal COM port.
195 */
196static int h3600_uart_set_wake(struct uart_port *port, u_int enable)
197{
198 int err = -EINVAL;
199
200 if (port->mapbase == _Ser3UTCR0) {
201 if (enable)
202 PWER |= PWER_GPIO23 | PWER_GPIO25; /* DCD and CTS */
203 else
204 PWER &= ~(PWER_GPIO23 | PWER_GPIO25); /* DCD and CTS */
205 err = 0;
206 }
207 return err;
208}
209
210static struct sa1100_port_fns h3600_port_fns __initdata = {
211 .set_mctrl = h3600_uart_set_mctrl,
212 .get_mctrl = h3600_uart_get_mctrl,
213 .pm = h3600_uart_pm,
214 .set_wake = h3600_uart_set_wake,
215};
216
217/*
218 * helper for sa1100fb
219 */
220static void h3xxx_lcd_power(int enable)
221{
222 assign_h3600_egpio(IPAQ_EGPIO_LCD_POWER, enable);
223}
224
225static struct map_desc h3600_io_desc[] __initdata = {
226 /* virtual physical length type */
227 { H3600_BANK_2_VIRT, SA1100_CS2_PHYS, 0x02800000, MT_DEVICE }, /* static memory bank 2 CS#2 */
228 { H3600_BANK_4_VIRT, SA1100_CS4_PHYS, 0x00800000, MT_DEVICE }, /* static memory bank 4 CS#4 */
229 { H3600_EGPIO_VIRT, H3600_EGPIO_PHYS, 0x01000000, MT_DEVICE }, /* EGPIO 0 CS#5 */
230};
231
232/*
233 * Common map_io initialization
234 */
235
236static void __init h3xxx_map_io(void)
237{
238 sa1100_map_io();
239 iotable_init(h3600_io_desc, ARRAY_SIZE(h3600_io_desc));
240
241 sa1100_register_uart_fns(&h3600_port_fns);
242 sa1100_register_uart(0, 3); /* Common serial port */
243// sa1100_register_uart(1, 1); /* Microcontroller on 3100/3600 */
244
245 /* Ensure those pins are outputs and driving low */
246 PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
247 PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
248
249 /* Configure suspend conditions */
250 PGSR = 0;
251 PWER = PWER_GPIO0 | PWER_RTC;
252 PCFR = PCFR_OPDE;
253 PSDR = 0;
254
255 sa1100fb_lcd_power = h3xxx_lcd_power;
256}
257
258static __inline__ void do_blank(int setp)
259{
260 if (ipaq_model_ops.blank_callback)
261 ipaq_model_ops.blank_callback(1-setp);
262}
263
264/************************* H3100 *************************/
265
266#ifdef CONFIG_SA1100_H3100
267
268#define H3100_EGPIO (*(volatile unsigned int *)H3600_EGPIO_VIRT)
269static unsigned int h3100_egpio = 0;
270
271static void h3100_control_egpio(enum ipaq_egpio_type x, int setp)
272{
273 unsigned int egpio = 0;
274 long gpio = 0;
275 unsigned long flags;
276
277 switch (x) {
278 case IPAQ_EGPIO_LCD_POWER:
279 egpio |= EGPIO_H3600_LCD_ON;
280 gpio |= GPIO_H3100_LCD_3V_ON;
281 do_blank(setp);
282 break;
283 case IPAQ_EGPIO_LCD_ENABLE:
284 break;
285 case IPAQ_EGPIO_CODEC_NRESET:
286 egpio |= EGPIO_H3600_CODEC_NRESET;
287 break;
288 case IPAQ_EGPIO_AUDIO_ON:
289 gpio |= GPIO_H3100_AUD_PWR_ON
290 | GPIO_H3100_AUD_ON;
291 break;
292 case IPAQ_EGPIO_QMUTE:
293 gpio |= GPIO_H3100_QMUTE;
294 break;
295 case IPAQ_EGPIO_OPT_NVRAM_ON:
296 egpio |= EGPIO_H3600_OPT_NVRAM_ON;
297 break;
298 case IPAQ_EGPIO_OPT_ON:
299 egpio |= EGPIO_H3600_OPT_ON;
300 break;
301 case IPAQ_EGPIO_CARD_RESET:
302 egpio |= EGPIO_H3600_CARD_RESET;
303 break;
304 case IPAQ_EGPIO_OPT_RESET:
305 egpio |= EGPIO_H3600_OPT_RESET;
306 break;
307 case IPAQ_EGPIO_IR_ON:
308 gpio |= GPIO_H3100_IR_ON;
309 break;
310 case IPAQ_EGPIO_IR_FSEL:
311 gpio |= GPIO_H3100_IR_FSEL;
312 break;
313 case IPAQ_EGPIO_RS232_ON:
314 egpio |= EGPIO_H3600_RS232_ON;
315 break;
316 case IPAQ_EGPIO_VPP_ON:
317 egpio |= EGPIO_H3600_VPP_ON;
318 break;
319 }
320
321 if (egpio || gpio) {
322 local_irq_save(flags);
323 if (setp) {
324 h3100_egpio |= egpio;
325 GPSR = gpio;
326 } else {
327 h3100_egpio &= ~egpio;
328 GPCR = gpio;
329 }
330 H3100_EGPIO = h3100_egpio;
331 local_irq_restore(flags);
332 }
333}
334
335static unsigned long h3100_read_egpio(void)
336{
337 return h3100_egpio;
338}
339
340static int h3100_pm_callback(int req)
341{
342 if (ipaq_model_ops.pm_callback_aux)
343 return ipaq_model_ops.pm_callback_aux(req);
344 return 0;
345}
346
347static struct ipaq_model_ops h3100_model_ops __initdata = {
348 .generic_name = "3100",
349 .control = h3100_control_egpio,
350 .read = h3100_read_egpio,
351 .pm_callback = h3100_pm_callback
352};
353
354#define H3100_DIRECT_EGPIO (GPIO_H3100_BT_ON \
355 | GPIO_H3100_GPIO3 \
356 | GPIO_H3100_QMUTE \
357 | GPIO_H3100_LCD_3V_ON \
358 | GPIO_H3100_AUD_ON \
359 | GPIO_H3100_AUD_PWR_ON \
360 | GPIO_H3100_IR_ON \
361 | GPIO_H3100_IR_FSEL)
362
363static void __init h3100_map_io(void)
364{
365 h3xxx_map_io();
366
367 /* Initialize h3100-specific values here */
368 GPCR = 0x0fffffff; /* All outputs are set low by default */
369 GPDR = GPIO_H3600_COM_RTS | GPIO_H3600_L3_CLOCK |
370 GPIO_H3600_L3_MODE | GPIO_H3600_L3_DATA |
371 GPIO_H3600_CLK_SET1 | GPIO_H3600_CLK_SET0 |
372 H3100_DIRECT_EGPIO;
373
374 /* Older bootldrs put GPIO2-9 in alternate mode on the
375 assumption that they are used for video */
376 GAFR &= ~H3100_DIRECT_EGPIO;
377
378 H3100_EGPIO = h3100_egpio;
379 ipaq_model_ops = h3100_model_ops;
380}
381
382MACHINE_START(H3100, "Compaq iPAQ H3100")
383 BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
384 BOOT_PARAMS(0xc0000100)
385 MAPIO(h3100_map_io)
386 INITIRQ(sa1100_init_irq)
387 .timer = &sa1100_timer,
388 .init_machine = h3xxx_mach_init,
389MACHINE_END
390
391#endif /* CONFIG_SA1100_H3100 */
392
393/************************* H3600 *************************/
394
395#ifdef CONFIG_SA1100_H3600
396
397#define H3600_EGPIO (*(volatile unsigned int *)H3600_EGPIO_VIRT)
398static unsigned int h3600_egpio = EGPIO_H3600_RS232_ON;
399
400static void h3600_control_egpio(enum ipaq_egpio_type x, int setp)
401{
402 unsigned int egpio = 0;
403 unsigned long flags;
404
405 switch (x) {
406 case IPAQ_EGPIO_LCD_POWER:
407 egpio |= EGPIO_H3600_LCD_ON |
408 EGPIO_H3600_LCD_PCI |
409 EGPIO_H3600_LCD_5V_ON |
410 EGPIO_H3600_LVDD_ON;
411 do_blank(setp);
412 break;
413 case IPAQ_EGPIO_LCD_ENABLE:
414 break;
415 case IPAQ_EGPIO_CODEC_NRESET:
416 egpio |= EGPIO_H3600_CODEC_NRESET;
417 break;
418 case IPAQ_EGPIO_AUDIO_ON:
419 egpio |= EGPIO_H3600_AUD_AMP_ON |
420 EGPIO_H3600_AUD_PWR_ON;
421 break;
422 case IPAQ_EGPIO_QMUTE:
423 egpio |= EGPIO_H3600_QMUTE;
424 break;
425 case IPAQ_EGPIO_OPT_NVRAM_ON:
426 egpio |= EGPIO_H3600_OPT_NVRAM_ON;
427 break;
428 case IPAQ_EGPIO_OPT_ON:
429 egpio |= EGPIO_H3600_OPT_ON;
430 break;
431 case IPAQ_EGPIO_CARD_RESET:
432 egpio |= EGPIO_H3600_CARD_RESET;
433 break;
434 case IPAQ_EGPIO_OPT_RESET:
435 egpio |= EGPIO_H3600_OPT_RESET;
436 break;
437 case IPAQ_EGPIO_IR_ON:
438 egpio |= EGPIO_H3600_IR_ON;
439 break;
440 case IPAQ_EGPIO_IR_FSEL:
441 egpio |= EGPIO_H3600_IR_FSEL;
442 break;
443 case IPAQ_EGPIO_RS232_ON:
444 egpio |= EGPIO_H3600_RS232_ON;
445 break;
446 case IPAQ_EGPIO_VPP_ON:
447 egpio |= EGPIO_H3600_VPP_ON;
448 break;
449 }
450
451 if (egpio) {
452 local_irq_save(flags);
453 if (setp)
454 h3600_egpio |= egpio;
455 else
456 h3600_egpio &= ~egpio;
457 H3600_EGPIO = h3600_egpio;
458 local_irq_restore(flags);
459 }
460}
461
462static unsigned long h3600_read_egpio(void)
463{
464 return h3600_egpio;
465}
466
467static int h3600_pm_callback(int req)
468{
469 if (ipaq_model_ops.pm_callback_aux)
470 return ipaq_model_ops.pm_callback_aux(req);
471 return 0;
472}
473
474static struct ipaq_model_ops h3600_model_ops __initdata = {
475 .generic_name = "3600",
476 .control = h3600_control_egpio,
477 .read = h3600_read_egpio,
478 .pm_callback = h3600_pm_callback
479};
480
481static void __init h3600_map_io(void)
482{
483 h3xxx_map_io();
484
485 /* Initialize h3600-specific values here */
486
487 GPCR = 0x0fffffff; /* All outputs are set low by default */
488 GPDR = GPIO_H3600_COM_RTS | GPIO_H3600_L3_CLOCK |
489 GPIO_H3600_L3_MODE | GPIO_H3600_L3_DATA |
490 GPIO_H3600_CLK_SET1 | GPIO_H3600_CLK_SET0 |
491 GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12 |
492 GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9 | GPIO_LDD8;
493
494 H3600_EGPIO = h3600_egpio; /* Maintains across sleep? */
495 ipaq_model_ops = h3600_model_ops;
496}
497
498MACHINE_START(H3600, "Compaq iPAQ H3600")
499 BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
500 BOOT_PARAMS(0xc0000100)
501 MAPIO(h3600_map_io)
502 INITIRQ(sa1100_init_irq)
503 .timer = &sa1100_timer,
504 .init_machine = h3xxx_mach_init,
505MACHINE_END
506
507#endif /* CONFIG_SA1100_H3600 */
508
509#ifdef CONFIG_SA1100_H3800
510
511#define SET_ASIC1(x) \
512 do {if (setp) { H3800_ASIC1_GPIO_OUT |= (x); } else { H3800_ASIC1_GPIO_OUT &= ~(x); }} while(0)
513
514#define SET_ASIC2(x) \
515 do {if (setp) { H3800_ASIC2_GPIOPIOD |= (x); } else { H3800_ASIC2_GPIOPIOD &= ~(x); }} while(0)
516
517#define CLEAR_ASIC1(x) \
518 do {if (setp) { H3800_ASIC1_GPIO_OUT &= ~(x); } else { H3800_ASIC1_GPIO_OUT |= (x); }} while(0)
519
520#define CLEAR_ASIC2(x) \
521 do {if (setp) { H3800_ASIC2_GPIOPIOD &= ~(x); } else { H3800_ASIC2_GPIOPIOD |= (x); }} while(0)
522
523
524/*
525 On screen enable, we get
526
527 h3800_video_power_on(1)
528 LCD controller starts
529 h3800_video_lcd_enable(1)
530
531 On screen disable, we get
532
533 h3800_video_lcd_enable(0)
534 LCD controller stops
535 h3800_video_power_on(0)
536*/
537
538
539static void h3800_video_power_on(int setp)
540{
541 if (setp) {
542 H3800_ASIC1_GPIO_OUT |= GPIO1_LCD_ON;
543 msleep(30);
544 H3800_ASIC1_GPIO_OUT |= GPIO1_VGL_ON;
545 msleep(5);
546 H3800_ASIC1_GPIO_OUT |= GPIO1_VGH_ON;
547 msleep(50);
548 H3800_ASIC1_GPIO_OUT |= GPIO1_LCD_5V_ON;
549 msleep(5);
550 } else {
551 msleep(5);
552 H3800_ASIC1_GPIO_OUT &= ~GPIO1_LCD_5V_ON;
553 msleep(50);
554 H3800_ASIC1_GPIO_OUT &= ~GPIO1_VGL_ON;
555 msleep(5);
556 H3800_ASIC1_GPIO_OUT &= ~GPIO1_VGH_ON;
557 msleep(100);
558 H3800_ASIC1_GPIO_OUT &= ~GPIO1_LCD_ON;
559 }
560}
561
562static void h3800_video_lcd_enable(int setp)
563{
564 if (setp) {
565 msleep(17); // Wait one from before turning on
566 H3800_ASIC1_GPIO_OUT |= GPIO1_LCD_PCI;
567 } else {
568 H3800_ASIC1_GPIO_OUT &= ~GPIO1_LCD_PCI;
569 msleep(30); // Wait before turning off
570 }
571}
572
573
574static void h3800_control_egpio(enum ipaq_egpio_type x, int setp)
575{
576 switch (x) {
577 case IPAQ_EGPIO_LCD_POWER:
578 h3800_video_power_on(setp);
579 break;
580 case IPAQ_EGPIO_LCD_ENABLE:
581 h3800_video_lcd_enable(setp);
582 break;
583 case IPAQ_EGPIO_CODEC_NRESET:
584 case IPAQ_EGPIO_AUDIO_ON:
585 case IPAQ_EGPIO_QMUTE:
586 printk("%s: error - should not be called\n", __FUNCTION__);
587 break;
588 case IPAQ_EGPIO_OPT_NVRAM_ON:
589 SET_ASIC2(GPIO2_OPT_ON_NVRAM);
590 break;
591 case IPAQ_EGPIO_OPT_ON:
592 SET_ASIC2(GPIO2_OPT_ON);
593 break;
594 case IPAQ_EGPIO_CARD_RESET:
595 SET_ASIC2(GPIO2_OPT_PCM_RESET);
596 break;
597 case IPAQ_EGPIO_OPT_RESET:
598 SET_ASIC2(GPIO2_OPT_RESET);
599 break;
600 case IPAQ_EGPIO_IR_ON:
601 CLEAR_ASIC1(GPIO1_IR_ON_N);
602 break;
603 case IPAQ_EGPIO_IR_FSEL:
604 break;
605 case IPAQ_EGPIO_RS232_ON:
606 SET_ASIC1(GPIO1_RS232_ON);
607 break;
608 case IPAQ_EGPIO_VPP_ON:
609 H3800_ASIC2_FlashWP_VPP_ON = setp;
610 break;
611 }
612}
613
614static unsigned long h3800_read_egpio(void)
615{
616 return H3800_ASIC1_GPIO_OUT | (H3800_ASIC2_GPIOPIOD << 16);
617}
618
619/* We need to fix ASIC2 GPIO over suspend/resume. At the moment,
620 it doesn't appear that ASIC1 GPIO has the same problem */
621
622static int h3800_pm_callback(int req)
623{
624 static u16 asic1_data;
625 static u16 asic2_data;
626 int result = 0;
627
628 printk("%s %d\n", __FUNCTION__, req);
629
630 switch (req) {
631 case PM_RESUME:
632 MSC2 = (MSC2 & 0x0000ffff) | 0xE4510000; /* Set MSC2 correctly */
633
634 H3800_ASIC2_GPIOPIOD = asic2_data;
635 H3800_ASIC2_GPIODIR = GPIO2_PEN_IRQ
636 | GPIO2_SD_DETECT
637 | GPIO2_EAR_IN_N
638 | GPIO2_USB_DETECT_N
639 | GPIO2_SD_CON_SLT;
640
641 H3800_ASIC1_GPIO_OUT = asic1_data;
642
643 if (ipaq_model_ops.pm_callback_aux)
644 result = ipaq_model_ops.pm_callback_aux(req);
645 break;
646
647 case PM_SUSPEND:
648 if (ipaq_model_ops.pm_callback_aux &&
649 ((result = ipaq_model_ops.pm_callback_aux(req)) != 0))
650 return result;
651
652 asic1_data = H3800_ASIC1_GPIO_OUT;
653 asic2_data = H3800_ASIC2_GPIOPIOD;
654 break;
655 default:
656 printk("%s: unrecognized PM callback\n", __FUNCTION__);
657 break;
658 }
659 return result;
660}
661
662static struct ipaq_model_ops h3800_model_ops __initdata = {
663 .generic_name = "3800",
664 .control = h3800_control_egpio,
665 .read = h3800_read_egpio,
666 .pm_callback = h3800_pm_callback
667};
668
669#define MAX_ASIC_ISR_LOOPS 20
670
671/* The order of these is important - see #include <asm/arch/irqs.h> */
672static u32 kpio_irq_mask[] = {
673 KPIO_KEY_ALL,
674 KPIO_SPI_INT,
675 KPIO_OWM_INT,
676 KPIO_ADC_INT,
677 KPIO_UART_0_INT,
678 KPIO_UART_1_INT,
679 KPIO_TIMER_0_INT,
680 KPIO_TIMER_1_INT,
681 KPIO_TIMER_2_INT
682};
683
684static u32 gpio_irq_mask[] = {
685 GPIO2_PEN_IRQ,
686 GPIO2_SD_DETECT,
687 GPIO2_EAR_IN_N,
688 GPIO2_USB_DETECT_N,
689 GPIO2_SD_CON_SLT,
690};
691
692static void h3800_IRQ_demux(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
693{
694 int i;
695
696 if (0) printk("%s: interrupt received\n", __FUNCTION__);
697
698 desc->chip->ack(irq);
699
700 for (i = 0; i < MAX_ASIC_ISR_LOOPS && (GPLR & GPIO_H3800_ASIC); i++) {
701 u32 irq;
702 int j;
703
704 /* KPIO */
705 irq = H3800_ASIC2_KPIINTFLAG;
706 if (0) printk("%s KPIO 0x%08X\n", __FUNCTION__, irq);
707 for (j = 0; j < H3800_KPIO_IRQ_COUNT; j++)
708 if (irq & kpio_irq_mask[j])
709 do_edge_IRQ(H3800_KPIO_IRQ_COUNT + j, irq_desc + H3800_KPIO_IRQ_COUNT + j, regs);
710
711 /* GPIO2 */
712 irq = H3800_ASIC2_GPIINTFLAG;
713 if (0) printk("%s GPIO 0x%08X\n", __FUNCTION__, irq);
714 for (j = 0; j < H3800_GPIO_IRQ_COUNT; j++)
715 if (irq & gpio_irq_mask[j])
716 do_edge_IRQ(H3800_GPIO_IRQ_COUNT + j, irq_desc + H3800_GPIO_IRQ_COUNT + j , regs);
717 }
718
719 if (i >= MAX_ASIC_ISR_LOOPS)
720 printk("%s: interrupt processing overrun\n", __FUNCTION__);
721
722 /* For level-based interrupts */
723 desc->chip->unmask(irq);
724
725}
726
727static struct irqaction h3800_irq = {
728 .name = "h3800_asic",
729 .handler = h3800_IRQ_demux,
730 .flags = SA_INTERRUPT,
731};
732
733u32 kpio_int_shadow = 0;
734
735
736/* mask_ack <- IRQ is first serviced.
737 mask <- IRQ is disabled.
738 unmask <- IRQ is enabled
739
740 The INTCLR registers are poorly documented. I believe that writing
741 a "1" to the register clears the specific interrupt, but the documentation
742 indicates writing a "0" clears the interrupt. In any case, they shouldn't
743 be read (that's the INTFLAG register)
744 */
745
746static void h3800_mask_ack_kpio_irq(unsigned int irq)
747{
748 u32 mask = kpio_irq_mask[irq - H3800_KPIO_IRQ_START];
749 kpio_int_shadow &= ~mask;
750 H3800_ASIC2_KPIINTSTAT = kpio_int_shadow;
751 H3800_ASIC2_KPIINTCLR = mask;
752}
753
754static void h3800_mask_kpio_irq(unsigned int irq)
755{
756 u32 mask = kpio_irq_mask[irq - H3800_KPIO_IRQ_START];
757 kpio_int_shadow &= ~mask;
758 H3800_ASIC2_KPIINTSTAT = kpio_int_shadow;
759}
760
761static void h3800_unmask_kpio_irq(unsigned int irq)
762{
763 u32 mask = kpio_irq_mask[irq - H3800_KPIO_IRQ_START];
764 kpio_int_shadow |= mask;
765 H3800_ASIC2_KPIINTSTAT = kpio_int_shadow;
766}
767
768static void h3800_mask_ack_gpio_irq(unsigned int irq)
769{
770 u32 mask = gpio_irq_mask[irq - H3800_GPIO_IRQ_START];
771 H3800_ASIC2_GPIINTSTAT &= ~mask;
772 H3800_ASIC2_GPIINTCLR = mask;
773}
774
775static void h3800_mask_gpio_irq(unsigned int irq)
776{
777 u32 mask = gpio_irq_mask[irq - H3800_GPIO_IRQ_START];
778 H3800_ASIC2_GPIINTSTAT &= ~mask;
779 }
780
781static void h3800_unmask_gpio_irq(unsigned int irq)
782{
783 u32 mask = gpio_irq_mask[irq - H3800_GPIO_IRQ_START];
784 H3800_ASIC2_GPIINTSTAT |= mask;
785}
786
787static void __init h3800_init_irq(void)
788{
789 int i;
790
791 /* Initialize standard IRQs */
792 sa1100_init_irq();
793
794 /* Disable all IRQs and set up clock */
795 H3800_ASIC2_KPIINTSTAT = 0; /* Disable all interrupts */
796 H3800_ASIC2_GPIINTSTAT = 0;
797
798 H3800_ASIC2_KPIINTCLR = 0; /* Clear all KPIO interrupts */
799 H3800_ASIC2_GPIINTCLR = 0; /* Clear all GPIO interrupts */
800
801// H3800_ASIC2_KPIINTCLR = 0xffff; /* Clear all KPIO interrupts */
802// H3800_ASIC2_GPIINTCLR = 0xffff; /* Clear all GPIO interrupts */
803
804 H3800_ASIC2_CLOCK_Enable |= ASIC2_CLOCK_EX0; /* 32 kHZ crystal on */
805 H3800_ASIC2_INTR_ClockPrescale |= ASIC2_INTCPS_SET;
806 H3800_ASIC2_INTR_ClockPrescale = ASIC2_INTCPS_CPS(0x0e) | ASIC2_INTCPS_SET;
807 H3800_ASIC2_INTR_TimerSet = 1;
808
809#if 0
810 for (i = 0; i < H3800_KPIO_IRQ_COUNT; i++) {
811 int irq = i + H3800_KPIO_IRQ_START;
812 irq_desc[irq].valid = 1;
813 irq_desc[irq].probe_ok = 1;
814 set_irq_chip(irq, &h3800_kpio_irqchip);
815 }
816
817 for (i = 0; i < H3800_GPIO_IRQ_COUNT; i++) {
818 int irq = i + H3800_GPIO_IRQ_START;
819 irq_desc[irq].valid = 1;
820 irq_desc[irq].probe_ok = 1;
821 set_irq_chip(irq, &h3800_gpio_irqchip);
822 }
823#endif
824 set_irq_type(IRQ_GPIO_H3800_ASIC, IRQT_RISING);
825 set_irq_chained_handler(IRQ_GPIO_H3800_ASIC, &h3800_IRQ_demux);
826}
827
828
829#define ASIC1_OUTPUTS 0x7fff /* First 15 bits are used */
830
831static void __init h3800_map_io(void)
832{
833 h3xxx_map_io();
834
835 /* Add wakeup on AC plug/unplug */
836 PWER |= PWER_GPIO12;
837
838 /* Initialize h3800-specific values here */
839 GPCR = 0x0fffffff; /* All outputs are set low by default */
840 GAFR = GPIO_H3800_CLK_OUT |
841 GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12 |
842 GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9 | GPIO_LDD8;
843 GPDR = GPIO_H3800_CLK_OUT |
844 GPIO_H3600_COM_RTS | GPIO_H3600_L3_CLOCK |
845 GPIO_H3600_L3_MODE | GPIO_H3600_L3_DATA |
846 GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12 |
847 GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9 | GPIO_LDD8;
848 TUCR = TUCR_3_6864MHz; /* Seems to be used only for the Bluetooth UART */
849
850 /* Fix the memory bus */
851 MSC2 = (MSC2 & 0x0000ffff) | 0xE4510000;
852
853 /* Set up ASIC #1 */
854 H3800_ASIC1_GPIO_DIR = ASIC1_OUTPUTS; /* All outputs */
855 H3800_ASIC1_GPIO_MASK = ASIC1_OUTPUTS; /* No interrupts */
856 H3800_ASIC1_GPIO_SLEEP_MASK = ASIC1_OUTPUTS;
857 H3800_ASIC1_GPIO_SLEEP_DIR = ASIC1_OUTPUTS;
858 H3800_ASIC1_GPIO_SLEEP_OUT = GPIO1_EAR_ON_N;
859 H3800_ASIC1_GPIO_BATT_FAULT_DIR = ASIC1_OUTPUTS;
860 H3800_ASIC1_GPIO_BATT_FAULT_OUT = GPIO1_EAR_ON_N;
861
862 H3800_ASIC1_GPIO_OUT = GPIO1_IR_ON_N
863 | GPIO1_RS232_ON
864 | GPIO1_EAR_ON_N;
865
866 /* Set up ASIC #2 */
867 H3800_ASIC2_GPIOPIOD = GPIO2_IN_Y1_N | GPIO2_IN_X1_N;
868 H3800_ASIC2_GPOBFSTAT = GPIO2_IN_Y1_N | GPIO2_IN_X1_N;
869
870 H3800_ASIC2_GPIODIR = GPIO2_PEN_IRQ
871 | GPIO2_SD_DETECT
872 | GPIO2_EAR_IN_N
873 | GPIO2_USB_DETECT_N
874 | GPIO2_SD_CON_SLT;
875
876 /* TODO : Set sleep states & battery fault states */
877
878 /* Clear VPP Enable */
879 H3800_ASIC2_FlashWP_VPP_ON = 0;
880 ipaq_model_ops = h3800_model_ops;
881}
882
883MACHINE_START(H3800, "Compaq iPAQ H3800")
884 BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
885 BOOT_PARAMS(0xc0000100)
886 MAPIO(h3800_map_io)
887 INITIRQ(h3800_init_irq)
888 .timer = &sa1100_timer,
889 .init_machine = h3xxx_mach_init,
890MACHINE_END
891
892#endif /* CONFIG_SA1100_H3800 */
diff --git a/arch/arm/mach-sa1100/hackkit.c b/arch/arm/mach-sa1100/hackkit.c
new file mode 100644
index 000000000000..570841779714
--- /dev/null
+++ b/arch/arm/mach-sa1100/hackkit.c
@@ -0,0 +1,200 @@
1/*
2 * linux/arch/arm/mach-sa1100/hackkit.c
3 *
4 * Copyright (C) 2002 Stefan Eletzhofer <stefan.eletzhofer@eletztrick.de>
5 *
6 * This file contains all HackKit tweaks. Based on original work from
7 * Nicolas Pitre's assabet fixes
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 *
13 */
14#include <linux/init.h>
15#include <linux/kernel.h>
16#include <linux/sched.h>
17#include <linux/tty.h>
18#include <linux/module.h>
19#include <linux/errno.h>
20#include <linux/cpufreq.h>
21#include <linux/serial_core.h>
22#include <linux/mtd/mtd.h>
23#include <linux/mtd/partitions.h>
24
25#include <asm/hardware.h>
26#include <asm/mach-types.h>
27#include <asm/setup.h>
28#include <asm/page.h>
29#include <asm/pgtable.h>
30#include <asm/irq.h>
31
32#include <asm/mach/arch.h>
33#include <asm/mach/flash.h>
34#include <asm/mach/map.h>
35#include <asm/mach/irq.h>
36#include <asm/mach/serial_sa1100.h>
37
38#include "generic.h"
39
40/**********************************************************************
41 * prototypes
42 */
43
44/* init funcs */
45static void __init hackkit_map_io(void);
46
47static u_int hackkit_get_mctrl(struct uart_port *port);
48static void hackkit_set_mctrl(struct uart_port *port, u_int mctrl);
49static void hackkit_uart_pm(struct uart_port *port, u_int state, u_int oldstate);
50
51/**********************************************************************
52 * global data
53 */
54
55/**********************************************************************
56 * static data
57 */
58
59static struct map_desc hackkit_io_desc[] __initdata = {
60 /* virtual physical length type */
61 { 0xe8000000, 0x00000000, 0x01000000, MT_DEVICE } /* Flash bank 0 */
62};
63
64static struct sa1100_port_fns hackkit_port_fns __initdata = {
65 .set_mctrl = hackkit_set_mctrl,
66 .get_mctrl = hackkit_get_mctrl,
67 .pm = hackkit_uart_pm,
68};
69
70/**********************************************************************
71 * Static functions
72 */
73
74static void __init hackkit_map_io(void)
75{
76 sa1100_map_io();
77 iotable_init(hackkit_io_desc, ARRAY_SIZE(hackkit_io_desc));
78
79 sa1100_register_uart_fns(&hackkit_port_fns);
80 sa1100_register_uart(0, 1); /* com port */
81 sa1100_register_uart(1, 2);
82 sa1100_register_uart(2, 3); /* radio module */
83
84 Ser1SDCR0 |= SDCR0_SUS;
85}
86
87/**
88 * hackkit_uart_pm - powermgmt callback function for system 3 UART
89 * @port: uart port structure
90 * @state: pm state
91 * @oldstate: old pm state
92 *
93 */
94static void hackkit_uart_pm(struct uart_port *port, u_int state, u_int oldstate)
95{
96 /* TODO: switch on/off uart in powersave mode */
97}
98
99/*
100 * Note! this can be called from IRQ context.
101 * FIXME: No modem ctrl lines yet.
102 */
103static void hackkit_set_mctrl(struct uart_port *port, u_int mctrl)
104{
105#if 0
106 if (port->mapbase == _Ser1UTCR0) {
107 u_int set = 0, clear = 0;
108
109 if (mctrl & TIOCM_RTS)
110 set |= PT_CTRL2_RS1_RTS;
111 else
112 clear |= PT_CTRL2_RS1_RTS;
113
114 if (mctrl & TIOCM_DTR)
115 set |= PT_CTRL2_RS1_DTR;
116 else
117 clear |= PT_CTRL2_RS1_DTR;
118
119 PTCTRL2_clear(clear);
120 PTCTRL2_set(set);
121 }
122#endif
123}
124
125static u_int hackkit_get_mctrl(struct uart_port *port)
126{
127 u_int ret = 0;
128#if 0
129 u_int irqsr = PT_IRQSR;
130
131 /* need 2 reads to read current value */
132 irqsr = PT_IRQSR;
133
134 /* TODO: check IRQ source register for modem/com
135 status lines and set them correctly. */
136#endif
137
138 ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR;
139
140 return ret;
141}
142
143static struct mtd_partition hackkit_partitions[] = {
144 {
145 .name = "BLOB",
146 .size = 0x00040000,
147 .offset = 0x00000000,
148 .mask_flags = MTD_WRITEABLE, /* force read-only */
149 }, {
150 .name = "config",
151 .size = 0x00040000,
152 .offset = MTDPART_OFS_APPEND,
153 }, {
154 .name = "kernel",
155 .size = 0x00100000,
156 .offset = MTDPART_OFS_APPEND,
157 }, {
158 .name = "initrd",
159 .size = 0x00180000,
160 .offset = MTDPART_OFS_APPEND,
161 }, {
162 .name = "rootfs",
163 .size = 0x700000,
164 .offset = MTDPART_OFS_APPEND,
165 }, {
166 .name = "data",
167 .size = MTDPART_SIZ_FULL,
168 .offset = MTDPART_OFS_APPEND,
169 }
170};
171
172static struct flash_platform_data hackkit_flash_data = {
173 .map_name = "cfi_probe",
174 .parts = hackkit_partitions,
175 .nr_parts = ARRAY_SIZE(hackkit_partitions),
176};
177
178static struct resource hackkit_flash_resource = {
179 .start = SA1100_CS0_PHYS,
180 .end = SA1100_CS0_PHYS + SZ_32M,
181 .flags = IORESOURCE_MEM,
182};
183
184static void __init hackkit_init(void)
185{
186 sa11x0_set_flash_data(&hackkit_flash_data, &hackkit_flash_resource, 1);
187}
188
189/**********************************************************************
190 * Exported Functions
191 */
192
193MACHINE_START(HACKKIT, "HackKit Cpu Board")
194 BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
195 BOOT_PARAMS(0xc0000100)
196 MAPIO(hackkit_map_io)
197 INITIRQ(sa1100_init_irq)
198 .timer = &sa1100_timer,
199 .init_machine = hackkit_init,
200MACHINE_END
diff --git a/arch/arm/mach-sa1100/irq.c b/arch/arm/mach-sa1100/irq.c
new file mode 100644
index 000000000000..66a929cb7bc5
--- /dev/null
+++ b/arch/arm/mach-sa1100/irq.c
@@ -0,0 +1,332 @@
1/*
2 * linux/arch/arm/mach-sa1100/irq.c
3 *
4 * Copyright (C) 1999-2001 Nicolas Pitre
5 *
6 * Generic IRQ handling for the SA11x0, GPIO 11-27 IRQ demultiplexing.
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#include <linux/init.h>
13#include <linux/module.h>
14#include <linux/ioport.h>
15#include <linux/ptrace.h>
16#include <linux/sysdev.h>
17
18#include <asm/hardware.h>
19#include <asm/irq.h>
20#include <asm/mach/irq.h>
21
22#include "generic.h"
23
24
25/*
26 * SA1100 GPIO edge detection for IRQs:
27 * IRQs are generated on Falling-Edge, Rising-Edge, or both.
28 * Use this instead of directly setting GRER/GFER.
29 */
30static int GPIO_IRQ_rising_edge;
31static int GPIO_IRQ_falling_edge;
32static int GPIO_IRQ_mask = (1 << 11) - 1;
33
34/*
35 * To get the GPIO number from an IRQ number
36 */
37#define GPIO_11_27_IRQ(i) ((i) - 21)
38#define GPIO11_27_MASK(irq) (1 << GPIO_11_27_IRQ(irq))
39
40static int sa1100_gpio_type(unsigned int irq, unsigned int type)
41{
42 unsigned int mask;
43
44 if (irq <= 10)
45 mask = 1 << irq;
46 else
47 mask = GPIO11_27_MASK(irq);
48
49 if (type == IRQT_PROBE) {
50 if ((GPIO_IRQ_rising_edge | GPIO_IRQ_falling_edge) & mask)
51 return 0;
52 type = __IRQT_RISEDGE | __IRQT_FALEDGE;
53 }
54
55 if (type & __IRQT_RISEDGE) {
56 GPIO_IRQ_rising_edge |= mask;
57 } else
58 GPIO_IRQ_rising_edge &= ~mask;
59 if (type & __IRQT_FALEDGE) {
60 GPIO_IRQ_falling_edge |= mask;
61 } else
62 GPIO_IRQ_falling_edge &= ~mask;
63
64 GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask;
65 GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask;
66
67 return 0;
68}
69
70/*
71 * GPIO IRQs must be acknowledged. This is for IRQs from 0 to 10.
72 */
73static void sa1100_low_gpio_ack(unsigned int irq)
74{
75 GEDR = (1 << irq);
76}
77
78static void sa1100_low_gpio_mask(unsigned int irq)
79{
80 ICMR &= ~(1 << irq);
81}
82
83static void sa1100_low_gpio_unmask(unsigned int irq)
84{
85 ICMR |= 1 << irq;
86}
87
88static int sa1100_low_gpio_wake(unsigned int irq, unsigned int on)
89{
90 if (on)
91 PWER |= 1 << irq;
92 else
93 PWER &= ~(1 << irq);
94 return 0;
95}
96
97static struct irqchip sa1100_low_gpio_chip = {
98 .ack = sa1100_low_gpio_ack,
99 .mask = sa1100_low_gpio_mask,
100 .unmask = sa1100_low_gpio_unmask,
101 .type = sa1100_gpio_type,
102 .wake = sa1100_low_gpio_wake,
103};
104
105/*
106 * IRQ11 (GPIO11 through 27) handler. We enter here with the
107 * irq_controller_lock held, and IRQs disabled. Decode the IRQ
108 * and call the handler.
109 */
110static void
111sa1100_high_gpio_handler(unsigned int irq, struct irqdesc *desc,
112 struct pt_regs *regs)
113{
114 unsigned int mask;
115
116 mask = GEDR & 0xfffff800;
117 do {
118 /*
119 * clear down all currently active IRQ sources.
120 * We will be processing them all.
121 */
122 GEDR = mask;
123
124 irq = IRQ_GPIO11;
125 desc = irq_desc + irq;
126 mask >>= 11;
127 do {
128 if (mask & 1)
129 desc->handle(irq, desc, regs);
130 mask >>= 1;
131 irq++;
132 desc++;
133 } while (mask);
134
135 mask = GEDR & 0xfffff800;
136 } while (mask);
137}
138
139/*
140 * Like GPIO0 to 10, GPIO11-27 IRQs need to be handled specially.
141 * In addition, the IRQs are all collected up into one bit in the
142 * interrupt controller registers.
143 */
144static void sa1100_high_gpio_ack(unsigned int irq)
145{
146 unsigned int mask = GPIO11_27_MASK(irq);
147
148 GEDR = mask;
149}
150
151static void sa1100_high_gpio_mask(unsigned int irq)
152{
153 unsigned int mask = GPIO11_27_MASK(irq);
154
155 GPIO_IRQ_mask &= ~mask;
156
157 GRER &= ~mask;
158 GFER &= ~mask;
159}
160
161static void sa1100_high_gpio_unmask(unsigned int irq)
162{
163 unsigned int mask = GPIO11_27_MASK(irq);
164
165 GPIO_IRQ_mask |= mask;
166
167 GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask;
168 GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask;
169}
170
171static int sa1100_high_gpio_wake(unsigned int irq, unsigned int on)
172{
173 if (on)
174 PWER |= GPIO11_27_MASK(irq);
175 else
176 PWER &= ~GPIO11_27_MASK(irq);
177 return 0;
178}
179
180static struct irqchip sa1100_high_gpio_chip = {
181 .ack = sa1100_high_gpio_ack,
182 .mask = sa1100_high_gpio_mask,
183 .unmask = sa1100_high_gpio_unmask,
184 .type = sa1100_gpio_type,
185 .wake = sa1100_high_gpio_wake,
186};
187
188/*
189 * We don't need to ACK IRQs on the SA1100 unless they're GPIOs
190 * this is for internal IRQs i.e. from 11 to 31.
191 */
192static void sa1100_mask_irq(unsigned int irq)
193{
194 ICMR &= ~(1 << irq);
195}
196
197static void sa1100_unmask_irq(unsigned int irq)
198{
199 ICMR |= (1 << irq);
200}
201
202static struct irqchip sa1100_normal_chip = {
203 .ack = sa1100_mask_irq,
204 .mask = sa1100_mask_irq,
205 .unmask = sa1100_unmask_irq,
206};
207
208static struct resource irq_resource = {
209 .name = "irqs",
210 .start = 0x90050000,
211 .end = 0x9005ffff,
212};
213
214static struct sa1100irq_state {
215 unsigned int saved;
216 unsigned int icmr;
217 unsigned int iclr;
218 unsigned int iccr;
219} sa1100irq_state;
220
221static int sa1100irq_suspend(struct sys_device *dev, pm_message_t state)
222{
223 struct sa1100irq_state *st = &sa1100irq_state;
224
225 st->saved = 1;
226 st->icmr = ICMR;
227 st->iclr = ICLR;
228 st->iccr = ICCR;
229
230 /*
231 * Disable all GPIO-based interrupts.
232 */
233 ICMR &= ~(IC_GPIO11_27|IC_GPIO10|IC_GPIO9|IC_GPIO8|IC_GPIO7|
234 IC_GPIO6|IC_GPIO5|IC_GPIO4|IC_GPIO3|IC_GPIO2|
235 IC_GPIO1|IC_GPIO0);
236
237 /*
238 * Set the appropriate edges for wakeup.
239 */
240 GRER = PWER & GPIO_IRQ_rising_edge;
241 GFER = PWER & GPIO_IRQ_falling_edge;
242
243 /*
244 * Clear any pending GPIO interrupts.
245 */
246 GEDR = GEDR;
247
248 return 0;
249}
250
251static int sa1100irq_resume(struct sys_device *dev)
252{
253 struct sa1100irq_state *st = &sa1100irq_state;
254
255 if (st->saved) {
256 ICCR = st->iccr;
257 ICLR = st->iclr;
258
259 GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask;
260 GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask;
261
262 ICMR = st->icmr;
263 }
264 return 0;
265}
266
267static struct sysdev_class sa1100irq_sysclass = {
268 set_kset_name("sa11x0-irq"),
269 .suspend = sa1100irq_suspend,
270 .resume = sa1100irq_resume,
271};
272
273static struct sys_device sa1100irq_device = {
274 .id = 0,
275 .cls = &sa1100irq_sysclass,
276};
277
278static int __init sa1100irq_init_devicefs(void)
279{
280 sysdev_class_register(&sa1100irq_sysclass);
281 return sysdev_register(&sa1100irq_device);
282}
283
284device_initcall(sa1100irq_init_devicefs);
285
286void __init sa1100_init_irq(void)
287{
288 unsigned int irq;
289
290 request_resource(&iomem_resource, &irq_resource);
291
292 /* disable all IRQs */
293 ICMR = 0;
294
295 /* all IRQs are IRQ, not FIQ */
296 ICLR = 0;
297
298 /* clear all GPIO edge detects */
299 GFER = 0;
300 GRER = 0;
301 GEDR = -1;
302
303 /*
304 * Whatever the doc says, this has to be set for the wait-on-irq
305 * instruction to work... on a SA1100 rev 9 at least.
306 */
307 ICCR = 1;
308
309 for (irq = 0; irq <= 10; irq++) {
310 set_irq_chip(irq, &sa1100_low_gpio_chip);
311 set_irq_handler(irq, do_edge_IRQ);
312 set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
313 }
314
315 for (irq = 12; irq <= 31; irq++) {
316 set_irq_chip(irq, &sa1100_normal_chip);
317 set_irq_handler(irq, do_level_IRQ);
318 set_irq_flags(irq, IRQF_VALID);
319 }
320
321 for (irq = 32; irq <= 48; irq++) {
322 set_irq_chip(irq, &sa1100_high_gpio_chip);
323 set_irq_handler(irq, do_edge_IRQ);
324 set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
325 }
326
327 /*
328 * Install handler for GPIO 11-27 edge detect interrupts
329 */
330 set_irq_chip(IRQ_GPIO11_27, &sa1100_normal_chip);
331 set_irq_chained_handler(IRQ_GPIO11_27, sa1100_high_gpio_handler);
332}
diff --git a/arch/arm/mach-sa1100/jornada720.c b/arch/arm/mach-sa1100/jornada720.c
new file mode 100644
index 000000000000..6be78291a878
--- /dev/null
+++ b/arch/arm/mach-sa1100/jornada720.c
@@ -0,0 +1,105 @@
1/*
2 * linux/arch/arm/mach-sa1100/jornada720.c
3 */
4
5#include <linux/init.h>
6#include <linux/kernel.h>
7#include <linux/tty.h>
8#include <linux/delay.h>
9#include <linux/device.h>
10#include <linux/ioport.h>
11
12#include <asm/hardware.h>
13#include <asm/hardware/sa1111.h>
14#include <asm/irq.h>
15#include <asm/mach-types.h>
16#include <asm/setup.h>
17
18#include <asm/mach/arch.h>
19#include <asm/mach/map.h>
20#include <asm/mach/serial_sa1100.h>
21
22#include "generic.h"
23
24
25#define JORTUCR_VAL 0x20000400
26
27static struct resource sa1111_resources[] = {
28 [0] = {
29 .start = 0x40000000,
30 .end = 0x40001fff,
31 .flags = IORESOURCE_MEM,
32 },
33 [1] = {
34 .start = IRQ_GPIO1,
35 .end = IRQ_GPIO1,
36 .flags = IORESOURCE_IRQ,
37 },
38};
39
40static u64 sa1111_dmamask = 0xffffffffUL;
41
42static struct platform_device sa1111_device = {
43 .name = "sa1111",
44 .id = 0,
45 .dev = {
46 .dma_mask = &sa1111_dmamask,
47 .coherent_dma_mask = 0xffffffff,
48 },
49 .num_resources = ARRAY_SIZE(sa1111_resources),
50 .resource = sa1111_resources,
51};
52
53static struct platform_device *devices[] __initdata = {
54 &sa1111_device,
55};
56
57static int __init jornada720_init(void)
58{
59 int ret = -ENODEV;
60
61 if (machine_is_jornada720()) {
62 GPDR |= GPIO_GPIO20;
63 TUCR = JORTUCR_VAL; /* set the oscillator out to the SA-1101 */
64
65 GPSR = GPIO_GPIO20;
66 udelay(1);
67 GPCR = GPIO_GPIO20;
68 udelay(1);
69 GPSR = GPIO_GPIO20;
70 udelay(20);
71
72 /* LDD4 is speaker, LDD3 is microphone */
73 PPSR &= ~(PPC_LDD3 | PPC_LDD4);
74 PPDR |= PPC_LDD3 | PPC_LDD4;
75
76 ret = platform_add_devices(devices, ARRAY_SIZE(devices));
77 }
78 return ret;
79}
80
81arch_initcall(jornada720_init);
82
83static struct map_desc jornada720_io_desc[] __initdata = {
84 /* virtual physical length type */
85 { 0xf0000000, 0x48000000, 0x00100000, MT_DEVICE }, /* Epson registers */
86 { 0xf1000000, 0x48200000, 0x00100000, MT_DEVICE }, /* Epson frame buffer */
87 { 0xf4000000, 0x40000000, 0x00100000, MT_DEVICE } /* SA-1111 */
88};
89
90static void __init jornada720_map_io(void)
91{
92 sa1100_map_io();
93 iotable_init(jornada720_io_desc, ARRAY_SIZE(jornada720_io_desc));
94
95 sa1100_register_uart(0, 3);
96 sa1100_register_uart(1, 1);
97}
98
99MACHINE_START(JORNADA720, "HP Jornada 720")
100 BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
101 BOOT_PARAMS(0xc0000100)
102 MAPIO(jornada720_map_io)
103 INITIRQ(sa1100_init_irq)
104 .timer = &sa1100_timer,
105MACHINE_END
diff --git a/arch/arm/mach-sa1100/lart.c b/arch/arm/mach-sa1100/lart.c
new file mode 100644
index 000000000000..51c08ccfb8db
--- /dev/null
+++ b/arch/arm/mach-sa1100/lart.c
@@ -0,0 +1,49 @@
1/*
2 * linux/arch/arm/mach-sa1100/lart.c
3 */
4
5#include <linux/init.h>
6#include <linux/kernel.h>
7#include <linux/tty.h>
8
9#include <asm/hardware.h>
10#include <asm/setup.h>
11#include <asm/mach-types.h>
12
13#include <asm/mach/arch.h>
14#include <asm/mach/map.h>
15#include <asm/mach/serial_sa1100.h>
16
17#include "generic.h"
18
19
20#warning "include/asm/arch-sa1100/ide.h needs fixing for lart"
21
22static struct map_desc lart_io_desc[] __initdata = {
23 /* virtual physical length type */
24 { 0xe8000000, 0x00000000, 0x00400000, MT_DEVICE }, /* main flash memory */
25 { 0xec000000, 0x08000000, 0x00400000, MT_DEVICE } /* main flash, alternative location */
26};
27
28static void __init lart_map_io(void)
29{
30 sa1100_map_io();
31 iotable_init(lart_io_desc, ARRAY_SIZE(lart_io_desc));
32
33 sa1100_register_uart(0, 3);
34 sa1100_register_uart(1, 1);
35 sa1100_register_uart(2, 2);
36
37 GAFR |= (GPIO_UART_TXD | GPIO_UART_RXD);
38 GPDR |= GPIO_UART_TXD;
39 GPDR &= ~GPIO_UART_RXD;
40 PPAR |= PPAR_UPR;
41}
42
43MACHINE_START(LART, "LART")
44 BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
45 BOOT_PARAMS(0xc0000100)
46 MAPIO(lart_map_io)
47 INITIRQ(sa1100_init_irq)
48 .timer = &sa1100_timer,
49MACHINE_END
diff --git a/arch/arm/mach-sa1100/leds-assabet.c b/arch/arm/mach-sa1100/leds-assabet.c
new file mode 100644
index 000000000000..e9aa9dff211a
--- /dev/null
+++ b/arch/arm/mach-sa1100/leds-assabet.c
@@ -0,0 +1,115 @@
1/*
2 * linux/arch/arm/mach-sa1100/leds-assabet.c
3 *
4 * Copyright (C) 2000 John Dorsey <john+@cs.cmu.edu>
5 *
6 * Original (leds-footbridge.c) by Russell King
7 *
8 * Assabet uses the LEDs as follows:
9 * - Green - toggles state every 50 timer interrupts
10 * - Red - on if system is not idle
11 */
12#include <linux/config.h>
13#include <linux/init.h>
14
15#include <asm/hardware.h>
16#include <asm/leds.h>
17#include <asm/system.h>
18#include <asm/arch/assabet.h>
19
20#include "leds.h"
21
22
23#define LED_STATE_ENABLED 1
24#define LED_STATE_CLAIMED 2
25
26static unsigned int led_state;
27static unsigned int hw_led_state;
28
29#define ASSABET_BCR_LED_MASK (ASSABET_BCR_LED_GREEN | ASSABET_BCR_LED_RED)
30
31void assabet_leds_event(led_event_t evt)
32{
33 unsigned long flags;
34
35 local_irq_save(flags);
36
37 switch (evt) {
38 case led_start:
39 hw_led_state = ASSABET_BCR_LED_RED | ASSABET_BCR_LED_GREEN;
40 led_state = LED_STATE_ENABLED;
41 break;
42
43 case led_stop:
44 led_state &= ~LED_STATE_ENABLED;
45 hw_led_state = ASSABET_BCR_LED_RED | ASSABET_BCR_LED_GREEN;
46 ASSABET_BCR_frob(ASSABET_BCR_LED_MASK, hw_led_state);
47 break;
48
49 case led_claim:
50 led_state |= LED_STATE_CLAIMED;
51 hw_led_state = ASSABET_BCR_LED_RED | ASSABET_BCR_LED_GREEN;
52 break;
53
54 case led_release:
55 led_state &= ~LED_STATE_CLAIMED;
56 hw_led_state = ASSABET_BCR_LED_RED | ASSABET_BCR_LED_GREEN;
57 break;
58
59#ifdef CONFIG_LEDS_TIMER
60 case led_timer:
61 if (!(led_state & LED_STATE_CLAIMED))
62 hw_led_state ^= ASSABET_BCR_LED_GREEN;
63 break;
64#endif
65
66#ifdef CONFIG_LEDS_CPU
67 case led_idle_start:
68 if (!(led_state & LED_STATE_CLAIMED))
69 hw_led_state |= ASSABET_BCR_LED_RED;
70 break;
71
72 case led_idle_end:
73 if (!(led_state & LED_STATE_CLAIMED))
74 hw_led_state &= ~ASSABET_BCR_LED_RED;
75 break;
76#endif
77
78 case led_halted:
79 break;
80
81 case led_green_on:
82 if (led_state & LED_STATE_CLAIMED)
83 hw_led_state &= ~ASSABET_BCR_LED_GREEN;
84 break;
85
86 case led_green_off:
87 if (led_state & LED_STATE_CLAIMED)
88 hw_led_state |= ASSABET_BCR_LED_GREEN;
89 break;
90
91 case led_amber_on:
92 break;
93
94 case led_amber_off:
95 break;
96
97 case led_red_on:
98 if (led_state & LED_STATE_CLAIMED)
99 hw_led_state &= ~ASSABET_BCR_LED_RED;
100 break;
101
102 case led_red_off:
103 if (led_state & LED_STATE_CLAIMED)
104 hw_led_state |= ASSABET_BCR_LED_RED;
105 break;
106
107 default:
108 break;
109 }
110
111 if (led_state & LED_STATE_ENABLED)
112 ASSABET_BCR_frob(ASSABET_BCR_LED_MASK, hw_led_state);
113
114 local_irq_restore(flags);
115}
diff --git a/arch/arm/mach-sa1100/leds-badge4.c b/arch/arm/mach-sa1100/leds-badge4.c
new file mode 100644
index 000000000000..0a8f87bb6c4f
--- /dev/null
+++ b/arch/arm/mach-sa1100/leds-badge4.c
@@ -0,0 +1,112 @@
1/*
2 * linux/arch/arm/mach-sa1100/leds-badge4.c
3 *
4 * Author: Christopher Hoover <ch@hpl.hp.com>
5 * Copyright (C) 2002 Hewlett-Packard Company
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 */
12
13#include <linux/config.h>
14#include <linux/init.h>
15
16#include <asm/hardware.h>
17#include <asm/leds.h>
18#include <asm/system.h>
19
20#include "leds.h"
21
22#define LED_STATE_ENABLED 1
23#define LED_STATE_CLAIMED 2
24
25static unsigned int led_state;
26static unsigned int hw_led_state;
27
28#define LED_RED GPIO_GPIO(7)
29#define LED_GREEN GPIO_GPIO(9)
30#define LED_MASK (LED_RED|LED_GREEN)
31
32#define LED_IDLE LED_GREEN
33#define LED_TIMER LED_RED
34
35void badge4_leds_event(led_event_t evt)
36{
37 unsigned long flags;
38
39 local_irq_save(flags);
40
41 switch (evt) {
42 case led_start:
43 GPDR |= LED_MASK;
44 hw_led_state = LED_MASK;
45 led_state = LED_STATE_ENABLED;
46 break;
47
48 case led_stop:
49 led_state &= ~LED_STATE_ENABLED;
50 break;
51
52 case led_claim:
53 led_state |= LED_STATE_CLAIMED;
54 hw_led_state = LED_MASK;
55 break;
56
57 case led_release:
58 led_state &= ~LED_STATE_CLAIMED;
59 hw_led_state = LED_MASK;
60 break;
61
62#ifdef CONFIG_LEDS_TIMER
63 case led_timer:
64 if (!(led_state & LED_STATE_CLAIMED))
65 hw_led_state ^= LED_TIMER;
66 break;
67#endif
68
69#ifdef CONFIG_LEDS_CPU
70 case led_idle_start:
71 /* LED off when system is idle */
72 if (!(led_state & LED_STATE_CLAIMED))
73 hw_led_state &= ~LED_IDLE;
74 break;
75
76 case led_idle_end:
77 if (!(led_state & LED_STATE_CLAIMED))
78 hw_led_state |= LED_IDLE;
79 break;
80#endif
81
82 case led_red_on:
83 if (!(led_state & LED_STATE_CLAIMED))
84 hw_led_state &= ~LED_RED;
85 break;
86
87 case led_red_off:
88 if (!(led_state & LED_STATE_CLAIMED))
89 hw_led_state |= LED_RED;
90 break;
91
92 case led_green_on:
93 if (!(led_state & LED_STATE_CLAIMED))
94 hw_led_state &= ~LED_GREEN;
95 break;
96
97 case led_green_off:
98 if (!(led_state & LED_STATE_CLAIMED))
99 hw_led_state |= LED_GREEN;
100 break;
101
102 default:
103 break;
104 }
105
106 if (led_state & LED_STATE_ENABLED) {
107 GPSR = hw_led_state;
108 GPCR = hw_led_state ^ LED_MASK;
109 }
110
111 local_irq_restore(flags);
112}
diff --git a/arch/arm/mach-sa1100/leds-cerf.c b/arch/arm/mach-sa1100/leds-cerf.c
new file mode 100644
index 000000000000..f6635a2d0e83
--- /dev/null
+++ b/arch/arm/mach-sa1100/leds-cerf.c
@@ -0,0 +1,111 @@
1/*
2 * linux/arch/arm/mach-sa1100/leds-cerf.c
3 *
4 * Author: ???
5 */
6#include <linux/config.h>
7#include <linux/init.h>
8
9#include <asm/hardware.h>
10#include <asm/leds.h>
11#include <asm/system.h>
12
13#include "leds.h"
14
15
16#define LED_STATE_ENABLED 1
17#define LED_STATE_CLAIMED 2
18
19static unsigned int led_state;
20static unsigned int hw_led_state;
21
22#define LED_D0 GPIO_GPIO(0)
23#define LED_D1 GPIO_GPIO(1)
24#define LED_D2 GPIO_GPIO(2)
25#define LED_D3 GPIO_GPIO(3)
26#define LED_MASK (LED_D0|LED_D1|LED_D2|LED_D3)
27
28void cerf_leds_event(led_event_t evt)
29{
30 unsigned long flags;
31
32 local_irq_save(flags);
33
34 switch (evt) {
35 case led_start:
36 hw_led_state = LED_MASK;
37 led_state = LED_STATE_ENABLED;
38 break;
39
40 case led_stop:
41 led_state &= ~LED_STATE_ENABLED;
42 break;
43
44 case led_claim:
45 led_state |= LED_STATE_CLAIMED;
46 hw_led_state = LED_MASK;
47 break;
48 case led_release:
49 led_state &= ~LED_STATE_CLAIMED;
50 hw_led_state = LED_MASK;
51 break;
52
53#ifdef CONFIG_LEDS_TIMER
54 case led_timer:
55 if (!(led_state & LED_STATE_CLAIMED))
56 hw_led_state ^= LED_D0;
57 break;
58#endif
59
60#ifdef CONFIG_LEDS_CPU
61 case led_idle_start:
62 if (!(led_state & LED_STATE_CLAIMED))
63 hw_led_state &= ~LED_D1;
64 break;
65
66 case led_idle_end:
67 if (!(led_state & LED_STATE_CLAIMED))
68 hw_led_state |= LED_D1;
69 break;
70#endif
71 case led_green_on:
72 if (!(led_state & LED_STATE_CLAIMED))
73 hw_led_state &= ~LED_D2;
74 break;
75
76 case led_green_off:
77 if (!(led_state & LED_STATE_CLAIMED))
78 hw_led_state |= LED_D2;
79 break;
80
81 case led_amber_on:
82 if (!(led_state & LED_STATE_CLAIMED))
83 hw_led_state &= ~LED_D3;
84 break;
85
86 case led_amber_off:
87 if (!(led_state & LED_STATE_CLAIMED))
88 hw_led_state |= LED_D3;
89 break;
90
91 case led_red_on:
92 if (!(led_state & LED_STATE_CLAIMED))
93 hw_led_state &= ~LED_D1;
94 break;
95
96 case led_red_off:
97 if (!(led_state & LED_STATE_CLAIMED))
98 hw_led_state |= LED_D1;
99 break;
100
101 default:
102 break;
103 }
104
105 if (led_state & LED_STATE_ENABLED) {
106 GPSR = hw_led_state;
107 GPCR = hw_led_state ^ LED_MASK;
108 }
109
110 local_irq_restore(flags);
111}
diff --git a/arch/arm/mach-sa1100/leds-hackkit.c b/arch/arm/mach-sa1100/leds-hackkit.c
new file mode 100644
index 000000000000..2e5fa14aa4eb
--- /dev/null
+++ b/arch/arm/mach-sa1100/leds-hackkit.c
@@ -0,0 +1,113 @@
1/*
2 * linux/arch/arm/mach-sa1100/leds-hackkit.c
3 *
4 * based on leds-lart.c
5 *
6 * (C) Erik Mouw (J.A.K.Mouw@its.tudelft.nl), April 21, 2000
7 * (C) Stefan Eletzhofer <stefan.eletzhofer@eletztrick.de>, 2002
8 *
9 * The HackKit has two leds (GPIO 22/23). The red led (gpio 22) is used
10 * as cpu led, the green one is used as timer led.
11 */
12#include <linux/config.h>
13#include <linux/init.h>
14
15#include <asm/hardware.h>
16#include <asm/leds.h>
17#include <asm/system.h>
18
19#include "leds.h"
20
21
22#define LED_STATE_ENABLED 1
23#define LED_STATE_CLAIMED 2
24
25static unsigned int led_state;
26static unsigned int hw_led_state;
27
28#define LED_GREEN GPIO_GPIO23
29#define LED_RED GPIO_GPIO22
30#define LED_MASK (LED_RED | LED_GREEN)
31
32void hackkit_leds_event(led_event_t evt)
33{
34 unsigned long flags;
35
36 local_irq_save(flags);
37
38 switch(evt) {
39 case led_start:
40 /* pin 22/23 are outputs */
41 GPDR |= LED_MASK;
42 hw_led_state = LED_MASK;
43 led_state = LED_STATE_ENABLED;
44 break;
45
46 case led_stop:
47 led_state &= ~LED_STATE_ENABLED;
48 break;
49
50 case led_claim:
51 led_state |= LED_STATE_CLAIMED;
52 hw_led_state = LED_MASK;
53 break;
54
55 case led_release:
56 led_state &= ~LED_STATE_CLAIMED;
57 hw_led_state = LED_MASK;
58 break;
59
60#ifdef CONFIG_LEDS_TIMER
61 case led_timer:
62 if (!(led_state & LED_STATE_CLAIMED))
63 hw_led_state ^= LED_GREEN;
64 break;
65#endif
66
67#ifdef CONFIG_LEDS_CPU
68 case led_idle_start:
69 /* The LART people like the LED to be off when the
70 system is idle... */
71 if (!(led_state & LED_STATE_CLAIMED))
72 hw_led_state &= ~LED_RED;
73 break;
74
75 case led_idle_end:
76 /* ... and on if the system is not idle */
77 if (!(led_state & LED_STATE_CLAIMED))
78 hw_led_state |= LED_RED;
79 break;
80#endif
81
82 case led_red_on:
83 if (led_state & LED_STATE_CLAIMED)
84 hw_led_state &= ~LED_RED;
85 break;
86
87 case led_red_off:
88 if (led_state & LED_STATE_CLAIMED)
89 hw_led_state |= LED_RED;
90 break;
91
92 case led_green_on:
93 if (led_state & LED_STATE_CLAIMED)
94 hw_led_state &= ~LED_GREEN;
95 break;
96
97 case led_green_off:
98 if (led_state & LED_STATE_CLAIMED)
99 hw_led_state |= LED_GREEN;
100 break;
101
102 default:
103 break;
104 }
105
106 /* Now set the GPIO state, or nothing will happen at all */
107 if (led_state & LED_STATE_ENABLED) {
108 GPSR = hw_led_state;
109 GPCR = hw_led_state ^ LED_MASK;
110 }
111
112 local_irq_restore(flags);
113}
diff --git a/arch/arm/mach-sa1100/leds-lart.c b/arch/arm/mach-sa1100/leds-lart.c
new file mode 100644
index 000000000000..187501490713
--- /dev/null
+++ b/arch/arm/mach-sa1100/leds-lart.c
@@ -0,0 +1,102 @@
1/*
2 * linux/arch/arm/mach-sa1100/leds-lart.c
3 *
4 * (C) Erik Mouw (J.A.K.Mouw@its.tudelft.nl), April 21, 2000
5 *
6 * LART uses the LED as follows:
7 * - GPIO23 is the LED, on if system is not idle
8 * You can use both CONFIG_LEDS_CPU and CONFIG_LEDS_TIMER at the same
9 * time, but in that case the timer events will still dictate the
10 * pace of the LED.
11 */
12#include <linux/config.h>
13#include <linux/init.h>
14
15#include <asm/hardware.h>
16#include <asm/leds.h>
17#include <asm/system.h>
18
19#include "leds.h"
20
21
22#define LED_STATE_ENABLED 1
23#define LED_STATE_CLAIMED 2
24
25static unsigned int led_state;
26static unsigned int hw_led_state;
27
28#define LED_23 GPIO_GPIO23
29#define LED_MASK (LED_23)
30
31void lart_leds_event(led_event_t evt)
32{
33 unsigned long flags;
34
35 local_irq_save(flags);
36
37 switch(evt) {
38 case led_start:
39 /* pin 23 is output pin */
40 GPDR |= LED_23;
41 hw_led_state = LED_MASK;
42 led_state = LED_STATE_ENABLED;
43 break;
44
45 case led_stop:
46 led_state &= ~LED_STATE_ENABLED;
47 break;
48
49 case led_claim:
50 led_state |= LED_STATE_CLAIMED;
51 hw_led_state = LED_MASK;
52 break;
53
54 case led_release:
55 led_state &= ~LED_STATE_CLAIMED;
56 hw_led_state = LED_MASK;
57 break;
58
59#ifdef CONFIG_LEDS_TIMER
60 case led_timer:
61 if (!(led_state & LED_STATE_CLAIMED))
62 hw_led_state ^= LED_23;
63 break;
64#endif
65
66#ifdef CONFIG_LEDS_CPU
67 case led_idle_start:
68 /* The LART people like the LED to be off when the
69 system is idle... */
70 if (!(led_state & LED_STATE_CLAIMED))
71 hw_led_state &= ~LED_23;
72 break;
73
74 case led_idle_end:
75 /* ... and on if the system is not idle */
76 if (!(led_state & LED_STATE_CLAIMED))
77 hw_led_state |= LED_23;
78 break;
79#endif
80
81 case led_red_on:
82 if (led_state & LED_STATE_CLAIMED)
83 hw_led_state &= ~LED_23;
84 break;
85
86 case led_red_off:
87 if (led_state & LED_STATE_CLAIMED)
88 hw_led_state |= LED_23;
89 break;
90
91 default:
92 break;
93 }
94
95 /* Now set the GPIO state, or nothing will happen at all */
96 if (led_state & LED_STATE_ENABLED) {
97 GPSR = hw_led_state;
98 GPCR = hw_led_state ^ LED_MASK;
99 }
100
101 local_irq_restore(flags);
102}
diff --git a/arch/arm/mach-sa1100/leds-simpad.c b/arch/arm/mach-sa1100/leds-simpad.c
new file mode 100644
index 000000000000..6a27a2d32206
--- /dev/null
+++ b/arch/arm/mach-sa1100/leds-simpad.c
@@ -0,0 +1,101 @@
1/*
2 * linux/arch/arm/mach-sa1100/leds-simpad.c
3 *
4 * Author: Juergen Messerer <juergen.messerer@siemens.ch>
5 */
6#include <linux/config.h>
7#include <linux/init.h>
8
9#include <asm/hardware.h>
10#include <asm/leds.h>
11#include <asm/system.h>
12#include <asm/arch/simpad.h>
13
14#include "leds.h"
15
16
17#define LED_STATE_ENABLED 1
18#define LED_STATE_CLAIMED 2
19
20static unsigned int led_state;
21static unsigned int hw_led_state;
22
23#define LED_GREEN (1)
24#define LED_MASK (1)
25
26extern void set_cs3_bit(int value);
27extern void clear_cs3_bit(int value);
28
29void simpad_leds_event(led_event_t evt)
30{
31 switch (evt)
32 {
33 case led_start:
34 hw_led_state = LED_GREEN;
35 led_state = LED_STATE_ENABLED;
36 break;
37
38 case led_stop:
39 led_state &= ~LED_STATE_ENABLED;
40 break;
41
42 case led_claim:
43 led_state |= LED_STATE_CLAIMED;
44 hw_led_state = LED_GREEN;
45 break;
46
47 case led_release:
48 led_state &= ~LED_STATE_CLAIMED;
49 hw_led_state = LED_GREEN;
50 break;
51
52#ifdef CONFIG_LEDS_TIMER
53 case led_timer:
54 if (!(led_state & LED_STATE_CLAIMED))
55 hw_led_state ^= LED_GREEN;
56 break;
57#endif
58
59#ifdef CONFIG_LEDS_CPU
60 case led_idle_start:
61 break;
62
63 case led_idle_end:
64 break;
65#endif
66
67 case led_halted:
68 break;
69
70 case led_green_on:
71 if (led_state & LED_STATE_CLAIMED)
72 hw_led_state |= LED_GREEN;
73 break;
74
75 case led_green_off:
76 if (led_state & LED_STATE_CLAIMED)
77 hw_led_state &= ~LED_GREEN;
78 break;
79
80 case led_amber_on:
81 break;
82
83 case led_amber_off:
84 break;
85
86 case led_red_on:
87 break;
88
89 case led_red_off:
90 break;
91
92 default:
93 break;
94 }
95
96 if (led_state & LED_STATE_ENABLED)
97 set_cs3_bit(LED2_ON);
98 else
99 clear_cs3_bit(LED2_ON);
100}
101
diff --git a/arch/arm/mach-sa1100/leds.c b/arch/arm/mach-sa1100/leds.c
new file mode 100644
index 000000000000..4cf7c565aaed
--- /dev/null
+++ b/arch/arm/mach-sa1100/leds.c
@@ -0,0 +1,52 @@
1/*
2 * linux/arch/arm/mach-sa1100/leds.c
3 *
4 * SA1100 LEDs dispatcher
5 *
6 * Copyright (C) 2001 Nicolas Pitre
7 */
8#include <linux/compiler.h>
9#include <linux/init.h>
10
11#include <asm/leds.h>
12#include <asm/mach-types.h>
13
14#include "leds.h"
15
16static int __init
17sa1100_leds_init(void)
18{
19 if (machine_is_assabet())
20 leds_event = assabet_leds_event;
21 if (machine_is_consus())
22 leds_event = consus_leds_event;
23 if (machine_is_badge4())
24 leds_event = badge4_leds_event;
25 if (machine_is_brutus())
26 leds_event = brutus_leds_event;
27 if (machine_is_cerf())
28 leds_event = cerf_leds_event;
29 if (machine_is_flexanet())
30 leds_event = flexanet_leds_event;
31 if (machine_is_graphicsclient())
32 leds_event = graphicsclient_leds_event;
33 if (machine_is_hackkit())
34 leds_event = hackkit_leds_event;
35 if (machine_is_lart())
36 leds_event = lart_leds_event;
37 if (machine_is_pfs168())
38 leds_event = pfs168_leds_event;
39 if (machine_is_graphicsmaster())
40 leds_event = graphicsmaster_leds_event;
41 if (machine_is_adsbitsy())
42 leds_event = adsbitsy_leds_event;
43 if (machine_is_pt_system3())
44 leds_event = system3_leds_event;
45 if (machine_is_simpad())
46 leds_event = simpad_leds_event; /* what about machine registry? including led, apm... -zecke */
47
48 leds_event(led_start);
49 return 0;
50}
51
52core_initcall(sa1100_leds_init);
diff --git a/arch/arm/mach-sa1100/leds.h b/arch/arm/mach-sa1100/leds.h
new file mode 100644
index 000000000000..68cc9f773d6d
--- /dev/null
+++ b/arch/arm/mach-sa1100/leds.h
@@ -0,0 +1,14 @@
1extern void assabet_leds_event(led_event_t evt);
2extern void badge4_leds_event(led_event_t evt);
3extern void consus_leds_event(led_event_t evt);
4extern void brutus_leds_event(led_event_t evt);
5extern void cerf_leds_event(led_event_t evt);
6extern void flexanet_leds_event(led_event_t evt);
7extern void graphicsclient_leds_event(led_event_t evt);
8extern void hackkit_leds_event(led_event_t evt);
9extern void lart_leds_event(led_event_t evt);
10extern void pfs168_leds_event(led_event_t evt);
11extern void graphicsmaster_leds_event(led_event_t evt);
12extern void adsbitsy_leds_event(led_event_t evt);
13extern void system3_leds_event(led_event_t evt);
14extern void simpad_leds_event(led_event_t evt);
diff --git a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c
new file mode 100644
index 000000000000..1405383463ea
--- /dev/null
+++ b/arch/arm/mach-sa1100/neponset.c
@@ -0,0 +1,342 @@
1/*
2 * linux/arch/arm/mach-sa1100/neponset.c
3 *
4 */
5#include <linux/kernel.h>
6#include <linux/init.h>
7#include <linux/ptrace.h>
8#include <linux/tty.h>
9#include <linux/ioport.h>
10#include <linux/serial_core.h>
11#include <linux/device.h>
12#include <linux/slab.h>
13
14#include <asm/hardware.h>
15#include <asm/mach-types.h>
16#include <asm/irq.h>
17#include <asm/mach/map.h>
18#include <asm/mach/irq.h>
19#include <asm/mach/serial_sa1100.h>
20#include <asm/arch/assabet.h>
21#include <asm/arch/neponset.h>
22#include <asm/hardware/sa1111.h>
23#include <asm/sizes.h>
24
25/*
26 * Install handler for Neponset IRQ. Note that we have to loop here
27 * since the ETHERNET and USAR IRQs are level based, and we need to
28 * ensure that the IRQ signal is deasserted before returning. This
29 * is rather unfortunate.
30 */
31static void
32neponset_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
33{
34 unsigned int irr;
35
36 while (1) {
37 struct irqdesc *d;
38
39 /*
40 * Acknowledge the parent IRQ.
41 */
42 desc->chip->ack(irq);
43
44 /*
45 * Read the interrupt reason register. Let's have all
46 * active IRQ bits high. Note: there is a typo in the
47 * Neponset user's guide for the SA1111 IRR level.
48 */
49 irr = IRR ^ (IRR_ETHERNET | IRR_USAR);
50
51 if ((irr & (IRR_ETHERNET | IRR_USAR | IRR_SA1111)) == 0)
52 break;
53
54 /*
55 * Since there is no individual mask, we have to
56 * mask the parent IRQ. This is safe, since we'll
57 * recheck the register for any pending IRQs.
58 */
59 if (irr & (IRR_ETHERNET | IRR_USAR)) {
60 desc->chip->mask(irq);
61
62 if (irr & IRR_ETHERNET) {
63 d = irq_desc + IRQ_NEPONSET_SMC9196;
64 d->handle(IRQ_NEPONSET_SMC9196, d, regs);
65 }
66
67 if (irr & IRR_USAR) {
68 d = irq_desc + IRQ_NEPONSET_USAR;
69 d->handle(IRQ_NEPONSET_USAR, d, regs);
70 }
71
72 desc->chip->unmask(irq);
73 }
74
75 if (irr & IRR_SA1111) {
76 d = irq_desc + IRQ_NEPONSET_SA1111;
77 d->handle(IRQ_NEPONSET_SA1111, d, regs);
78 }
79 }
80}
81
82static void neponset_set_mctrl(struct uart_port *port, u_int mctrl)
83{
84 u_int mdm_ctl0 = MDM_CTL_0;
85
86 if (port->mapbase == _Ser1UTCR0) {
87 if (mctrl & TIOCM_RTS)
88 mdm_ctl0 &= ~MDM_CTL0_RTS2;
89 else
90 mdm_ctl0 |= MDM_CTL0_RTS2;
91
92 if (mctrl & TIOCM_DTR)
93 mdm_ctl0 &= ~MDM_CTL0_DTR2;
94 else
95 mdm_ctl0 |= MDM_CTL0_DTR2;
96 } else if (port->mapbase == _Ser3UTCR0) {
97 if (mctrl & TIOCM_RTS)
98 mdm_ctl0 &= ~MDM_CTL0_RTS1;
99 else
100 mdm_ctl0 |= MDM_CTL0_RTS1;
101
102 if (mctrl & TIOCM_DTR)
103 mdm_ctl0 &= ~MDM_CTL0_DTR1;
104 else
105 mdm_ctl0 |= MDM_CTL0_DTR1;
106 }
107
108 MDM_CTL_0 = mdm_ctl0;
109}
110
111static u_int neponset_get_mctrl(struct uart_port *port)
112{
113 u_int ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR;
114 u_int mdm_ctl1 = MDM_CTL_1;
115
116 if (port->mapbase == _Ser1UTCR0) {
117 if (mdm_ctl1 & MDM_CTL1_DCD2)
118 ret &= ~TIOCM_CD;
119 if (mdm_ctl1 & MDM_CTL1_CTS2)
120 ret &= ~TIOCM_CTS;
121 if (mdm_ctl1 & MDM_CTL1_DSR2)
122 ret &= ~TIOCM_DSR;
123 } else if (port->mapbase == _Ser3UTCR0) {
124 if (mdm_ctl1 & MDM_CTL1_DCD1)
125 ret &= ~TIOCM_CD;
126 if (mdm_ctl1 & MDM_CTL1_CTS1)
127 ret &= ~TIOCM_CTS;
128 if (mdm_ctl1 & MDM_CTL1_DSR1)
129 ret &= ~TIOCM_DSR;
130 }
131
132 return ret;
133}
134
135static struct sa1100_port_fns neponset_port_fns __initdata = {
136 .set_mctrl = neponset_set_mctrl,
137 .get_mctrl = neponset_get_mctrl,
138};
139
140static int neponset_probe(struct device *dev)
141{
142 sa1100_register_uart_fns(&neponset_port_fns);
143
144 /*
145 * Install handler for GPIO25.
146 */
147 set_irq_type(IRQ_GPIO25, IRQT_RISING);
148 set_irq_chained_handler(IRQ_GPIO25, neponset_irq_handler);
149
150 /*
151 * We would set IRQ_GPIO25 to be a wake-up IRQ, but
152 * unfortunately something on the Neponset activates
153 * this IRQ on sleep (ethernet?)
154 */
155#if 0
156 enable_irq_wake(IRQ_GPIO25);
157#endif
158
159 /*
160 * Setup other Neponset IRQs. SA1111 will be done by the
161 * generic SA1111 code.
162 */
163 set_irq_handler(IRQ_NEPONSET_SMC9196, do_simple_IRQ);
164 set_irq_flags(IRQ_NEPONSET_SMC9196, IRQF_VALID | IRQF_PROBE);
165 set_irq_handler(IRQ_NEPONSET_USAR, do_simple_IRQ);
166 set_irq_flags(IRQ_NEPONSET_USAR, IRQF_VALID | IRQF_PROBE);
167
168 /*
169 * Disable GPIO 0/1 drivers so the buttons work on the module.
170 */
171 NCR_0 = NCR_GP01_OFF;
172
173 return 0;
174}
175
176#ifdef CONFIG_PM
177
178/*
179 * LDM power management.
180 */
181static int neponset_suspend(struct device *dev, pm_message_t state, u32 level)
182{
183 /*
184 * Save state.
185 */
186 if (level == SUSPEND_SAVE_STATE ||
187 level == SUSPEND_DISABLE ||
188 level == SUSPEND_POWER_DOWN) {
189 if (!dev->power.saved_state)
190 dev->power.saved_state = kmalloc(sizeof(unsigned int), GFP_KERNEL);
191 if (!dev->power.saved_state)
192 return -ENOMEM;
193
194 *(unsigned int *)dev->power.saved_state = NCR_0;
195 }
196
197 return 0;
198}
199
200static int neponset_resume(struct device *dev, u32 level)
201{
202 if (level == RESUME_RESTORE_STATE || level == RESUME_ENABLE) {
203 if (dev->power.saved_state) {
204 NCR_0 = *(unsigned int *)dev->power.saved_state;
205 kfree(dev->power.saved_state);
206 dev->power.saved_state = NULL;
207 }
208 }
209
210 return 0;
211}
212
213#else
214#define neponset_suspend NULL
215#define neponset_resume NULL
216#endif
217
218static struct device_driver neponset_device_driver = {
219 .name = "neponset",
220 .bus = &platform_bus_type,
221 .probe = neponset_probe,
222 .suspend = neponset_suspend,
223 .resume = neponset_resume,
224};
225
226static struct resource neponset_resources[] = {
227 [0] = {
228 .start = 0x10000000,
229 .end = 0x17ffffff,
230 .flags = IORESOURCE_MEM,
231 },
232};
233
234static struct platform_device neponset_device = {
235 .name = "neponset",
236 .id = 0,
237 .num_resources = ARRAY_SIZE(neponset_resources),
238 .resource = neponset_resources,
239};
240
241static struct resource sa1111_resources[] = {
242 [0] = {
243 .start = 0x40000000,
244 .end = 0x40001fff,
245 .flags = IORESOURCE_MEM,
246 },
247 [1] = {
248 .start = IRQ_NEPONSET_SA1111,
249 .end = IRQ_NEPONSET_SA1111,
250 .flags = IORESOURCE_IRQ,
251 },
252};
253
254static u64 sa1111_dmamask = 0xffffffffUL;
255
256static struct platform_device sa1111_device = {
257 .name = "sa1111",
258 .id = 0,
259 .dev = {
260 .dma_mask = &sa1111_dmamask,
261 .coherent_dma_mask = 0xffffffff,
262 },
263 .num_resources = ARRAY_SIZE(sa1111_resources),
264 .resource = sa1111_resources,
265};
266
267static struct resource smc91x_resources[] = {
268 [0] = {
269 .name = "smc91x-regs",
270 .start = SA1100_CS3_PHYS,
271 .end = SA1100_CS3_PHYS + 0x01ffffff,
272 .flags = IORESOURCE_MEM,
273 },
274 [1] = {
275 .start = IRQ_NEPONSET_SMC9196,
276 .end = IRQ_NEPONSET_SMC9196,
277 .flags = IORESOURCE_IRQ,
278 },
279 [2] = {
280 .name = "smc91x-attrib",
281 .start = SA1100_CS3_PHYS + 0x02000000,
282 .end = SA1100_CS3_PHYS + 0x03ffffff,
283 .flags = IORESOURCE_MEM,
284 },
285};
286
287static struct platform_device smc91x_device = {
288 .name = "smc91x",
289 .id = 0,
290 .num_resources = ARRAY_SIZE(smc91x_resources),
291 .resource = smc91x_resources,
292};
293
294static struct platform_device *devices[] __initdata = {
295 &neponset_device,
296 &sa1111_device,
297 &smc91x_device,
298};
299
300static int __init neponset_init(void)
301{
302 driver_register(&neponset_device_driver);
303
304 /*
305 * The Neponset is only present on the Assabet machine type.
306 */
307 if (!machine_is_assabet())
308 return -ENODEV;
309
310 /*
311 * Ensure that the memory bus request/grant signals are setup,
312 * and the grant is held in its inactive state, whether or not
313 * we actually have a Neponset attached.
314 */
315 sa1110_mb_disable();
316
317 if (!machine_has_neponset()) {
318 printk(KERN_DEBUG "Neponset expansion board not present\n");
319 return -ENODEV;
320 }
321
322 if (WHOAMI != 0x11) {
323 printk(KERN_WARNING "Neponset board detected, but "
324 "wrong ID: %02x\n", WHOAMI);
325 return -ENODEV;
326 }
327
328 return platform_add_devices(devices, ARRAY_SIZE(devices));
329}
330
331subsys_initcall(neponset_init);
332
333static struct map_desc neponset_io_desc[] __initdata = {
334 /* virtual physical length type */
335 { 0xf3000000, 0x10000000, SZ_1M, MT_DEVICE }, /* System Registers */
336 { 0xf4000000, 0x40000000, SZ_1M, MT_DEVICE } /* SA-1111 */
337};
338
339void __init neponset_map_io(void)
340{
341 iotable_init(neponset_io_desc, ARRAY_SIZE(neponset_io_desc));
342}
diff --git a/arch/arm/mach-sa1100/pleb.c b/arch/arm/mach-sa1100/pleb.c
new file mode 100644
index 000000000000..5606bd71b024
--- /dev/null
+++ b/arch/arm/mach-sa1100/pleb.c
@@ -0,0 +1,154 @@
1/*
2 * linux/arch/arm/mach-sa1100/pleb.c
3 */
4
5#include <linux/init.h>
6#include <linux/kernel.h>
7#include <linux/tty.h>
8#include <linux/ioport.h>
9#include <linux/device.h>
10
11#include <linux/mtd/partitions.h>
12
13#include <asm/hardware.h>
14#include <asm/io.h>
15#include <asm/setup.h>
16#include <asm/mach-types.h>
17
18#include <asm/mach/arch.h>
19#include <asm/mach/map.h>
20#include <asm/mach/flash.h>
21#include <asm/mach/serial_sa1100.h>
22#include <asm/arch/irqs.h>
23
24#include "generic.h"
25
26
27/*
28 * Ethernet IRQ mappings
29 */
30
31#define PLEB_ETH0_P (0x20000300) /* Ethernet 0 in PCMCIA0 IO */
32#define PLEB_ETH0_V (0xf6000300)
33
34#define GPIO_ETH0_IRQ GPIO_GPIO(21)
35#define GPIO_ETH0_EN GPIO_GPIO(26)
36
37#define IRQ_GPIO_ETH0_IRQ IRQ_GPIO21
38
39static struct resource smc91x_resources[] = {
40 [0] = {
41 .start = PLEB_ETH0_P,
42 .end = PLEB_ETH0_P | 0x03ffffff,
43 .flags = IORESOURCE_MEM,
44 },
45#if 0 /* Autoprobe instead, to get rising/falling edge characteristic right */
46 [1] = {
47 .start = IRQ_GPIO_ETH0_IRQ,
48 .end = IRQ_GPIO_ETH0_IRQ,
49 .flags = IORESOURCE_IRQ,
50 },
51#endif
52};
53
54
55static struct platform_device smc91x_device = {
56 .name = "smc91x",
57 .id = 0,
58 .num_resources = ARRAY_SIZE(smc91x_resources),
59 .resource = smc91x_resources,
60};
61
62static struct platform_device *devices[] __initdata = {
63 &smc91x_device,
64};
65
66
67/*
68 * Pleb's memory map
69 * has flash memory (typically 4 or 8 meg) selected by
70 * the two SA1100 lowest chip select outputs.
71 */
72static struct resource pleb_flash_resources[] = {
73 [0] = {
74 .start = SA1100_CS0_PHYS,
75 .end = SA1100_CS0_PHYS + SZ_8M - 1,
76 .flags = IORESOURCE_MEM,
77 },
78 [1] = {
79 .start = SA1100_CS1_PHYS,
80 .end = SA1100_CS1_PHYS + SZ_8M - 1,
81 .flags = IORESOURCE_MEM,
82 }
83};
84
85
86static struct mtd_partition pleb_partitions[] = {
87 {
88 .name = "blob",
89 .offset = 0,
90 .size = 0x00020000,
91 }, {
92 .name = "kernel",
93 .offset = MTDPART_OFS_APPEND,
94 .size = 0x000e0000,
95 }, {
96 .name = "rootfs",
97 .offset = MTDPART_OFS_APPEND,
98 .size = 0x00300000,
99 }
100};
101
102
103static struct flash_platform_data pleb_flash_data = {
104 .map_name = "cfi_probe",
105 .parts = pleb_partitions,
106 .nr_parts = ARRAY_SIZE(pleb_partitions),
107};
108
109
110static void __init pleb_init(void)
111{
112 sa11x0_set_flash_data(&pleb_flash_data, pleb_flash_resources,
113 ARRAY_SIZE(pleb_flash_resources));
114
115
116 platform_add_devices(devices, ARRAY_SIZE(devices));
117}
118
119
120static void __init pleb_map_io(void)
121{
122 sa1100_map_io();
123
124 sa1100_register_uart(0, 3);
125 sa1100_register_uart(1, 1);
126
127 GAFR |= (GPIO_UART_TXD | GPIO_UART_RXD);
128 GPDR |= GPIO_UART_TXD;
129 GPDR &= ~GPIO_UART_RXD;
130 PPAR |= PPAR_UPR;
131
132 /*
133 * Fix expansion memory timing for network card
134 */
135 MECR = ((2<<10) | (2<<5) | (2<<0));
136
137 /*
138 * Enable the SMC ethernet controller
139 */
140 GPDR |= GPIO_ETH0_EN; /* set to output */
141 GPCR = GPIO_ETH0_EN; /* clear MCLK (enable smc) */
142
143 GPDR &= ~GPIO_ETH0_IRQ;
144
145 set_irq_type(GPIO_ETH0_IRQ, IRQT_FALLING);
146}
147
148MACHINE_START(PLEB, "PLEB")
149 BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
150 MAPIO(pleb_map_io)
151 INITIRQ(sa1100_init_irq)
152 .timer = &sa1100_timer,
153 .init_machine = pleb_init,
154MACHINE_END
diff --git a/arch/arm/mach-sa1100/pm.c b/arch/arm/mach-sa1100/pm.c
new file mode 100644
index 000000000000..379ea5e3950f
--- /dev/null
+++ b/arch/arm/mach-sa1100/pm.c
@@ -0,0 +1,167 @@
1/*
2 * SA1100 Power Management Routines
3 *
4 * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License.
8 *
9 * History:
10 *
11 * 2001-02-06: Cliff Brake Initial code
12 *
13 * 2001-02-25: Sukjae Cho <sjcho@east.isi.edu> &
14 * Chester Kuo <chester@linux.org.tw>
15 * Save more value for the resume function! Support
16 * Bitsy/Assabet/Freebird board
17 *
18 * 2001-08-29: Nicolas Pitre <nico@cam.org>
19 * Cleaned up, pushed platform dependent stuff
20 * in the platform specific files.
21 *
22 * 2002-05-27: Nicolas Pitre Killed sleep.h and the kmalloced save array.
23 * Storage is local on the stack now.
24 */
25#include <linux/init.h>
26#include <linux/suspend.h>
27#include <linux/errno.h>
28#include <linux/time.h>
29
30#include <asm/hardware.h>
31#include <asm/memory.h>
32#include <asm/system.h>
33#include <asm/mach/time.h>
34
35extern void sa1100_cpu_suspend(void);
36extern void sa1100_cpu_resume(void);
37
38#define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x
39#define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x]
40
41/*
42 * List of global SA11x0 peripheral registers to preserve.
43 * More ones like CP and general purpose register values are preserved
44 * on the stack and then the stack pointer is stored last in sleep.S.
45 */
46enum { SLEEP_SAVE_SP = 0,
47
48 SLEEP_SAVE_GPDR, SLEEP_SAVE_GAFR,
49 SLEEP_SAVE_PPDR, SLEEP_SAVE_PPSR, SLEEP_SAVE_PPAR, SLEEP_SAVE_PSDR,
50
51 SLEEP_SAVE_Ser1SDCR0,
52
53 SLEEP_SAVE_SIZE
54};
55
56
57static int sa11x0_pm_enter(suspend_state_t state)
58{
59 unsigned long gpio, sleep_save[SLEEP_SAVE_SIZE];
60 struct timespec delta, rtc;
61
62 if (state != PM_SUSPEND_MEM)
63 return -EINVAL;
64
65 /* preserve current time */
66 rtc.tv_sec = RCNR;
67 rtc.tv_nsec = 0;
68 save_time_delta(&delta, &rtc);
69 gpio = GPLR;
70
71 /* save vital registers */
72 SAVE(GPDR);
73 SAVE(GAFR);
74
75 SAVE(PPDR);
76 SAVE(PPSR);
77 SAVE(PPAR);
78 SAVE(PSDR);
79
80 SAVE(Ser1SDCR0);
81
82 /* Clear previous reset status */
83 RCSR = RCSR_HWR | RCSR_SWR | RCSR_WDR | RCSR_SMR;
84
85 /* set resume return address */
86 PSPR = virt_to_phys(sa1100_cpu_resume);
87
88 /* go zzz */
89 sa1100_cpu_suspend();
90
91 /*
92 * Ensure not to come back here if it wasn't intended
93 */
94 PSPR = 0;
95
96 /*
97 * Ensure interrupt sources are disabled; we will re-init
98 * the interrupt subsystem via the device manager.
99 */
100 ICLR = 0;
101 ICCR = 1;
102 ICMR = 0;
103
104 /* restore registers */
105 RESTORE(GPDR);
106 RESTORE(GAFR);
107
108 RESTORE(PPDR);
109 RESTORE(PPSR);
110 RESTORE(PPAR);
111 RESTORE(PSDR);
112
113 RESTORE(Ser1SDCR0);
114
115 GPSR = gpio;
116 GPCR = ~gpio;
117
118 /*
119 * Clear the peripheral sleep-hold bit.
120 */
121 PSSR = PSSR_PH;
122
123 /* restore current time */
124 rtc.tv_sec = RCNR;
125 restore_time_delta(&delta, &rtc);
126
127 return 0;
128}
129
130unsigned long sleep_phys_sp(void *sp)
131{
132 return virt_to_phys(sp);
133}
134
135/*
136 * Called after processes are frozen, but before we shut down devices.
137 */
138static int sa11x0_pm_prepare(suspend_state_t state)
139{
140 return 0;
141}
142
143/*
144 * Called after devices are re-setup, but before processes are thawed.
145 */
146static int sa11x0_pm_finish(suspend_state_t state)
147{
148 return 0;
149}
150
151/*
152 * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk.
153 */
154static struct pm_ops sa11x0_pm_ops = {
155 .pm_disk_mode = PM_DISK_FIRMWARE,
156 .prepare = sa11x0_pm_prepare,
157 .enter = sa11x0_pm_enter,
158 .finish = sa11x0_pm_finish,
159};
160
161static int __init sa11x0_pm_init(void)
162{
163 pm_set_ops(&sa11x0_pm_ops);
164 return 0;
165}
166
167late_initcall(sa11x0_pm_init);
diff --git a/arch/arm/mach-sa1100/shannon.c b/arch/arm/mach-sa1100/shannon.c
new file mode 100644
index 000000000000..edddd559be02
--- /dev/null
+++ b/arch/arm/mach-sa1100/shannon.c
@@ -0,0 +1,85 @@
1/*
2 * linux/arch/arm/mach-sa1100/shannon.c
3 */
4
5#include <linux/config.h>
6#include <linux/init.h>
7#include <linux/device.h>
8#include <linux/kernel.h>
9#include <linux/tty.h>
10#include <linux/mtd/mtd.h>
11#include <linux/mtd/partitions.h>
12
13#include <asm/hardware.h>
14#include <asm/mach-types.h>
15#include <asm/setup.h>
16
17#include <asm/mach/arch.h>
18#include <asm/mach/flash.h>
19#include <asm/mach/map.h>
20#include <asm/mach/serial_sa1100.h>
21#include <asm/arch/shannon.h>
22
23#include "generic.h"
24
25static struct mtd_partition shannon_partitions[] = {
26 {
27 .name = "BLOB boot loader",
28 .offset = 0,
29 .size = 0x20000
30 },
31 {
32 .name = "kernel",
33 .offset = MTDPART_OFS_APPEND,
34 .size = 0xe0000
35 },
36 {
37 .name = "initrd",
38 .offset = MTDPART_OFS_APPEND,
39 .size = MTDPART_SIZ_FULL
40 }
41};
42
43static struct flash_platform_data shannon_flash_data = {
44 .map_name = "cfi_probe",
45 .parts = shannon_partitions,
46 .nr_parts = ARRAY_SIZE(shannon_partitions),
47};
48
49static struct resource shannon_flash_resource = {
50 .start = SA1100_CS0_PHYS,
51 .end = SA1100_CS0_PHYS + SZ_4M - 1,
52 .flags = IORESOURCE_MEM,
53};
54
55static void __init shannon_init(void)
56{
57 sa11x0_set_flash_data(&shannon_flash_data, &shannon_flash_resource, 1);
58}
59
60static void __init shannon_map_io(void)
61{
62 sa1100_map_io();
63
64 sa1100_register_uart(0, 3);
65 sa1100_register_uart(1, 1);
66
67 Ser1SDCR0 |= SDCR0_SUS;
68 GAFR |= (GPIO_UART_TXD | GPIO_UART_RXD);
69 GPDR |= GPIO_UART_TXD | SHANNON_GPIO_CODEC_RESET;
70 GPDR &= ~GPIO_UART_RXD;
71 PPAR |= PPAR_UPR;
72
73 /* reset the codec */
74 GPCR = SHANNON_GPIO_CODEC_RESET;
75 GPSR = SHANNON_GPIO_CODEC_RESET;
76}
77
78MACHINE_START(SHANNON, "Shannon (AKA: Tuxscreen)")
79 BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
80 BOOT_PARAMS(0xc0000100)
81 MAPIO(shannon_map_io)
82 INITIRQ(sa1100_init_irq)
83 .timer = &sa1100_timer,
84 .init_machine = shannon_init,
85MACHINE_END
diff --git a/arch/arm/mach-sa1100/simpad.c b/arch/arm/mach-sa1100/simpad.c
new file mode 100644
index 000000000000..8d113d629867
--- /dev/null
+++ b/arch/arm/mach-sa1100/simpad.c
@@ -0,0 +1,224 @@
1/*
2 * linux/arch/arm/mach-sa1100/simpad.c
3 */
4
5#include <linux/config.h>
6#include <linux/module.h>
7#include <linux/init.h>
8#include <linux/kernel.h>
9#include <linux/tty.h>
10#include <linux/proc_fs.h>
11#include <linux/string.h>
12#include <linux/pm.h>
13#include <linux/device.h>
14#include <linux/mtd/mtd.h>
15#include <linux/mtd/partitions.h>
16
17#include <asm/irq.h>
18#include <asm/hardware.h>
19#include <asm/setup.h>
20
21#include <asm/mach-types.h>
22#include <asm/mach/arch.h>
23#include <asm/mach/flash.h>
24#include <asm/mach/map.h>
25#include <asm/mach/serial_sa1100.h>
26#include <asm/arch/simpad.h>
27
28#include <linux/serial_core.h>
29#include <linux/ioport.h>
30#include <asm/io.h>
31
32#include "generic.h"
33
34long cs3_shadow;
35
36long get_cs3_shadow(void)
37{
38 return cs3_shadow;
39}
40
41void set_cs3(long value)
42{
43 *(CS3BUSTYPE *)(CS3_BASE) = cs3_shadow = value;
44}
45
46void set_cs3_bit(int value)
47{
48 cs3_shadow |= value;
49 *(CS3BUSTYPE *)(CS3_BASE) = cs3_shadow;
50}
51
52void clear_cs3_bit(int value)
53{
54 cs3_shadow &= ~value;
55 *(CS3BUSTYPE *)(CS3_BASE) = cs3_shadow;
56}
57
58EXPORT_SYMBOL(set_cs3_bit);
59EXPORT_SYMBOL(clear_cs3_bit);
60
61static struct map_desc simpad_io_desc[] __initdata = {
62 /* virtual physical length type */
63 /* MQ200 */
64 { 0xf2800000, 0x4b800000, 0x00800000, MT_DEVICE },
65 /* Paules CS3, write only */
66 { 0xf1000000, 0x18000000, 0x00100000, MT_DEVICE },
67};
68
69
70static void simpad_uart_pm(struct uart_port *port, u_int state, u_int oldstate)
71{
72 if (port->mapbase == (u_int)&Ser1UTCR0) {
73 if (state)
74 {
75 clear_cs3_bit(RS232_ON);
76 clear_cs3_bit(DECT_POWER_ON);
77 }else
78 {
79 set_cs3_bit(RS232_ON);
80 set_cs3_bit(DECT_POWER_ON);
81 }
82 }
83}
84
85static struct sa1100_port_fns simpad_port_fns __initdata = {
86 .pm = simpad_uart_pm,
87};
88
89
90static struct mtd_partition simpad_partitions[] = {
91 {
92 .name = "SIMpad boot firmware",
93 .size = 0x00080000,
94 .offset = 0,
95 .mask_flags = MTD_WRITEABLE,
96 }, {
97 .name = "SIMpad kernel",
98 .size = 0x0010000,
99 .offset = MTDPART_OFS_APPEND,
100 }, {
101 .name = "SIMpad root jffs2",
102 .size = MTDPART_SIZ_FULL,
103 .offset = MTDPART_OFS_APPEND,
104 }
105};
106
107static struct flash_platform_data simpad_flash_data = {
108 .map_name = "cfi_probe",
109 .parts = simpad_partitions,
110 .nr_parts = ARRAY_SIZE(simpad_partitions),
111};
112
113
114static struct resource simpad_flash_resources [] = {
115 {
116 .start = SA1100_CS0_PHYS,
117 .end = SA1100_CS0_PHYS + SZ_16M -1,
118 .flags = IORESOURCE_MEM,
119 }, {
120 .start = SA1100_CS1_PHYS,
121 .end = SA1100_CS1_PHYS + SZ_16M -1,
122 .flags = IORESOURCE_MEM,
123 }
124};
125
126
127
128static void __init simpad_map_io(void)
129{
130 sa1100_map_io();
131
132 iotable_init(simpad_io_desc, ARRAY_SIZE(simpad_io_desc));
133
134 set_cs3_bit (EN1 | EN0 | LED2_ON | DISPLAY_ON | RS232_ON |
135 ENABLE_5V | RESET_SIMCARD | DECT_POWER_ON);
136
137
138 sa1100_register_uart_fns(&simpad_port_fns);
139 sa1100_register_uart(0, 3); /* serial interface */
140 sa1100_register_uart(1, 1); /* DECT */
141
142 // Reassign UART 1 pins
143 GAFR |= GPIO_UART_TXD | GPIO_UART_RXD;
144 GPDR |= GPIO_UART_TXD | GPIO_LDD13 | GPIO_LDD15;
145 GPDR &= ~GPIO_UART_RXD;
146 PPAR |= PPAR_UPR;
147
148 /*
149 * Set up registers for sleep mode.
150 */
151
152
153 PWER = PWER_GPIO0| PWER_RTC;
154 PGSR = 0x818;
155 PCFR = 0;
156 PSDR = 0;
157
158 sa11x0_set_flash_data(&simpad_flash_data, simpad_flash_resources,
159 ARRAY_SIZE(simpad_flash_resources));
160}
161
162static void simpad_power_off(void)
163{
164 local_irq_disable(); // was cli
165 set_cs3(0x800); /* only SD_MEDIAQ */
166
167 /* disable internal oscillator, float CS lines */
168 PCFR = (PCFR_OPDE | PCFR_FP | PCFR_FS);
169 /* enable wake-up on GPIO0 (Assabet...) */
170 PWER = GFER = GRER = 1;
171 /*
172 * set scratchpad to zero, just in case it is used as a
173 * restart address by the bootloader.
174 */
175 PSPR = 0;
176 PGSR = 0;
177 /* enter sleep mode */
178 PMCR = PMCR_SF;
179 while(1);
180
181 local_irq_enable(); /* we won't ever call it */
182
183
184}
185
186
187/*
188 * MediaQ Video Device
189 */
190static struct platform_device simpad_mq200fb = {
191 .name = "simpad-mq200",
192 .id = 0,
193};
194
195static struct platform_device *devices[] __initdata = {
196 &simpad_mq200fb
197};
198
199
200
201static int __init simpad_init(void)
202{
203 int ret;
204
205 pm_power_off = simpad_power_off;
206
207 ret = platform_add_devices(devices, ARRAY_SIZE(devices));
208 if(ret)
209 printk(KERN_WARNING "simpad: Unable to register mq200 framebuffer device");
210
211 return 0;
212}
213
214arch_initcall(simpad_init);
215
216
217MACHINE_START(SIMPAD, "Simpad")
218 MAINTAINER("Holger Freyther")
219 BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
220 BOOT_PARAMS(0xc0000100)
221 MAPIO(simpad_map_io)
222 INITIRQ(sa1100_init_irq)
223 .timer = &sa1100_timer,
224MACHINE_END
diff --git a/arch/arm/mach-sa1100/sleep.S b/arch/arm/mach-sa1100/sleep.S
new file mode 100644
index 000000000000..2fa1e289d177
--- /dev/null
+++ b/arch/arm/mach-sa1100/sleep.S
@@ -0,0 +1,215 @@
1/*
2 * SA11x0 Assembler Sleep/WakeUp Management Routines
3 *
4 * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License.
8 *
9 * History:
10 *
11 * 2001-02-06: Cliff Brake Initial code
12 *
13 * 2001-08-29: Nicolas Pitre Simplified.
14 *
15 * 2002-05-27: Nicolas Pitre Revisited, more cleanup and simplification.
16 * Storage is on the stack now.
17 */
18
19#include <linux/linkage.h>
20#include <asm/assembler.h>
21#include <asm/hardware.h>
22
23
24
25 .text
26
27
28
29/*
30 * sa1100_cpu_suspend()
31 *
32 * Causes sa11x0 to enter sleep state
33 *
34 */
35
36ENTRY(sa1100_cpu_suspend)
37
38 stmfd sp!, {r4 - r12, lr} @ save registers on stack
39
40 @ get coprocessor registers
41 mrc p15, 0, r4, c3, c0, 0 @ domain ID
42 mrc p15, 0, r5, c2, c0, 0 @ translation table base addr
43 mrc p15, 0, r6, c13, c0, 0 @ PID
44 mrc p15, 0, r7, c1, c0, 0 @ control reg
45
46 @ store them plus current virtual stack ptr on stack
47 mov r8, sp
48 stmfd sp!, {r4 - r8}
49
50 @ preserve phys address of stack
51 mov r0, sp
52 bl sleep_phys_sp
53 ldr r1, =sleep_save_sp
54 str r0, [r1]
55
56 @ clean data cache and invalidate WB
57 bl v4wb_flush_kern_cache_all
58
59 @ disable clock switching
60 mcr p15, 0, r1, c15, c2, 2
61
62 @ Adjust memory timing before lowering CPU clock
63 @ Clock speed adjustment without changing memory timing makes
64 @ CPU hang in some cases
65 ldr r0, =MDREFR
66 ldr r1, [r0]
67 orr r1, r1, #MDREFR_K1DB2
68 str r1, [r0]
69
70 @ delay 90us and set CPU PLL to lowest speed
71 @ fixes resume problem on high speed SA1110
72 mov r0, #90
73 bl __udelay
74 ldr r0, =PPCR
75 mov r1, #0
76 str r1, [r0]
77 mov r0, #90
78 bl __udelay
79
80 /*
81 * SA1110 SDRAM controller workaround. register values:
82 *
83 * r0 = &MSC0
84 * r1 = &MSC1
85 * r2 = &MSC2
86 * r3 = MSC0 value
87 * r4 = MSC1 value
88 * r5 = MSC2 value
89 * r6 = &MDREFR
90 * r7 = first MDREFR value
91 * r8 = second MDREFR value
92 * r9 = &MDCNFG
93 * r10 = MDCNFG value
94 * r11 = third MDREFR value
95 * r12 = &PMCR
96 * r13 = PMCR value (1)
97 */
98
99 ldr r0, =MSC0
100 ldr r1, =MSC1
101 ldr r2, =MSC2
102
103 ldr r3, [r0]
104 bic r3, r3, #FMsk(MSC_RT)
105 bic r3, r3, #FMsk(MSC_RT)<<16
106
107 ldr r4, [r1]
108 bic r4, r4, #FMsk(MSC_RT)
109 bic r4, r4, #FMsk(MSC_RT)<<16
110
111 ldr r5, [r2]
112 bic r5, r5, #FMsk(MSC_RT)
113 bic r5, r5, #FMsk(MSC_RT)<<16
114
115 ldr r6, =MDREFR
116
117 ldr r7, [r6]
118 bic r7, r7, #0x0000FF00
119 bic r7, r7, #0x000000F0
120 orr r8, r7, #MDREFR_SLFRSH
121
122 ldr r9, =MDCNFG
123 ldr r10, [r9]
124 bic r10, r10, #(MDCNFG_DE0+MDCNFG_DE1)
125 bic r10, r10, #(MDCNFG_DE2+MDCNFG_DE3)
126
127 bic r11, r8, #MDREFR_SLFRSH
128 bic r11, r11, #MDREFR_E1PIN
129
130 ldr r12, =PMCR
131
132 mov r13, #PMCR_SF
133
134 b sa1110_sdram_controller_fix
135
136 .align 5
137sa1110_sdram_controller_fix:
138
139 @ Step 1 clear RT field of all MSCx registers
140 str r3, [r0]
141 str r4, [r1]
142 str r5, [r2]
143
144 @ Step 2 clear DRI field in MDREFR
145 str r7, [r6]
146
147 @ Step 3 set SLFRSH bit in MDREFR
148 str r8, [r6]
149
150 @ Step 4 clear DE bis in MDCNFG
151 str r10, [r9]
152
153 @ Step 5 clear DRAM refresh control register
154 str r11, [r6]
155
156 @ Wow, now the hardware suspend request pins can be used, that makes them functional for
157 @ about 7 ns out of the entire time that the CPU is running!
158
159 @ Step 6 set force sleep bit in PMCR
160
161 str r13, [r12]
162
16320: b 20b @ loop waiting for sleep
164
165/*
166 * cpu_sa1100_resume()
167 *
168 * entry point from bootloader into kernel during resume
169 *
170 * Note: Yes, part of the following code is located into the .data section.
171 * This is to allow sleep_save_sp to be accessed with a relative load
172 * while we can't rely on any MMU translation. We could have put
173 * sleep_save_sp in the .text section as well, but some setups might
174 * insist on it to be truly read-only.
175 */
176
177 .data
178 .align 5
179ENTRY(sa1100_cpu_resume)
180 mov r0, #PSR_F_BIT | PSR_I_BIT | MODE_SVC
181 msr cpsr_c, r0 @ set SVC, irqs off
182
183 ldr r0, sleep_save_sp @ stack phys addr
184 ldr r2, =resume_after_mmu @ its absolute virtual address
185 ldmfd r0, {r4 - r7, sp} @ CP regs + virt stack ptr
186
187 mov r1, #0
188 mcr p15, 0, r1, c8, c7, 0 @ flush I+D TLBs
189 mcr p15, 0, r1, c7, c7, 0 @ flush I&D cache
190 mcr p15, 0, r1, c9, c0, 0 @ invalidate RB
191 mcr p15, 0, r1, c9, c0, 5 @ allow user space to use RB
192
193 mcr p15, 0, r4, c3, c0, 0 @ domain ID
194 mcr p15, 0, r5, c2, c0, 0 @ translation table base addr
195 mcr p15, 0, r6, c13, c0, 0 @ PID
196 b resume_turn_on_mmu @ cache align execution
197
198 .align 5
199resume_turn_on_mmu:
200 mcr p15, 0, r7, c1, c0, 0 @ turn on MMU, caches, etc.
201 nop
202 mov pc, r2 @ jump to virtual addr
203 nop
204 nop
205 nop
206
207sleep_save_sp:
208 .word 0 @ preserve stack phys ptr here
209
210 .text
211resume_after_mmu:
212 mcr p15, 0, r1, c15, c1, 2 @ enable clock switching
213 ldmfd sp!, {r4 - r12, pc} @ return to caller
214
215
diff --git a/arch/arm/mach-sa1100/ssp.c b/arch/arm/mach-sa1100/ssp.c
new file mode 100644
index 000000000000..1604dadf27fc
--- /dev/null
+++ b/arch/arm/mach-sa1100/ssp.c
@@ -0,0 +1,214 @@
1/*
2 * linux/arch/arm/mach-sa1100/ssp.c
3 *
4 * Copyright (C) 2003 Russell King.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * Generic SSP driver. This provides the generic core for simple
11 * IO-based SSP applications.
12 */
13#include <linux/module.h>
14#include <linux/kernel.h>
15#include <linux/sched.h>
16#include <linux/errno.h>
17#include <linux/interrupt.h>
18#include <linux/ioport.h>
19#include <linux/init.h>
20
21#include <asm/io.h>
22#include <asm/irq.h>
23#include <asm/hardware.h>
24#include <asm/hardware/ssp.h>
25
26static irqreturn_t ssp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
27{
28 unsigned int status = Ser4SSSR;
29
30 if (status & SSSR_ROR) {
31 printk(KERN_WARNING "SSP: receiver overrun\n");
32 }
33
34 Ser4SSSR = SSSR_ROR;
35
36 return status ? IRQ_HANDLED : IRQ_NONE;
37}
38
39/**
40 * ssp_write_word - write a word to the SSP port
41 * @data: 16-bit, MSB justified data to write.
42 *
43 * Wait for a free entry in the SSP transmit FIFO, and write a data
44 * word to the SSP port. Wait for the SSP port to start sending
45 * the data.
46 *
47 * The caller is expected to perform the necessary locking.
48 *
49 * Returns:
50 * %-ETIMEDOUT timeout occurred (for future)
51 * 0 success
52 */
53int ssp_write_word(u16 data)
54{
55 while (!(Ser4SSSR & SSSR_TNF))
56 cpu_relax();
57
58 Ser4SSDR = data;
59
60 while (!(Ser4SSSR & SSSR_BSY))
61 cpu_relax();
62
63 return 0;
64}
65
66/**
67 * ssp_read_word - read a word from the SSP port
68 *
69 * Wait for a data word in the SSP receive FIFO, and return the
70 * received data. Data is LSB justified.
71 *
72 * Note: Currently, if data is not expected to be received, this
73 * function will wait for ever.
74 *
75 * The caller is expected to perform the necessary locking.
76 *
77 * Returns:
78 * %-ETIMEDOUT timeout occurred (for future)
79 * 16-bit data success
80 */
81int ssp_read_word(void)
82{
83 while (!(Ser4SSSR & SSSR_RNE))
84 cpu_relax();
85
86 return Ser4SSDR;
87}
88
89/**
90 * ssp_flush - flush the transmit and receive FIFOs
91 *
92 * Wait for the SSP to idle, and ensure that the receive FIFO
93 * is empty.
94 *
95 * The caller is expected to perform the necessary locking.
96 */
97void ssp_flush(void)
98{
99 do {
100 while (Ser4SSSR & SSSR_RNE) {
101 (void) Ser4SSDR;
102 }
103 } while (Ser4SSSR & SSSR_BSY);
104}
105
106/**
107 * ssp_enable - enable the SSP port
108 *
109 * Turn on the SSP port.
110 */
111void ssp_enable(void)
112{
113 Ser4SSCR0 |= SSCR0_SSE;
114}
115
116/**
117 * ssp_disable - shut down the SSP port
118 *
119 * Turn off the SSP port, optionally powering it down.
120 */
121void ssp_disable(void)
122{
123 Ser4SSCR0 &= ~SSCR0_SSE;
124}
125
126/**
127 * ssp_save_state - save the SSP configuration
128 * @ssp: pointer to structure to save SSP configuration
129 *
130 * Save the configured SSP state for suspend.
131 */
132void ssp_save_state(struct ssp_state *ssp)
133{
134 ssp->cr0 = Ser4SSCR0;
135 ssp->cr1 = Ser4SSCR1;
136
137 Ser4SSCR0 &= ~SSCR0_SSE;
138}
139
140/**
141 * ssp_restore_state - restore a previously saved SSP configuration
142 * @ssp: pointer to configuration saved by ssp_save_state
143 *
144 * Restore the SSP configuration saved previously by ssp_save_state.
145 */
146void ssp_restore_state(struct ssp_state *ssp)
147{
148 Ser4SSSR = SSSR_ROR;
149
150 Ser4SSCR0 = ssp->cr0 & ~SSCR0_SSE;
151 Ser4SSCR1 = ssp->cr1;
152 Ser4SSCR0 = ssp->cr0;
153}
154
155/**
156 * ssp_init - setup the SSP port
157 *
158 * initialise and claim resources for the SSP port.
159 *
160 * Returns:
161 * %-ENODEV if the SSP port is unavailable
162 * %-EBUSY if the resources are already in use
163 * %0 on success
164 */
165int ssp_init(void)
166{
167 int ret;
168
169 if (!(PPAR & PPAR_SPR) && (Ser4MCCR0 & MCCR0_MCE))
170 return -ENODEV;
171
172 if (!request_mem_region(__PREG(Ser4SSCR0), 0x18, "SSP")) {
173 return -EBUSY;
174 }
175
176 Ser4SSSR = SSSR_ROR;
177
178 ret = request_irq(IRQ_Ser4SSP, ssp_interrupt, 0, "SSP", NULL);
179 if (ret)
180 goto out_region;
181
182 return 0;
183
184 out_region:
185 release_mem_region(__PREG(Ser4SSCR0), 0x18);
186 return ret;
187}
188
189/**
190 * ssp_exit - undo the effects of ssp_init
191 *
192 * release and free resources for the SSP port.
193 */
194void ssp_exit(void)
195{
196 Ser4SSCR0 &= ~SSCR0_SSE;
197
198 free_irq(IRQ_Ser4SSP, NULL);
199 release_mem_region(__PREG(Ser4SSCR0), 0x18);
200}
201
202MODULE_AUTHOR("Russell King");
203MODULE_DESCRIPTION("SA11x0 SSP PIO driver");
204MODULE_LICENSE("GPL");
205
206EXPORT_SYMBOL(ssp_write_word);
207EXPORT_SYMBOL(ssp_read_word);
208EXPORT_SYMBOL(ssp_flush);
209EXPORT_SYMBOL(ssp_enable);
210EXPORT_SYMBOL(ssp_disable);
211EXPORT_SYMBOL(ssp_save_state);
212EXPORT_SYMBOL(ssp_restore_state);
213EXPORT_SYMBOL(ssp_init);
214EXPORT_SYMBOL(ssp_exit);
diff --git a/arch/arm/mach-sa1100/time.c b/arch/arm/mach-sa1100/time.c
new file mode 100644
index 000000000000..19b0c0fd6377
--- /dev/null
+++ b/arch/arm/mach-sa1100/time.c
@@ -0,0 +1,159 @@
1/*
2 * linux/arch/arm/mach-sa1100/time.c
3 *
4 * Copyright (C) 1998 Deborah Wallach.
5 * Twiddles (C) 1999 Hugo Fiennes <hugo@empeg.com>
6 *
7 * 2000/03/29 (C) Nicolas Pitre <nico@cam.org>
8 * Rewritten: big cleanup, much simpler, better HZ accuracy.
9 *
10 */
11#include <linux/init.h>
12#include <linux/errno.h>
13#include <linux/interrupt.h>
14#include <linux/timex.h>
15#include <linux/signal.h>
16
17#include <asm/mach/time.h>
18#include <asm/hardware.h>
19
20#define RTC_DEF_DIVIDER (32768 - 1)
21#define RTC_DEF_TRIM 0
22
23static unsigned long __init sa1100_get_rtc_time(void)
24{
25 /*
26 * According to the manual we should be able to let RTTR be zero
27 * and then a default diviser for a 32.768KHz clock is used.
28 * Apparently this doesn't work, at least for my SA1110 rev 5.
29 * If the clock divider is uninitialized then reset it to the
30 * default value to get the 1Hz clock.
31 */
32 if (RTTR == 0) {
33 RTTR = RTC_DEF_DIVIDER + (RTC_DEF_TRIM << 16);
34 printk(KERN_WARNING "Warning: uninitialized Real Time Clock\n");
35 /* The current RTC value probably doesn't make sense either */
36 RCNR = 0;
37 return 0;
38 }
39 return RCNR;
40}
41
42static int sa1100_set_rtc(void)
43{
44 unsigned long current_time = xtime.tv_sec;
45
46 if (RTSR & RTSR_ALE) {
47 /* make sure not to forward the clock over an alarm */
48 unsigned long alarm = RTAR;
49 if (current_time >= alarm && alarm >= RCNR)
50 return -ERESTARTSYS;
51 }
52 RCNR = current_time;
53 return 0;
54}
55
56/* IRQs are disabled before entering here from do_gettimeofday() */
57static unsigned long sa1100_gettimeoffset (void)
58{
59 unsigned long ticks_to_match, elapsed, usec;
60
61 /* Get ticks before next timer match */
62 ticks_to_match = OSMR0 - OSCR;
63
64 /* We need elapsed ticks since last match */
65 elapsed = LATCH - ticks_to_match;
66
67 /* Now convert them to usec */
68 usec = (unsigned long)(elapsed * (tick_nsec / 1000))/LATCH;
69
70 return usec;
71}
72
73/*
74 * We will be entered with IRQs enabled.
75 *
76 * Loop until we get ahead of the free running timer.
77 * This ensures an exact clock tick count and time accuracy.
78 * IRQs are disabled inside the loop to ensure coherence between
79 * lost_ticks (updated in do_timer()) and the match reg value, so we
80 * can use do_gettimeofday() from interrupt handlers.
81 */
82static irqreturn_t
83sa1100_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
84{
85 unsigned int next_match;
86
87 write_seqlock(&xtime_lock);
88
89 do {
90 timer_tick(regs);
91 OSSR = OSSR_M0; /* Clear match on timer 0 */
92 next_match = (OSMR0 += LATCH);
93 } while ((signed long)(next_match - OSCR) <= 0);
94
95 write_sequnlock(&xtime_lock);
96
97 return IRQ_HANDLED;
98}
99
100static struct irqaction sa1100_timer_irq = {
101 .name = "SA11xx Timer Tick",
102 .flags = SA_INTERRUPT,
103 .handler = sa1100_timer_interrupt
104};
105
106static void __init sa1100_timer_init(void)
107{
108 struct timespec tv;
109
110 set_rtc = sa1100_set_rtc;
111
112 tv.tv_nsec = 0;
113 tv.tv_sec = sa1100_get_rtc_time();
114 do_settimeofday(&tv);
115
116 OSMR0 = 0; /* set initial match at 0 */
117 OSSR = 0xf; /* clear status on all timers */
118 setup_irq(IRQ_OST0, &sa1100_timer_irq);
119 OIER |= OIER_E0; /* enable match on timer 0 to cause interrupts */
120 OSCR = 0; /* initialize free-running timer, force first match */
121}
122
123#ifdef CONFIG_PM
124unsigned long osmr[4], oier;
125
126static void sa1100_timer_suspend(void)
127{
128 osmr[0] = OSMR0;
129 osmr[1] = OSMR1;
130 osmr[2] = OSMR2;
131 osmr[3] = OSMR3;
132 oier = OIER;
133}
134
135static void sa1100_timer_resume(void)
136{
137 OSSR = 0x0f;
138 OSMR0 = osmr[0];
139 OSMR1 = osmr[1];
140 OSMR2 = osmr[2];
141 OSMR3 = osmr[3];
142 OIER = oier;
143
144 /*
145 * OSMR0 is the system timer: make sure OSCR is sufficiently behind
146 */
147 OSCR = OSMR0 - LATCH;
148}
149#else
150#define sa1100_timer_suspend NULL
151#define sa1100_timer_resume NULL
152#endif
153
154struct sys_timer sa1100_timer = {
155 .init = sa1100_timer_init,
156 .suspend = sa1100_timer_suspend,
157 .resume = sa1100_timer_resume,
158 .offset = sa1100_gettimeoffset,
159};