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 *serial_dev
;
16 #define CTRL(addr) (*(volatile unsigned char *)(addr))
17 #ifdef CONFIG_DRIVER_ESCC_SUN
18 #define DATA(addr) (*(volatile unsigned char *)(addr + 2))
20 #define DATA(addr) (*(volatile unsigned char *)(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 uart_charav(int port
)
59 return (CTRL(port
) & Rx_CH_AV
) != 0;
62 char uart_getchar(int port
)
64 while (!uart_charav(port
))
66 return DATA(port
) & 0177;
69 static void uart_putchar(int port
, unsigned char c
)
75 uart_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 uart_init(uint64_t port
, unsigned long speed
)
107 #ifdef CONFIG_DRIVER_ESCC_SUN
108 serial_dev
= map_io(port
& ~7ULL, ZS_REGS
);
109 serial_dev
+= port
& 7ULL;
111 serial_dev
= (unsigned char *)(unsigned long)port
;
113 uart_init_line(serial_dev
, speed
);
117 void serial_putchar(int c
)
119 uart_putchar((int)serial_dev
, (unsigned char) (c
& 0xff));
122 void serial_cls(void)
132 /* ( addr len -- actual ) */
134 escc_read(unsigned long *address
)
140 addr
= (char *)cell2pointer(POP());
143 printk("escc_read: bad len, addr %x len %x\n", (unsigned int)addr
, len
);
145 if (uart_charav(*address
)) {
146 *addr
= (char)uart_getchar(*address
);
153 /* ( addr len -- actual ) */
155 escc_write(unsigned long *address
)
161 addr
= (unsigned char *)cell2pointer(POP());
163 for (i
= 0; i
< len
; i
++) {
164 uart_putchar(*address
, addr
[i
]);
175 escc_open(unsigned long *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)serial_dev
; // XXX
202 DECLARE_UNNAMED_NODE(escc
, INSTALL_OPEN
, sizeof(unsigned long));
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(uint64_t base
)
216 kbd_dev
= 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 %x len %x\n", (unsigned int)addr
, len
);
300 if (keyboard_dataready()) {
301 *addr
= keyboard_readdata();
308 DECLARE_UNNAMED_NODE(escc_keyboard
, INSTALL_OPEN
, sizeof(unsigned long));
310 NODE_METHODS(escc_keyboard
) = {
311 { "open", escc_open
},
312 { "close", escc_close
},
313 { "read", escc_read_keyboard
},
317 ob_zs_init(uint64_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");
345 fword("finish-device");
347 snprintf(nodebuff
, sizeof(nodebuff
), "/obio/zs@0,%x",
348 (int)offset
& 0xffffffff);
350 REGISTER_NODE_METHODS(escc_keyboard
, nodebuff
);
352 aliases
= find_dev("/aliases");
353 set_property(aliases
, "keyboard", nodebuff
, strlen(nodebuff
) + 1);
355 REGISTER_NODE_METHODS(escc
, nodebuff
);
357 aliases
= find_dev("/aliases");
358 snprintf(nodebuff
, sizeof(nodebuff
), "/obio/zs@0,%x:a",
359 (int)offset
& 0xffffffff);
360 set_property(aliases
, "ttya", nodebuff
, strlen(nodebuff
) + 1);
362 snprintf(nodebuff
, sizeof(nodebuff
), "/obio/zs@0,%x:b",
363 (int)offset
& 0xffffffff);
364 set_property(aliases
, "ttyb", nodebuff
, strlen(nodebuff
) + 1);
372 escc_add_channel(const char *path
, const char *node
, uint32_t addr
,
375 char buf
[64], tty
[32];
376 phandle_t dnode
, aliases
;
382 snprintf(buf
, sizeof(buf
), "%s/ch-%s", path
, node
);
384 REGISTER_NAMED_NODE(escc
, buf
);
386 activate_device(buf
);
390 aliases
= find_dev("/aliases");
392 snprintf(buf
, sizeof(buf
), "%s/ch-%s", path
, node
);
393 OLDWORLD(snprintf(tty
, sizeof(tty
), "tty%s", node
));
394 OLDWORLD(set_property(aliases
, tty
, buf
, strlen(buf
) + 1));
395 snprintf(tty
, sizeof(tty
), "scc%s", node
);
396 set_property(aliases
, tty
, buf
, strlen(buf
) + 1);
400 dnode
= find_dev(buf
);
401 set_property(dnode
, "device_type", "serial",
402 strlen("serial") + 1);
404 snprintf(buf
, sizeof(buf
), "ch-%s", node
);
405 len
= strlen(buf
) + 1;
406 snprintf(buf
+ len
, sizeof(buf
) - len
, "CHRP,es2");
407 set_property(dnode
, "compatible", buf
, len
+ 9);
409 props
[0] = IO_ESCC_OFFSET
+ offset
* 0x20;
410 props
[1] = 0x00000020;
411 set_property(dnode
, "reg", (char *)&props
, 2 * sizeof(cell
));
413 props
[0] = addr
+ IO_ESCC_OFFSET
+ offset
* 0x20;
414 OLDWORLD(set_property(dnode
, "AAPL,address",
415 (char *)&props
, 1 * sizeof(cell
)));
417 props
[0] = 0x00000010 - offset
;
418 OLDWORLD(set_property(dnode
, "AAPL,interrupts",
419 (char *)&props
, 1 * sizeof(cell
)));
421 props
[0] = (0x24) + offset
;
423 NEWWORLD(set_property(dnode
, "interrupts",
424 (char *)&props
, 2 * sizeof(cell
)));
428 uart_init_line((unsigned char*)addr
+ IO_ESCC_OFFSET
+ offset
* 0x20,
429 CONFIG_SERIAL_SPEED
);
433 escc_init(const char *path
, unsigned long addr
)
440 fword("find-device");
444 fword("device-name");
446 snprintf(buf
, sizeof(buf
), "%s/escc", path
);
448 dnode
= find_dev(buf
);
450 set_int_property(dnode
, "#address-cells", 1);
451 props
[0] = __cpu_to_be32(IO_ESCC_OFFSET
);
452 props
[1] = __cpu_to_be32(IO_ESCC_SIZE
);
453 set_property(dnode
, "reg", (char *)&props
, sizeof(props
));
454 set_property(dnode
, "device_type", "escc",
456 set_property(dnode
, "compatible", "escc\0CHRP,es0", 14);
458 fword("finish-device");
460 escc_add_channel(buf
, "a", addr
, 1);
461 escc_add_channel(buf
, "b", addr
, 0);
463 serial_dev
= (unsigned char *)addr
+ IO_ESCC_OFFSET
+
464 (CONFIG_SERIAL_PORT
? 0 : 0x20);