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