Linux-2.6.12-rc2
[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
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  */
282 static 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
295 static void __init
296 fixup_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
308 static 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  */
326 static 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
346 static 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
377 static 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
383 static 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
389 static 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
433 MACHINE_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,
441 MACHINE_END