linux/drivers/tty/hvc/hvc_dcc.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/* Copyright (c) 2010, 2014 The Linux Foundation. All rights reserved.  */
   3
   4#include <linux/console.h>
   5#include <linux/init.h>
   6#include <linux/serial.h>
   7#include <linux/serial_core.h>
   8
   9#include <asm/dcc.h>
  10#include <asm/processor.h>
  11
  12#include "hvc_console.h"
  13
  14/* DCC Status Bits */
  15#define DCC_STATUS_RX           (1 << 30)
  16#define DCC_STATUS_TX           (1 << 29)
  17
  18static void dcc_uart_console_putchar(struct uart_port *port, int ch)
  19{
  20        while (__dcc_getstatus() & DCC_STATUS_TX)
  21                cpu_relax();
  22
  23        __dcc_putchar(ch);
  24}
  25
  26static void dcc_early_write(struct console *con, const char *s, unsigned n)
  27{
  28        struct earlycon_device *dev = con->data;
  29
  30        uart_console_write(&dev->port, s, n, dcc_uart_console_putchar);
  31}
  32
  33static int __init dcc_early_console_setup(struct earlycon_device *device,
  34                                          const char *opt)
  35{
  36        device->con->write = dcc_early_write;
  37
  38        return 0;
  39}
  40
  41EARLYCON_DECLARE(dcc, dcc_early_console_setup);
  42
  43static int hvc_dcc_put_chars(uint32_t vt, const char *buf, int count)
  44{
  45        int i;
  46
  47        for (i = 0; i < count; i++) {
  48                while (__dcc_getstatus() & DCC_STATUS_TX)
  49                        cpu_relax();
  50
  51                __dcc_putchar(buf[i]);
  52        }
  53
  54        return count;
  55}
  56
  57static int hvc_dcc_get_chars(uint32_t vt, char *buf, int count)
  58{
  59        int i;
  60
  61        for (i = 0; i < count; ++i)
  62                if (__dcc_getstatus() & DCC_STATUS_RX)
  63                        buf[i] = __dcc_getchar();
  64                else
  65                        break;
  66
  67        return i;
  68}
  69
  70static bool hvc_dcc_check(void)
  71{
  72        unsigned long time = jiffies + (HZ / 10);
  73
  74        /* Write a test character to check if it is handled */
  75        __dcc_putchar('\n');
  76
  77        while (time_is_after_jiffies(time)) {
  78                if (!(__dcc_getstatus() & DCC_STATUS_TX))
  79                        return true;
  80        }
  81
  82        return false;
  83}
  84
  85static const struct hv_ops hvc_dcc_get_put_ops = {
  86        .get_chars = hvc_dcc_get_chars,
  87        .put_chars = hvc_dcc_put_chars,
  88};
  89
  90static int __init hvc_dcc_console_init(void)
  91{
  92        int ret;
  93
  94        if (!hvc_dcc_check())
  95                return -ENODEV;
  96
  97        /* Returns -1 if error */
  98        ret = hvc_instantiate(0, 0, &hvc_dcc_get_put_ops);
  99
 100        return ret < 0 ? -ENODEV : 0;
 101}
 102console_initcall(hvc_dcc_console_init);
 103
 104static int __init hvc_dcc_init(void)
 105{
 106        struct hvc_struct *p;
 107
 108        if (!hvc_dcc_check())
 109                return -ENODEV;
 110
 111        p = hvc_alloc(0, 0, &hvc_dcc_get_put_ops, 128);
 112
 113        return PTR_ERR_OR_ZERO(p);
 114}
 115device_initcall(hvc_dcc_init);
 116