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