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"
10 /* ******************************************************************
11 * serial console functions
12 * ****************************************************************** */
14 static volatile unsigned char *escc_serial_dev;
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))
20 #define DATA(addr) (*(volatile unsigned char *)(uintptr_t)(addr + 16))
23 /* Conversion routines to/from brg time constants from/to bits
26 #define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
28 #ifdef CONFIG_DRIVER_ESCC_SUN
29 #define ESCC_CLOCK 4915200 /* Zilog input clock rate. */
31 #define ESCC_CLOCK 3686400
33 #define ESCC_CLOCK_DIVISOR 16 /* Divisor this driver uses. */
35 /* Write Register 3 */
36 #define RxENAB 0x1 /* Rx Enable */
37 #define Rx8 0xc0 /* Rx 8 Bits/Character */
39 /* Write Register 4 */
40 #define SB1 0x4 /* 1 stop bit/char */
41 #define X16CLK 0x40 /* x16 clock mode */
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 */
49 /* Write Register 14 (Misc control bits) */
50 #define BRENAB 1 /* Baud rate generator enable */
51 #define BRSRC 2 /* Baud rate generator source */
54 #define Rx_CH_AV 0x1 /* Rx Character Available */
55 #define Tx_BUF_EMP 0x4 /* Tx Buffer empty */
57 int escc_uart_charav(uintptr_t port)
59 return (CTRL(port) & Rx_CH_AV) != 0;
62 char escc_uart_getchar(uintptr_t port)
64 while (!escc_uart_charav(port))
66 return DATA(port) & 0177;
69 static void escc_uart_port_putchar(uintptr_t port, unsigned char c)
75 escc_uart_port_putchar(port, '\r');
76 while (!(CTRL(port) & Tx_BUF_EMP))
81 static void uart_init_line(volatile unsigned char *port, unsigned long baud)
83 CTRL(port) = 4; // reg 4
84 CTRL(port) = SB1 | X16CLK; // no parity, async, 1 stop bit, 16x
87 baud = BPS_TO_BRG(baud, ESCC_CLOCK / ESCC_CLOCK_DIVISOR);
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;
96 CTRL(port) = 3; // reg 3
97 CTRL(port) = RxENAB | Rx8; // enable rx, 8 bits/char
99 CTRL(port) = 5; // reg 5
100 CTRL(port) = RTS | TxENAB | Tx8 | DTR; // enable tx, 8 bits/char,
105 int escc_uart_init(phys_addr_t port, unsigned long speed)
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;
111 escc_serial_dev = (unsigned char *)(uintptr_t)port;
113 uart_init_line(escc_serial_dev, speed);
117 void escc_uart_putchar(int c)
119 escc_uart_port_putchar((uintptr_t)escc_serial_dev, (unsigned char) (c & 0xff));
122 void serial_cls(void)
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');
132 /* ( addr len -- actual ) */
134 escc_read(ucell *address)
140 addr = (char *)cell2pointer(POP());
143 printk("escc_read: bad len, addr %p len %x\n", addr, len);
145 if (escc_uart_charav(*address)) {
146 *addr = (char)escc_uart_getchar(*address);
153 /* ( addr len -- actual ) */
155 escc_write(ucell *address)
161 addr = (unsigned char *)cell2pointer(POP());
163 for (i = 0; i < len; i++) {
164 escc_uart_port_putchar(*address, addr[i]);
175 escc_open(ucell *address)
177 #ifdef CONFIG_DRIVER_ESCC_SUN
184 fword("ihandle>phandle");
185 ph = (phandle_t)POP();
186 prop = (unsigned long *)get_property(ph, "address", &len);
189 args = pop_fstr_copy();
193 //printk("escc_open: address %lx, args %s\n", *address, args);
197 *address = (unsigned long)escc_serial_dev; // XXX
202 DECLARE_UNNAMED_NODE(escc, INSTALL_OPEN, sizeof(ucell));
204 NODE_METHODS(escc) = {
205 { "open", escc_open },
206 { "close", escc_close },
207 { "read", escc_read },
208 { "write", escc_write },
211 #ifdef CONFIG_DRIVER_ESCC_SUN
212 static volatile unsigned char *kbd_dev;
214 void kbd_init(phys_addr_t base)
216 kbd_dev = (unsigned char *)ofmem_map_io(base, 2 * 4);
220 static const unsigned char sunkbd_keycode[128] = {
221 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
222 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
223 '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 0, 8,
224 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,
225 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']',
226 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
227 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '\\', 13,
228 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
229 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/',
230 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
234 static const unsigned char sunkbd_keycode_shifted[128] = {
235 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
236 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
237 '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', 0, 8,
238 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,
239 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}',
240 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
241 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '|', 13,
242 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
243 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?',
244 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
248 static int shiftstate;
251 keyboard_dataready(void)
253 return ((kbd_dev[0] & 1) == 1);
257 keyboard_readdata(void)
261 while (!keyboard_dataready()) { }
264 ch = kbd_dev[2] & 0xff;
273 //printk("getch: %d\n", ch);
274 } // If release, wait for key press
275 while ((ch & 0x80) == 0x80 || ch == 238 || ch == 227);
276 //printk("getch rel: %d\n", ch);
279 ch = sunkbd_keycode_shifted[ch];
281 ch = sunkbd_keycode[ch];
282 //printk("getch xlate: %d\n", ch);
287 /* ( addr len -- actual ) */
289 escc_read_keyboard(void)
295 addr = (unsigned char *)POP();
298 printk("escc_read: bad len, addr %p len %x\n", addr, len);
300 if (keyboard_dataready()) {
301 *addr = keyboard_readdata();
308 DECLARE_UNNAMED_NODE(escc_keyboard, INSTALL_OPEN, sizeof(ucell));
310 NODE_METHODS(escc_keyboard) = {
311 { "open", escc_open },
312 { "close", escc_close },
313 { "read", escc_read_keyboard },
317 ob_zs_init(phys_addr_t base, uint64_t offset, int intr, int slave, int keyboard)
322 ob_new_obio_device("zs", "serial");
324 ob_reg(base, offset, ZS_REGS, 1);
334 push_str("keyboard");
347 push_str("port-a-ignore-cd");
352 push_str("port-b-ignore-cd");
355 fword("finish-device");
357 snprintf(nodebuff, sizeof(nodebuff), "/obio/zs@0,%x",
358 (int)offset & 0xffffffff);
360 REGISTER_NODE_METHODS(escc_keyboard, nodebuff);
362 aliases = find_dev("/aliases");
363 set_property(aliases, "keyboard", nodebuff, strlen(nodebuff) + 1);
365 REGISTER_NODE_METHODS(escc, nodebuff);
367 aliases = find_dev("/aliases");
368 snprintf(nodebuff, sizeof(nodebuff), "/obio/zs@0,%x:a",
369 (int)offset & 0xffffffff);
370 set_property(aliases, "ttya", nodebuff, strlen(nodebuff) + 1);
372 snprintf(nodebuff, sizeof(nodebuff), "/obio/zs@0,%x:b",
373 (int)offset & 0xffffffff);
374 set_property(aliases, "ttyb", nodebuff, strlen(nodebuff) + 1);
382 escc_add_channel(const char *path, const char *node, phys_addr_t addr,
385 char buf[64], tty[32];
386 phandle_t dnode, aliases;
393 int dbdma_offsets[2][2] = {
400 int reg_offsets[2][2][3] = {
403 { 0x00, 0x10, 0x40 },
415 case 2: index = 1; legacy = 0; break;
416 case 3: index = 0; legacy = 0; break;
417 case 4: index = 1; legacy = 1; break;
418 case 5: index = 0; legacy = 1; break;
424 snprintf(buf, sizeof(buf), "%s/ch-%s", path, node);
426 REGISTER_NAMED_NODE(escc, buf);
428 activate_device(buf);
432 aliases = find_dev("/aliases");
434 snprintf(buf, sizeof(buf), "%s/ch-%s", path, node);
435 OLDWORLD(snprintf(tty, sizeof(tty), "tty%s", node));
436 OLDWORLD(set_property(aliases, tty, buf, strlen(buf) + 1));
437 snprintf(tty, sizeof(tty), "scc%s", node);
438 set_property(aliases, tty, buf, strlen(buf) + 1);
442 dnode = find_dev(buf);
443 set_property(dnode, "device_type", "serial",
444 strlen("serial") + 1);
446 snprintf(buf, sizeof(buf), "chrp,es%d", esnum);
447 set_property(dnode, "compatible", buf, 9);
450 offset = IO_ESCC_LEGACY_OFFSET;
452 offset = IO_ESCC_OFFSET;
455 props[0] = offset + reg_offsets[legacy][index][0];
457 props[2] = offset + reg_offsets[legacy][index][1];
459 props[4] = offset + reg_offsets[legacy][index][2];
461 props[6] = 0x8000 + dbdma_offsets[index][0] * 0x100;
463 props[8] = 0x8000 + dbdma_offsets[index][1] * 0x100;
465 set_property(dnode, "reg", (char *)&props, 10 * sizeof(cell));
467 props[0] = addr + offset + reg_offsets[legacy][index][0];
468 OLDWORLD(set_property(dnode, "AAPL,address",
469 (char *)&props, 1 * sizeof(cell)));
471 props[0] = 0x10 - index;
472 OLDWORLD(set_property(dnode, "AAPL,interrupts",
473 (char *)&props, 1 * sizeof(cell)));
475 props[0] = (0x24) + index;
477 props[2] = dbdma_offsets[index][0];
479 props[4] = dbdma_offsets[index][1];
481 NEWWORLD(set_property(dnode, "interrupts",
482 (char *)&props, 6 * sizeof(cell)));
484 set_int_property(dnode, "slot-names", 0);
488 uart_init_line((unsigned char*)addr + offset + reg_offsets[legacy][index][0],
489 CONFIG_SERIAL_SPEED);
493 escc_init(const char *path, phys_addr_t addr)
500 fword("find-device");
504 fword("device-name");
506 snprintf(buf, sizeof(buf), "%s/escc", path);
508 dnode = find_dev(buf);
510 set_int_property(dnode, "#address-cells", 1);
511 props[0] = __cpu_to_be32(IO_ESCC_OFFSET);
512 props[1] = __cpu_to_be32(IO_ESCC_SIZE);
513 set_property(dnode, "reg", (char *)&props, sizeof(props));
514 set_property(dnode, "device_type", "escc",
516 set_property(dnode, "compatible", "escc\0CHRP,es0", 14);
517 set_property(dnode, "ranges", "", 0);
519 fword("finish-device");
521 escc_add_channel(buf, "a", addr, 2);
522 escc_add_channel(buf, "b", addr, 3);
524 escc_serial_dev = (unsigned char *)addr + IO_ESCC_OFFSET +
525 (CONFIG_SERIAL_PORT ? 0 : 0x20);
528 fword("find-device");
531 push_str("escc-legacy");
532 fword("device-name");
534 snprintf(buf, sizeof(buf), "%s/escc-legacy", path);
536 dnode = find_dev(buf);
538 set_int_property(dnode, "#address-cells", 1);
539 props[0] = __cpu_to_be32(IO_ESCC_LEGACY_OFFSET);
540 props[1] = __cpu_to_be32(IO_ESCC_LEGACY_SIZE);
541 set_property(dnode, "reg", (char *)&props, sizeof(props));
542 set_property(dnode, "device_type", "escc-legacy",
543 strlen("escc-legacy") + 1);
544 set_property(dnode, "compatible", "chrp,es1", 9);
545 set_property(dnode, "ranges", "", 0);
547 fword("finish-device");
549 escc_add_channel(buf, "a", addr, 4);
550 escc_add_channel(buf, "b", addr, 5);