blob: 02629a1f193d7ff5bd4343b1259c6a693284a2b4 [file] [log] [blame]
Greg Kroah-Hartmane3b3d0f2017-11-06 18:11:51 +01001// SPDX-License-Identifier: GPL-2.0
Greg Kroah-Hartmana9f96f02017-11-06 18:11:53 +01002/* Copyright (c) 2010, 2014 The Linux Foundation. All rights reserved. */
Daniel Walker16c63f82010-11-30 11:25:39 -08003
Daniel Walker16c63f82010-11-30 11:25:39 -08004#include <linux/init.h>
Daniel Walker16c63f82010-11-30 11:25:39 -08005
Christopher Covington4061f492014-05-22 18:07:18 -04006#include <asm/dcc.h>
Daniel Walker16c63f82010-11-30 11:25:39 -08007#include <asm/processor.h>
8
9#include "hvc_console.h"
10
11/* DCC Status Bits */
12#define DCC_STATUS_RX (1 << 30)
13#define DCC_STATUS_TX (1 << 29)
14
Daniel Walker16c63f82010-11-30 11:25:39 -080015static int hvc_dcc_put_chars(uint32_t vt, const char *buf, int count)
16{
17 int i;
18
19 for (i = 0; i < count; i++) {
20 while (__dcc_getstatus() & DCC_STATUS_TX)
21 cpu_relax();
22
Stephen Boydbf73bd32011-02-03 15:48:35 -080023 __dcc_putchar(buf[i]);
Daniel Walker16c63f82010-11-30 11:25:39 -080024 }
25
26 return count;
27}
28
29static int hvc_dcc_get_chars(uint32_t vt, char *buf, int count)
30{
31 int i;
32
Stephen Boydbf73bd32011-02-03 15:48:35 -080033 for (i = 0; i < count; ++i)
Daniel Walker16c63f82010-11-30 11:25:39 -080034 if (__dcc_getstatus() & DCC_STATUS_RX)
Stephen Boydbf73bd32011-02-03 15:48:35 -080035 buf[i] = __dcc_getchar();
36 else
Daniel Walker16c63f82010-11-30 11:25:39 -080037 break;
Daniel Walker16c63f82010-11-30 11:25:39 -080038
39 return i;
40}
41
Rob Herringf3777752013-09-24 21:05:58 -050042static bool hvc_dcc_check(void)
43{
44 unsigned long time = jiffies + (HZ / 10);
45
46 /* Write a test character to check if it is handled */
47 __dcc_putchar('\n');
48
49 while (time_is_after_jiffies(time)) {
50 if (!(__dcc_getstatus() & DCC_STATUS_TX))
51 return true;
52 }
53
54 return false;
55}
56
Daniel Walker16c63f82010-11-30 11:25:39 -080057static const struct hv_ops hvc_dcc_get_put_ops = {
58 .get_chars = hvc_dcc_get_chars,
59 .put_chars = hvc_dcc_put_chars,
60};
61
62static int __init hvc_dcc_console_init(void)
63{
Timur Tabi3d270702015-09-12 12:44:38 -050064 int ret;
65
Rob Herringf3777752013-09-24 21:05:58 -050066 if (!hvc_dcc_check())
67 return -ENODEV;
68
Timur Tabi3d270702015-09-12 12:44:38 -050069 /* Returns -1 if error */
70 ret = hvc_instantiate(0, 0, &hvc_dcc_get_put_ops);
71
72 return ret < 0 ? -ENODEV : 0;
Daniel Walker16c63f82010-11-30 11:25:39 -080073}
74console_initcall(hvc_dcc_console_init);
75
76static int __init hvc_dcc_init(void)
77{
Timur Tabi3d270702015-09-12 12:44:38 -050078 struct hvc_struct *p;
79
Rob Herringf3777752013-09-24 21:05:58 -050080 if (!hvc_dcc_check())
81 return -ENODEV;
82
Timur Tabi3d270702015-09-12 12:44:38 -050083 p = hvc_alloc(0, 0, &hvc_dcc_get_put_ops, 128);
84
85 return PTR_ERR_OR_ZERO(p);
Daniel Walker16c63f82010-11-30 11:25:39 -080086}
87device_initcall(hvc_dcc_init);