vserver 1.9.5.x5
[linux-2.6.git] / arch / arm / mach-sa1100 / assabet.c
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
54 unsigned long SCR_value = ASSABET_SCR_INIT;
55 EXPORT_SYMBOL(SCR_value);
56
57 static unsigned long BCR_value = ASSABET_BCR_DB1110;
58
59 void 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
69 EXPORT_SYMBOL(ASSABET_BCR_frob);
70
71 static 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  */
87 static 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  */
107 static 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  */
128 static 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
147 static 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
153 static 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
170 static 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
188 static 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
196 static struct irda_platform_data assabet_irda_data = {
197         .set_power      = assabet_irda_set_power,
198         .set_speed      = assabet_irda_set_speed,
199 };
200
201 static 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  */
257 static 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         pmd_val(pmd) = phys | prot;
264         set_pmd(pmd_offset(pgd_offset_k(virt), virt), pmd);
265 }
266
267 /*
268  * Read System Configuration "Register"
269  * (taken from "Intel StrongARM SA-1110 Microprocessor Development Board
270  * User's Guide", section 4.4.1)
271  *
272  * This same scan is performed in arch/arm/boot/compressed/head-sa1100.S
273  * to set up the serial port for decompression status messages. We
274  * repeat it here because the kernel may not be loaded as a zImage, and
275  * also because it's a hassle to communicate the SCR value to the kernel
276  * from the decompressor.
277  *
278  * Note that IRQs are guaranteed to be disabled.
279  */
280 static void __init get_assabet_scr(void)
281 {
282         unsigned long scr, i;
283
284         GPDR |= 0x3fc;                  /* Configure GPIO 9:2 as outputs */
285         GPSR = 0x3fc;                   /* Write 0xFF to GPIO 9:2 */
286         GPDR &= ~(0x3fc);               /* Configure GPIO 9:2 as inputs */
287         for(i = 100; i--; scr = GPLR);  /* Read GPIO 9:2 */
288         GPDR |= 0x3fc;                  /*  restore correct pin direction */
289         scr &= 0x3fc;                   /* save as system configuration byte. */
290         SCR_value = scr;
291 }
292
293 static void __init
294 fixup_assabet(struct machine_desc *desc, struct tag *tags,
295               char **cmdline, struct meminfo *mi)
296 {
297         /* This must be done before any call to machine_has_neponset() */
298         map_sa1100_gpio_regs();
299         get_assabet_scr();
300
301         if (machine_has_neponset())
302                 printk("Neponset expansion board detected\n");
303 }
304
305
306 static void assabet_uart_pm(struct uart_port *port, u_int state, u_int oldstate)
307 {
308         if (port->mapbase == _Ser1UTCR0) {
309                 if (state)
310                         ASSABET_BCR_clear(ASSABET_BCR_RS232EN |
311                                           ASSABET_BCR_COM_RTS |
312                                           ASSABET_BCR_COM_DTR);
313                 else
314                         ASSABET_BCR_set(ASSABET_BCR_RS232EN |
315                                         ASSABET_BCR_COM_RTS |
316                                         ASSABET_BCR_COM_DTR);
317         }
318 }
319
320 /*
321  * Assabet uses COM_RTS and COM_DTR for both UART1 (com port)
322  * and UART3 (radio module).  We only handle them for UART1 here.
323  */
324 static void assabet_set_mctrl(struct uart_port *port, u_int mctrl)
325 {
326         if (port->mapbase == _Ser1UTCR0) {
327                 u_int set = 0, clear = 0;
328
329                 if (mctrl & TIOCM_RTS)
330                         clear |= ASSABET_BCR_COM_RTS;
331                 else
332                         set |= ASSABET_BCR_COM_RTS;
333
334                 if (mctrl & TIOCM_DTR)
335                         clear |= ASSABET_BCR_COM_DTR;
336                 else
337                         set |= ASSABET_BCR_COM_DTR;
338
339                 ASSABET_BCR_clear(clear);
340                 ASSABET_BCR_set(set);
341         }
342 }
343
344 static u_int assabet_get_mctrl(struct uart_port *port)
345 {
346         u_int ret = 0;
347         u_int bsr = ASSABET_BSR;
348
349         /* need 2 reads to read current value */
350         bsr = ASSABET_BSR;
351
352         if (port->mapbase == _Ser1UTCR0) {
353                 if (bsr & ASSABET_BSR_COM_DCD)
354                         ret |= TIOCM_CD;
355                 if (bsr & ASSABET_BSR_COM_CTS)
356                         ret |= TIOCM_CTS;
357                 if (bsr & ASSABET_BSR_COM_DSR)
358                         ret |= TIOCM_DSR;
359         } else if (port->mapbase == _Ser3UTCR0) {
360                 if (bsr & ASSABET_BSR_RAD_DCD)
361                         ret |= TIOCM_CD;
362                 if (bsr & ASSABET_BSR_RAD_CTS)
363                         ret |= TIOCM_CTS;
364                 if (bsr & ASSABET_BSR_RAD_DSR)
365                         ret |= TIOCM_DSR;
366                 if (bsr & ASSABET_BSR_RAD_RI)
367                         ret |= TIOCM_RI;
368         } else {
369                 ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR;
370         }
371
372         return ret;
373 }
374
375 static struct sa1100_port_fns assabet_port_fns __initdata = {
376         .set_mctrl      = assabet_set_mctrl,
377         .get_mctrl      = assabet_get_mctrl,
378         .pm             = assabet_uart_pm,
379 };
380
381 static struct map_desc assabet_io_desc[] __initdata = {
382  /* virtual     physical    length      type */
383   { 0xf1000000, 0x12000000, 0x00100000, MT_DEVICE }, /* Board Control Register */
384   { 0xf2800000, 0x4b800000, 0x00800000, MT_DEVICE }  /* MQ200 */
385 };
386
387 static void __init assabet_map_io(void)
388 {
389         sa1100_map_io();
390         iotable_init(assabet_io_desc, ARRAY_SIZE(assabet_io_desc));
391
392         /*
393          * Set SUS bit in SDCR0 so serial port 1 functions.
394          * Its called GPCLKR0 in my SA1110 manual.
395          */
396         Ser1SDCR0 |= SDCR0_SUS;
397
398         if (machine_has_neponset()) {
399 #ifdef CONFIG_ASSABET_NEPONSET
400                 extern void neponset_map_io(void);
401
402                 /*
403                  * We map Neponset registers even if it isn't present since
404                  * many drivers will try to probe their stuff (and fail).
405                  * This is still more friendly than a kernel paging request
406                  * crash.
407                  */
408                 neponset_map_io();
409 #endif
410         } else {
411                 sa1100_register_uart_fns(&assabet_port_fns);
412         }
413
414         /*
415          * When Neponset is attached, the first UART should be
416          * UART3.  That's what Angel is doing and many documents
417          * are stating this.
418          *
419          * We do the Neponset mapping even if Neponset support
420          * isn't compiled in so the user will still get something on
421          * the expected physical serial port.
422          *
423          * We no longer do this; not all boot loaders support it,
424          * and UART3 appears to be somewhat unreliable with blob.
425          */
426         sa1100_register_uart(0, 1);
427         sa1100_register_uart(2, 3);
428 }
429
430
431 MACHINE_START(ASSABET, "Intel-Assabet")
432         BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
433         BOOT_PARAMS(0xc0000100)
434         FIXUP(fixup_assabet)
435         MAPIO(assabet_map_io)
436         INITIRQ(sa1100_init_irq)
437         .timer          = &sa1100_timer,
438         .init_machine   = assabet_init,
439 MACHINE_END