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;
392 snprintf(buf, sizeof(buf), "%s/ch-%s", path, node);
394 REGISTER_NAMED_NODE(escc, buf);
396 activate_device(buf);
400 aliases = find_dev("/aliases");
402 snprintf(buf, sizeof(buf), "%s/ch-%s", path, node);
403 OLDWORLD(snprintf(tty, sizeof(tty), "tty%s", node));
404 OLDWORLD(set_property(aliases, tty, buf, strlen(buf) + 1));
405 snprintf(tty, sizeof(tty), "scc%s", node);
406 set_property(aliases, tty, buf, strlen(buf) + 1);
410 dnode = find_dev(buf);
411 set_property(dnode, "device_type", "serial",
412 strlen("serial") + 1);
414 snprintf(buf, sizeof(buf), "ch-%s", node);
415 len = strlen(buf) + 1;
416 snprintf(buf + len, sizeof(buf) - len, "CHRP,es2");
417 set_property(dnode, "compatible", buf, len + 9);
419 props[0] = IO_ESCC_OFFSET + offset * 0x20;
420 props[1] = 0x00000020;
421 set_property(dnode, "reg", (char *)&props, 2 * sizeof(cell));
423 props[0] = addr + IO_ESCC_OFFSET + offset * 0x20;
424 OLDWORLD(set_property(dnode, "AAPL,address",
425 (char *)&props, 1 * sizeof(cell)));
427 props[0] = 0x00000010 - offset;
428 OLDWORLD(set_property(dnode, "AAPL,interrupts",
429 (char *)&props, 1 * sizeof(cell)));
431 props[0] = (0x24) + offset;
433 NEWWORLD(set_property(dnode, "interrupts",
434 (char *)&props, 2 * sizeof(cell)));
438 uart_init_line((unsigned char*)addr + IO_ESCC_OFFSET + offset * 0x20,
439 CONFIG_SERIAL_SPEED);
443 escc_init(const char *path, phys_addr_t addr)
450 fword("find-device");
454 fword("device-name");
456 snprintf(buf, sizeof(buf), "%s/escc", path);
458 dnode = find_dev(buf);
460 set_int_property(dnode, "#address-cells", 1);
461 props[0] = __cpu_to_be32(IO_ESCC_OFFSET);
462 props[1] = __cpu_to_be32(IO_ESCC_SIZE);
463 set_property(dnode, "reg", (char *)&props, sizeof(props));
464 set_property(dnode, "device_type", "escc",
466 set_property(dnode, "compatible", "escc\0CHRP,es0", 14);
468 fword("finish-device");
470 escc_add_channel(buf, "a", addr, 1);
471 escc_add_channel(buf, "b", addr, 0);
473 escc_serial_dev = (unsigned char *)addr + IO_ESCC_OFFSET +
474 (CONFIG_SERIAL_PORT ? 0 : 0x20);