| /* | 
 |  * linux/arch/arm/plat-omap/common.c | 
 |  * | 
 |  * Code common to all OMAP machines. | 
 |  * | 
 |  * This program is free software; you can redistribute it and/or modify | 
 |  * it under the terms of the GNU General Public License version 2 as | 
 |  * published by the Free Software Foundation. | 
 |  */ | 
 | #include <linux/module.h> | 
 | #include <linux/kernel.h> | 
 | #include <linux/init.h> | 
 | #include <linux/delay.h> | 
 | #include <linux/pm.h> | 
 | #include <linux/console.h> | 
 | #include <linux/serial.h> | 
 | #include <linux/tty.h> | 
 | #include <linux/serial_8250.h> | 
 | #include <linux/serial_reg.h> | 
 | #include <linux/clk.h> | 
 |  | 
 | #include <asm/hardware.h> | 
 | #include <asm/system.h> | 
 | #include <asm/pgtable.h> | 
 | #include <asm/mach/map.h> | 
 | #include <asm/io.h> | 
 | #include <asm/setup.h> | 
 |  | 
 | #include <asm/arch/board.h> | 
 | #include <asm/arch/mux.h> | 
 | #include <asm/arch/fpga.h> | 
 |  | 
 | #include <asm/arch/clock.h> | 
 |  | 
 | #define NO_LENGTH_CHECK 0xffffffff | 
 |  | 
 | unsigned char omap_bootloader_tag[512]; | 
 | int omap_bootloader_tag_len; | 
 |  | 
 | struct omap_board_config_kernel *omap_board_config; | 
 | int omap_board_config_size; | 
 |  | 
 | static const void *get_config(u16 tag, size_t len, int skip, size_t *len_out) | 
 | { | 
 | 	struct omap_board_config_kernel *kinfo = NULL; | 
 | 	int i; | 
 |  | 
 | #ifdef CONFIG_OMAP_BOOT_TAG | 
 | 	struct omap_board_config_entry *info = NULL; | 
 |  | 
 | 	if (omap_bootloader_tag_len > 4) | 
 | 		info = (struct omap_board_config_entry *) omap_bootloader_tag; | 
 | 	while (info != NULL) { | 
 | 		u8 *next; | 
 |  | 
 | 		if (info->tag == tag) { | 
 | 			if (skip == 0) | 
 | 				break; | 
 | 			skip--; | 
 | 		} | 
 |  | 
 | 		if ((info->len & 0x03) != 0) { | 
 | 			/* We bail out to avoid an alignment fault */ | 
 | 			printk(KERN_ERR "OMAP peripheral config: Length (%d) not word-aligned (tag %04x)\n", | 
 | 			       info->len, info->tag); | 
 | 			return NULL; | 
 | 		} | 
 | 		next = (u8 *) info + sizeof(*info) + info->len; | 
 | 		if (next >= omap_bootloader_tag + omap_bootloader_tag_len) | 
 | 			info = NULL; | 
 | 		else | 
 | 			info = (struct omap_board_config_entry *) next; | 
 | 	} | 
 | 	if (info != NULL) { | 
 | 		/* Check the length as a lame attempt to check for | 
 | 		 * binary inconsistancy. */ | 
 | 		if (len != NO_LENGTH_CHECK) { | 
 | 			/* Word-align len */ | 
 | 			if (len & 0x03) | 
 | 				len = (len + 3) & ~0x03; | 
 | 			if (info->len != len) { | 
 | 				printk(KERN_ERR "OMAP peripheral config: Length mismatch with tag %x (want %d, got %d)\n", | 
 | 				       tag, len, info->len); | 
 | 				return NULL; | 
 | 			} | 
 | 		} | 
 | 		if (len_out != NULL) | 
 | 			*len_out = info->len; | 
 | 		return info->data; | 
 | 	} | 
 | #endif | 
 | 	/* Try to find the config from the board-specific structures | 
 | 	 * in the kernel. */ | 
 | 	for (i = 0; i < omap_board_config_size; i++) { | 
 | 		if (omap_board_config[i].tag == tag) { | 
 | 			kinfo = &omap_board_config[i]; | 
 | 			break; | 
 | 		} | 
 | 	} | 
 | 	if (kinfo == NULL) | 
 | 		return NULL; | 
 | 	return kinfo->data; | 
 | } | 
 |  | 
 | const void *__omap_get_config(u16 tag, size_t len, int nr) | 
 | { | 
 |         return get_config(tag, len, nr, NULL); | 
 | } | 
 | EXPORT_SYMBOL(__omap_get_config); | 
 |  | 
 | const void *omap_get_var_config(u16 tag, size_t *len) | 
 | { | 
 |         return get_config(tag, NO_LENGTH_CHECK, 0, len); | 
 | } | 
 | EXPORT_SYMBOL(omap_get_var_config); | 
 |  | 
 | static int __init omap_add_serial_console(void) | 
 | { | 
 | 	const struct omap_serial_console_config *con_info; | 
 | 	const struct omap_uart_config *uart_info; | 
 | 	static char speed[11], *opt = NULL; | 
 | 	int line, i, uart_idx; | 
 |  | 
 | 	uart_info = omap_get_config(OMAP_TAG_UART, struct omap_uart_config); | 
 | 	con_info = omap_get_config(OMAP_TAG_SERIAL_CONSOLE, | 
 | 					struct omap_serial_console_config); | 
 | 	if (uart_info == NULL || con_info == NULL) | 
 | 		return 0; | 
 |  | 
 | 	if (con_info->console_uart == 0) | 
 | 		return 0; | 
 |  | 
 | 	if (con_info->console_speed) { | 
 | 		snprintf(speed, sizeof(speed), "%u", con_info->console_speed); | 
 | 		opt = speed; | 
 | 	} | 
 |  | 
 | 	uart_idx = con_info->console_uart - 1; | 
 | 	if (uart_idx >= OMAP_MAX_NR_PORTS) { | 
 | 		printk(KERN_INFO "Console: external UART#%d. " | 
 | 			"Not adding it as console this time.\n", | 
 | 			uart_idx + 1); | 
 | 		return 0; | 
 | 	} | 
 | 	if (!(uart_info->enabled_uarts & (1 << uart_idx))) { | 
 | 		printk(KERN_ERR "Console: Selected UART#%d is " | 
 | 			"not enabled for this platform\n", | 
 | 			uart_idx + 1); | 
 | 		return -1; | 
 | 	} | 
 | 	line = 0; | 
 | 	for (i = 0; i < uart_idx; i++) { | 
 | 		if (uart_info->enabled_uarts & (1 << i)) | 
 | 			line++; | 
 | 	} | 
 | 	return add_preferred_console("ttyS", line, opt); | 
 | } | 
 | console_initcall(omap_add_serial_console); |