2017-11-06 18:11:51 +01:00
// SPDX-License-Identifier: GPL-2.0
2017-11-06 18:11:53 +01:00
/* Copyright (c) 2010, 2014 The Linux Foundation. All rights reserved. */
2010-11-30 11:25:39 -08:00
# include <linux/init.h>
2014-05-22 18:07:18 -04:00
# include <asm/dcc.h>
2010-11-30 11:25:39 -08:00
# include <asm/processor.h>
# include "hvc_console.h"
/* DCC Status Bits */
# define DCC_STATUS_RX (1 << 30)
# define DCC_STATUS_TX (1 << 29)
static int hvc_dcc_put_chars ( uint32_t vt , const char * buf , int count )
{
int i ;
for ( i = 0 ; i < count ; i + + ) {
while ( __dcc_getstatus ( ) & DCC_STATUS_TX )
cpu_relax ( ) ;
2011-02-03 15:48:35 -08:00
__dcc_putchar ( buf [ i ] ) ;
2010-11-30 11:25:39 -08:00
}
return count ;
}
static int hvc_dcc_get_chars ( uint32_t vt , char * buf , int count )
{
int i ;
2011-02-03 15:48:35 -08:00
for ( i = 0 ; i < count ; + + i )
2010-11-30 11:25:39 -08:00
if ( __dcc_getstatus ( ) & DCC_STATUS_RX )
2011-02-03 15:48:35 -08:00
buf [ i ] = __dcc_getchar ( ) ;
else
2010-11-30 11:25:39 -08:00
break ;
return i ;
}
2013-09-24 21:05:58 -05:00
static bool hvc_dcc_check ( void )
{
unsigned long time = jiffies + ( HZ / 10 ) ;
/* Write a test character to check if it is handled */
__dcc_putchar ( ' \n ' ) ;
while ( time_is_after_jiffies ( time ) ) {
if ( ! ( __dcc_getstatus ( ) & DCC_STATUS_TX ) )
return true ;
}
return false ;
}
2010-11-30 11:25:39 -08:00
static const struct hv_ops hvc_dcc_get_put_ops = {
. get_chars = hvc_dcc_get_chars ,
. put_chars = hvc_dcc_put_chars ,
} ;
static int __init hvc_dcc_console_init ( void )
{
2015-09-12 12:44:38 -05:00
int ret ;
2013-09-24 21:05:58 -05:00
if ( ! hvc_dcc_check ( ) )
return - ENODEV ;
2015-09-12 12:44:38 -05:00
/* Returns -1 if error */
ret = hvc_instantiate ( 0 , 0 , & hvc_dcc_get_put_ops ) ;
return ret < 0 ? - ENODEV : 0 ;
2010-11-30 11:25:39 -08:00
}
console_initcall ( hvc_dcc_console_init ) ;
static int __init hvc_dcc_init ( void )
{
2015-09-12 12:44:38 -05:00
struct hvc_struct * p ;
2013-09-24 21:05:58 -05:00
if ( ! hvc_dcc_check ( ) )
return - ENODEV ;
2015-09-12 12:44:38 -05:00
p = hvc_alloc ( 0 , 0 , & hvc_dcc_get_put_ops , 128 ) ;
return PTR_ERR_OR_ZERO ( p ) ;
2010-11-30 11:25:39 -08:00
}
device_initcall ( hvc_dcc_init ) ;