1 #include "config.h"
2 #include "libopenbios/bindings.h"
3 #include "libc/byteorder.h"
4 #include "libc/vsprintf.h"
5 #include "drivers/drivers.h"
6 #include "libopenbios/ofmem.h"
7
8 #include "escc.h"
9
10 /* ******************************************************************
11 * serial console functions
12 * ****************************************************************** */
13
14 static volatile unsigned char *escc_serial_dev;
15
16 #define CTRL(addr) (*(volatile unsigned char *)(uintptr_t)(addr))
17 #ifdef CONFIG_DRIVER_ESCC_SUN
18 #define DATA(addr) (*(volatile unsigned char *)(uintptr_t)(addr + 2))
19 #else
20 #define DATA(addr) (*(volatile unsigned char *)(uintptr_t)(addr + 16))
21 #endif
22
23 /* Conversion routines to/from brg time constants from/to bits
24 * per second.
25 */
26 #define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
27
28 #ifdef CONFIG_DRIVER_ESCC_SUN
29 #define ESCC_CLOCK 4915200 /* Zilog input clock rate. */
30 #else
31 #define ESCC_CLOCK 3686400
32 #endif
33 #define ESCC_CLOCK_DIVISOR 16 /* Divisor this driver uses. */
34
35 /* Write Register 3 */
36 #define RxENAB 0x1 /* Rx Enable */
37 #define Rx8 0xc0 /* Rx 8 Bits/Character */
38
39 /* Write Register 4 */
40 #define SB1 0x4 /* 1 stop bit/char */
41 #define X16CLK 0x40 /* x16 clock mode */
42
43 /* Write Register 5 */
44 #define RTS 0x2 /* RTS */
45 #define TxENAB 0x8 /* Tx Enable */
46 #define Tx8 0x60 /* Tx 8 bits/character */
47 #define DTR 0x80 /* DTR */
48
49 /* Write Register 14 (Misc control bits) */
50 #define BRENAB 1 /* Baud rate generator enable */
51 #define BRSRC 2 /* Baud rate generator source */
52
53 /* Read Register 0 */
54 #define Rx_CH_AV 0x1 /* Rx Character Available */
55 #define Tx_BUF_EMP 0x4 /* Tx Buffer empty */
56
escc_uart_charav(uintptr_t port)57 int escc_uart_charav(uintptr_t port)
58 {
59 return (CTRL(port) & Rx_CH_AV) != 0;
60 }
61
escc_uart_getchar(uintptr_t port)62 char escc_uart_getchar(uintptr_t port)
63 {
64 while (!escc_uart_charav(port))
65 ;
66 return DATA(port) & 0177;
67 }
68
escc_uart_port_putchar(uintptr_t port,unsigned char c)69 static void escc_uart_port_putchar(uintptr_t port, unsigned char c)
70 {
71 if (!escc_serial_dev)
72 return;
73
74 if (c == '\n')
75 escc_uart_port_putchar(port, '\r');
76 while (!(CTRL(port) & Tx_BUF_EMP))
77 ;
78 DATA(port) = c;
79 }
80
uart_init_line(volatile unsigned char * port,unsigned long baud)81 static void uart_init_line(volatile unsigned char *port, unsigned long baud)
82 {
83 CTRL(port) = 4; // reg 4
84 CTRL(port) = SB1 | X16CLK; // no parity, async, 1 stop bit, 16x
85 // clock
86
87 baud = BPS_TO_BRG(baud, ESCC_CLOCK / ESCC_CLOCK_DIVISOR);
88
89 CTRL(port) = 12; // reg 12
90 CTRL(port) = baud & 0xff;
91 CTRL(port) = 13; // reg 13
92 CTRL(port) = (baud >> 8) & 0xff;
93 CTRL(port) = 14; // reg 14
94 CTRL(port) = BRSRC | BRENAB;
95
96 CTRL(port) = 3; // reg 3
97 CTRL(port) = RxENAB | Rx8; // enable rx, 8 bits/char
98
99 CTRL(port) = 5; // reg 5
100 CTRL(port) = RTS | TxENAB | Tx8 | DTR; // enable tx, 8 bits/char,
101 // set RTS & DTR
102
103 }
104
escc_uart_init(phys_addr_t port,unsigned long speed)105 int escc_uart_init(phys_addr_t port, unsigned long speed)
106 {
107 #ifdef CONFIG_DRIVER_ESCC_SUN
108 escc_serial_dev = (unsigned char *)ofmem_map_io(port & ~7ULL, ZS_REGS);
109 escc_serial_dev += port & 7ULL;
110 #else
111 escc_serial_dev = (unsigned char *)(uintptr_t)port;
112 #endif
113 uart_init_line(escc_serial_dev, speed);
114 return -1;
115 }
116
escc_uart_putchar(int c)117 void escc_uart_putchar(int c)
118 {
119 escc_uart_port_putchar((uintptr_t)escc_serial_dev, (unsigned char) (c & 0xff));
120 }
121
serial_cls(void)122 void serial_cls(void)
123 {
124 escc_uart_putchar(27);
125 escc_uart_putchar('[');
126 escc_uart_putchar('H');
127 escc_uart_putchar(27);
128 escc_uart_putchar('[');
129 escc_uart_putchar('J');
130 }
131
132 /* ( addr len -- actual ) */
133 static void
escc_port_read(ucell * address)134 escc_port_read(ucell *address)
135 {
136 char *addr;
137 int len;
138
139 len = POP();
140 addr = (char *)cell2pointer(POP());
141
142 if (len < 1)
143 printk("escc_read: bad len, addr %p len %x\n", addr, len);
144
145 if (escc_uart_charav(*address)) {
146 *addr = (char)escc_uart_getchar(*address);
147 PUSH(1);
148 } else {
149 PUSH(0);
150 }
151 }
152
153 /* ( addr len -- actual ) */
154 static void
escc_port_write(ucell * address)155 escc_port_write(ucell *address)
156 {
157 unsigned char *addr;
158 int i, len;
159
160 len = POP();
161 addr = (unsigned char *)cell2pointer(POP());
162
163 for (i = 0; i < len; i++) {
164 escc_uart_port_putchar(*address, addr[i]);
165 }
166 PUSH(len);
167 }
168
169 static void
escc_port_close(void)170 escc_port_close(void)
171 {
172 }
173
174 #ifdef CONFIG_DRIVER_ESCC_SUN
175 static void
escc_port_open(ucell * address)176 escc_port_open(ucell *address)
177 {
178
179 int len;
180 phandle_t ph;
181 unsigned long *prop;
182 char *args;
183
184 fword("my-self");
185 fword("ihandle>phandle");
186 ph = (phandle_t)POP();
187 prop = (unsigned long *)get_property(ph, "address", &len);
188 *address = *prop;
189 fword("my-args");
190 args = pop_fstr_copy();
191 if (args) {
192 if (args[0] == 'a')
193 *address += 4;
194 //printk("escc_open: address %lx, args %s\n", *address, args);
195 free(args);
196 }
197
198 RET ( -1 );
199 }
200
201 #else
202
203 static void
escc_port_open(ucell * address)204 escc_port_open(ucell *address)
205 {
206 *address = (unsigned long)escc_serial_dev; // XXX
207 RET(-1);
208 }
209
210 static void
escc_open(int * idx)211 escc_open(int *idx)
212 {
213 RET(-1);
214 }
215
216 static void
escc_close(int * idx)217 escc_close(int *idx)
218 {
219 }
220
221 DECLARE_UNNAMED_NODE(escc, 0, sizeof(int *));
222
223 NODE_METHODS(escc) = {
224 { "open", escc_open },
225 { "close", escc_close },
226 };
227
228 #endif
229
230 DECLARE_UNNAMED_NODE(escc_port, 0, sizeof(ucell));
231
232 NODE_METHODS(escc_port) = {
233 { "open", escc_port_open },
234 { "close", escc_port_close },
235 { "read", escc_port_read },
236 { "write", escc_port_write },
237 };
238
239 #ifdef CONFIG_DRIVER_ESCC_SUN
240 static volatile unsigned char *kbd_dev;
241
kbd_init(phys_addr_t base)242 void kbd_init(phys_addr_t base)
243 {
244 kbd_dev = (unsigned char *)ofmem_map_io(base, 2 * 4);
245 kbd_dev += 4;
246 }
247
248 static const unsigned char sunkbd_keycode[128] = {
249 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
250 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
251 '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 0, 8,
252 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,
253 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']',
254 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
255 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '\\', 13,
256 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
257 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/',
258 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
259 ' ',
260 };
261
262 static const unsigned char sunkbd_keycode_shifted[128] = {
263 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
264 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
265 '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', 0, 8,
266 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,
267 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}',
268 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
269 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '|', 13,
270 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
271 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?',
272 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
273 ' ',
274 };
275
276 static int shiftstate;
277
278 int
keyboard_dataready(void)279 keyboard_dataready(void)
280 {
281 return ((kbd_dev[0] & 1) == 1);
282 }
283
284 unsigned char
keyboard_readdata(void)285 keyboard_readdata(void)
286 {
287 volatile unsigned char ch;
288
289 while (!keyboard_dataready()) { }
290
291 do {
292 ch = kbd_dev[2] & 0xff;
293 if (ch == 99)
294 shiftstate |= 1;
295 else if (ch == 110)
296 shiftstate |= 2;
297 else if (ch == 227)
298 shiftstate &= ~1;
299 else if (ch == 238)
300 shiftstate &= ~2;
301 //printk("getch: %d\n", ch);
302 } // If release, wait for key press
303 while ((ch & 0x80) == 0x80 || ch == 238 || ch == 227);
304 //printk("getch rel: %d\n", ch);
305 ch &= 0x7f;
306 if (shiftstate)
307 ch = sunkbd_keycode_shifted[ch];
308 else
309 ch = sunkbd_keycode[ch];
310 //printk("getch xlate: %d\n", ch);
311
312 return ch;
313 }
314
315 /* ( addr len -- actual ) */
316 static void
escc_read_keyboard(void)317 escc_read_keyboard(void)
318 {
319 unsigned char *addr;
320 int len;
321
322 len = POP();
323 addr = (unsigned char *)POP();
324
325 if (len < 1)
326 printk("escc_read: bad len, addr %p len %x\n", addr, len);
327
328 if (keyboard_dataready()) {
329 *addr = keyboard_readdata();
330 PUSH(1);
331 } else {
332 PUSH(0);
333 }
334 }
335
336 DECLARE_UNNAMED_NODE(escc_keyboard, 0, sizeof(ucell));
337
338 NODE_METHODS(escc_keyboard) = {
339 { "open", escc_port_open },
340 { "close", escc_port_close },
341 { "read", escc_read_keyboard },
342 };
343
344 void
ob_zs_init(phys_addr_t base,uint64_t offset,int intr,int slave,int keyboard)345 ob_zs_init(phys_addr_t base, uint64_t offset, int intr, int slave, int keyboard)
346 {
347 char nodebuff[256];
348 phandle_t aliases;
349
350 ob_new_obio_device("zs", "serial");
351
352 ob_reg(base, offset, ZS_REGS, 1);
353
354 PUSH(slave);
355 fword("encode-int");
356 push_str("slave");
357 fword("property");
358
359 if (keyboard) {
360 PUSH(0);
361 PUSH(0);
362 push_str("keyboard");
363 fword("property");
364
365 PUSH(0);
366 PUSH(0);
367 push_str("mouse");
368 fword("property");
369 }
370
371 ob_intr(intr);
372
373 PUSH(0);
374 PUSH(0);
375 push_str("port-a-ignore-cd");
376 fword("property");
377
378 PUSH(0);
379 PUSH(0);
380 push_str("port-b-ignore-cd");
381 fword("property");
382
383 if (keyboard) {
384 BIND_NODE_METHODS(get_cur_dev(), escc_keyboard);
385 } else {
386 BIND_NODE_METHODS(get_cur_dev(), escc_port);
387 }
388
389 fword("finish-device");
390
391 aliases = find_dev("/aliases");
392 if (keyboard) {
393 snprintf(nodebuff, sizeof(nodebuff), "/obio/zs@0,%x",
394 (int)offset & 0xffffffff);
395 set_property(aliases, "keyboard", nodebuff, strlen(nodebuff) + 1);
396 } else {
397 snprintf(nodebuff, sizeof(nodebuff), "/obio/zs@0,%x:a",
398 (int)offset & 0xffffffff);
399 set_property(aliases, "ttya", nodebuff, strlen(nodebuff) + 1);
400
401 snprintf(nodebuff, sizeof(nodebuff), "/obio/zs@0,%x:b",
402 (int)offset & 0xffffffff);
403 set_property(aliases, "ttyb", nodebuff, strlen(nodebuff) + 1);
404
405 }
406 }
407
408 #else
409
410 static void
escc_add_channel(const char * path,const char * node,phys_addr_t addr,int esnum)411 escc_add_channel(const char *path, const char *node, phys_addr_t addr,
412 int esnum)
413 {
414 char buf[64], tty[32];
415 phandle_t dnode, aliases;
416
417 cell props[10];
418 ucell offset;
419 int index;
420 int legacy;
421
422 int dbdma_offsets[2][2] = {
423 /* ch-b */
424 { 0x6, 0x7 },
425 /* ch-a */
426 { 0x4, 0x5 }
427 };
428
429 int reg_offsets[2][2][3] = {
430 {
431 /* ch-b */
432 { 0x00, 0x10, 0x40 },
433 /* ch-a */
434 { 0x20, 0x30, 0x50 }
435 },{
436 /* legacy ch-b */
437 { 0x0, 0x4, 0x8 },
438 /* legacy ch-a */
439 { 0x2, 0x6, 0xa }
440 }
441 };
442
443 switch (esnum) {
444 case 2: index = 1; legacy = 0; break;
445 case 3: index = 0; legacy = 0; break;
446 case 4: index = 1; legacy = 1; break;
447 case 5: index = 0; legacy = 1; break;
448 default: return;
449 }
450
451 /* add device */
452
453 fword("new-device");
454
455 snprintf(buf, sizeof(buf), "ch-%s", node);
456 push_str(buf);
457 fword("device-name");
458
459 BIND_NODE_METHODS(get_cur_dev(), escc_port);
460
461 /* add aliases */
462
463 if (!legacy) {
464 aliases = find_dev("/aliases");
465
466 snprintf(buf, sizeof(buf), "%s/ch-%s", path, node);
467 OLDWORLD(snprintf(tty, sizeof(tty), "tty%s", node));
468 OLDWORLD(set_property(aliases, tty, buf, strlen(buf) + 1));
469 snprintf(tty, sizeof(tty), "scc%s", node);
470 set_property(aliases, tty, buf, strlen(buf) + 1);
471 }
472 /* add properties */
473
474 dnode = get_cur_dev();
475 set_property(dnode, "device_type", "serial",
476 strlen("serial") + 1);
477
478 snprintf(buf, sizeof(buf), "chrp,es%d", esnum);
479 set_property(dnode, "compatible", buf, 9);
480
481 if (legacy) {
482 offset = IO_ESCC_LEGACY_OFFSET;
483 } else {
484 offset = IO_ESCC_OFFSET;
485 }
486
487 props[0] = offset + reg_offsets[legacy][index][0];
488 props[1] = 0x1;
489 props[2] = offset + reg_offsets[legacy][index][1];
490 props[3] = 0x1;
491 props[4] = offset + reg_offsets[legacy][index][2];
492 props[5] = 0x1;
493 props[6] = 0x8000 + dbdma_offsets[index][0] * 0x100;
494 props[7] = 0x100;
495 props[8] = 0x8000 + dbdma_offsets[index][1] * 0x100;
496 props[9] = 0x100;
497 set_property(dnode, "reg", (char *)&props, 10 * sizeof(cell));
498
499 props[0] = addr + offset + reg_offsets[legacy][index][0];
500 OLDWORLD(set_property(dnode, "AAPL,address",
501 (char *)&props, 1 * sizeof(cell)));
502
503 props[0] = 0x10 - index;
504 OLDWORLD(set_property(dnode, "AAPL,interrupts",
505 (char *)&props, 1 * sizeof(cell)));
506
507 props[0] = (0x24) + index;
508 props[1] = 0x1;
509 props[2] = dbdma_offsets[index][0];
510 props[3] = 0x0;
511 props[4] = dbdma_offsets[index][1];
512 props[5] = 0x0;
513 NEWWORLD(set_property(dnode, "interrupts",
514 (char *)&props, 6 * sizeof(cell)));
515
516 set_int_property(dnode, "slot-names", 0);
517
518 fword("finish-device");
519
520 uart_init_line((unsigned char*)addr + offset + reg_offsets[legacy][index][0],
521 CONFIG_SERIAL_SPEED);
522 }
523
524 void
escc_init(const char * path,phys_addr_t addr)525 escc_init(const char *path, phys_addr_t addr)
526 {
527 char buf[64];
528 int props[2];
529 phandle_t dnode;
530
531 fword("new-device");
532
533 push_str("escc");
534 fword("device-name");
535
536 dnode = get_cur_dev();
537 set_int_property(dnode, "#address-cells", 1);
538 props[0] = __cpu_to_be32(IO_ESCC_OFFSET);
539 props[1] = __cpu_to_be32(IO_ESCC_SIZE);
540 set_property(dnode, "reg", (char *)&props, sizeof(props));
541 set_property(dnode, "device_type", "escc",
542 strlen("escc") + 1);
543 set_property(dnode, "compatible", "escc\0CHRP,es0", 14);
544 set_property(dnode, "ranges", "", 0);
545
546 snprintf(buf, sizeof(buf), "%s/escc", path);
547 escc_add_channel(buf, "a", addr, 2);
548 escc_add_channel(buf, "b", addr, 3);
549
550 BIND_NODE_METHODS(dnode, escc);
551 fword("finish-device");
552
553 escc_serial_dev = (unsigned char *)addr + IO_ESCC_OFFSET +
554 (CONFIG_SERIAL_PORT ? 0 : 0x20);
555
556 fword("new-device");
557
558 push_str("escc-legacy");
559 fword("device-name");
560
561 dnode = get_cur_dev();
562 set_int_property(dnode, "#address-cells", 1);
563 props[0] = __cpu_to_be32(IO_ESCC_LEGACY_OFFSET);
564 props[1] = __cpu_to_be32(IO_ESCC_LEGACY_SIZE);
565 set_property(dnode, "reg", (char *)&props, sizeof(props));
566 set_property(dnode, "device_type", "escc-legacy",
567 strlen("escc-legacy") + 1);
568 set_property(dnode, "compatible", "chrp,es1", 9);
569 set_property(dnode, "ranges", "", 0);
570
571 snprintf(buf, sizeof(buf), "%s/escc-legacy", path);
572 escc_add_channel(buf, "a", addr, 4);
573 escc_add_channel(buf, "b", addr, 5);
574
575 BIND_NODE_METHODS(dnode, escc);
576 fword("finish-device");
577 }
578 #endif
579