]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/linkstation/avr.c
Merge branch 'u-boot/master' into u-boot-arm/master
[karo-tx-uboot.git] / board / linkstation / avr.c
1 /*
2  * avr.c
3  *
4  * AVR functions
5  *
6  * Copyright (C) 2006 Mihai Georgian <u-boot@linuxnotincluded.org.uk>
7  *
8  * SPDX-License-Identifier:     GPL-2.0+
9  */
10 #include <common.h>
11 #include <ns16550.h>
12 #include <stdio_dev.h>
13
14 /* Button codes from the AVR */
15 #define PWRR                    0x20            /* Power button release */
16 #define PWRP                    0x21            /* Power button push    */
17 #define RESR                    0x22            /* Reset button release */
18 #define RESP                    0x23            /* Reset button push    */
19 #define AVRINIT                 0x33            /* Init complete        */
20 #define AVRRESET                0x31            /* Reset request        */
21
22 /* LED commands */
23 #define PWRBLINKSTRT            '['             /* Blink power LED      */
24 #define PWRBLINKSTOP            'Z'             /* Solid power LED      */
25 #define HDDLEDON                'W'             /* HDD LED on           */
26 #define HDDLEDOFF               'V'             /* HDD LED off          */
27 #define HDDBLINKSTRT            'Y'             /* HDD LED start blink  */
28 #define HDDBLINKSTOP            'X'             /* HDD LED stop blink   */
29
30 /* Timings for LEDs blinking to show choice */
31 #define PULSETIME               250             /* msecs                */
32 #define LONGPAUSE               (5 * PULSETIME)
33
34 /* Button press times */
35 #define PUSHHOLD                1000            /* msecs                */
36 #define NOBUTTON                (6 * (LONGPAUSE+PULSETIME))
37
38 /* Boot and console choices */
39 #define MAX_BOOT_CHOICE         3
40
41 static char *consoles[] = {
42         "serial",
43 #if defined(CONFIG_NETCONSOLE)
44         "nc",
45 #endif
46 };
47 #define MAX_CONS_CHOICE         (sizeof(consoles)/sizeof(char *))
48
49 #if !defined(CONFIG_NETCONSOLE)
50 #define DEF_CONS_CHOICE         0
51 #else
52 #define DEF_CONS_CHOICE         1
53 #endif
54
55 #define perror(fmt, args...) printf("%s: " fmt, __FUNCTION__ , ##args)
56
57 extern void miconCntl_SendCmd(unsigned char dat);
58 extern void miconCntl_DisWDT(void);
59
60 static int boot_stop;
61
62 static int boot_choice = 1;
63 static int cons_choice = DEF_CONS_CHOICE;
64
65 static char envbuffer[16];
66
67 void init_AVR_DUART (void)
68 {
69         NS16550_t AVR_port = (NS16550_t) CONFIG_SYS_NS16550_COM2;
70         int clock_divisor = CONFIG_SYS_NS16550_CLK / 16 / 9600;
71
72         /*
73          * AVR port init sequence taken from
74          * the original Linkstation init code
75          * Normal U-Boot serial reinit doesn't
76          * work because the AVR uses even parity
77          */
78         AVR_port->lcr = 0x00;
79         AVR_port->ier = 0x00;
80         AVR_port->lcr = UART_LCR_BKSE;
81         AVR_port->dll = clock_divisor & 0xff;
82         AVR_port->dlm = (clock_divisor >> 8) & 0xff;
83         AVR_port->lcr = UART_LCR_WLS_8 | UART_LCR_PEN | UART_LCR_EPS;
84         AVR_port->mcr = 0x00;
85         AVR_port->fcr = UART_FCR_FIFO_EN | UART_FCR_RXSR | UART_FCR_TXSR;
86
87         miconCntl_DisWDT();
88
89         boot_stop = 0;
90         miconCntl_SendCmd(PWRBLINKSTRT);
91 }
92
93 static inline int avr_tstc(void)
94 {
95         return (NS16550_tstc((NS16550_t)CONFIG_SYS_NS16550_COM2));
96 }
97
98 static inline char avr_getc(void)
99 {
100         return (NS16550_getc((NS16550_t)CONFIG_SYS_NS16550_COM2));
101 }
102
103 static int push_timeout(char button_code)
104 {
105         ulong push_start = get_timer(0);
106         while (get_timer(push_start) <= PUSHHOLD)
107                 if (avr_tstc() && avr_getc() == button_code)
108                         return 0;
109         return 1;
110 }
111
112 static void next_boot_choice(void)
113 {
114         ulong return_start;
115         ulong pulse_start;
116         int on_times;
117         int button_on;
118         int led_state;
119         char c;
120
121         button_on = 0;
122         return_start = get_timer(0);
123
124         on_times = boot_choice;
125         led_state = 0;
126         miconCntl_SendCmd(HDDLEDOFF);
127         pulse_start = get_timer(0);
128
129         while (get_timer(return_start) <= NOBUTTON || button_on) {
130                 if (avr_tstc()) {
131                         c = avr_getc();
132                         if (c == PWRP)
133                                 button_on = 1;
134                         else if (c == PWRR) {
135                                 button_on = 0;
136                                 return_start = get_timer(0);
137                                 if (++boot_choice > MAX_BOOT_CHOICE)
138                                         boot_choice = 1;
139                                 sprintf(envbuffer, "bootcmd%d", boot_choice);
140                                 if (getenv(envbuffer)) {
141                                         sprintf(envbuffer, "run bootcmd%d", boot_choice);
142                                         setenv("bootcmd", envbuffer);
143                                 }
144                                 on_times = boot_choice;
145                                 led_state = 1;
146                                 miconCntl_SendCmd(HDDLEDON);
147                                 pulse_start = get_timer(0);
148                         } else {
149                                 perror("Unexpected code: 0x%02X\n", c);
150                         }
151                 }
152                 if (on_times && get_timer(pulse_start) > PULSETIME) {
153                         if (led_state == 1) {
154                                 --on_times;
155                                 led_state = 0;
156                                 miconCntl_SendCmd(HDDLEDOFF);
157                         } else {
158                                 led_state = 1;
159                                 miconCntl_SendCmd(HDDLEDON);
160                         }
161                         pulse_start = get_timer(0);
162                 }
163                 if (!on_times && get_timer(pulse_start) > LONGPAUSE) {
164                         on_times = boot_choice;
165                         led_state = 1;
166                         miconCntl_SendCmd(HDDLEDON);
167                         pulse_start = get_timer(0);
168                 }
169         }
170         if (led_state)
171                 miconCntl_SendCmd(HDDLEDOFF);
172 }
173
174 void next_cons_choice(int console)
175 {
176         ulong return_start;
177         ulong pulse_start;
178         int on_times;
179         int button_on;
180         int led_state;
181         char c;
182
183         button_on = 0;
184         cons_choice = console;
185         return_start = get_timer(0);
186
187         on_times = cons_choice+1;
188         led_state = 1;
189         miconCntl_SendCmd(HDDLEDON);
190         pulse_start = get_timer(0);
191
192         while (get_timer(return_start) <= NOBUTTON || button_on) {
193                 if (avr_tstc()) {
194                         c = avr_getc();
195                         if (c == RESP)
196                                 button_on = 1;
197                         else if (c == RESR) {
198                                 button_on = 0;
199                                 return_start = get_timer(0);
200                                 cons_choice = (cons_choice + 1) % MAX_CONS_CHOICE;
201                                 console_assign(stdin, consoles[cons_choice]);
202                                 console_assign(stdout, consoles[cons_choice]);
203                                 console_assign(stderr, consoles[cons_choice]);
204                                 on_times = cons_choice+1;
205                                 led_state = 0;
206                                 miconCntl_SendCmd(HDDLEDOFF);
207                                 pulse_start = get_timer(0);
208                         } else {
209                                 perror("Unexpected code: 0x%02X\n", c);
210                         }
211                 }
212                 if (on_times && get_timer(pulse_start) > PULSETIME) {
213                         if (led_state == 0) {
214                                 --on_times;
215                                 led_state = 1;
216                                 miconCntl_SendCmd(HDDLEDON);
217                         } else {
218                                 led_state = 0;
219                                 miconCntl_SendCmd(HDDLEDOFF);
220                         }
221                         pulse_start = get_timer(0);
222                 }
223                 if (!on_times && get_timer(pulse_start) > LONGPAUSE) {
224                         on_times = cons_choice+1;
225                         led_state = 0;
226                         miconCntl_SendCmd(HDDLEDOFF);
227                         pulse_start = get_timer(0);
228                 }
229         }
230         if (led_state);
231         miconCntl_SendCmd(HDDLEDOFF);
232 }
233
234 int avr_input(void)
235 {
236         char avr_button;
237
238         if (!avr_tstc())
239                 return 0;
240
241         avr_button = avr_getc();
242         switch (avr_button) {
243         case PWRP:
244                 if (push_timeout(PWRR)) {
245                         /* Timeout before power button release */
246                         boot_stop = ~boot_stop;
247                         if (boot_stop)
248                                 miconCntl_SendCmd(PWRBLINKSTOP);
249                         else
250                                 miconCntl_SendCmd(PWRBLINKSTRT);
251                         /* Wait for power button release */
252                         while (avr_getc() != PWRR)
253                                 ;
254                 } else
255                         /* Power button released */
256                         next_boot_choice();
257                 break;
258         case RESP:
259                 /* Wait for Reset button release */
260                 while (avr_getc() != RESR)
261                         ;
262                 next_cons_choice(cons_choice);
263                 break;
264         case AVRINIT:
265                 return 0;
266         default:
267                 perror("Unexpected code: 0x%02X\n", avr_button);
268                 return 0;
269         }
270         if (boot_stop)
271                 return (-3);
272         else
273                 return (-2);
274 }
275
276 void avr_StopBoot(void)
277 {
278         boot_stop = ~0;
279         miconCntl_SendCmd(PWRBLINKSTOP);
280 }