Merge branch 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6-microblaze.git] / drivers / tty / hvc / hvc_bfin_jtag.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Console via Blackfin JTAG Communication
4  *
5  * Copyright 2008-2011 Analog Devices Inc.
6  *
7  * Enter bugs at http://blackfin.uclinux.org/
8  */
9
10 #include <linux/console.h>
11 #include <linux/delay.h>
12 #include <linux/err.h>
13 #include <linux/init.h>
14 #include <linux/moduleparam.h>
15 #include <linux/types.h>
16
17 #include "hvc_console.h"
18
19 /* See the Debug/Emulation chapter in the HRM */
20 #define EMUDOF   0x00000001     /* EMUDAT_OUT full & valid */
21 #define EMUDIF   0x00000002     /* EMUDAT_IN full & valid */
22 #define EMUDOOVF 0x00000004     /* EMUDAT_OUT overflow */
23 #define EMUDIOVF 0x00000008     /* EMUDAT_IN overflow */
24
25 /* Helper functions to glue the register API to simple C operations */
26 static inline uint32_t bfin_write_emudat(uint32_t emudat)
27 {
28         __asm__ __volatile__("emudat = %0;" : : "d"(emudat));
29         return emudat;
30 }
31
32 static inline uint32_t bfin_read_emudat(void)
33 {
34         uint32_t emudat;
35         __asm__ __volatile__("%0 = emudat;" : "=d"(emudat));
36         return emudat;
37 }
38
39 /* Send data to the host */
40 static int hvc_bfin_put_chars(uint32_t vt, const char *buf, int count)
41 {
42         static uint32_t outbound_len;
43         uint32_t emudat;
44         int ret;
45
46         if (bfin_read_DBGSTAT() & EMUDOF)
47                 return 0;
48
49         if (!outbound_len) {
50                 outbound_len = count;
51                 bfin_write_emudat(outbound_len);
52                 return 0;
53         }
54
55         ret = min(outbound_len, (uint32_t)4);
56         memcpy(&emudat, buf, ret);
57         bfin_write_emudat(emudat);
58         outbound_len -= ret;
59
60         return ret;
61 }
62
63 /* Receive data from the host */
64 static int hvc_bfin_get_chars(uint32_t vt, char *buf, int count)
65 {
66         static uint32_t inbound_len;
67         uint32_t emudat;
68         int ret;
69
70         if (!(bfin_read_DBGSTAT() & EMUDIF))
71                 return 0;
72         emudat = bfin_read_emudat();
73
74         if (!inbound_len) {
75                 inbound_len = emudat;
76                 return 0;
77         }
78
79         ret = min(inbound_len, (uint32_t)4);
80         memcpy(buf, &emudat, ret);
81         inbound_len -= ret;
82
83         return ret;
84 }
85
86 /* Glue the HVC layers to the Blackfin layers */
87 static const struct hv_ops hvc_bfin_get_put_ops = {
88         .get_chars = hvc_bfin_get_chars,
89         .put_chars = hvc_bfin_put_chars,
90 };
91
92 static int __init hvc_bfin_console_init(void)
93 {
94         hvc_instantiate(0, 0, &hvc_bfin_get_put_ops);
95         return 0;
96 }
97 console_initcall(hvc_bfin_console_init);
98
99 static int __init hvc_bfin_init(void)
100 {
101         hvc_alloc(0, 0, &hvc_bfin_get_put_ops, 128);
102         return 0;
103 }
104 device_initcall(hvc_bfin_init);