^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * Generic serial console support
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Author: Mark A. Greer <mgreer@mvista.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Code in serial_edit_cmdline() copied from <file:arch/ppc/boot/simple/misc.c>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * and was written by Matt Porter <mporter@kernel.crashing.org>.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * 2001,2006 (c) MontaVista Software, Inc. This file is licensed under
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * the terms of the GNU General Public License version 2. This program
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * is licensed "as is" without any warranty of any kind, whether express
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * or implied.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <stdarg.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <stddef.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include "types.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include "string.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include "stdio.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include "io.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include "ops.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) static int serial_open(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) struct serial_console_data *scdp = console_ops.data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) return scdp->open();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) static void serial_write(const char *buf, int len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) struct serial_console_data *scdp = console_ops.data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) while (*buf != '\0')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) scdp->putc(*buf++);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) static void serial_edit_cmdline(char *buf, int len, unsigned int timeout)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) int timer = 0, count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) char ch, *cp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) struct serial_console_data *scdp = console_ops.data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) cp = buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) count = strlen(buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) cp = &buf[count];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) if (scdp->tstc()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) while (((ch = scdp->getc()) != '\n') && (ch != '\r')) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) /* Test for backspace/delete */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) if ((ch == '\b') || (ch == '\177')) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) if (cp != buf) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) cp--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) count--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) printf("\b \b");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) /* Test for ^x/^u (and wipe the line) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) } else if ((ch == '\030') || (ch == '\025')) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) while (cp != buf) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) cp--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) count--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) printf("\b \b");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) } else if (count < len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) *cp++ = ch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) scdp->putc(ch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) break; /* Exit 'timer' loop */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) udelay(1000); /* 1 msec */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) } while (timer++ < timeout);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) *cp = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) static void serial_close(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) struct serial_console_data *scdp = console_ops.data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) if (scdp->close)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) scdp->close();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) static void *serial_get_stdout_devp(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) void *devp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) char devtype[MAX_PROP_LEN];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) char path[MAX_PATH_LEN];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) devp = finddevice("/chosen");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) if (devp == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) goto err_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) if (getprop(devp, "linux,stdout-path", path, MAX_PATH_LEN) > 0 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) getprop(devp, "stdout-path", path, MAX_PATH_LEN) > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) devp = finddevice(path);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) if (devp == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) goto err_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) if ((getprop(devp, "device_type", devtype, sizeof(devtype)) > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) && !strcmp(devtype, "serial"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) return devp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) err_out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) static struct serial_console_data serial_cd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) /* Node's "compatible" property determines which serial driver to use */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) int serial_console_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) void *devp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) int rc = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) devp = serial_get_stdout_devp();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) if (devp == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) goto err_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) if (dt_is_compatible(devp, "ns16550") ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) dt_is_compatible(devp, "pnpPNP,501"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) rc = ns16550_console_init(devp, &serial_cd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) #ifdef CONFIG_CPM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) else if (dt_is_compatible(devp, "fsl,cpm1-scc-uart") ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) dt_is_compatible(devp, "fsl,cpm1-smc-uart") ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) dt_is_compatible(devp, "fsl,cpm2-scc-uart") ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) dt_is_compatible(devp, "fsl,cpm2-smc-uart"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) rc = cpm_console_init(devp, &serial_cd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) #ifdef CONFIG_PPC_MPC52xx
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) else if (dt_is_compatible(devp, "fsl,mpc5200-psc-uart"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) rc = mpc5200_psc_console_init(devp, &serial_cd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) #ifdef CONFIG_PPC64_BOOT_WRAPPER
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) else if (dt_is_compatible(devp, "ibm,opal-console-raw"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) rc = opal_console_init(devp, &serial_cd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) /* Add other serial console driver calls here */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) if (!rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) console_ops.open = serial_open;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) console_ops.write = serial_write;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) console_ops.close = serial_close;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) console_ops.data = &serial_cd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) if (serial_cd.getc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) console_ops.edit_cmdline = serial_edit_cmdline;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) err_out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) }