ppc64: Don't set Kp bit on SLB
[openbios/afaerber.git] / drivers / escc.c
blob892dc8c9fe5dc4a0f97deefa2ddae6efe4699c3e
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"
8 #include "escc.h"
10 /* ******************************************************************
11 * serial console functions
12 * ****************************************************************** */
14 static volatile unsigned char *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))
19 #else
20 #define DATA(addr) (*(volatile unsigned char *)(uintptr_t)(addr + 16))
21 #endif
23 /* Conversion routines to/from brg time constants from/to bits
24 * per second.
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. */
30 #else
31 #define ESCC_CLOCK 3686400
32 #endif
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 */
53 /* Read Register 0 */
54 #define Rx_CH_AV 0x1 /* Rx Character Available */
55 #define Tx_BUF_EMP 0x4 /* Tx Buffer empty */
57 int uart_charav(uintptr_t port)
59 return (CTRL(port) & Rx_CH_AV) != 0;
62 char uart_getchar(uintptr_t port)
64 while (!uart_charav(port))
66 return DATA(port) & 0177;
69 static void uart_putchar(uintptr_t port, unsigned char c)
71 if (!serial_dev)
72 return;
74 if (c == '\n')
75 uart_putchar(port, '\r');
76 while (!(CTRL(port) & Tx_BUF_EMP))
78 DATA(port) = c;
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
85 // clock
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,
101 // set RTS & DTR
105 int uart_init(phys_addr_t port, unsigned long speed)
107 #ifdef CONFIG_DRIVER_ESCC_SUN
108 serial_dev = (unsigned char *)ofmem_map_io(port & ~7ULL, ZS_REGS);
109 serial_dev += port & 7ULL;
110 #else
111 serial_dev = (unsigned char *)(uintptr_t)port;
112 #endif
113 uart_init_line(serial_dev, speed);
114 return -1;
117 void serial_putchar(int c)
119 uart_putchar((uintptr_t)serial_dev, (unsigned char) (c & 0xff));
122 void serial_cls(void)
124 serial_putchar(27);
125 serial_putchar('[');
126 serial_putchar('H');
127 serial_putchar(27);
128 serial_putchar('[');
129 serial_putchar('J');
132 /* ( addr len -- actual ) */
133 static void
134 escc_read(phys_addr_t *address)
136 char *addr;
137 int len;
139 len = POP();
140 addr = (char *)cell2pointer(POP());
142 if (len < 1)
143 printk("escc_read: bad len, addr %p len %x\n", addr, len);
145 if (uart_charav(*address)) {
146 *addr = (char)uart_getchar(*address);
147 PUSH(1);
148 } else {
149 PUSH(0);
153 /* ( addr len -- actual ) */
154 static void
155 escc_write(phys_addr_t *address)
157 unsigned char *addr;
158 int i, len;
160 len = POP();
161 addr = (unsigned char *)cell2pointer(POP());
163 for (i = 0; i < len; i++) {
164 uart_putchar(*address, addr[i]);
166 PUSH(len);
169 static void
170 escc_close(void)
174 static void
175 escc_open(phys_addr_t *address)
177 #ifdef CONFIG_DRIVER_ESCC_SUN
178 int len;
179 phandle_t ph;
180 unsigned long *prop;
181 char *args;
183 fword("my-self");
184 fword("ihandle>phandle");
185 ph = (phandle_t)POP();
186 prop = (unsigned long *)get_property(ph, "address", &len);
187 *address = *prop;
188 fword("my-args");
189 args = pop_fstr_copy();
190 if (args) {
191 if (args[0] == 'a')
192 *address += 4;
193 //printk("escc_open: address %lx, args %s\n", *address, args);
194 free(args);
196 #else
197 *address = (unsigned long)serial_dev; // XXX
198 #endif
199 RET ( -1 );
202 DECLARE_UNNAMED_NODE(escc, INSTALL_OPEN, sizeof(phys_addr_t));
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);
217 kbd_dev += 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,
231 ' ',
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,
245 ' ',
248 static int shiftstate;
251 keyboard_dataready(void)
253 return ((kbd_dev[0] & 1) == 1);
256 unsigned char
257 keyboard_readdata(void)
259 unsigned char ch;
261 while (!keyboard_dataready()) { }
263 do {
264 ch = kbd_dev[2] & 0xff;
265 if (ch == 99)
266 shiftstate |= 1;
267 else if (ch == 110)
268 shiftstate |= 2;
269 else if (ch == 227)
270 shiftstate &= ~1;
271 else if (ch == 238)
272 shiftstate &= ~2;
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);
277 ch &= 0x7f;
278 if (shiftstate)
279 ch = sunkbd_keycode_shifted[ch];
280 else
281 ch = sunkbd_keycode[ch];
282 //printk("getch xlate: %d\n", ch);
284 return ch;
287 /* ( addr len -- actual ) */
288 static void
289 escc_read_keyboard(void)
291 unsigned char *addr;
292 int len;
294 len = POP();
295 addr = (unsigned char *)POP();
297 if (len < 1)
298 printk("escc_read: bad len, addr %p len %x\n", addr, len);
300 if (keyboard_dataready()) {
301 *addr = keyboard_readdata();
302 PUSH(1);
303 } else {
304 PUSH(0);
308 DECLARE_UNNAMED_NODE(escc_keyboard, INSTALL_OPEN, sizeof(phys_addr_t));
310 NODE_METHODS(escc_keyboard) = {
311 { "open", escc_open },
312 { "close", escc_close },
313 { "read", escc_read_keyboard },
316 void
317 ob_zs_init(phys_addr_t base, uint64_t offset, int intr, int slave, int keyboard)
319 char nodebuff[256];
320 phandle_t aliases;
322 ob_new_obio_device("zs", "serial");
324 ob_reg(base, offset, ZS_REGS, 1);
326 PUSH(slave);
327 fword("encode-int");
328 push_str("slave");
329 fword("property");
331 if (keyboard) {
332 PUSH(-1);
333 fword("encode-int");
334 push_str("keyboard");
335 fword("property");
337 PUSH(-1);
338 fword("encode-int");
339 push_str("mouse");
340 fword("property");
343 ob_intr(intr);
345 PUSH(0);
346 PUSH(0);
347 push_str("port-a-ignore-cd");
348 fword("property");
350 PUSH(0);
351 PUSH(0);
352 push_str("port-b-ignore-cd");
353 fword("property");
355 fword("finish-device");
357 snprintf(nodebuff, sizeof(nodebuff), "/obio/zs@0,%x",
358 (int)offset & 0xffffffff);
359 if (keyboard) {
360 REGISTER_NODE_METHODS(escc_keyboard, nodebuff);
362 aliases = find_dev("/aliases");
363 set_property(aliases, "keyboard", nodebuff, strlen(nodebuff) + 1);
364 } else {
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);
379 #else
381 static void
382 escc_add_channel(const char *path, const char *node, phys_addr_t addr,
383 uint32_t offset)
385 char buf[64], tty[32];
386 phandle_t dnode, aliases;
387 int len;
388 cell props[2];
390 /* add device */
392 snprintf(buf, sizeof(buf), "%s/ch-%s", path, node);
394 REGISTER_NAMED_NODE(escc, buf);
396 activate_device(buf);
398 /* add aliases */
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);
408 /* add properties */
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;
432 props[1] = 0;
433 NEWWORLD(set_property(dnode, "interrupts",
434 (char *)&props, 2 * sizeof(cell)));
436 device_end();
438 uart_init_line((unsigned char*)addr + IO_ESCC_OFFSET + offset * 0x20,
439 CONFIG_SERIAL_SPEED);
442 void
443 escc_init(const char *path, phys_addr_t addr)
445 char buf[64];
446 int props[2];
447 phandle_t dnode;
449 push_str(path);
450 fword("find-device");
451 fword("new-device");
453 push_str("escc");
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",
465 strlen("escc") + 1);
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 serial_dev = (unsigned char *)addr + IO_ESCC_OFFSET +
474 (CONFIG_SERIAL_PORT ? 0 : 0x20);
476 #endif