blob: 809920d80a66da7c08f8cd653451fa2fdcec636e [file] [log] [blame]
Christopher Covington4061f492014-05-22 18:07:18 -04001/* Copyright (c) 2010, 2014 The Linux Foundation. All rights reserved.
Daniel Walker16c63f82010-11-30 11:25:39 -08002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
Daniel Walker16c63f82010-11-30 11:25:39 -080011 */
12
Daniel Walker16c63f82010-11-30 11:25:39 -080013#include <linux/init.h>
Daniel Walker16c63f82010-11-30 11:25:39 -080014
Christopher Covington4061f492014-05-22 18:07:18 -040015#include <asm/dcc.h>
Daniel Walker16c63f82010-11-30 11:25:39 -080016#include <asm/processor.h>
17
18#include "hvc_console.h"
19
20/* DCC Status Bits */
21#define DCC_STATUS_RX (1 << 30)
22#define DCC_STATUS_TX (1 << 29)
23
Daniel Walker16c63f82010-11-30 11:25:39 -080024static int hvc_dcc_put_chars(uint32_t vt, const char *buf, int count)
25{
26 int i;
27
28 for (i = 0; i < count; i++) {
29 while (__dcc_getstatus() & DCC_STATUS_TX)
30 cpu_relax();
31
Stephen Boydbf73bd32011-02-03 15:48:35 -080032 __dcc_putchar(buf[i]);
Daniel Walker16c63f82010-11-30 11:25:39 -080033 }
34
35 return count;
36}
37
38static int hvc_dcc_get_chars(uint32_t vt, char *buf, int count)
39{
40 int i;
41
Stephen Boydbf73bd32011-02-03 15:48:35 -080042 for (i = 0; i < count; ++i)
Daniel Walker16c63f82010-11-30 11:25:39 -080043 if (__dcc_getstatus() & DCC_STATUS_RX)
Stephen Boydbf73bd32011-02-03 15:48:35 -080044 buf[i] = __dcc_getchar();
45 else
Daniel Walker16c63f82010-11-30 11:25:39 -080046 break;
Daniel Walker16c63f82010-11-30 11:25:39 -080047
48 return i;
49}
50
Rob Herringf3777752013-09-24 21:05:58 -050051static bool hvc_dcc_check(void)
52{
53 unsigned long time = jiffies + (HZ / 10);
54
55 /* Write a test character to check if it is handled */
56 __dcc_putchar('\n');
57
58 while (time_is_after_jiffies(time)) {
59 if (!(__dcc_getstatus() & DCC_STATUS_TX))
60 return true;
61 }
62
63 return false;
64}
65
Daniel Walker16c63f82010-11-30 11:25:39 -080066static const struct hv_ops hvc_dcc_get_put_ops = {
67 .get_chars = hvc_dcc_get_chars,
68 .put_chars = hvc_dcc_put_chars,
69};
70
71static int __init hvc_dcc_console_init(void)
72{
Rob Herringf3777752013-09-24 21:05:58 -050073 if (!hvc_dcc_check())
74 return -ENODEV;
75
Daniel Walker16c63f82010-11-30 11:25:39 -080076 hvc_instantiate(0, 0, &hvc_dcc_get_put_ops);
77 return 0;
78}
79console_initcall(hvc_dcc_console_init);
80
81static int __init hvc_dcc_init(void)
82{
Rob Herringf3777752013-09-24 21:05:58 -050083 if (!hvc_dcc_check())
84 return -ENODEV;
85
Daniel Walker16c63f82010-11-30 11:25:39 -080086 hvc_alloc(0, 0, &hvc_dcc_get_put_ops, 128);
87 return 0;
88}
89device_initcall(hvc_dcc_init);