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