mirror of
				https://github.com/smaeul/u-boot.git
				synced 2025-10-30 19:48:19 +00:00 
			
		
		
		
	So far the console API uses the following naming convention: ======Extract====== typedef struct device_t; int device_register (device_t * dev); int devices_init (void); int device_deregister(char *devname); struct list_head* device_get_list(void); device_t* device_get_by_name(char* name); device_t* device_clone(device_t *dev); ======= which is too generic and confusing. Instead of using device_XX and device_t we change this into stdio_XX and stdio_dev This will also allow to add later a generic device mechanism in order to have support for multiple devices and driver instances. Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> Edited commit message. Signed-off-by: Wolfgang Denk <wd@denx.de>
		
			
				
	
	
		
			294 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			294 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * avr.c
 | |
|  *
 | |
|  * AVR functions
 | |
|  *
 | |
|  * Copyright (C) 2006 Mihai Georgian <u-boot@linuxnotincluded.org.uk>
 | |
|  *
 | |
|  * This program is free software; you can redistribute it and/or
 | |
|  * modify it under the terms of the GNU General Public License as
 | |
|  * published by the Free Software Foundation; either version 2 of
 | |
|  * the License, or (at your option) any later version.
 | |
|  *
 | |
|  * This program is distributed in the hope that it will be useful,
 | |
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|  * GNU General Public License for more details.
 | |
|  *
 | |
|  * You should have received a copy of the GNU General Public License
 | |
|  * along with this program; if not, write to the Free Software
 | |
|  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 | |
|  * MA 02111-1307 USA
 | |
|  */
 | |
| #include <common.h>
 | |
| #include <ns16550.h>
 | |
| #include <stdio_dev.h>
 | |
| 
 | |
| /* Button codes from the AVR */
 | |
| #define PWRR			0x20		/* Power button release	*/
 | |
| #define PWRP			0x21		/* Power button push	*/
 | |
| #define RESR			0x22		/* Reset button release	*/
 | |
| #define RESP			0x23		/* Reset button push	*/
 | |
| #define AVRINIT			0x33		/* Init complete	*/
 | |
| #define AVRRESET		0x31		/* Reset request	*/
 | |
| 
 | |
| /* LED commands */
 | |
| #define PWRBLINKSTRT		'['		/* Blink power LED	*/
 | |
| #define PWRBLINKSTOP		'Z'		/* Solid power LED	*/
 | |
| #define HDDLEDON		'W'		/* HDD LED on		*/
 | |
| #define HDDLEDOFF		'V'		/* HDD LED off		*/
 | |
| #define HDDBLINKSTRT		'Y'		/* HDD LED start blink	*/
 | |
| #define HDDBLINKSTOP		'X'		/* HDD LED stop blink	*/
 | |
| 
 | |
| /* Timings for LEDs blinking to show choice */
 | |
| #define PULSETIME		250		/* msecs		*/
 | |
| #define LONGPAUSE		(5 * PULSETIME)
 | |
| 
 | |
| /* Button press times */
 | |
| #define PUSHHOLD		1000		/* msecs		*/
 | |
| #define NOBUTTON		(6 * (LONGPAUSE+PULSETIME))
 | |
| 
 | |
| /* Boot and console choices */
 | |
| #define MAX_BOOT_CHOICE		3
 | |
| 
 | |
| static char *consoles[] = {
 | |
| 	"serial",
 | |
| #if defined(CONFIG_NETCONSOLE)
 | |
| 	"nc",
 | |
| #endif
 | |
| };
 | |
| #define MAX_CONS_CHOICE		(sizeof(consoles)/sizeof(char *))
 | |
| 
 | |
| #if !defined(CONFIG_NETCONSOLE)
 | |
| #define DEF_CONS_CHOICE		0
 | |
| #else
 | |
| #define DEF_CONS_CHOICE		1
 | |
| #endif
 | |
| 
 | |
| #define perror(fmt, args...) printf("%s: " fmt, __FUNCTION__ , ##args)
 | |
| 
 | |
| extern void miconCntl_SendCmd(unsigned char dat);
 | |
| extern void miconCntl_DisWDT(void);
 | |
| 
 | |
| static int boot_stop;
 | |
| 
 | |
| static int boot_choice = 1;
 | |
| static int cons_choice = DEF_CONS_CHOICE;
 | |
| 
 | |
| static char envbuffer[16];
 | |
| 
 | |
| void init_AVR_DUART (void)
 | |
| {
 | |
| 	NS16550_t AVR_port = (NS16550_t) CONFIG_SYS_NS16550_COM2;
 | |
| 	int clock_divisor = CONFIG_SYS_NS16550_CLK / 16 / 9600;
 | |
| 
 | |
| 	/*
 | |
| 	 * AVR port init sequence taken from
 | |
| 	 * the original Linkstation init code
 | |
| 	 * Normal U-Boot serial reinit doesn't
 | |
| 	 * work because the AVR uses even parity
 | |
| 	 */
 | |
| 	AVR_port->lcr = 0x00;
 | |
| 	AVR_port->ier = 0x00;
 | |
| 	AVR_port->lcr = UART_LCR_BKSE;
 | |
| 	AVR_port->dll = clock_divisor & 0xff;
 | |
| 	AVR_port->dlm = (clock_divisor >> 8) & 0xff;
 | |
| 	AVR_port->lcr = UART_LCR_WLS_8 | UART_LCR_PEN | UART_LCR_EPS;
 | |
| 	AVR_port->mcr = 0x00;
 | |
| 	AVR_port->fcr = UART_FCR_FIFO_EN | UART_FCR_RXSR | UART_FCR_TXSR;
 | |
| 
 | |
| 	miconCntl_DisWDT();
 | |
| 
 | |
| 	boot_stop = 0;
 | |
| 	miconCntl_SendCmd(PWRBLINKSTRT);
 | |
| }
 | |
| 
 | |
| static inline int avr_tstc(void)
 | |
| {
 | |
| 	return (NS16550_tstc((NS16550_t)CONFIG_SYS_NS16550_COM2));
 | |
| }
 | |
| 
 | |
| static inline char avr_getc(void)
 | |
| {
 | |
| 	return (NS16550_getc((NS16550_t)CONFIG_SYS_NS16550_COM2));
 | |
| }
 | |
| 
 | |
| static int push_timeout(char button_code)
 | |
| {
 | |
| 	ulong push_start = get_timer(0);
 | |
| 	while (get_timer(push_start) <= PUSHHOLD)
 | |
| 		if (avr_tstc() && avr_getc() == button_code)
 | |
| 			return 0;
 | |
| 	return 1;
 | |
| }
 | |
| 
 | |
| static void next_boot_choice(void)
 | |
| {
 | |
| 	ulong return_start;
 | |
| 	ulong pulse_start;
 | |
| 	int on_times;
 | |
| 	int button_on;
 | |
| 	int led_state;
 | |
| 	char c;
 | |
| 
 | |
| 	button_on = 0;
 | |
| 	return_start = get_timer(0);
 | |
| 
 | |
| 	on_times = boot_choice;
 | |
| 	led_state = 0;
 | |
| 	miconCntl_SendCmd(HDDLEDOFF);
 | |
| 	pulse_start = get_timer(0);
 | |
| 
 | |
| 	while (get_timer(return_start) <= NOBUTTON || button_on) {
 | |
| 		if (avr_tstc()) {
 | |
| 			c = avr_getc();
 | |
| 			if (c == PWRP)
 | |
| 				button_on = 1;
 | |
| 			else if (c == PWRR) {
 | |
| 				button_on = 0;
 | |
| 				return_start = get_timer(0);
 | |
| 				if (++boot_choice > MAX_BOOT_CHOICE)
 | |
| 					boot_choice = 1;
 | |
| 				sprintf(envbuffer, "bootcmd%d", boot_choice);
 | |
| 				if (getenv(envbuffer)) {
 | |
| 					sprintf(envbuffer, "run bootcmd%d", boot_choice);
 | |
| 					setenv("bootcmd", envbuffer);
 | |
| 				}
 | |
| 				on_times = boot_choice;
 | |
| 				led_state = 1;
 | |
| 				miconCntl_SendCmd(HDDLEDON);
 | |
| 				pulse_start = get_timer(0);
 | |
| 			} else {
 | |
| 				perror("Unexpected code: 0x%02X\n", c);
 | |
| 			}
 | |
| 		}
 | |
| 		if (on_times && get_timer(pulse_start) > PULSETIME) {
 | |
| 			if (led_state == 1) {
 | |
| 				--on_times;
 | |
| 				led_state = 0;
 | |
| 				miconCntl_SendCmd(HDDLEDOFF);
 | |
| 			} else {
 | |
| 				led_state = 1;
 | |
| 				miconCntl_SendCmd(HDDLEDON);
 | |
| 			}
 | |
| 			pulse_start = get_timer(0);
 | |
| 		}
 | |
| 		if (!on_times && get_timer(pulse_start) > LONGPAUSE) {
 | |
| 			on_times = boot_choice;
 | |
| 			led_state = 1;
 | |
| 			miconCntl_SendCmd(HDDLEDON);
 | |
| 			pulse_start = get_timer(0);
 | |
| 		}
 | |
| 	}
 | |
| 	if (led_state)
 | |
| 		miconCntl_SendCmd(HDDLEDOFF);
 | |
| }
 | |
| 
 | |
| void next_cons_choice(int console)
 | |
| {
 | |
| 	ulong return_start;
 | |
| 	ulong pulse_start;
 | |
| 	int on_times;
 | |
| 	int button_on;
 | |
| 	int led_state;
 | |
| 	char c;
 | |
| 
 | |
| 	button_on = 0;
 | |
| 	cons_choice = console;
 | |
| 	return_start = get_timer(0);
 | |
| 
 | |
| 	on_times = cons_choice+1;
 | |
| 	led_state = 1;
 | |
| 	miconCntl_SendCmd(HDDLEDON);
 | |
| 	pulse_start = get_timer(0);
 | |
| 
 | |
| 	while (get_timer(return_start) <= NOBUTTON || button_on) {
 | |
| 		if (avr_tstc()) {
 | |
| 			c = avr_getc();
 | |
| 			if (c == RESP)
 | |
| 				button_on = 1;
 | |
| 			else if (c == RESR) {
 | |
| 				button_on = 0;
 | |
| 				return_start = get_timer(0);
 | |
| 				cons_choice = (cons_choice + 1) % MAX_CONS_CHOICE;
 | |
| 				console_assign(stdin, consoles[cons_choice]);
 | |
| 				console_assign(stdout, consoles[cons_choice]);
 | |
| 				console_assign(stderr, consoles[cons_choice]);
 | |
| 				on_times = cons_choice+1;
 | |
| 				led_state = 0;
 | |
| 				miconCntl_SendCmd(HDDLEDOFF);
 | |
| 				pulse_start = get_timer(0);
 | |
| 			} else {
 | |
| 				perror("Unexpected code: 0x%02X\n", c);
 | |
| 			}
 | |
| 		}
 | |
| 		if (on_times && get_timer(pulse_start) > PULSETIME) {
 | |
| 			if (led_state == 0) {
 | |
| 				--on_times;
 | |
| 				led_state = 1;
 | |
| 				miconCntl_SendCmd(HDDLEDON);
 | |
| 			} else {
 | |
| 				led_state = 0;
 | |
| 				miconCntl_SendCmd(HDDLEDOFF);
 | |
| 			}
 | |
| 			pulse_start = get_timer(0);
 | |
| 		}
 | |
| 		if (!on_times && get_timer(pulse_start) > LONGPAUSE) {
 | |
| 			on_times = cons_choice+1;
 | |
| 			led_state = 0;
 | |
| 			miconCntl_SendCmd(HDDLEDOFF);
 | |
| 			pulse_start = get_timer(0);
 | |
| 		}
 | |
| 	}
 | |
| 	if (led_state);
 | |
| 	miconCntl_SendCmd(HDDLEDOFF);
 | |
| }
 | |
| 
 | |
| int avr_input(void)
 | |
| {
 | |
| 	char avr_button;
 | |
| 
 | |
| 	if (!avr_tstc())
 | |
| 		return 0;
 | |
| 
 | |
| 	avr_button = avr_getc();
 | |
| 	switch (avr_button) {
 | |
| 	case PWRP:
 | |
| 		if (push_timeout(PWRR)) {
 | |
| 			/* Timeout before power button release */
 | |
| 			boot_stop = ~boot_stop;
 | |
| 			if (boot_stop)
 | |
| 				miconCntl_SendCmd(PWRBLINKSTOP);
 | |
| 			else
 | |
| 				miconCntl_SendCmd(PWRBLINKSTRT);
 | |
| 			/* Wait for power button release */
 | |
| 			while (avr_getc() != PWRR)
 | |
| 				;
 | |
| 		} else
 | |
| 			/* Power button released */
 | |
| 			next_boot_choice();
 | |
| 		break;
 | |
| 	case RESP:
 | |
| 		/* Wait for Reset button release */
 | |
| 		while (avr_getc() != RESR)
 | |
| 			;
 | |
| 		next_cons_choice(cons_choice);
 | |
| 		break;
 | |
| 	case AVRINIT:
 | |
| 		return 0;
 | |
| 	default:
 | |
| 		perror("Unexpected code: 0x%02X\n", avr_button);
 | |
| 		return 0;
 | |
| 	}
 | |
| 	if (boot_stop)
 | |
| 		return (-3);
 | |
| 	else
 | |
| 		return (-2);
 | |
| }
 | |
| 
 | |
| void avr_StopBoot(void)
 | |
| {
 | |
| 	boot_stop = ~0;
 | |
| 	miconCntl_SendCmd(PWRBLINKSTOP);
 | |
| }
 |