avr.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. /*
  2. * avr.c
  3. *
  4. * AVR functions
  5. *
  6. * Copyright (C) 2006 Mihai Georgian <u-boot@linuxnotincluded.org.uk>
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License as
  10. * published by the Free Software Foundation; either version 2 of
  11. * the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  21. * MA 02111-1307 USA
  22. */
  23. #include <common.h>
  24. #include <ns16550.h>
  25. #include <console.h>
  26. /* Button codes from the AVR */
  27. #define PWRR 0x20 /* Power button release */
  28. #define PWRP 0x21 /* Power button push */
  29. #define RESR 0x22 /* Reset button release */
  30. #define RESP 0x23 /* Reset button push */
  31. #define AVRINIT 0x33 /* Init complete */
  32. #define AVRRESET 0x31 /* Reset request */
  33. /* LED commands */
  34. #define PWRBLINKSTRT '[' /* Blink power LED */
  35. #define PWRBLINKSTOP 'Z' /* Solid power LED */
  36. #define HDDLEDON 'W' /* HDD LED on */
  37. #define HDDLEDOFF 'V' /* HDD LED off */
  38. #define HDDBLINKSTRT 'Y' /* HDD LED start blink */
  39. #define HDDBLINKSTOP 'X' /* HDD LED stop blink */
  40. /* Timings for LEDs blinking to show choice */
  41. #define PULSETIME 250 /* msecs */
  42. #define LONGPAUSE (5 * PULSETIME)
  43. /* Button press times */
  44. #define PUSHHOLD 1000 /* msecs */
  45. #define NOBUTTON (6 * (LONGPAUSE+PULSETIME))
  46. /* Boot and console choices */
  47. #define MAX_BOOT_CHOICE 3
  48. static char *consoles[] = {
  49. "serial",
  50. #if defined(CONFIG_NETCONSOLE)
  51. "nc",
  52. #endif
  53. };
  54. #define MAX_CONS_CHOICE (sizeof(consoles)/sizeof(char *))
  55. #if !defined(CONFIG_NETCONSOLE)
  56. #define DEF_CONS_CHOICE 0
  57. #else
  58. #define DEF_CONS_CHOICE 1
  59. #endif
  60. #define perror(fmt, args...) printf("%s: " fmt, __FUNCTION__ , ##args)
  61. extern void miconCntl_SendCmd(unsigned char dat);
  62. extern void miconCntl_DisWDT(void);
  63. static int boot_stop;
  64. static int boot_choice = 1;
  65. static int cons_choice = DEF_CONS_CHOICE;
  66. static char envbuffer[16];
  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. * AVR port init sequence taken from
  73. * the original Linkstation init code
  74. * Normal U-Boot serial reinit doesn't
  75. * work because the AVR uses even parity
  76. */
  77. AVR_port->lcr = 0x00;
  78. AVR_port->ier = 0x00;
  79. AVR_port->lcr = UART_LCR_BKSE;
  80. AVR_port->dll = clock_divisor & 0xff;
  81. AVR_port->dlm = (clock_divisor >> 8) & 0xff;
  82. AVR_port->lcr = UART_LCR_WLS_8 | UART_LCR_PEN | UART_LCR_EPS;
  83. AVR_port->mcr = 0x00;
  84. AVR_port->fcr = UART_FCR_FIFO_EN | UART_FCR_RXSR | UART_FCR_TXSR;
  85. miconCntl_DisWDT();
  86. boot_stop = 0;
  87. miconCntl_SendCmd(PWRBLINKSTRT);
  88. }
  89. static inline int avr_tstc(void)
  90. {
  91. return (NS16550_tstc((NS16550_t)CONFIG_SYS_NS16550_COM2));
  92. }
  93. static inline char avr_getc(void)
  94. {
  95. return (NS16550_getc((NS16550_t)CONFIG_SYS_NS16550_COM2));
  96. }
  97. static int push_timeout(char button_code)
  98. {
  99. ulong push_start = get_timer(0);
  100. while (get_timer(push_start) <= PUSHHOLD)
  101. if (avr_tstc() && avr_getc() == button_code)
  102. return 0;
  103. return 1;
  104. }
  105. static void next_boot_choice(void)
  106. {
  107. ulong return_start;
  108. ulong pulse_start;
  109. int on_times;
  110. int button_on;
  111. int led_state;
  112. char c;
  113. button_on = 0;
  114. return_start = get_timer(0);
  115. on_times = boot_choice;
  116. led_state = 0;
  117. miconCntl_SendCmd(HDDLEDOFF);
  118. pulse_start = get_timer(0);
  119. while (get_timer(return_start) <= NOBUTTON || button_on) {
  120. if (avr_tstc()) {
  121. c = avr_getc();
  122. if (c == PWRP)
  123. button_on = 1;
  124. else if (c == PWRR) {
  125. button_on = 0;
  126. return_start = get_timer(0);
  127. if (++boot_choice > MAX_BOOT_CHOICE)
  128. boot_choice = 1;
  129. sprintf(envbuffer, "bootcmd%d", boot_choice);
  130. if (getenv(envbuffer)) {
  131. sprintf(envbuffer, "run bootcmd%d", boot_choice);
  132. setenv("bootcmd", envbuffer);
  133. }
  134. on_times = boot_choice;
  135. led_state = 1;
  136. miconCntl_SendCmd(HDDLEDON);
  137. pulse_start = get_timer(0);
  138. } else {
  139. perror("Unexpected code: 0x%02X\n", c);
  140. }
  141. }
  142. if (on_times && get_timer(pulse_start) > PULSETIME) {
  143. if (led_state == 1) {
  144. --on_times;
  145. led_state = 0;
  146. miconCntl_SendCmd(HDDLEDOFF);
  147. } else {
  148. led_state = 1;
  149. miconCntl_SendCmd(HDDLEDON);
  150. }
  151. pulse_start = get_timer(0);
  152. }
  153. if (!on_times && get_timer(pulse_start) > LONGPAUSE) {
  154. on_times = boot_choice;
  155. led_state = 1;
  156. miconCntl_SendCmd(HDDLEDON);
  157. pulse_start = get_timer(0);
  158. }
  159. }
  160. if (led_state)
  161. miconCntl_SendCmd(HDDLEDOFF);
  162. }
  163. void next_cons_choice(int console)
  164. {
  165. ulong return_start;
  166. ulong pulse_start;
  167. int on_times;
  168. int button_on;
  169. int led_state;
  170. char c;
  171. button_on = 0;
  172. cons_choice = console;
  173. return_start = get_timer(0);
  174. on_times = cons_choice+1;
  175. led_state = 1;
  176. miconCntl_SendCmd(HDDLEDON);
  177. pulse_start = get_timer(0);
  178. while (get_timer(return_start) <= NOBUTTON || button_on) {
  179. if (avr_tstc()) {
  180. c = avr_getc();
  181. if (c == RESP)
  182. button_on = 1;
  183. else if (c == RESR) {
  184. button_on = 0;
  185. return_start = get_timer(0);
  186. cons_choice = (cons_choice + 1) % MAX_CONS_CHOICE;
  187. console_assign(stdin, consoles[cons_choice]);
  188. console_assign(stdout, consoles[cons_choice]);
  189. console_assign(stderr, consoles[cons_choice]);
  190. on_times = cons_choice+1;
  191. led_state = 0;
  192. miconCntl_SendCmd(HDDLEDOFF);
  193. pulse_start = get_timer(0);
  194. } else {
  195. perror("Unexpected code: 0x%02X\n", c);
  196. }
  197. }
  198. if (on_times && get_timer(pulse_start) > PULSETIME) {
  199. if (led_state == 0) {
  200. --on_times;
  201. led_state = 1;
  202. miconCntl_SendCmd(HDDLEDON);
  203. } else {
  204. led_state = 0;
  205. miconCntl_SendCmd(HDDLEDOFF);
  206. }
  207. pulse_start = get_timer(0);
  208. }
  209. if (!on_times && get_timer(pulse_start) > LONGPAUSE) {
  210. on_times = cons_choice+1;
  211. led_state = 0;
  212. miconCntl_SendCmd(HDDLEDOFF);
  213. pulse_start = get_timer(0);
  214. }
  215. }
  216. if (led_state);
  217. miconCntl_SendCmd(HDDLEDOFF);
  218. }
  219. int avr_input(void)
  220. {
  221. char avr_button;
  222. if (!avr_tstc())
  223. return 0;
  224. avr_button = avr_getc();
  225. switch (avr_button) {
  226. case PWRP:
  227. if (push_timeout(PWRR)) {
  228. /* Timeout before power button release */
  229. boot_stop = ~boot_stop;
  230. if (boot_stop)
  231. miconCntl_SendCmd(PWRBLINKSTOP);
  232. else
  233. miconCntl_SendCmd(PWRBLINKSTRT);
  234. /* Wait for power button release */
  235. while (avr_getc() != PWRR)
  236. ;
  237. } else
  238. /* Power button released */
  239. next_boot_choice();
  240. break;
  241. case RESP:
  242. /* Wait for Reset button release */
  243. while (avr_getc() != RESR)
  244. ;
  245. next_cons_choice(cons_choice);
  246. break;
  247. case AVRINIT:
  248. return 0;
  249. default:
  250. perror("Unexpected code: 0x%02X\n", avr_button);
  251. return 0;
  252. }
  253. if (boot_stop)
  254. return (-3);
  255. else
  256. return (-2);
  257. }
  258. void avr_StopBoot(void)
  259. {
  260. boot_stop = ~0;
  261. miconCntl_SendCmd(PWRBLINKSTOP);
  262. }