uboot/board/inka4x0/inkadiag.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2008, 2009 Andreas Pfefferle,
   3 *     DENX Software Engineering, ap@denx.de.
   4 * (C) Copyright 2009 Detlev Zundel,
   5 *     DENX Software Engineering, dzu@denx.de.
   6 *
   7 * See file CREDITS for list of people who contributed to this
   8 * project.
   9 *
  10 * This program is free software; you can redistribute it and/or
  11 * modify it under the terms of the GNU General Public License as
  12 * published by the Free Software Foundation; either version 2 of
  13 * the License, or (at your option) any later version.
  14 *
  15 * This program is distributed in the hope that it will be useful,
  16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18 * GNU General Public License for more details.
  19 *
  20 * You should have received a copy of the GNU General Public License
  21 * along with this program; if not, write to the Free Software
  22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  23 * MA 02111-1307 USA
  24 */
  25
  26#include <asm/io.h>
  27#include <common.h>
  28#include <config.h>
  29#include <mpc5xxx.h>
  30#include <pci.h>
  31
  32#include <command.h>
  33
  34/* This is needed for the includes in ns16550.h */
  35#define CONFIG_SYS_NS16550_REG_SIZE 1
  36#include <ns16550.h>
  37
  38#define GPIO_BASE               ((u_char *)CONFIG_SYS_CS3_START)
  39
  40#define DIGIN_TOUCHSCR_MASK     0x00003000      /* Inputs 12-13 */
  41#define DIGIN_KEYB_MASK         0x00010000      /* Input 16 */
  42
  43#define DIGIN_DRAWER_SW1        0x00400000      /* Input 22 */
  44#define DIGIN_DRAWER_SW2        0x00800000      /* Input 23 */
  45
  46#define DIGIO_LED0              0x00000001      /* Output 0 */
  47#define DIGIO_LED1              0x00000002      /* Output 1 */
  48#define DIGIO_LED2              0x00000004      /* Output 2 */
  49#define DIGIO_LED3              0x00000008      /* Output 3 */
  50#define DIGIO_LED4              0x00000010      /* Output 4 */
  51#define DIGIO_LED5              0x00000020      /* Output 5 */
  52
  53#define DIGIO_DRAWER1           0x00000100      /* Output 8 */
  54#define DIGIO_DRAWER2           0x00000200      /* Output 9 */
  55
  56#define SERIAL_PORT_BASE        ((u_char *)CONFIG_SYS_CS2_START)
  57
  58#define PSC_OP1_RTS     0x01
  59#define PSC_OP0_RTS     0x01
  60
  61/*
  62 * Table with supported baudrates (defined in inka4x0.h)
  63 */
  64static const unsigned long baudrate_table[] = CONFIG_SYS_BAUDRATE_TABLE;
  65#define N_BAUDRATES (sizeof(baudrate_table) / sizeof(baudrate_table[0]))
  66
  67static unsigned int inka_digin_get_input(void)
  68{
  69        return in_8(GPIO_BASE + 0) << 0 | in_8(GPIO_BASE + 1) << 8 |
  70                in_8(GPIO_BASE + 2) << 16 | in_8(GPIO_BASE + 3) << 24;
  71}
  72
  73#define LED_HIGH(NUM)                                                   \
  74        do {                                                            \
  75                setbits_be32((unsigned *)MPC5XXX_GPT##NUM##_ENABLE, 0x10); \
  76        } while (0)
  77
  78#define LED_LOW(NUM)                                                    \
  79        do {                                                            \
  80                clrbits_be32((unsigned *)MPC5XXX_GPT##NUM##_ENABLE, 0x10); \
  81        } while (0)
  82
  83#define CHECK_LED(NUM) \
  84    do { \
  85            if (state & (1 << NUM)) {           \
  86                    LED_HIGH(NUM);              \
  87            } else {                            \
  88                    LED_LOW(NUM);               \
  89            }                                   \
  90    } while (0)
  91
  92static void inka_digio_set_output(unsigned int state, int which)
  93{
  94        volatile struct mpc5xxx_gpio *gpio = (struct mpc5xxx_gpio *)MPC5XXX_GPIO;
  95
  96        if (which == 0) {
  97                /* other */
  98                CHECK_LED(0);
  99                CHECK_LED(1);
 100                CHECK_LED(2);
 101                CHECK_LED(3);
 102                CHECK_LED(4);
 103                CHECK_LED(5);
 104        } else {
 105                if (which == 1) {
 106                        /* drawer1 */
 107                        if (state) {
 108                                clrbits_be32(&gpio->simple_dvo, 0x1000);
 109                                udelay(1);
 110                                setbits_be32(&gpio->simple_dvo, 0x1000);
 111                        } else {
 112                                setbits_be32(&gpio->simple_dvo, 0x1000);
 113                                udelay(1);
 114                                clrbits_be32(&gpio->simple_dvo, 0x1000);
 115                        }
 116                }
 117                if (which == 2) {
 118                        /* drawer 2 */
 119                        if (state) {
 120                                clrbits_be32(&gpio->simple_dvo, 0x2000);
 121                                udelay(1);
 122                                setbits_be32(&gpio->simple_dvo, 0x2000);
 123                        } else {
 124                                setbits_be32(&gpio->simple_dvo, 0x2000);
 125                                udelay(1);
 126                                clrbits_be32(&gpio->simple_dvo, 0x2000);
 127                        }
 128                }
 129        }
 130        udelay(1);
 131}
 132
 133static int do_inkadiag_io(cmd_tbl_t *cmdtp, int flag, int argc,
 134                          char *argv[]) {
 135        unsigned int state, val;
 136
 137        switch (argc) {
 138        case 3:
 139                /* Write a value */
 140                val = simple_strtol(argv[2], NULL, 16);
 141
 142                if (strcmp(argv[1], "drawer1") == 0) {
 143                        inka_digio_set_output(val, 1);
 144                } else if (strcmp(argv[1], "drawer2") == 0) {
 145                        inka_digio_set_output(val, 2);
 146                } else if (strcmp(argv[1], "other") == 0)
 147                        inka_digio_set_output(val, 0);
 148                else {
 149                        printf("Invalid argument: %s\n", argv[1]);
 150                        return -1;
 151                }
 152                /* fall through */
 153        case 2:
 154                /* Read a value */
 155                state = inka_digin_get_input();
 156
 157                if (strcmp(argv[1], "drawer1") == 0) {
 158                        val = (state & DIGIN_DRAWER_SW1) >> (ffs(DIGIN_DRAWER_SW1) - 1);
 159                } else if (strcmp(argv[1], "drawer2") == 0) {
 160                        val = (state & DIGIN_DRAWER_SW2) >> (ffs(DIGIN_DRAWER_SW2) - 1);
 161                } else if (strcmp(argv[1], "other") == 0) {
 162                        val = ((state & DIGIN_KEYB_MASK) >> (ffs(DIGIN_KEYB_MASK) - 1))
 163                                | (state & DIGIN_TOUCHSCR_MASK) >> (ffs(DIGIN_TOUCHSCR_MASK) - 2);
 164                } else {
 165                        printf("Invalid argument: %s\n", argv[1]);
 166                        return -1;
 167                }
 168                printf("exit code: 0x%X\n", val);
 169                return 0;
 170        default:
 171                cmd_usage(cmdtp);
 172                break;
 173        }
 174
 175        return -1;
 176}
 177
 178DECLARE_GLOBAL_DATA_PTR;
 179
 180static int ser_init(volatile struct mpc5xxx_psc *psc, int baudrate)
 181{
 182        unsigned long baseclk;
 183        int div;
 184
 185        /* reset PSC */
 186        out_8(&psc->command, PSC_SEL_MODE_REG_1);
 187
 188        /* select clock sources */
 189
 190        out_be16(&psc->psc_clock_select, 0);
 191        baseclk = (gd->ipb_clk + 16) / 32;
 192
 193        /* switch to UART mode */
 194        out_be32(&psc->sicr, 0);
 195
 196        /* configure parity, bit length and so on */
 197
 198        out_8(&psc->mode, PSC_MODE_8_BITS | PSC_MODE_PARNONE);
 199        out_8(&psc->mode, PSC_MODE_ONE_STOP);
 200
 201        /* set up UART divisor */
 202        div = (baseclk + (baudrate / 2)) / baudrate;
 203        out_8(&psc->ctur, (div >> 8) & 0xff);
 204        out_8(&psc->ctlr, div & 0xff);
 205
 206        /* disable all interrupts */
 207        out_be16(&psc->psc_imr, 0);
 208
 209        /* reset and enable Rx/Tx */
 210        out_8(&psc->command, PSC_RST_RX);
 211        out_8(&psc->command, PSC_RST_TX);
 212        out_8(&psc->command, PSC_RX_ENABLE | PSC_TX_ENABLE);
 213
 214        return 0;
 215}
 216
 217static void ser_putc(volatile struct mpc5xxx_psc *psc, const char c)
 218{
 219        /* Wait 1 second for last character to go. */
 220        int i = 0;
 221
 222        while (!(psc->psc_status & PSC_SR_TXEMP) && (i++ < 1000000/10))
 223                udelay(10);
 224        psc->psc_buffer_8 = c;
 225
 226}
 227
 228static int ser_getc(volatile struct mpc5xxx_psc *psc)
 229{
 230        /* Wait for a character to arrive. */
 231        int i = 0;
 232
 233        while (!(in_be16(&psc->psc_status) & PSC_SR_RXRDY) && (i++ < 1000000/10))
 234                udelay(10);
 235
 236        return in_8(&psc->psc_buffer_8);
 237}
 238
 239static int do_inkadiag_serial(cmd_tbl_t *cmdtp, int flag, int argc,
 240                              char *argv[]) {
 241        volatile struct NS16550 *uart;
 242        volatile struct mpc5xxx_psc *psc;
 243        unsigned int num, mode;
 244        int combrd, baudrate, i, j, len;
 245        int address;
 246
 247        if (argc < 5) {
 248                cmd_usage(cmdtp);
 249                return 1;
 250        }
 251
 252        argc--;
 253        argv++;
 254
 255        num = simple_strtol(argv[0], NULL, 0);
 256        if (num < 0 || num > 11) {
 257                printf("invalid argument for num: %d\n", num);
 258                return -1;
 259        }
 260
 261        mode = simple_strtol(argv[1], NULL, 0);
 262
 263        combrd = 0;
 264        baudrate = simple_strtoul(argv[2], NULL, 10);
 265        for (i=0; i<N_BAUDRATES; ++i) {
 266                if (baudrate == baudrate_table[i])
 267                        break;
 268        }
 269        if (i == N_BAUDRATES) {
 270                printf("## Baudrate %d bps not supported\n",
 271                       baudrate);
 272                return 1;
 273        }
 274        combrd = 115200 / baudrate;
 275
 276        uart = (struct NS16550 *)(SERIAL_PORT_BASE + (num << 3));
 277
 278        printf("Testing uart %d.\n\n", num);
 279
 280        if ((num >= 0) && (num <= 7)) {
 281                if (mode & 1) {
 282                        /* turn on 'loopback' mode */
 283                        out_8(&uart->mcr, UART_MCR_LOOP);
 284                } else {
 285                        /*
 286                         * establish the UART's operational parameters
 287                         * set DLAB=1, so rbr accesses DLL
 288                         */
 289                        out_8(&uart->lcr, UART_LCR_DLAB);
 290                        /* set baudrate */
 291                        out_8(&uart->rbr, combrd);
 292                        /* set data-format: 8-N-1 */
 293                        out_8(&uart->lcr, UART_LCR_WLS_8);
 294                }
 295
 296                if (mode & 2) {
 297                        /* set request to send */
 298                        out_8(&uart->mcr, UART_MCR_RTS);
 299                        udelay(10);
 300                        /* check clear to send */
 301                        if ((in_8(&uart->msr) & UART_MSR_CTS) == 0x00)
 302                                return -1;
 303                }
 304                if (mode & 4) {
 305                        /* set data terminal ready */
 306                        out_8(&uart->mcr, UART_MCR_DTR);
 307                        udelay(10);
 308                        /* check data set ready and carrier detect */
 309                        if ((in_8(&uart->msr) & (UART_MSR_DSR | UART_MSR_DCD))
 310                            != (UART_MSR_DSR | UART_MSR_DCD))
 311                                return -1;
 312                }
 313
 314                /* write each message-character, read it back, and display it */
 315                for (i = 0, len = strlen(argv[3]); i < len; ++i) {
 316                        j = 0;
 317                        while ((in_8(&uart->lsr) & UART_LSR_THRE) ==    0x00) {
 318                                if (j++ > CONFIG_SYS_HZ)
 319                                        break;
 320                                udelay(10);
 321                        }
 322                        out_8(&uart->rbr, argv[3][i]);
 323                        j = 0;
 324                        while ((in_8(&uart->lsr) & UART_LSR_DR) == 0x00) {
 325                                if (j++ > CONFIG_SYS_HZ)
 326                                        break;
 327                                udelay(10);
 328                        }
 329                        printf("%c", in_8(&uart->rbr));
 330                }
 331                printf("\n\n");
 332                out_8(&uart->mcr, 0x00);
 333        } else {
 334                address = 0;
 335
 336                switch (num) {
 337                case 8:
 338                        address = MPC5XXX_PSC6;
 339                        break;
 340                case 9:
 341                        address = MPC5XXX_PSC3;
 342                        break;
 343                case 10:
 344                        address = MPC5XXX_PSC2;
 345                        break;
 346                case 11:
 347                        address = MPC5XXX_PSC1;
 348                        break;
 349                }
 350                psc = (struct mpc5xxx_psc *)address;
 351                ser_init(psc, simple_strtol(argv[2], NULL, 0));
 352                if (mode & 2) {
 353                        /* set request to send */
 354                        out_8(&psc->op0, PSC_OP0_RTS);
 355                        udelay(10);
 356                        /* check clear to send */
 357                        if ((in_8(&psc->ip) & PSC_IPCR_CTS) == 0)
 358                                return -1;
 359                }
 360                len = strlen(argv[3]);
 361                for (i = 0; i < len; ++i) {
 362                        ser_putc(psc, argv[3][i]);
 363                        printf("%c", ser_getc(psc));
 364                }
 365                printf("\n\n");
 366        }
 367        return 0;
 368}
 369
 370#define BUZZER_GPT      (MPC5XXX_GPT + 0x60)    /* GPT6 */
 371static void buzzer_turn_on(unsigned int freq)
 372{
 373        volatile struct mpc5xxx_gpt *gpt = (struct mpc5xxx_gpt *)(BUZZER_GPT);
 374
 375        const u32 prescale = gd->ipb_clk / freq / 128;
 376        const u32 count = 128;
 377        const u32 width = 64;
 378
 379        gpt->cir = (prescale << 16) | count;
 380        gpt->pwmcr = width << 16;
 381        gpt->emsr = 3;          /* Timer enabled for PWM */
 382}
 383
 384static void buzzer_turn_off(void)
 385{
 386        volatile struct mpc5xxx_gpt *gpt = (struct mpc5xxx_gpt *)(BUZZER_GPT);
 387
 388        gpt->emsr = 0;
 389}
 390
 391static int do_inkadiag_buzzer(cmd_tbl_t *cmdtp, int flag, int argc,
 392                              char *argv[]) {
 393
 394        unsigned int period, freq;
 395        int prev, i;
 396
 397        if (argc != 3) {
 398                cmd_usage(cmdtp);
 399                return 1;
 400        }
 401
 402        argc--;
 403        argv++;
 404
 405        period = simple_strtol(argv[0], NULL, 0);
 406        if (!period)
 407                printf("Zero period is senseless\n");
 408        argc--;
 409        argv++;
 410
 411        freq = simple_strtol(argv[0], NULL, 0);
 412        /* avoid zero prescale in buzzer_turn_on() */
 413        if (freq > gd->ipb_clk / 128) {
 414                printf("%dHz exceeds maximum (%ldHz)\n", freq,
 415                       gd->ipb_clk / 128);
 416        } else if (!freq)
 417                printf("Zero frequency is senseless\n");
 418        else
 419                buzzer_turn_on(freq);
 420
 421        clear_ctrlc();
 422        prev = disable_ctrlc(0);
 423
 424        printf("Buzzing for %d ms. Type ^C to abort!\n\n", period);
 425
 426        i = 0;
 427        while (!ctrlc() && (i++ < CONFIG_SYS_HZ))
 428                udelay(period);
 429
 430        clear_ctrlc();
 431        disable_ctrlc(prev);
 432
 433        buzzer_turn_off();
 434
 435        return 0;
 436}
 437
 438static int do_inkadiag_help(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
 439
 440cmd_tbl_t cmd_inkadiag_sub[] = {
 441        U_BOOT_CMD_MKENT(io, 1, 1, do_inkadiag_io, "read digital input",
 442         "<drawer1|drawer2|other> [value] - get or set specified signal\n"),
 443        U_BOOT_CMD_MKENT(serial, 4, 1, do_inkadiag_serial, "test serial port",
 444         "<num> <mode> <baudrate> <msg>  - test uart num [0..11] in mode\n"
 445         "and baudrate with msg\n"),
 446        U_BOOT_CMD_MKENT(buzzer, 2, 1, do_inkadiag_buzzer, "activate buzzer",
 447         "<period> <freq> - turn buzzer on for period ms with freq hz\n"),
 448        U_BOOT_CMD_MKENT(help, 4, 1, do_inkadiag_help, "get help",
 449         "[command] - get help for command\n"),
 450};
 451
 452static int do_inkadiag_help(cmd_tbl_t *cmdtp, int flag,
 453                            int argc, char *argv[]) {
 454        extern int _do_help (cmd_tbl_t *cmd_start, int cmd_items,
 455                             cmd_tbl_t *cmdtp, int flag,
 456                             int argc, char *argv[]);
 457        /* do_help prints command name - we prepend inkadiag to our subcommands! */
 458#ifdef CONFIG_SYS_LONGHELP
 459        puts ("inkadiag ");
 460#endif
 461        return _do_help(&cmd_inkadiag_sub[0],
 462                ARRAY_SIZE(cmd_inkadiag_sub), cmdtp, flag, argc, argv);
 463}
 464
 465static int do_inkadiag(cmd_tbl_t *cmdtp, int flag, int argc,
 466                       char *argv[]) {
 467        cmd_tbl_t *c;
 468
 469        c = find_cmd_tbl(argv[1], &cmd_inkadiag_sub[0], ARRAY_SIZE(cmd_inkadiag_sub));
 470
 471        if (c) {
 472                argc--;
 473                argv++;
 474                return c->cmd(c, flag, argc, argv);
 475        } else {
 476                /* Unrecognized command */
 477                cmd_usage(cmdtp);
 478                return 1;
 479        }
 480}
 481
 482U_BOOT_CMD(inkadiag, 6, 1, do_inkadiag,
 483           "inkadiag - inka diagnosis\n",
 484           "[inkadiag what ...]\n"
 485           "    - perform a diagnosis on inka hardware\n"
 486           "'inkadiag' performs hardware tests.\n\n");
 487
 488/* Relocate the command table function pointers when running in RAM */
 489int inkadiag_init_r (void) {
 490        cmd_tbl_t *cmdtp;
 491
 492        for (cmdtp = &cmd_inkadiag_sub[0]; cmdtp !=
 493                     &cmd_inkadiag_sub[ARRAY_SIZE(cmd_inkadiag_sub)]; cmdtp++) {
 494                ulong addr;
 495
 496                addr = (ulong) (cmdtp->cmd) + gd->reloc_off;
 497                cmdtp->cmd = (int (*)(struct cmd_tbl_s *, int, int, char *[]))addr;
 498
 499                addr = (ulong)(cmdtp->name) + gd->reloc_off;
 500                cmdtp->name = (char *)addr;
 501
 502                if (cmdtp->usage) {
 503                        addr = (ulong)(cmdtp->usage) + gd->reloc_off;
 504                        cmdtp->usage = (char *)addr;
 505                }
 506#ifdef CONFIG_SYS_LONGHELP
 507                if (cmdtp->help) {
 508                        addr = (ulong)(cmdtp->help) + gd->reloc_off;
 509                        cmdtp->help = (char *)addr;
 510                }
 511#endif
 512        }
 513        return 0;
 514}
 515