http://downloads.netgear.com/files/GPL/GPL_Source_V361j_DM111PSP_series_consumer_rele...
[bcm963xx.git] / kernel / linux / 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
13 #include <linux/config.h>
14 #include <linux/init.h>
15 #include <linux/kernel.h>
16 #include <linux/tty.h>
17 #include <linux/module.h>
18 #include <linux/mm.h>
19 #include <linux/errno.h>
20 #include <linux/serial_core.h>
21 #include <linux/delay.h>
22
23 #include <asm/hardware.h>
24 #include <asm/mach-types.h>
25 #include <asm/irq.h>
26 #include <asm/setup.h>
27 #include <asm/page.h>
28 #include <asm/pgtable.h>
29 #include <asm/tlbflush.h>
30
31 #include <asm/mach/arch.h>
32 #include <asm/mach/map.h>
33 #include <asm/mach/serial_sa1100.h>
34 #include <asm/arch/assabet.h>
35
36 #include "generic.h"
37
38 #define ASSABET_BCR_DB1110 \
39         (ASSABET_BCR_SPK_OFF    | ASSABET_BCR_QMUTE     | \
40          ASSABET_BCR_LED_GREEN  | ASSABET_BCR_LED_RED   | \
41          ASSABET_BCR_RS232EN    | ASSABET_BCR_LCD_12RGB | \
42          ASSABET_BCR_IRDA_MD0)
43
44 #define ASSABET_BCR_DB1111 \
45         (ASSABET_BCR_SPK_OFF    | ASSABET_BCR_QMUTE     | \
46          ASSABET_BCR_LED_GREEN  | ASSABET_BCR_LED_RED   | \
47          ASSABET_BCR_RS232EN    | ASSABET_BCR_LCD_12RGB | \
48          ASSABET_BCR_CF_BUS_OFF | ASSABET_BCR_STEREO_LB | \
49          ASSABET_BCR_IRDA_MD0   | ASSABET_BCR_CF_RST)
50
51 unsigned long SCR_value = ASSABET_SCR_INIT;
52 EXPORT_SYMBOL(SCR_value);
53
54 static unsigned long BCR_value = ASSABET_BCR_DB1110;
55
56 void ASSABET_BCR_frob(unsigned int mask, unsigned int val)
57 {
58         unsigned long flags;
59
60         local_irq_save(flags);
61         BCR_value = (BCR_value & ~mask) | val;
62         ASSABET_BCR = BCR_value;
63         local_irq_restore(flags);
64 }
65
66 EXPORT_SYMBOL(ASSABET_BCR_frob);
67
68 static void assabet_backlight_power(int on)
69 {
70 #ifndef ASSABET_PAL_VIDEO
71         if (on)
72                 ASSABET_BCR_set(ASSABET_BCR_LIGHT_ON);
73         else
74 #endif
75                 ASSABET_BCR_clear(ASSABET_BCR_LIGHT_ON);
76 }
77
78 /*
79  * Turn on/off the backlight.  When turning the backlight on,
80  * we wait 500us after turning it on so we don't cause the
81  * supplies to droop when we enable the LCD controller (and
82  * cause a hard reset.)
83  */
84 static void assabet_lcd_power(int on)
85 {
86 #ifndef ASSABET_PAL_VIDEO
87         if (on) {
88                 ASSABET_BCR_set(ASSABET_BCR_LCD_ON);
89                 udelay(500);
90         } else
91 #endif
92                 ASSABET_BCR_clear(ASSABET_BCR_LCD_ON);
93 }
94
95 static void __init assabet_init(void)
96 {
97         /*
98          * Ensure that the power supply is in "high power" mode.
99          */
100         GPDR |= GPIO_GPIO16;
101         GPSR = GPIO_GPIO16;
102
103         /*
104          * Ensure that these pins are set as outputs and are driving
105          * logic 0.  This ensures that we won't inadvertently toggle
106          * the WS latch in the CPLD, and we don't float causing
107          * excessive power drain.  --rmk
108          */
109         GPDR |= GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM;
110         GPCR = GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM;
111
112         /*
113          * Set up registers for sleep mode.
114          */
115         PWER = PWER_GPIO0;
116         PGSR = 0;
117         PCFR = 0;
118         PSDR = 0;
119         PPDR |= PPC_TXD3 | PPC_TXD1;
120         PPSR |= PPC_TXD3 | PPC_TXD1;
121
122         sa1100fb_lcd_power = assabet_lcd_power;
123         sa1100fb_backlight_power = assabet_backlight_power;
124
125         if (machine_has_neponset()) {
126                 /*
127                  * Angel sets this, but other bootloaders may not.
128                  *
129                  * This must precede any driver calls to BCR_set()
130                  * or BCR_clear().
131                  */
132                 ASSABET_BCR = BCR_value = ASSABET_BCR_DB1111;
133
134 #ifndef CONFIG_ASSABET_NEPONSET
135                 printk( "Warning: Neponset detected but full support "
136                         "hasn't been configured in the kernel\n" );
137 #endif
138         }
139 }
140
141 /*
142  * On Assabet, we must probe for the Neponset board _before_
143  * paging_init() has occurred to actually determine the amount
144  * of RAM available.  To do so, we map the appropriate IO section
145  * in the page table here in order to access GPIO registers.
146  */
147 static void __init map_sa1100_gpio_regs( void )
148 {
149         unsigned long phys = __PREG(GPLR) & PMD_MASK;
150         unsigned long virt = io_p2v(phys);
151         int prot = PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_DOMAIN(DOMAIN_IO);
152         pmd_t pmd;
153         pmd_val(pmd) = phys | prot;
154         set_pmd(pmd_offset(pgd_offset_k(virt), virt), pmd);
155 }
156
157 /*
158  * Read System Configuration "Register"
159  * (taken from "Intel StrongARM SA-1110 Microprocessor Development Board
160  * User's Guide", section 4.4.1)
161  *
162  * This same scan is performed in arch/arm/boot/compressed/head-sa1100.S
163  * to set up the serial port for decompression status messages. We
164  * repeat it here because the kernel may not be loaded as a zImage, and
165  * also because it's a hassle to communicate the SCR value to the kernel
166  * from the decompressor.
167  *
168  * Note that IRQs are guaranteed to be disabled.
169  */
170 static void __init get_assabet_scr(void)
171 {
172         unsigned long scr, i;
173
174         GPDR |= 0x3fc;                  /* Configure GPIO 9:2 as outputs */
175         GPSR = 0x3fc;                   /* Write 0xFF to GPIO 9:2 */
176         GPDR &= ~(0x3fc);               /* Configure GPIO 9:2 as inputs */
177         for(i = 100; i--; scr = GPLR);  /* Read GPIO 9:2 */
178         GPDR |= 0x3fc;                  /*  restore correct pin direction */
179         scr &= 0x3fc;                   /* save as system configuration byte. */
180         SCR_value = scr;
181 }
182
183 static void __init
184 fixup_assabet(struct machine_desc *desc, struct tag *tags,
185               char **cmdline, struct meminfo *mi)
186 {
187         /* This must be done before any call to machine_has_neponset() */
188         map_sa1100_gpio_regs();
189         get_assabet_scr();
190
191         if (machine_has_neponset())
192                 printk("Neponset expansion board detected\n");
193 }
194
195
196 static void assabet_uart_pm(struct uart_port *port, u_int state, u_int oldstate)
197 {
198         if (port->mapbase == _Ser1UTCR0) {
199                 if (state)
200                         ASSABET_BCR_clear(ASSABET_BCR_RS232EN |
201                                           ASSABET_BCR_COM_RTS |
202                                           ASSABET_BCR_COM_DTR);
203                 else
204                         ASSABET_BCR_set(ASSABET_BCR_RS232EN |
205                                         ASSABET_BCR_COM_RTS |
206                                         ASSABET_BCR_COM_DTR);
207         }
208 }
209
210 /*
211  * Assabet uses COM_RTS and COM_DTR for both UART1 (com port)
212  * and UART3 (radio module).  We only handle them for UART1 here.
213  */
214 static void assabet_set_mctrl(struct uart_port *port, u_int mctrl)
215 {
216         if (port->mapbase == _Ser1UTCR0) {
217                 u_int set = 0, clear = 0;
218
219                 if (mctrl & TIOCM_RTS)
220                         clear |= ASSABET_BCR_COM_RTS;
221                 else
222                         set |= ASSABET_BCR_COM_RTS;
223
224                 if (mctrl & TIOCM_DTR)
225                         clear |= ASSABET_BCR_COM_DTR;
226                 else
227                         set |= ASSABET_BCR_COM_DTR;
228
229                 ASSABET_BCR_clear(clear);
230                 ASSABET_BCR_set(set);
231         }
232 }
233
234 static u_int assabet_get_mctrl(struct uart_port *port)
235 {
236         u_int ret = 0;
237         u_int bsr = ASSABET_BSR;
238
239         /* need 2 reads to read current value */
240         bsr = ASSABET_BSR;
241
242         if (port->mapbase == _Ser1UTCR0) {
243                 if (bsr & ASSABET_BSR_COM_DCD)
244                         ret |= TIOCM_CD;
245                 if (bsr & ASSABET_BSR_COM_CTS)
246                         ret |= TIOCM_CTS;
247                 if (bsr & ASSABET_BSR_COM_DSR)
248                         ret |= TIOCM_DSR;
249         } else if (port->mapbase == _Ser3UTCR0) {
250                 if (bsr & ASSABET_BSR_RAD_DCD)
251                         ret |= TIOCM_CD;
252                 if (bsr & ASSABET_BSR_RAD_CTS)
253                         ret |= TIOCM_CTS;
254                 if (bsr & ASSABET_BSR_RAD_DSR)
255                         ret |= TIOCM_DSR;
256                 if (bsr & ASSABET_BSR_RAD_RI)
257                         ret |= TIOCM_RI;
258         } else {
259                 ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR;
260         }
261
262         return ret;
263 }
264
265 static struct sa1100_port_fns assabet_port_fns __initdata = {
266         .set_mctrl      = assabet_set_mctrl,
267         .get_mctrl      = assabet_get_mctrl,
268         .pm             = assabet_uart_pm,
269 };
270
271 static struct map_desc assabet_io_desc[] __initdata = {
272  /* virtual     physical    length      type */
273   { 0xf1000000, 0x12000000, 0x00100000, MT_DEVICE }, /* Board Control Register */
274   { 0xf2800000, 0x4b800000, 0x00800000, MT_DEVICE }  /* MQ200 */
275 };
276
277 static void __init assabet_map_io(void)
278 {
279         sa1100_map_io();
280         iotable_init(assabet_io_desc, ARRAY_SIZE(assabet_io_desc));
281
282         /*
283          * Set SUS bit in SDCR0 so serial port 1 functions.
284          * Its called GPCLKR0 in my SA1110 manual.
285          */
286         Ser1SDCR0 |= SDCR0_SUS;
287
288         if (machine_has_neponset()) {
289 #ifdef CONFIG_ASSABET_NEPONSET
290                 extern void neponset_map_io(void);
291
292                 /*
293                  * We map Neponset registers even if it isn't present since
294                  * many drivers will try to probe their stuff (and fail).
295                  * This is still more friendly than a kernel paging request
296                  * crash.
297                  */
298                 neponset_map_io();
299 #endif
300         } else {
301                 sa1100_register_uart_fns(&assabet_port_fns);
302         }
303
304         /*
305          * When Neponset is attached, the first UART should be
306          * UART3.  That's what Angel is doing and many documents
307          * are stating this.
308          *
309          * We do the Neponset mapping even if Neponset support
310          * isn't compiled in so the user will still get something on
311          * the expected physical serial port.
312          *
313          * We no longer do this; not all boot loaders support it,
314          * and UART3 appears to be somewhat unreliable with blob.
315          */
316         sa1100_register_uart(0, 1);
317         sa1100_register_uart(2, 3);
318 }
319
320
321 MACHINE_START(ASSABET, "Intel-Assabet")
322         BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
323         BOOT_PARAMS(0xc0000100)
324         FIXUP(fixup_assabet)
325         MAPIO(assabet_map_io)
326         INITIRQ(sa1100_init_irq)
327         INITTIME(sa1100_init_time)
328         INIT_MACHINE(assabet_init)
329 MACHINE_END