162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * IBM RTAS driver interface to hvc_console.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * (C) Copyright IBM Corporation 2001-2005 662306a36Sopenharmony_ci * (C) Copyright Red Hat, Inc. 2005 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Author(s): Maximino Augilar <IBM STI Design Center> 962306a36Sopenharmony_ci * : Ryan S. Arnold <rsa@us.ibm.com> 1062306a36Sopenharmony_ci * : Utz Bacher <utz.bacher@de.ibm.com> 1162306a36Sopenharmony_ci * : David Woodhouse <dwmw2@infradead.org> 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * inspired by drivers/char/hvc_console.c 1462306a36Sopenharmony_ci * written by Anton Blanchard and Paul Mackerras 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <linux/console.h> 1862306a36Sopenharmony_ci#include <linux/delay.h> 1962306a36Sopenharmony_ci#include <linux/err.h> 2062306a36Sopenharmony_ci#include <linux/init.h> 2162306a36Sopenharmony_ci#include <linux/moduleparam.h> 2262306a36Sopenharmony_ci#include <linux/types.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include <asm/irq.h> 2562306a36Sopenharmony_ci#include <asm/rtas.h> 2662306a36Sopenharmony_ci#include "hvc_console.h" 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#define hvc_rtas_cookie 0x67781e15 2962306a36Sopenharmony_cistatic struct hvc_struct *hvc_rtas_dev; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic int rtascons_put_char_token = RTAS_UNKNOWN_SERVICE; 3262306a36Sopenharmony_cistatic int rtascons_get_char_token = RTAS_UNKNOWN_SERVICE; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic inline int hvc_rtas_write_console(uint32_t vtermno, const char *buf, 3562306a36Sopenharmony_ci int count) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci int i; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci for (i = 0; i < count; i++) { 4062306a36Sopenharmony_ci if (rtas_call(rtascons_put_char_token, 1, 1, NULL, buf[i])) 4162306a36Sopenharmony_ci break; 4262306a36Sopenharmony_ci } 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci return i; 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic int hvc_rtas_read_console(uint32_t vtermno, char *buf, int count) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci int i, c; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci for (i = 0; i < count; i++) { 5262306a36Sopenharmony_ci if (rtas_call(rtascons_get_char_token, 0, 2, &c)) 5362306a36Sopenharmony_ci break; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci buf[i] = c; 5662306a36Sopenharmony_ci } 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci return i; 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic const struct hv_ops hvc_rtas_get_put_ops = { 6262306a36Sopenharmony_ci .get_chars = hvc_rtas_read_console, 6362306a36Sopenharmony_ci .put_chars = hvc_rtas_write_console, 6462306a36Sopenharmony_ci}; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic int __init hvc_rtas_init(void) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci struct hvc_struct *hp; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci if (rtascons_put_char_token == RTAS_UNKNOWN_SERVICE) 7162306a36Sopenharmony_ci rtascons_put_char_token = rtas_token("put-term-char"); 7262306a36Sopenharmony_ci if (rtascons_put_char_token == RTAS_UNKNOWN_SERVICE) 7362306a36Sopenharmony_ci return -EIO; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci if (rtascons_get_char_token == RTAS_UNKNOWN_SERVICE) 7662306a36Sopenharmony_ci rtascons_get_char_token = rtas_token("get-term-char"); 7762306a36Sopenharmony_ci if (rtascons_get_char_token == RTAS_UNKNOWN_SERVICE) 7862306a36Sopenharmony_ci return -EIO; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci BUG_ON(hvc_rtas_dev); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci /* Allocate an hvc_struct for the console device we instantiated 8362306a36Sopenharmony_ci * earlier. Save off hp so that we can return it on exit */ 8462306a36Sopenharmony_ci hp = hvc_alloc(hvc_rtas_cookie, 0, &hvc_rtas_get_put_ops, 16); 8562306a36Sopenharmony_ci if (IS_ERR(hp)) 8662306a36Sopenharmony_ci return PTR_ERR(hp); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci hvc_rtas_dev = hp; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci return 0; 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_cidevice_initcall(hvc_rtas_init); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci/* This will happen prior to module init. There is no tty at this time? */ 9562306a36Sopenharmony_cistatic int __init hvc_rtas_console_init(void) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci rtascons_put_char_token = rtas_token("put-term-char"); 9862306a36Sopenharmony_ci if (rtascons_put_char_token == RTAS_UNKNOWN_SERVICE) 9962306a36Sopenharmony_ci return -EIO; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci rtascons_get_char_token = rtas_token("get-term-char"); 10262306a36Sopenharmony_ci if (rtascons_get_char_token == RTAS_UNKNOWN_SERVICE) 10362306a36Sopenharmony_ci return -EIO; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci hvc_instantiate(hvc_rtas_cookie, 0, &hvc_rtas_get_put_ops); 10662306a36Sopenharmony_ci add_preferred_console("hvc", 0, NULL); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci return 0; 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ciconsole_initcall(hvc_rtas_console_init); 111