zs_ap.c revision 1.1 1 /* $NetBSD: zs_ap.c,v 1.1 1999/12/22 05:55:25 tsubai Exp $ */
2
3 /*-
4 * Copyright (c) 1996 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Gordon W. Ross.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /*
40 * Zilog Z8530 Dual UART driver (machine-dependent part)
41 *
42 * Runs two serial lines per chip using slave drivers.
43 * Plain tty/async lines use the zs_async slave.
44 * Sun keyboard/mouse uses the zs_kbd/zs_ms slaves.
45 */
46
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/device.h>
50 #include <sys/tty.h>
51
52 #include <machine/adrsmap.h>
53 #include <machine/cpu.h>
54 #include <machine/z8530var.h>
55
56 #include <dev/cons.h>
57 #include <dev/ic/z8530reg.h>
58
59 #include <newsmips/apbus/apbusvar.h>
60
61 #include "zsc.h" /* NZSC */
62 #define NZS NZSC
63
64 /* Make life easier for the initialized arrays here. */
65 #if NZS < 2
66 #undef NZS
67 #define NZS 2
68 #endif
69
70 #define MODE_REGISTER (-0x00080000)
71 #define FIFO_CH0 0x00000000
72 #define FIFO_CH1 0x00010000
73 #define FIFO_CH2 0x00020000
74 #define FIFO_CH3 0x00030000
75 #define FIFO_DEVWIN0 0x00040000
76 #define FIFO_DEVWIN1 0x00050000
77 #define FIFO_DEVWIN2 0x00060000
78 #define FIFO_DEVWIN3 0x00070000
79
80 #define PORTB_XPORT FIFO_CH0
81 #define PORTB_RPORT FIFO_CH1
82 #define PORTA_XPORT FIFO_CH2
83 #define PORTA_RPORT FIFO_CH3
84 #define PORTB_OFFSET FIFO_DEVWIN0
85 #define PORTA_OFFSET FIFO_DEVWIN1
86
87 extern int zs_def_cflag;
88 extern void (*zs_delay) __P((void));
89
90 /*
91 * The news5000 provides a 9.8304 MHz clock to the ZS chips.
92 */
93 #define PCLK (9600 * 1024) /* PCLK pin input clock rate */
94
95 #define ZS_DELAY() DELAY(2)
96
97 /* The layout of this is hardware-dependent (padding, order). */
98 struct zschan {
99 volatile u_char pad1[3];
100 volatile u_char zc_csr; /* ctrl,status, and indirect access */
101 volatile u_char pad2[3];
102 volatile u_char zc_data; /* data */
103 };
104
105 static caddr_t zsaddr[NZS];
106
107 /* Flags from cninit() */
108 static int zs_hwflags[NZS][2];
109
110 /* Default speed for all channels */
111 static int zs_defspeed = 9600;
112
113 static u_char zs_init_reg[16] = {
114 0, /* 0: CMD (reset, etc.) */
115 0, /* 1: No interrupts yet. */
116 0, /* IVECT */
117 ZSWR3_RX_8 | ZSWR3_RX_ENABLE,
118 ZSWR4_CLK_X16 | ZSWR4_ONESB | ZSWR4_EVENP,
119 ZSWR5_TX_8 | ZSWR5_TX_ENABLE,
120 0, /* 6: TXSYNC/SYNCLO */
121 0, /* 7: RXSYNC/SYNCHI */
122 0, /* 8: alias for data port */
123 ZSWR9_MASTER_IE,
124 0, /*10: Misc. TX/RX control bits */
125 ZSWR11_TXCLK_BAUD | ZSWR11_RXCLK_BAUD,
126 ((PCLK/32)/9600)-2, /*12: BAUDLO (default=9600) */
127 0, /*13: BAUDHI (default=9600) */
128 ZSWR14_BAUD_ENA | ZSWR14_BAUD_FROM_PCLK,
129 ZSWR15_BREAK_IE,
130 };
131
132 static struct zschan * zs_get_chan_addr __P((int, int));
133 static void zs_ap_delay __P((void));
134 static void zshard __P((void *));
135 static void zssoft __P((void *));
136 static int zs_getc __P((void *));
137 static void zs_putc __P((void *, int));
138 int zs_get_speed __P((struct zs_chanstate *));
139
140 struct zschan *
141 zs_get_chan_addr(zs_unit, channel)
142 int zs_unit, channel;
143 {
144 caddr_t addr;
145 struct zschan *zc;
146
147 if (zs_unit >= NZS)
148 return NULL;
149 addr = zsaddr[zs_unit];
150 if (addr == NULL)
151 return NULL;
152 if (channel == 0) {
153 zc = (void *)(addr + PORTA_OFFSET);
154 } else {
155 zc = (void *)(addr + PORTB_OFFSET);
156 }
157 return (zc);
158 }
159
160 void
161 zs_ap_delay()
162 {
163 ZS_DELAY();
164 }
165
166 /****************************************************************
167 * Autoconfig
168 ****************************************************************/
169
170 /* Definition of the driver for autoconfig. */
171 int zs_ap_match __P((struct device *, struct cfdata *, void *));
172 void zs_ap_attach __P((struct device *, struct device *, void *));
173 int zs_print __P((void *, const char *name));
174
175 struct cfattach zsc_ap_ca = {
176 sizeof(struct zsc_softc), zs_ap_match, zs_ap_attach
177 };
178
179 extern struct cfdriver zsc_cd;
180
181 /*
182 * Is the zs chip present?
183 */
184 int
185 zs_ap_match(parent, cf, aux)
186 struct device *parent;
187 struct cfdata *cf;
188 void *aux;
189 {
190 struct apbus_attach_args *apa = aux;
191
192 if (strcmp("esccf", apa->apa_name) != 0)
193 return 0;
194
195 return 1;
196 }
197
198 /*
199 * Attach a found zs.
200 *
201 * Match slave number to zs unit number, so that misconfiguration will
202 * not set up the keyboard as ttya, etc.
203 */
204 void
205 zs_ap_attach(parent, self, aux)
206 struct device *parent;
207 struct device *self;
208 void *aux;
209 {
210 struct zsc_softc *zsc = (void *)self;
211 struct apbus_attach_args *apa = aux;
212 struct zsc_attach_args zsc_args;
213 volatile struct zschan *zc;
214 struct zs_chanstate *cs;
215 int s, zs_unit, channel;
216 volatile u_int *txBfifo = (void *)(apa->apa_hwbase + FIFO_CH0);
217 volatile u_int *rxBfifo = (void *)(apa->apa_hwbase + FIFO_CH1);
218 volatile u_int *txAfifo = (void *)(apa->apa_hwbase + FIFO_CH2);
219 volatile u_int *rxAfifo = (void *)(apa->apa_hwbase + FIFO_CH3);
220 volatile u_int *devwin0 = (void *)(apa->apa_hwbase + FIFO_DEVWIN0);
221 volatile u_int *devwin1 = (void *)(apa->apa_hwbase + FIFO_DEVWIN1);
222 volatile u_int *devwin2 = (void *)(apa->apa_hwbase + FIFO_DEVWIN2);
223 static int didintr;
224
225 zs_unit = zsc->zsc_dev.dv_unit;
226 zsaddr[zs_unit] = (caddr_t)apa->apa_hwbase;
227
228 printf(" slot%d addr 0x%lx\n", apa->apa_slotno, apa->apa_hwbase);
229
230 /* enable DMA external ready */
231 txAfifo[3] = rxAfifo[3] = 8;
232 txBfifo[3] = rxBfifo[3] = 8;
233
234 /* assert DTR */ /* XXX */
235 devwin0[2] = devwin1[2] = 0x04;
236
237 /* select RS-232C (ch1 only) */
238 devwin1[3] = 0x02;
239
240 /* enable SCC interrupts */
241 devwin2[1] = 0x01;
242
243 zs_delay = zs_ap_delay;
244
245 /*
246 * Initialize software state for each channel.
247 */
248 for (channel = 0; channel < 2; channel++) {
249 zsc_args.channel = channel;
250 zsc_args.hwflags = zs_hwflags[zs_unit][channel];
251 cs = &zsc->zsc_cs_store[channel];
252 zsc->zsc_cs[channel] = cs;
253
254 cs->cs_channel = channel;
255 cs->cs_private = NULL;
256 cs->cs_ops = &zsops_null;
257 cs->cs_brg_clk = PCLK / 16;
258
259 zc = zs_get_chan_addr(zs_unit, channel);
260 cs->cs_reg_csr = &zc->zc_csr;
261 cs->cs_reg_data = &zc->zc_data;
262
263 bcopy(zs_init_reg, cs->cs_creg, 16);
264 bcopy(zs_init_reg, cs->cs_preg, 16);
265
266 /* XXX: Get these from the EEPROM instead? */
267 /* XXX: See the mvme167 code. Better. */
268 if (zsc_args.hwflags & ZS_HWFLAG_CONSOLE)
269 cs->cs_defspeed = zs_get_speed(cs);
270 else
271 cs->cs_defspeed = zs_defspeed;
272 cs->cs_defcflag = zs_def_cflag;
273
274 /* Make these correspond to cs_defcflag (-crtscts) */
275 cs->cs_rr0_dcd = ZSRR0_DCD;
276 cs->cs_rr0_cts = 0;
277 cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS;
278 cs->cs_wr5_rts = 0;
279
280 /*
281 * Clear the master interrupt enable.
282 * The INTENA is common to both channels,
283 * so just do it on the A channel.
284 */
285 if (channel == 0) {
286 zs_write_reg(cs, 9, 0);
287 }
288
289 /*
290 * Look for a child driver for this channel.
291 * The child attach will setup the hardware.
292 */
293 if (!config_found(self, (void *)&zsc_args, zs_print)) {
294 /* No sub-driver. Just reset it. */
295 u_char reset = (channel == 0) ?
296 ZSWR9_A_RESET : ZSWR9_B_RESET;
297 s = splhigh();
298 zs_write_reg(cs, 9, reset);
299 splx(s);
300 }
301 }
302
303 /*
304 * Now safe to install interrupt handlers. Note the arguments
305 * to the interrupt handlers aren't used. Note, we only do this
306 * once since both SCCs interrupt at the same level and vector.
307 */
308 if (!didintr) {
309 didintr = 1;
310
311 apbus_intr_establish(1, /* interrupt level ( 0 or 1 ) */
312 NEWS5000_INT1_SERIAL,
313 0, /* priority */
314 zshard, zsc,
315 apa->apa_name, apa->apa_ctlnum);
316 }
317 /* XXX; evcnt_attach() ? */
318
319 #if 0
320 {
321 u_int x;
322
323 /* determine SCC/ESCC type */
324 x = zs_read_reg(cs, 15);
325 zs_write_reg(cs, 15, x | ZSWR15_ENABLE_ENHANCED);
326
327 if (zs_read_reg(cs, 15) & ZSWR15_ENABLE_ENHANCED) { /* ESCC Z85230 */
328 zs_write_reg(cs, 7, ZSWR7P_EXTEND_READ | ZSWR7P_TX_FIFO);
329 }
330 }
331 #endif
332
333 /*
334 * Set the master interrupt enable and interrupt vector.
335 * (common to both channels, do it on A)
336 */
337 cs = zsc->zsc_cs[0];
338 s = splhigh();
339 /* interrupt vector */
340 zs_write_reg(cs, 2, zs_init_reg[2]);
341 /* master interrupt control (enable) */
342 zs_write_reg(cs, 9, zs_init_reg[9]);
343 splx(s);
344 }
345
346 static volatile int zssoftpending;
347
348 /*
349 * Our ZS chips all share a common, autovectored interrupt,
350 * so we have to look at all of them on each interrupt.
351 */
352 static void
353 zshard(arg)
354 void *arg;
355 {
356 register struct zsc_softc *zsc;
357 register int unit, rval, softreq;
358
359 rval = softreq = 0;
360 for (unit = 0; unit < zsc_cd.cd_ndevs; unit++) {
361 zsc = zsc_cd.cd_devs[unit];
362 if (zsc == NULL)
363 continue;
364 rval |= zsc_intr_hard(zsc);
365 softreq |= zsc->zsc_cs[0]->cs_softreq;
366 softreq |= zsc->zsc_cs[1]->cs_softreq;
367 }
368
369 /* We are at splzs here, so no need to lock. */
370 if (softreq && (zssoftpending == 0)) {
371 zssoftpending = 1;
372 zssoft(arg); /*isr_soft_request(ZSSOFT_PRI);*/
373 }
374 }
375
376 /*
377 * Similar scheme as for zshard (look at all of them)
378 */
379 static void
380 zssoft(arg)
381 void *arg;
382 {
383 register struct zsc_softc *zsc;
384 register int s, unit;
385
386 /* This is not the only ISR on this IPL. */
387 if (zssoftpending == 0)
388 return;
389
390 /*
391 * The soft intr. bit will be set by zshard only if
392 * the variable zssoftpending is zero. The order of
393 * these next two statements prevents our clearing
394 * the soft intr bit just after zshard has set it.
395 */
396 /*isr_soft_clear(ZSSOFT_PRI);*/
397 /*zssoftpending = 0;*/
398
399 /* Make sure we call the tty layer at spltty. */
400 s = spltty();
401 for (unit = 0; unit < zsc_cd.cd_ndevs; unit++) {
402 zsc = zsc_cd.cd_devs[unit];
403 if (zsc == NULL)
404 continue;
405 (void) zsc_intr_soft(zsc);
406 }
407 splx(s);
408 zssoftpending = 0;
409 return;
410 }
411
412 /*
413 * Polled input char.
414 */
415 int
416 zs_getc(arg)
417 void *arg;
418 {
419 register volatile struct zschan *zc = arg;
420 register int s, c, rr0;
421
422 s = splhigh();
423 /* Wait for a character to arrive. */
424 do {
425 rr0 = zc->zc_csr;
426 ZS_DELAY();
427 } while ((rr0 & ZSRR0_RX_READY) == 0);
428
429 c = zc->zc_data;
430 ZS_DELAY();
431 splx(s);
432
433 /*
434 * This is used by the kd driver to read scan codes,
435 * so don't translate '\r' ==> '\n' here...
436 */
437 return (c);
438 }
439
440 /*
441 * Polled output char.
442 */
443 void
444 zs_putc(arg, c)
445 void *arg;
446 int c;
447 {
448 register volatile struct zschan *zc = arg;
449 register int s, rr0;
450
451 s = splhigh();
452 /* Wait for transmitter to become ready. */
453 do {
454 rr0 = zc->zc_csr;
455 ZS_DELAY();
456 } while ((rr0 & ZSRR0_TX_READY) == 0);
457
458 zc->zc_data = c;
459 ZS_DELAY();
460 splx(s);
461 }
462
463 /*****************************************************************/
464
465 static void zscnprobe __P((struct consdev *));
466 static void zscninit __P((struct consdev *));
467 static int zscngetc __P((dev_t));
468 static void zscnputc __P((dev_t, int));
469 static void zscnpollc __P((dev_t, int));
470
471 struct consdev consdev_zs_ap = {
472 zscnprobe,
473 zscninit,
474 zscngetc,
475 zscnputc,
476 zscnpollc
477 };
478
479 void
480 zscnprobe(cn)
481 struct consdev *cn;
482 {
483 }
484
485 void
486 zscninit(cn)
487 struct consdev *cn;
488 {
489 cn->cn_dev = makedev(zs_major, 0);
490 cn->cn_pri = CN_REMOTE;
491 zs_hwflags[0][0] = ZS_HWFLAG_CONSOLE;
492 }
493
494 int
495 zscngetc(dev)
496 dev_t dev;
497 {
498 return zs_getc((void *)NEWS5000_SCCPORT0A);
499 }
500
501 void
502 zscnputc(dev, c)
503 dev_t dev;
504 int c;
505 {
506 zs_putc((void *)NEWS5000_SCCPORT0A, c);
507 }
508
509 void
510 zscnpollc(dev, on)
511 dev_t dev;
512 int on;
513 {
514 }
515