linux-old/arch/ppc/xmon/start.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 1996 Paul Mackerras.
   3 */
   4#include <linux/config.h>
   5#include <linux/string.h>
   6#include <asm/machdep.h>
   7#include <asm/io.h>
   8#include <asm/page.h>
   9#include <linux/adb.h>
  10#include <linux/pmu.h>
  11#include <linux/cuda.h>
  12#include <linux/kernel.h>
  13#include <linux/errno.h>
  14#include <linux/sysrq.h>
  15#include <asm/prom.h>
  16#include <asm/bootx.h>
  17#include <asm/machdep.h>
  18#include <asm/errno.h>
  19#include <asm/pmac_feature.h>
  20#include <asm/processor.h>
  21#include <asm/delay.h>
  22#include <asm/btext.h>
  23#ifdef CONFIG_SMP
  24#include <asm/bitops.h>
  25#endif
  26
  27static volatile unsigned char *sccc, *sccd;
  28unsigned int TXRDY, RXRDY, DLAB;
  29extern void xmon_printf(const char *fmt, ...);
  30static int xmon_expect(const char *str, unsigned int timeout);
  31
  32static int use_screen;
  33static int via_modem;
  34static int xmon_use_sccb;
  35static struct device_node *channel_node;
  36
  37#define TB_SPEED        25000000
  38
  39static inline unsigned int readtb(void)
  40{
  41        unsigned int ret;
  42
  43        asm volatile("mftb %0" : "=r" (ret) :);
  44        return ret;
  45}
  46
  47void buf_access(void)
  48{
  49        if (DLAB)
  50                sccd[3] &= ~DLAB;       /* reset DLAB */
  51}
  52
  53extern int adb_init(void);
  54
  55#ifdef CONFIG_ALL_PPC
  56/*
  57 * This looks in the "ranges" property for the primary PCI host bridge
  58 * to find the physical address of the start of PCI/ISA I/O space.
  59 * It is basically a cut-down version of pci_process_bridge_OF_ranges.
  60 */
  61static unsigned long chrp_find_phys_io_base(void)
  62{
  63        struct device_node *node;
  64        unsigned int *ranges;
  65        unsigned long base = CHRP_ISA_IO_BASE;
  66        int rlen = 0;
  67        int np;
  68
  69        node = find_devices("isa");
  70        if (node != NULL) {
  71                node = node->parent;
  72                if (node == NULL || node->type == NULL
  73                    || strcmp(node->type, "pci") != 0)
  74                        node = NULL;
  75        }
  76        if (node == NULL)
  77                node = find_devices("pci");
  78        if (node == NULL)
  79                return base;
  80
  81        ranges = (unsigned int *) get_property(node, "ranges", &rlen);
  82        np = prom_n_addr_cells(node) + 5;
  83        while ((rlen -= np * sizeof(unsigned int)) >= 0) {
  84                if ((ranges[0] >> 24) == 1 && ranges[2] == 0) {
  85                        /* I/O space starting at 0, grab the phys base */
  86                        base = ranges[np - 3];
  87                        break;
  88                }
  89                ranges += np;
  90        }
  91        return base;
  92}
  93#endif /* CONFIG_ALL_PPC */
  94
  95static void sysrq_handle_xmon(int key, struct pt_regs *regs,
  96                              struct kbd_struct *kbd, struct tty_struct *tty)
  97{
  98        xmon(regs);
  99}
 100
 101static struct sysrq_key_op sysrq_xmon_op =
 102{
 103        handler:        sysrq_handle_xmon,
 104        help_msg:       "Xmon",
 105        action_msg:     "Entering xmon\n",
 106};
 107
 108void
 109xmon_map_scc(void)
 110{
 111#ifdef CONFIG_ALL_PPC
 112        volatile unsigned char *base;
 113
 114        use_screen = 0;
 115
 116        if (_machine == _MACH_Pmac) {
 117                struct device_node *np;
 118                unsigned long addr;
 119#ifdef CONFIG_BOOTX_TEXT
 120                if (!machine_is_compatible("iMac")) {
 121                        /* see if there is a keyboard in the device tree
 122                           with a parent of type "adb" */
 123                        for (np = find_devices("keyboard"); np; np = np->next)
 124                                if (np->parent && np->parent->type
 125                                    && strcmp(np->parent->type, "adb") == 0)
 126                                        break;
 127
 128                        /* needs to be hacked if xmon_printk is to be used
 129                           from within find_via_pmu() */
 130#ifdef CONFIG_ADB_PMU
 131                        if (np != NULL && boot_text_mapped && find_via_pmu())
 132                                use_screen = 1;
 133#endif
 134#ifdef CONFIG_ADB_CUDA
 135                        if (np != NULL && boot_text_mapped && find_via_cuda())
 136                                use_screen = 1;
 137#endif
 138                }
 139                if (!use_screen && (np = find_devices("escc")) != NULL) {
 140                        /*
 141                         * look for the device node for the serial port
 142                         * we're using and see if it says it has a modem
 143                         */
 144                        char *name = xmon_use_sccb? "ch-b": "ch-a";
 145                        char *slots;
 146                        int l;
 147
 148                        np = np->child;
 149                        while (np != NULL && strcmp(np->name, name) != 0)
 150                                np = np->sibling;
 151                        if (np != NULL) {
 152                                /* XXX should parse this properly */
 153                                channel_node = np;
 154                                slots = get_property(np, "slot-names", &l);
 155                                if (slots != NULL && l >= 10
 156                                    && strcmp(slots+4, "Modem") == 0)
 157                                        via_modem = 1;
 158                        }
 159                }
 160                btext_drawstring("xmon uses ");
 161                if (use_screen)
 162                        btext_drawstring("screen and keyboard\n");
 163                else {
 164                        if (via_modem)
 165                                btext_drawstring("modem on ");
 166                        btext_drawstring(xmon_use_sccb? "printer": "modem");
 167                        btext_drawstring(" port\n");
 168                }
 169
 170#endif /* CONFIG_BOOTX_TEXT */
 171
 172#ifdef CHRP_ESCC
 173                addr = 0xc1013020;
 174#else
 175                addr = 0xf3013020;
 176#endif
 177                TXRDY = 4;
 178                RXRDY = 1;
 179
 180                np = find_devices("mac-io");
 181                if (np && np->n_addrs)
 182                        addr = np->addrs[0].address + 0x13020;
 183                base = (volatile unsigned char *) ioremap(addr & PAGE_MASK, PAGE_SIZE);
 184                sccc = base + (addr & ~PAGE_MASK);
 185                sccd = sccc + 0x10;
 186
 187        } else {
 188                base = (volatile unsigned char *) isa_io_base;
 189                if (_machine == _MACH_chrp)
 190                        base = (volatile unsigned char *)
 191                                ioremap(chrp_find_phys_io_base(), 0x1000);
 192
 193                sccc = base + 0x3fd;
 194                sccd = base + 0x3f8;
 195                if (xmon_use_sccb) {
 196                        sccc -= 0x100;
 197                        sccd -= 0x100;
 198                }
 199                TXRDY = 0x20;
 200                RXRDY = 1;
 201                DLAB = 0x80;
 202        }
 203#elif defined(CONFIG_GEMINI)
 204        /* should already be mapped by the kernel boot */
 205        sccc = (volatile unsigned char *) 0xffeffb0d;
 206        sccd = (volatile unsigned char *) 0xffeffb08;
 207        TXRDY = 0x20;
 208        RXRDY = 1;
 209        DLAB = 0x80;
 210#elif defined(CONFIG_405GP) || defined(CONFIG_405LP) || defined(CONFIG_405EP)
 211        sccc = (volatile unsigned char *)0xef600305;
 212        sccd = (volatile unsigned char *)0xef600300;
 213        TXRDY = 0x20;
 214        RXRDY = 1;
 215        DLAB = 0x80;
 216#endif /* platform */
 217
 218        __sysrq_put_key_op('x', &sysrq_xmon_op);
 219}
 220
 221static int scc_initialized = 0;
 222
 223void xmon_init_scc(void);
 224extern void pmu_poll(void);
 225extern void cuda_poll(void);
 226
 227static inline void do_poll_adb(void)
 228{
 229#ifdef CONFIG_ADB_PMU
 230        if (sys_ctrler == SYS_CTRLER_PMU)
 231                pmu_poll();
 232#endif /* CONFIG_ADB_PMU */
 233#ifdef CONFIG_ADB_CUDA
 234        if (sys_ctrler == SYS_CTRLER_CUDA)
 235                cuda_poll();
 236#endif /* CONFIG_ADB_CUDA */
 237}
 238
 239int
 240xmon_write(void *handle, void *ptr, int nb)
 241{
 242        char *p = ptr;
 243        int i, c, ct;
 244
 245#ifdef CONFIG_SMP
 246        static unsigned long xmon_write_lock;
 247        int lock_wait = 1000000;
 248        int locked;
 249
 250        while ((locked = test_and_set_bit(0, &xmon_write_lock)) != 0)
 251                if (--lock_wait == 0)
 252                        break;
 253#endif
 254
 255#ifdef CONFIG_BOOTX_TEXT
 256        if (use_screen) {
 257                /* write it on the screen */
 258                for (i = 0; i < nb; ++i)
 259                        btext_drawchar(*p++);
 260                goto out;
 261        }
 262#endif
 263        if (!scc_initialized)
 264                xmon_init_scc();
 265        ct = 0;
 266        for (i = 0; i < nb; ++i) {
 267                while ((*sccc & TXRDY) == 0)
 268                        do_poll_adb();
 269                c = p[i];
 270                if (c == '\n' && !ct) {
 271                        c = '\r';
 272                        ct = 1;
 273                        --i;
 274                } else {
 275                        ct = 0;
 276                }
 277                buf_access();
 278                *sccd = c;
 279                eieio();
 280        }
 281
 282 out:
 283#ifdef CONFIG_SMP
 284        if (!locked)
 285                clear_bit(0, &xmon_write_lock);
 286#endif
 287        return nb;
 288}
 289
 290int xmon_wants_key;
 291int xmon_adb_keycode;
 292
 293#ifdef CONFIG_BOOTX_TEXT
 294static int xmon_adb_shiftstate;
 295
 296static unsigned char xmon_keytab[128] =
 297        "asdfhgzxcv\000bqwer"                           /* 0x00 - 0x0f */
 298        "yt123465=97-80]o"                              /* 0x10 - 0x1f */
 299        "u[ip\rlj'k;\\,/nm."                            /* 0x20 - 0x2f */
 300        "\t `\177\0\033\0\0\0\0\0\0\0\0\0\0"            /* 0x30 - 0x3f */
 301        "\0.\0*\0+\0\0\0\0\0/\r\0-\0"                   /* 0x40 - 0x4f */
 302        "\0\0000123456789\0\0\0";                       /* 0x50 - 0x5f */
 303
 304static unsigned char xmon_shift_keytab[128] =
 305        "ASDFHGZXCV\000BQWER"                           /* 0x00 - 0x0f */
 306        "YT!@#$^%+(&_*)}O"                              /* 0x10 - 0x1f */
 307        "U{IP\rLJ\"K:|<?NM>"                            /* 0x20 - 0x2f */
 308        "\t ~\177\0\033\0\0\0\0\0\0\0\0\0\0"            /* 0x30 - 0x3f */
 309        "\0.\0*\0+\0\0\0\0\0/\r\0-\0"                   /* 0x40 - 0x4f */
 310        "\0\0000123456789\0\0\0";                       /* 0x50 - 0x5f */
 311
 312static int
 313xmon_get_adb_key(void)
 314{
 315        int k, t, on;
 316
 317        xmon_wants_key = 1;
 318        for (;;) {
 319                xmon_adb_keycode = -1;
 320                t = 0;
 321                on = 0;
 322                do {
 323                        if (--t < 0) {
 324                                on = 1 - on;
 325                                btext_drawchar(on? 0xdb: 0x20);
 326                                btext_drawchar('\b');
 327                                t = 200000;
 328                        }
 329                        do_poll_adb();
 330                } while (xmon_adb_keycode == -1);
 331                k = xmon_adb_keycode;
 332                if (on)
 333                        btext_drawstring(" \b");
 334
 335                /* test for shift keys */
 336                if ((k & 0x7f) == 0x38 || (k & 0x7f) == 0x7b) {
 337                        xmon_adb_shiftstate = (k & 0x80) == 0;
 338                        continue;
 339                }
 340                if (k >= 0x80)
 341                        continue;       /* ignore up transitions */
 342                k = (xmon_adb_shiftstate? xmon_shift_keytab: xmon_keytab)[k];
 343                if (k != 0)
 344                        break;
 345        }
 346        xmon_wants_key = 0;
 347        return k;
 348}
 349#endif /* CONFIG_BOOTX_TEXT */
 350
 351int
 352xmon_read(void *handle, void *ptr, int nb)
 353{
 354    char *p = ptr;
 355    int i;
 356
 357#ifdef CONFIG_BOOTX_TEXT
 358    if (use_screen) {
 359        for (i = 0; i < nb; ++i)
 360            *p++ = xmon_get_adb_key();
 361        return i;
 362    }
 363#endif
 364    if (!scc_initialized)
 365        xmon_init_scc();
 366    for (i = 0; i < nb; ++i) {
 367        while ((*sccc & RXRDY) == 0)
 368            do_poll_adb();
 369        buf_access();
 370        *p++ = *sccd;
 371    }
 372    return i;
 373}
 374
 375int
 376xmon_read_poll(void)
 377{
 378        if ((*sccc & RXRDY) == 0) {
 379                do_poll_adb();
 380                return -1;
 381        }
 382        buf_access();
 383        return *sccd;
 384}
 385
 386static unsigned char scc_inittab[] = {
 387    13, 0,              /* set baud rate divisor */
 388    12, 1,
 389    14, 1,              /* baud rate gen enable, src=rtxc */
 390    11, 0x50,           /* clocks = br gen */
 391    5,  0xea,           /* tx 8 bits, assert DTR & RTS */
 392    4,  0x46,           /* x16 clock, 1 stop */
 393    3,  0xc1,           /* rx enable, 8 bits */
 394};
 395
 396void
 397xmon_init_scc()
 398{
 399        if ( _machine == _MACH_chrp )
 400        {
 401                sccd[3] = 0x83; eieio();        /* LCR = 8N1 + DLAB */
 402                sccd[0] = 12; eieio();          /* DLL = 9600 baud */
 403                sccd[1] = 0; eieio();
 404                sccd[2] = 0; eieio();           /* FCR = 0 */
 405                sccd[3] = 3; eieio();           /* LCR = 8N1 */
 406                sccd[1] = 0; eieio();           /* IER = 0 */
 407        }
 408        else if ( _machine == _MACH_Pmac )
 409        {
 410                int i, x;
 411
 412                if (channel_node != 0)
 413                        pmac_call_feature(
 414                                PMAC_FTR_SCC_ENABLE,
 415                                channel_node,
 416                                PMAC_SCC_ASYNC | PMAC_SCC_FLAG_XMON, 1);
 417                        printk(KERN_INFO "Serial port locked ON by debugger !\n");
 418                if (via_modem && channel_node != 0) {
 419                        unsigned int t0;
 420
 421                        pmac_call_feature(
 422                                PMAC_FTR_MODEM_ENABLE,
 423                                channel_node, 0, 1);
 424                        printk(KERN_INFO "Modem powered up by debugger !\n");
 425                        t0 = readtb();
 426                        while (readtb() - t0 < 3*TB_SPEED)
 427                                eieio();
 428                }
 429                /* use the B channel if requested */
 430                if (xmon_use_sccb) {
 431                        sccc = (volatile unsigned char *)
 432                                ((unsigned long)sccc & ~0x20);
 433                        sccd = sccc + 0x10;
 434                }
 435                for (i = 20000; i != 0; --i) {
 436                        x = *sccc; eieio();
 437                }
 438                *sccc = 9; eieio();             /* reset A or B side */
 439                *sccc = ((unsigned long)sccc & 0x20)? 0x80: 0x40; eieio();
 440                for (i = 0; i < sizeof(scc_inittab); ++i) {
 441                        *sccc = scc_inittab[i];
 442                        eieio();
 443                }
 444        }
 445        scc_initialized = 1;
 446        if (via_modem) {
 447                for (;;) {
 448                        xmon_write(0, "ATE1V1\r", 7);
 449                        if (xmon_expect("OK", 5)) {
 450                                xmon_write(0, "ATA\r", 4);
 451                                if (xmon_expect("CONNECT", 40))
 452                                        break;
 453                        }
 454                        xmon_write(0, "+++", 3);
 455                        xmon_expect("OK", 3);
 456                }
 457        }
 458}
 459
 460#if 0
 461extern int (*prom_entry)(void *);
 462
 463int
 464xmon_exit(void)
 465{
 466    struct prom_args {
 467        char *service;
 468    } args;
 469
 470    for (;;) {
 471        args.service = "exit";
 472        (*prom_entry)(&args);
 473    }
 474}
 475#endif
 476
 477void *xmon_stdin;
 478void *xmon_stdout;
 479void *xmon_stderr;
 480
 481void
 482xmon_init(void)
 483{
 484}
 485
 486int
 487xmon_putc(int c, void *f)
 488{
 489    char ch = c;
 490
 491    if (c == '\n')
 492        xmon_putc('\r', f);
 493    return xmon_write(f, &ch, 1) == 1? c: -1;
 494}
 495
 496int
 497xmon_putchar(int c)
 498{
 499    return xmon_putc(c, xmon_stdout);
 500}
 501
 502int
 503xmon_fputs(char *str, void *f)
 504{
 505    int n = strlen(str);
 506
 507    return xmon_write(f, str, n) == n? 0: -1;
 508}
 509
 510int
 511xmon_readchar(void)
 512{
 513    char ch;
 514
 515    for (;;) {
 516        switch (xmon_read(xmon_stdin, &ch, 1)) {
 517        case 1:
 518            return ch;
 519        case -1:
 520            xmon_printf("read(stdin) returned -1\r\n", 0, 0);
 521            return -1;
 522        }
 523    }
 524}
 525
 526static char line[256];
 527static char *lineptr;
 528static int lineleft;
 529
 530int xmon_expect(const char *str, unsigned int timeout)
 531{
 532        int c;
 533        unsigned int t0;
 534
 535        timeout *= TB_SPEED;
 536        t0 = readtb();
 537        do {
 538                lineptr = line;
 539                for (;;) {
 540                        c = xmon_read_poll();
 541                        if (c == -1) {
 542                                if (readtb() - t0 > timeout)
 543                                        return 0;
 544                                continue;
 545                        }
 546                        if (c == '\n')
 547                                break;
 548                        if (c != '\r' && lineptr < &line[sizeof(line) - 1])
 549                                *lineptr++ = c;
 550                }
 551                *lineptr = 0;
 552        } while (strstr(line, str) == NULL);
 553        return 1;
 554}
 555
 556int
 557xmon_getchar(void)
 558{
 559    int c;
 560
 561    if (lineleft == 0) {
 562        lineptr = line;
 563        for (;;) {
 564            c = xmon_readchar();
 565            if (c == -1 || c == 4)
 566                break;
 567            if (c == '\r' || c == '\n') {
 568                *lineptr++ = '\n';
 569                xmon_putchar('\n');
 570                break;
 571            }
 572            switch (c) {
 573            case 0177:
 574            case '\b':
 575                if (lineptr > line) {
 576                    xmon_putchar('\b');
 577                    xmon_putchar(' ');
 578                    xmon_putchar('\b');
 579                    --lineptr;
 580                }
 581                break;
 582            case 'U' & 0x1F:
 583                while (lineptr > line) {
 584                    xmon_putchar('\b');
 585                    xmon_putchar(' ');
 586                    xmon_putchar('\b');
 587                    --lineptr;
 588                }
 589                break;
 590            default:
 591                if (lineptr >= &line[sizeof(line) - 1])
 592                    xmon_putchar('\a');
 593                else {
 594                    xmon_putchar(c);
 595                    *lineptr++ = c;
 596                }
 597            }
 598        }
 599        lineleft = lineptr - line;
 600        lineptr = line;
 601    }
 602    if (lineleft == 0)
 603        return -1;
 604    --lineleft;
 605    return *lineptr++;
 606}
 607
 608char *
 609xmon_fgets(char *str, int nb, void *f)
 610{
 611    char *p;
 612    int c;
 613
 614    for (p = str; p < str + nb - 1; ) {
 615        c = xmon_getchar();
 616        if (c == -1) {
 617            if (p == str)
 618                return 0;
 619            break;
 620        }
 621        *p++ = c;
 622        if (c == '\n')
 623            break;
 624    }
 625    *p = 0;
 626    return str;
 627}
 628
 629void
 630xmon_enter(void)
 631{
 632#ifdef CONFIG_ADB_PMU
 633        if (_machine == _MACH_Pmac) {
 634                pmu_suspend();
 635        }
 636#endif
 637}
 638
 639void
 640xmon_leave(void)
 641{
 642#ifdef CONFIG_ADB_PMU
 643        if (_machine == _MACH_Pmac) {
 644                pmu_resume();
 645        }
 646#endif
 647}
 648
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.