1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2010, 2014 The Linux Foundation. All rights reserved. */ 3 4 #include <linux/init.h> 5 6 #include <asm/dcc.h> 7 #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 15 static 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 23 __dcc_putchar(buf[i]); 24 } 25 26 return count; 27 } 28 29 static int hvc_dcc_get_chars(uint32_t vt, char *buf, int count) 30 { 31 int i; 32 33 for (i = 0; i < count; ++i) 34 if (__dcc_getstatus() & DCC_STATUS_RX) 35 buf[i] = __dcc_getchar(); 36 else 37 break; 38 39 return i; 40 } 41 42 static 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 57 static 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 62 static int __init hvc_dcc_console_init(void) 63 { 64 int ret; 65 66 if (!hvc_dcc_check()) 67 return -ENODEV; 68 69 /* Returns -1 if error */ 70 ret = hvc_instantiate(0, 0, &hvc_dcc_get_put_ops); 71 72 return ret < 0 ? -ENODEV : 0; 73 } 74 console_initcall(hvc_dcc_console_init); 75 76 static int __init hvc_dcc_init(void) 77 { 78 struct hvc_struct *p; 79 80 if (!hvc_dcc_check()) 81 return -ENODEV; 82 83 p = hvc_alloc(0, 0, &hvc_dcc_get_put_ops, 128); 84 85 return PTR_ERR_OR_ZERO(p); 86 } 87 device_initcall(hvc_dcc_init); 88