^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) * IBM RTAS driver interface to hvc_console.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * (C) Copyright IBM Corporation 2001-2005
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * (C) Copyright Red Hat, Inc. 2005
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Author(s): Maximino Augilar <IBM STI Design Center>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * : Ryan S. Arnold <rsa@us.ibm.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * : Utz Bacher <utz.bacher@de.ibm.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * : David Woodhouse <dwmw2@infradead.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * inspired by drivers/char/hvc_console.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * written by Anton Blanchard and Paul Mackerras
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/console.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/moduleparam.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <asm/irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <asm/rtas.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include "hvc_console.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #define hvc_rtas_cookie 0x67781e15
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) struct hvc_struct *hvc_rtas_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) static int rtascons_put_char_token = RTAS_UNKNOWN_SERVICE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) static int rtascons_get_char_token = RTAS_UNKNOWN_SERVICE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) static inline int hvc_rtas_write_console(uint32_t vtermno, const char *buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) int count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) for (i = 0; i < count; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) if (rtas_call(rtascons_put_char_token, 1, 1, NULL, buf[i]))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) return i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) static int hvc_rtas_read_console(uint32_t vtermno, char *buf, int count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) int i, c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) for (i = 0; i < count; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) if (rtas_call(rtascons_get_char_token, 0, 2, &c))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) buf[i] = c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) return i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) static const struct hv_ops hvc_rtas_get_put_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) .get_chars = hvc_rtas_read_console,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) .put_chars = hvc_rtas_write_console,
^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) static int __init hvc_rtas_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) struct hvc_struct *hp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) if (rtascons_put_char_token == RTAS_UNKNOWN_SERVICE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) rtascons_put_char_token = rtas_token("put-term-char");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) if (rtascons_put_char_token == RTAS_UNKNOWN_SERVICE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) if (rtascons_get_char_token == RTAS_UNKNOWN_SERVICE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) rtascons_get_char_token = rtas_token("get-term-char");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) if (rtascons_get_char_token == RTAS_UNKNOWN_SERVICE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) BUG_ON(hvc_rtas_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) /* Allocate an hvc_struct for the console device we instantiated
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) * earlier. Save off hp so that we can return it on exit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) hp = hvc_alloc(hvc_rtas_cookie, 0, &hvc_rtas_get_put_ops, 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) if (IS_ERR(hp))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) return PTR_ERR(hp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) hvc_rtas_dev = hp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) device_initcall(hvc_rtas_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) /* This will happen prior to module init. There is no tty at this time? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) static int __init hvc_rtas_console_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) rtascons_put_char_token = rtas_token("put-term-char");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) if (rtascons_put_char_token == RTAS_UNKNOWN_SERVICE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) rtascons_get_char_token = rtas_token("get-term-char");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) if (rtascons_get_char_token == RTAS_UNKNOWN_SERVICE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) hvc_instantiate(hvc_rtas_cookie, 0, &hvc_rtas_get_put_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) add_preferred_console("hvc", 0, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) console_initcall(hvc_rtas_console_init);