| 1 | |
| 2 | |
| 3 | * C interface for trapping into the standard LinuxSH BIOS.
|
| 4 | *
|
| 5 | * Copyright (C) 2000 Greg Banks, Mitch Davis
|
| 6 | * Copyright (C) 1999, 2000 Niibe Yutaka
|
| 7 | * Copyright (C) 2002 M. R. Brown
|
| 8 | * Copyright (C) 2004 - 2010 Paul Mundt
|
| 9 |
|
| 10 | #include <linux/module.h>
|
| 11 | #include <linux/console.h>
|
| 12 | #include <linux/tty.h>
|
| 13 | #include <linux/init.h>
|
| 14 | #include <linux/io.h>
|
| 15 | #include <linux/delay.h>
|
| 16 | #include <asm/sh_bios.h>
|
| 17 |
|
| 18 | #define BIOS_CALL_CONSOLE_WRITE 0
|
| 19 | #define BIOS_CALL_ETH_NODE_ADDR 10
|
| 20 | #define BIOS_CALL_SHUTDOWN 11
|
| 21 | #define BIOS_CALL_GDB_DETACH 0xff
|
| 22 |
|
| 23 | void *gdb_vbr_vector = NULL;
|
| 24 |
|
| 25 | static inline long sh_bios_call(long func, long arg0, long arg1, long arg2,
|
| 26 | long arg3)
|
| 27 | {
|
| 28 | register long r0 __asm__("r0") = func;
|
| 29 | register long r4 __asm__("r4") = arg0;
|
| 30 | register long r5 __asm__("r5") = arg1;
|
| 31 | register long r6 __asm__("r6") = arg2;
|
| 32 | register long r7 __asm__("r7") = arg3;
|
| 33 |
|
| 34 | if (!gdb_vbr_vector)
|
| 35 | return -ENOSYS;
|
| 36 |
|
| 37 | __asm__ __volatile__("trapa #0x3f":"=z"(r0)
|
| 38 | :"0"(r0), "r"(r4), "r"(r5), "r"(r6), "r"(r7)
|
| 39 | :"memory");
|
| 40 | return r0;
|
| 41 | }
|
| 42 |
|
| 43 | void sh_bios_console_write(const char *buf, unsigned int len)
|
| 44 | {
|
| 45 | sh_bios_call(BIOS_CALL_CONSOLE_WRITE, (long)buf, (long)len, 0, 0);
|
| 46 | }
|
| 47 |
|
| 48 | void sh_bios_gdb_detach(void)
|
| 49 | {
|
| 50 | sh_bios_call(BIOS_CALL_GDB_DETACH, 0, 0, 0, 0);
|
| 51 | }
|
| 52 | EXPORT_SYMBOL_GPL(sh_bios_gdb_detach);
|
| 53 |
|
| 54 | void sh_bios_get_node_addr(unsigned char *node_addr)
|
| 55 | {
|
| 56 | sh_bios_call(BIOS_CALL_ETH_NODE_ADDR, 0, (long)node_addr, 0, 0);
|
| 57 | }
|
| 58 | EXPORT_SYMBOL_GPL(sh_bios_get_node_addr);
|
| 59 |
|
| 60 | void sh_bios_shutdown(unsigned int how)
|
| 61 | {
|
| 62 | sh_bios_call(BIOS_CALL_SHUTDOWN, how, 0, 0, 0);
|
| 63 | }
|
| 64 |
|
| 65 | |
| 66 | * Read the old value of the VBR register to initialise the vector
|
| 67 | * through which debug and BIOS traps are delegated by the Linux trap
|
| 68 | * handler.
|
| 69 |
|
| 70 | void sh_bios_vbr_init(void)
|
| 71 | {
|
| 72 | unsigned long vbr;
|
| 73 |
|
| 74 | if (unlikely(gdb_vbr_vector))
|
| 75 | return;
|
| 76 |
|
| 77 | __asm__ __volatile__ ("stc vbr, %0" : "=r" (vbr));
|
| 78 |
|
| 79 | if (vbr) {
|
| 80 | gdb_vbr_vector = (void *)(vbr + 0x100);
|
| 81 | printk(KERN_NOTICE "Setting GDB trap vector to %p\n",
|
| 82 | gdb_vbr_vector);
|
| 83 | } else
|
| 84 | printk(KERN_NOTICE "SH-BIOS not detected\n");
|
| 85 | }
|
| 86 |
|
| 87 | |
| 88 | * sh_bios_vbr_reload - Re-load the system VBR from the BIOS vector.
|
| 89 | *
|
| 90 | * This can be used by save/restore code to reinitialize the system VBR
|
| 91 | * from the fixed BIOS VBR. A no-op if no BIOS VBR is known.
|
| 92 |
|
| 93 | void sh_bios_vbr_reload(void)
|
| 94 | {
|
| 95 | if (gdb_vbr_vector)
|
| 96 | __asm__ __volatile__ (
|
| 97 | "ldc %0, vbr"
|
| 98 | :
|
| 99 | : "r" (((unsigned long) gdb_vbr_vector) - 0x100)
|
| 100 | : "memory"
|
| 101 | );
|
| 102 | }
|
| 103 |
|
| 104 | #ifdef CONFIG_EARLY_PRINTK
|
| 105 | |
| 106 | * Print a string through the BIOS
|
| 107 |
|
| 108 | static void sh_console_write(struct console *co, const char *s,
|
| 109 | unsigned count)
|
| 110 | {
|
| 111 | sh_bios_console_write(s, count);
|
| 112 | }
|
| 113 |
|
| 114 | |
| 115 | * Setup initial baud/bits/parity. We do two things here:
|
| 116 | * - construct a cflag setting for the first rs_open()
|
| 117 | * - initialize the serial port
|
| 118 | * Return non-zero if we didn't find a serial port.
|
| 119 |
|
| 120 | static int __init sh_console_setup(struct console *co, char *options)
|
| 121 | {
|
| 122 | int cflag = CREAD | HUPCL | CLOCAL;
|
| 123 |
|
| 124 | |
| 125 | * Now construct a cflag setting.
|
| 126 | * TODO: this is a totally bogus cflag, as we have
|
| 127 | * no idea what serial settings the BIOS is using, or
|
| 128 | * even if its using the serial port at all.
|
| 129 |
|
| 130 | cflag |= B115200 | CS8 | 0;
|
| 131 |
|
| 132 | co->cflag = cflag;
|
| 133 |
|
| 134 | return 0;
|
| 135 | }
|
| 136 |
|
| 137 | static struct console bios_console = {
|
| 138 | .name = "bios",
|
| 139 | .write = sh_console_write,
|
| 140 | .setup = sh_console_setup,
|
| 141 | .flags = CON_PRINTBUFFER,
|
| 142 | .index = -1,
|
| 143 | };
|
| 144 |
|
| 145 | static int __init setup_early_printk(char *buf)
|
| 146 | {
|
| 147 | int keep_early = 0;
|
| 148 |
|
| 149 | if (!buf)
|
| 150 | return 0;
|
| 151 |
|
| 152 | if (strstr(buf, "keep"))
|
| 153 | keep_early = 1;
|
| 154 |
|
| 155 | if (!strncmp(buf, "bios", 4))
|
| 156 | early_console = &bios_console;
|
| 157 |
|
| 158 | if (likely(early_console)) {
|
| 159 | if (keep_early)
|
| 160 | early_console->flags &= ~CON_BOOT;
|
| 161 | else
|
| 162 | early_console->flags |= CON_BOOT;
|
| 163 | register_console(early_console);
|
| 164 | }
|
| 165 |
|
| 166 | return 0;
|
| 167 | }
|
| 168 | early_param("earlyprintk", setup_early_printk);
|
| 169 | #endif
|