13cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou/*
23cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou * Beat hypervisor console driver
33cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou *
43cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou * (C) Copyright 2006 TOSHIBA CORPORATION
53cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou *
63cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou * This code is based on drivers/char/hvc_rtas.c:
73cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou * (C) Copyright IBM Corporation 2001-2005
83cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou * (C) Copyright Red Hat, Inc. 2005
93cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou *
103cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou * This program is free software; you can redistribute it and/or modify
113cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou * it under the terms of the GNU General Public License as published by
123cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou * the Free Software Foundation; either version 2 of the License, or
133cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou * (at your option) any later version.
143cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou *
153cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou * This program is distributed in the hope that it will be useful,
163cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou * but WITHOUT ANY WARRANTY; without even the implied warranty of
173cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
183cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou * GNU General Public License for more details.
193cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou *
203cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou * You should have received a copy of the GNU General Public License along
213cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou * with this program; if not, write to the Free Software Foundation, Inc.,
223cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
233cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou */
243cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou
253cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou#include <linux/module.h>
263cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou#include <linux/init.h>
273cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou#include <linux/err.h>
283cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou#include <linux/string.h>
293cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou#include <linux/console.h>
303cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou#include <asm/prom.h>
313cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou#include <asm/hvconsole.h>
323cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou#include <asm/firmware.h>
333cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou
343cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou#include "hvc_console.h"
353cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou
363cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kouextern int64_t beat_get_term_char(uint64_t, uint64_t *, uint64_t *, uint64_t *);
373cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kouextern int64_t beat_put_term_char(uint64_t, uint64_t, uint64_t, uint64_t);
383cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou
393cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Koustruct hvc_struct *hvc_beat_dev = NULL;
403cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou
413cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou/* bug: only one queue is available regardless of vtermno */
423cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Koustatic int hvc_beat_get_chars(uint32_t vtermno, char *buf, int cnt)
433cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou{
443cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou	static unsigned char q[sizeof(unsigned long) * 2]
453cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou		__attribute__((aligned(sizeof(unsigned long))));
463cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou	static int qlen = 0;
4719b0bd025d6647549e07becf02b99e5168c17432Ingo Molnar	u64 got;
483cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou
493cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kouagain:
503cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou	if (qlen) {
513cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou		if (qlen > cnt) {
523cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou			memcpy(buf, q, cnt);
533cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou			qlen -= cnt;
543cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou			memmove(q + cnt, q, qlen);
553cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou			return cnt;
563cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou		} else {	/* qlen <= cnt */
573cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou			int	r;
583cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou
593cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou			memcpy(buf, q, qlen);
603cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou			r = qlen;
613cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou			qlen = 0;
623cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou			return r;
633cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou		}
643cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou	}
653cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou	if (beat_get_term_char(vtermno, &got,
6619b0bd025d6647549e07becf02b99e5168c17432Ingo Molnar		((u64 *)q), ((u64 *)q) + 1) == 0) {
673cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou		qlen = got;
683cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou		goto again;
693cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou	}
703cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou	return 0;
713cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou}
723cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou
733cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Koustatic int hvc_beat_put_chars(uint32_t vtermno, const char *buf, int cnt)
743cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou{
753cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou	unsigned long kb[2];
763cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou	int rest, nlen;
773cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou
783cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou	for (rest = cnt; rest > 0; rest -= nlen) {
793cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou		nlen = (rest > 16) ? 16 : rest;
803cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou		memcpy(kb, buf, nlen);
8155045d47d7a8c4c61bc0ca6f2fac5087dd598bc3Ishizaki Kou		beat_put_term_char(vtermno, nlen, kb[0], kb[1]);
8255045d47d7a8c4c61bc0ca6f2fac5087dd598bc3Ishizaki Kou		buf += nlen;
833cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou	}
843cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou	return cnt;
853cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou}
863cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou
871dff399616a79b8ef5d61ad68f2ef1e1f590b465Rusty Russellstatic const struct hv_ops hvc_beat_get_put_ops = {
883cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou	.get_chars = hvc_beat_get_chars,
893cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou	.put_chars = hvc_beat_put_chars,
903cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou};
913cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou
923cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Koustatic int hvc_beat_useit = 1;
933cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou
943cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Koustatic int hvc_beat_config(char *p)
953cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou{
963cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou	hvc_beat_useit = simple_strtoul(p, NULL, 0);
973cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou	return 0;
983cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou}
993cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou
100301d9cb80b4f64ba24d4b141ad3ca58165a29afbIshizaki Koustatic int __init hvc_beat_console_init(void)
1013cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou{
10271a157e8edca55198e808f8561dd49017a54ee34Grant Likely	if (hvc_beat_useit && of_machine_is_compatible("Beat")) {
1033cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou		hvc_instantiate(0, 0, &hvc_beat_get_put_ops);
1043cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou	}
1053cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou	return 0;
1063cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou}
1073cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou
1083cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou/* temp */
109301d9cb80b4f64ba24d4b141ad3ca58165a29afbIshizaki Koustatic int __init hvc_beat_init(void)
1103cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou{
1113cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou	struct hvc_struct *hp;
1123cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou
1133cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou	if (!firmware_has_feature(FW_FEATURE_BEAT))
1143cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou		return -ENODEV;
1153cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou
116d4e33fac2408d37f7b52e80ca2a89f9fb482914fAlan Cox	hp = hvc_alloc(0, 0, &hvc_beat_get_put_ops, 16);
1173cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou	if (IS_ERR(hp))
1183cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou		return PTR_ERR(hp);
1193cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou	hvc_beat_dev = hp;
1203cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou	return 0;
1213cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou}
1223cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou
1233cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Koustatic void __exit hvc_beat_exit(void)
1243cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou{
1253cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou	if (hvc_beat_dev)
1263cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou		hvc_remove(hvc_beat_dev);
1273cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou}
1283cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou
1293cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Koumodule_init(hvc_beat_init);
1303cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Koumodule_exit(hvc_beat_exit);
1313cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou
1323cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou__setup("hvc_beat=", hvc_beat_config);
1333cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kou
1343cdc20e51791bd2fd67781e65640a4650f99c63eIshizaki Kouconsole_initcall(hvc_beat_console_init);
135