1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun #include <linux/string.h>
3*4882a593Smuzhiyun #include <linux/kernel.h>
4*4882a593Smuzhiyun #include <linux/errno.h>
5*4882a593Smuzhiyun #include <linux/bitops.h>
6*4882a593Smuzhiyun #include <linux/ptrace.h>
7*4882a593Smuzhiyun #include <linux/adb.h>
8*4882a593Smuzhiyun #include <linux/pmu.h>
9*4882a593Smuzhiyun #include <linux/cuda.h>
10*4882a593Smuzhiyun #include <asm/machdep.h>
11*4882a593Smuzhiyun #include <asm/io.h>
12*4882a593Smuzhiyun #include <asm/page.h>
13*4882a593Smuzhiyun #include <asm/xmon.h>
14*4882a593Smuzhiyun #include <asm/prom.h>
15*4882a593Smuzhiyun #include <asm/bootx.h>
16*4882a593Smuzhiyun #include <asm/errno.h>
17*4882a593Smuzhiyun #include <asm/pmac_feature.h>
18*4882a593Smuzhiyun #include <asm/processor.h>
19*4882a593Smuzhiyun #include <asm/delay.h>
20*4882a593Smuzhiyun #include <asm/btext.h>
21*4882a593Smuzhiyun #include <asm/time.h>
22*4882a593Smuzhiyun #include <asm/udbg.h>
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun /*
25*4882a593Smuzhiyun * This implementation is "special", it can "patch" the current
26*4882a593Smuzhiyun * udbg implementation and work on top of it. It must thus be
27*4882a593Smuzhiyun * initialized last
28*4882a593Smuzhiyun */
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun static void (*udbg_adb_old_putc)(char c);
31*4882a593Smuzhiyun static int (*udbg_adb_old_getc)(void);
32*4882a593Smuzhiyun static int (*udbg_adb_old_getc_poll)(void);
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun static enum {
35*4882a593Smuzhiyun input_adb_none,
36*4882a593Smuzhiyun input_adb_pmu,
37*4882a593Smuzhiyun input_adb_cuda,
38*4882a593Smuzhiyun } input_type = input_adb_none;
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun int xmon_wants_key, xmon_adb_keycode;
41*4882a593Smuzhiyun
udbg_adb_poll(void)42*4882a593Smuzhiyun static inline void udbg_adb_poll(void)
43*4882a593Smuzhiyun {
44*4882a593Smuzhiyun #ifdef CONFIG_ADB_PMU
45*4882a593Smuzhiyun if (input_type == input_adb_pmu)
46*4882a593Smuzhiyun pmu_poll_adb();
47*4882a593Smuzhiyun #endif /* CONFIG_ADB_PMU */
48*4882a593Smuzhiyun #ifdef CONFIG_ADB_CUDA
49*4882a593Smuzhiyun if (input_type == input_adb_cuda)
50*4882a593Smuzhiyun cuda_poll();
51*4882a593Smuzhiyun #endif /* CONFIG_ADB_CUDA */
52*4882a593Smuzhiyun }
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun #ifdef CONFIG_BOOTX_TEXT
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun static int udbg_adb_use_btext;
57*4882a593Smuzhiyun static int xmon_adb_shiftstate;
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun static unsigned char xmon_keytab[128] =
60*4882a593Smuzhiyun "asdfhgzxcv\000bqwer" /* 0x00 - 0x0f */
61*4882a593Smuzhiyun "yt123465=97-80]o" /* 0x10 - 0x1f */
62*4882a593Smuzhiyun "u[ip\rlj'k;\\,/nm." /* 0x20 - 0x2f */
63*4882a593Smuzhiyun "\t `\177\0\033\0\0\0\0\0\0\0\0\0\0" /* 0x30 - 0x3f */
64*4882a593Smuzhiyun "\0.\0*\0+\0\0\0\0\0/\r\0-\0" /* 0x40 - 0x4f */
65*4882a593Smuzhiyun "\0\0000123456789\0\0\0"; /* 0x50 - 0x5f */
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun static unsigned char xmon_shift_keytab[128] =
68*4882a593Smuzhiyun "ASDFHGZXCV\000BQWER" /* 0x00 - 0x0f */
69*4882a593Smuzhiyun "YT!@#$^%+(&_*)}O" /* 0x10 - 0x1f */
70*4882a593Smuzhiyun "U{IP\rLJ\"K:|<?NM>" /* 0x20 - 0x2f */
71*4882a593Smuzhiyun "\t ~\177\0\033\0\0\0\0\0\0\0\0\0\0" /* 0x30 - 0x3f */
72*4882a593Smuzhiyun "\0.\0*\0+\0\0\0\0\0/\r\0-\0" /* 0x40 - 0x4f */
73*4882a593Smuzhiyun "\0\0000123456789\0\0\0"; /* 0x50 - 0x5f */
74*4882a593Smuzhiyun
udbg_adb_local_getc(void)75*4882a593Smuzhiyun static int udbg_adb_local_getc(void)
76*4882a593Smuzhiyun {
77*4882a593Smuzhiyun int k, t, on;
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun xmon_wants_key = 1;
80*4882a593Smuzhiyun for (;;) {
81*4882a593Smuzhiyun xmon_adb_keycode = -1;
82*4882a593Smuzhiyun t = 0;
83*4882a593Smuzhiyun on = 0;
84*4882a593Smuzhiyun k = -1;
85*4882a593Smuzhiyun do {
86*4882a593Smuzhiyun if (--t < 0) {
87*4882a593Smuzhiyun on = 1 - on;
88*4882a593Smuzhiyun btext_drawchar(on? 0xdb: 0x20);
89*4882a593Smuzhiyun btext_drawchar('\b');
90*4882a593Smuzhiyun t = 200000;
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun udbg_adb_poll();
93*4882a593Smuzhiyun if (udbg_adb_old_getc_poll)
94*4882a593Smuzhiyun k = udbg_adb_old_getc_poll();
95*4882a593Smuzhiyun } while (k == -1 && xmon_adb_keycode == -1);
96*4882a593Smuzhiyun if (on)
97*4882a593Smuzhiyun btext_drawstring(" \b");
98*4882a593Smuzhiyun if (k != -1)
99*4882a593Smuzhiyun return k;
100*4882a593Smuzhiyun k = xmon_adb_keycode;
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun /* test for shift keys */
103*4882a593Smuzhiyun if ((k & 0x7f) == 0x38 || (k & 0x7f) == 0x7b) {
104*4882a593Smuzhiyun xmon_adb_shiftstate = (k & 0x80) == 0;
105*4882a593Smuzhiyun continue;
106*4882a593Smuzhiyun }
107*4882a593Smuzhiyun if (k >= 0x80)
108*4882a593Smuzhiyun continue; /* ignore up transitions */
109*4882a593Smuzhiyun k = (xmon_adb_shiftstate? xmon_shift_keytab: xmon_keytab)[k];
110*4882a593Smuzhiyun if (k != 0)
111*4882a593Smuzhiyun break;
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun xmon_wants_key = 0;
114*4882a593Smuzhiyun return k;
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun #endif /* CONFIG_BOOTX_TEXT */
117*4882a593Smuzhiyun
udbg_adb_getc(void)118*4882a593Smuzhiyun static int udbg_adb_getc(void)
119*4882a593Smuzhiyun {
120*4882a593Smuzhiyun #ifdef CONFIG_BOOTX_TEXT
121*4882a593Smuzhiyun if (udbg_adb_use_btext && input_type != input_adb_none)
122*4882a593Smuzhiyun return udbg_adb_local_getc();
123*4882a593Smuzhiyun #endif
124*4882a593Smuzhiyun if (udbg_adb_old_getc)
125*4882a593Smuzhiyun return udbg_adb_old_getc();
126*4882a593Smuzhiyun return -1;
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun /* getc_poll() is not really used, unless you have the xmon-over modem
130*4882a593Smuzhiyun * hack that doesn't quite concern us here, thus we just poll the low level
131*4882a593Smuzhiyun * ADB driver to prevent it from timing out and call back the original poll
132*4882a593Smuzhiyun * routine.
133*4882a593Smuzhiyun */
udbg_adb_getc_poll(void)134*4882a593Smuzhiyun static int udbg_adb_getc_poll(void)
135*4882a593Smuzhiyun {
136*4882a593Smuzhiyun udbg_adb_poll();
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun if (udbg_adb_old_getc_poll)
139*4882a593Smuzhiyun return udbg_adb_old_getc_poll();
140*4882a593Smuzhiyun return -1;
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun
udbg_adb_putc(char c)143*4882a593Smuzhiyun static void udbg_adb_putc(char c)
144*4882a593Smuzhiyun {
145*4882a593Smuzhiyun #ifdef CONFIG_BOOTX_TEXT
146*4882a593Smuzhiyun if (udbg_adb_use_btext)
147*4882a593Smuzhiyun btext_drawchar(c);
148*4882a593Smuzhiyun #endif
149*4882a593Smuzhiyun if (udbg_adb_old_putc)
150*4882a593Smuzhiyun return udbg_adb_old_putc(c);
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun
udbg_adb_init_early(void)153*4882a593Smuzhiyun void __init udbg_adb_init_early(void)
154*4882a593Smuzhiyun {
155*4882a593Smuzhiyun #ifdef CONFIG_BOOTX_TEXT
156*4882a593Smuzhiyun if (btext_find_display(1) == 0) {
157*4882a593Smuzhiyun udbg_adb_use_btext = 1;
158*4882a593Smuzhiyun udbg_putc = udbg_adb_putc;
159*4882a593Smuzhiyun }
160*4882a593Smuzhiyun #endif
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun
udbg_adb_init(int force_btext)163*4882a593Smuzhiyun int __init udbg_adb_init(int force_btext)
164*4882a593Smuzhiyun {
165*4882a593Smuzhiyun struct device_node *np;
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun /* Capture existing callbacks */
168*4882a593Smuzhiyun udbg_adb_old_putc = udbg_putc;
169*4882a593Smuzhiyun udbg_adb_old_getc = udbg_getc;
170*4882a593Smuzhiyun udbg_adb_old_getc_poll = udbg_getc_poll;
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun /* Check if our early init was already called */
173*4882a593Smuzhiyun if (udbg_adb_old_putc == udbg_adb_putc)
174*4882a593Smuzhiyun udbg_adb_old_putc = NULL;
175*4882a593Smuzhiyun #ifdef CONFIG_BOOTX_TEXT
176*4882a593Smuzhiyun if (udbg_adb_old_putc == btext_drawchar)
177*4882a593Smuzhiyun udbg_adb_old_putc = NULL;
178*4882a593Smuzhiyun #endif
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun /* Set ours as output */
181*4882a593Smuzhiyun udbg_putc = udbg_adb_putc;
182*4882a593Smuzhiyun udbg_getc = udbg_adb_getc;
183*4882a593Smuzhiyun udbg_getc_poll = udbg_adb_getc_poll;
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun #ifdef CONFIG_BOOTX_TEXT
186*4882a593Smuzhiyun /* Check if we should use btext output */
187*4882a593Smuzhiyun if (btext_find_display(force_btext) == 0)
188*4882a593Smuzhiyun udbg_adb_use_btext = 1;
189*4882a593Smuzhiyun #endif
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun /* See if there is a keyboard in the device tree with a parent
192*4882a593Smuzhiyun * of type "adb". If not, we return a failure, but we keep the
193*4882a593Smuzhiyun * bext output set for now
194*4882a593Smuzhiyun */
195*4882a593Smuzhiyun for_each_node_by_name(np, "keyboard") {
196*4882a593Smuzhiyun struct device_node *parent = of_get_parent(np);
197*4882a593Smuzhiyun int found = of_node_is_type(parent, "adb");
198*4882a593Smuzhiyun of_node_put(parent);
199*4882a593Smuzhiyun if (found)
200*4882a593Smuzhiyun break;
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun if (np == NULL)
203*4882a593Smuzhiyun return -ENODEV;
204*4882a593Smuzhiyun of_node_put(np);
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun #ifdef CONFIG_ADB_PMU
207*4882a593Smuzhiyun if (find_via_pmu())
208*4882a593Smuzhiyun input_type = input_adb_pmu;
209*4882a593Smuzhiyun #endif
210*4882a593Smuzhiyun #ifdef CONFIG_ADB_CUDA
211*4882a593Smuzhiyun if (find_via_cuda())
212*4882a593Smuzhiyun input_type = input_adb_cuda;
213*4882a593Smuzhiyun #endif
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun /* Same as above: nothing found, keep btext set for output */
216*4882a593Smuzhiyun if (input_type == input_adb_none)
217*4882a593Smuzhiyun return -ENODEV;
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun return 0;
220*4882a593Smuzhiyun }
221