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