zs_ap.c revision 1.27 1 /* $NetBSD: zs_ap.c,v 1.27 2010/06/26 03:49:52 tsutsui 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 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 /*
33 * Zilog Z8530 Dual UART driver (machine-dependent part)
34 *
35 * Runs two serial lines per chip using slave drivers.
36 * Plain tty/async lines use the zs_async slave.
37 * Sun keyboard/mouse uses the zs_kbd/zs_ms slaves.
38 */
39
40 #include <sys/cdefs.h>
41 __KERNEL_RCSID(0, "$NetBSD: zs_ap.c,v 1.27 2010/06/26 03:49:52 tsutsui Exp $");
42
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/device.h>
46 #include <sys/tty.h>
47 #include <sys/conf.h>
48 #include <sys/cpu.h>
49 #include <sys/intr.h>
50
51 #include <machine/adrsmap.h>
52 #include <machine/z8530var.h>
53
54 #include <dev/cons.h>
55 #include <dev/ic/z8530reg.h>
56
57 #include <newsmips/apbus/apbusvar.h>
58
59 #include "zsc.h" /* NZSC */
60 #define NZS NZSC
61
62 /* Make life easier for the initialized arrays here. */
63 #if NZS < 2
64 #undef NZS
65 #define NZS 2
66 #endif
67
68 #define PORTB_XPORT 0x00000000
69 #define PORTB_RPORT 0x00010000
70 #define PORTA_XPORT 0x00020000
71 #define PORTA_RPORT 0x00030000
72 #define DMA_MODE_REG 3
73 #define DMA_ENABLE 0x01 /* DMA enable */
74 #define DMA_DIR_DM 0x00 /* device to memory */
75 #define DMA_DIR_MD 0x02 /* memory to device */
76 #define DMA_EXTRDY 0x08 /* DMA external ready */
77 #define PORTB_OFFSET 0x00040000
78 #define PORTA_OFFSET 0x00050000
79 #define PORT_CTL 2
80 #define PORTCTL_RI 0x01
81 #define PORTCTL_DSR 0x02
82 #define PORTCTL_DTR 0x04
83 #define PORT_SEL 3
84 #define PORTSEL_LOCALTALK 0x01
85 #define PORTSEL_RS232C 0x02
86 #define ESCC_REG 0x00060000
87 #define ESCCREG_INTSTAT 0
88 #define INTSTAT_SCC 0x01
89 #define ESCCREG_INTMASK 1
90 #define INTMASK_SCC 0x01
91
92 extern int zs_def_cflag;
93 extern void (*zs_delay)(void);
94
95 /*
96 * The news5000 provides a 9.8304 MHz clock to the ZS chips.
97 */
98 #define PCLK (9600 * 1024) /* PCLK pin input clock rate */
99
100 #define ZS_DELAY() DELAY(2)
101
102 /* The layout of this is hardware-dependent (padding, order). */
103 struct zschan {
104 volatile uint8_t pad1[3];
105 volatile uint8_t zc_csr; /* ctrl,status, and indirect access */
106 volatile uint8_t pad2[3];
107 volatile uint8_t zc_data; /* data */
108 };
109
110 static void *zsaddr[NZS];
111
112 /* Flags from cninit() */
113 static int zs_hwflags[NZS][2];
114
115 /* Default speed for all channels */
116 static int zs_defspeed = 9600;
117
118 static uint8_t zs_init_reg[16] = {
119 0, /* 0: CMD (reset, etc.) */
120 0, /* 1: No interrupts yet. */
121 0, /* IVECT */
122 ZSWR3_RX_8 | ZSWR3_RX_ENABLE,
123 ZSWR4_CLK_X16 | ZSWR4_ONESB | ZSWR4_EVENP,
124 ZSWR5_TX_8 | ZSWR5_TX_ENABLE,
125 0, /* 6: TXSYNC/SYNCLO */
126 0, /* 7: RXSYNC/SYNCHI */
127 0, /* 8: alias for data port */
128 ZSWR9_MASTER_IE,
129 0, /*10: Misc. TX/RX control bits */
130 ZSWR11_TXCLK_BAUD | ZSWR11_RXCLK_BAUD,
131 ((PCLK/32)/9600)-2, /*12: BAUDLO (default=9600) */
132 0, /*13: BAUDHI (default=9600) */
133 ZSWR14_BAUD_ENA | ZSWR14_BAUD_FROM_PCLK,
134 ZSWR15_BREAK_IE,
135 };
136
137 static struct zschan * zs_get_chan_addr(int, int);
138 static void zs_ap_delay(void);
139 static int zshard_ap(void *);
140 static int zs_getc(void *);
141 static void zs_putc(void *, int);
142
143 struct zschan *
144 zs_get_chan_addr(int zs_unit, int channel)
145 {
146 void *addr;
147 struct zschan *zc;
148
149 if (zs_unit >= NZS)
150 return NULL;
151 addr = zsaddr[zs_unit];
152 if (addr == NULL)
153 return NULL;
154 if (channel == 0) {
155 zc = (void *)((uint8_t *)addr + PORTA_OFFSET);
156 } else {
157 zc = (void *)((uint8_t *)addr + PORTB_OFFSET);
158 }
159 return zc;
160 }
161
162 void
163 zs_ap_delay(void)
164 {
165
166 ZS_DELAY();
167 }
168
169 /****************************************************************
170 * Autoconfig
171 ****************************************************************/
172
173 /* Definition of the driver for autoconfig. */
174 int zs_ap_match(device_t, cfdata_t, void *);
175 void zs_ap_attach(device_t, device_t, void *);
176
177 CFATTACH_DECL_NEW(zsc_ap, sizeof(struct zsc_softc),
178 zs_ap_match, zs_ap_attach, NULL, NULL);
179
180 /*
181 * Is the zs chip present?
182 */
183 int
184 zs_ap_match(device_t parent, cfdata_t cf, void *aux)
185 {
186 struct apbus_attach_args *apa = aux;
187
188 if (strcmp("esccf", apa->apa_name) != 0)
189 return 0;
190
191 return 1;
192 }
193
194 /*
195 * Attach a found zs.
196 *
197 * Match slave number to zs unit number, so that misconfiguration will
198 * not set up the keyboard as ttya, etc.
199 */
200 void
201 zs_ap_attach(device_t parent, device_t self, void *aux)
202 {
203 struct zsc_softc *zsc = device_private(self);
204 struct apbus_attach_args *apa = aux;
205 struct zsc_attach_args zsc_args;
206 volatile struct zschan *zc;
207 struct zs_chanstate *cs;
208 int s, zs_unit, channel;
209 volatile u_int *txBfifo = (void *)(apa->apa_hwbase + PORTB_XPORT);
210 volatile u_int *rxBfifo = (void *)(apa->apa_hwbase + PORTB_RPORT);
211 volatile u_int *txAfifo = (void *)(apa->apa_hwbase + PORTA_XPORT);
212 volatile u_int *rxAfifo = (void *)(apa->apa_hwbase + PORTA_RPORT);
213 volatile u_int *portBctl = (void *)(apa->apa_hwbase + PORTB_OFFSET);
214 volatile u_int *portActl = (void *)(apa->apa_hwbase + PORTA_OFFSET);
215 volatile u_int *esccregs = (void *)(apa->apa_hwbase + ESCC_REG);
216
217 zsc->zsc_dev = self;
218 zs_unit = device_unit(self);
219 zsaddr[zs_unit] = (void *)apa->apa_hwbase;
220
221 aprint_normal(" slot%d addr 0x%lx\n", apa->apa_slotno, apa->apa_hwbase);
222
223 txAfifo[DMA_MODE_REG] = rxAfifo[DMA_MODE_REG] = DMA_EXTRDY;
224 txBfifo[DMA_MODE_REG] = rxBfifo[DMA_MODE_REG] = DMA_EXTRDY;
225
226 /* assert DTR */ /* XXX */
227 portBctl[PORT_CTL] = portActl[PORT_CTL] = PORTCTL_DTR;
228
229 /* select RS-232C (ch1 only) */
230 portActl[PORT_SEL] = PORTSEL_RS232C;
231
232 /* enable SCC interrupts */
233 esccregs[ESCCREG_INTMASK] = INTMASK_SCC;
234
235 zs_delay = zs_ap_delay;
236
237 /*
238 * Initialize software state for each channel.
239 */
240 for (channel = 0; channel < 2; channel++) {
241 zsc_args.channel = channel;
242 zsc_args.hwflags = zs_hwflags[zs_unit][channel];
243 cs = &zsc->zsc_cs_store[channel];
244 zsc->zsc_cs[channel] = cs;
245
246 zs_lock_init(cs);
247 cs->cs_channel = channel;
248 cs->cs_private = NULL;
249 cs->cs_ops = &zsops_null;
250 cs->cs_brg_clk = PCLK / 16;
251
252 zc = zs_get_chan_addr(zs_unit, channel);
253 cs->cs_reg_csr = &zc->zc_csr;
254 cs->cs_reg_data = &zc->zc_data;
255
256 memcpy(cs->cs_creg, zs_init_reg, 16);
257 memcpy(cs->cs_preg, zs_init_reg, 16);
258
259 /* XXX: Get these from the EEPROM instead? */
260 /* XXX: See the mvme167 code. Better. */
261 if (zsc_args.hwflags & ZS_HWFLAG_CONSOLE)
262 cs->cs_defspeed = zs_get_speed(cs);
263 else
264 cs->cs_defspeed = zs_defspeed;
265 cs->cs_defcflag = zs_def_cflag;
266
267 /* Make these correspond to cs_defcflag (-crtscts) */
268 cs->cs_rr0_dcd = ZSRR0_DCD;
269 cs->cs_rr0_cts = 0;
270 cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS;
271 cs->cs_wr5_rts = 0;
272
273 /*
274 * Clear the master interrupt enable.
275 * The INTENA is common to both channels,
276 * so just do it on the A channel.
277 */
278 if (channel == 0) {
279 zs_write_reg(cs, 9, 0);
280 }
281
282 /*
283 * Look for a child driver for this channel.
284 * The child attach will setup the hardware.
285 */
286 if (!config_found(self, (void *)&zsc_args, zs_print)) {
287 /* No sub-driver. Just reset it. */
288 uint8_t reset = (channel == 0) ?
289 ZSWR9_A_RESET : ZSWR9_B_RESET;
290 s = splhigh();
291 zs_write_reg(cs, 9, reset);
292 splx(s);
293 }
294 }
295
296 /*
297 * Now safe to install interrupt handlers.
298 */
299 zsc->zsc_si = softint_establish(SOFTINT_SERIAL,
300 (void (*)(void *))zsc_intr_soft, zsc);
301 apbus_intr_establish(1, /* interrupt level ( 0 or 1 ) */
302 NEWS5000_INT1_SCC, 0, /* priority */
303 zshard_ap, zsc, apa->apa_name, apa->apa_ctlnum);
304 /* XXX; evcnt_attach() ? */
305
306 #if 0
307 {
308 u_int x;
309
310 /* determine SCC/ESCC type */
311 x = zs_read_reg(cs, 15);
312 zs_write_reg(cs, 15, x | ZSWR15_ENABLE_ENHANCED);
313
314 if (zs_read_reg(cs, 15) & ZSWR15_ENABLE_ENHANCED) { /* ESCC Z85230 */
315 zs_write_reg(cs, 7, ZSWR7P_EXTEND_READ | ZSWR7P_TX_FIFO);
316 }
317 }
318 #endif
319
320 /*
321 * Set the master interrupt enable and interrupt vector.
322 * (common to both channels, do it on A)
323 */
324 cs = zsc->zsc_cs[0];
325 s = splhigh();
326 /* interrupt vector */
327 zs_write_reg(cs, 2, zs_init_reg[2]);
328 /* master interrupt control (enable) */
329 zs_write_reg(cs, 9, zs_init_reg[9]);
330 splx(s);
331 }
332
333 static int
334 zshard_ap(void *arg)
335 {
336
337 zshard(arg);
338 return 1;
339 }
340
341 /*
342 * Polled input char.
343 */
344 int
345 zs_getc(void *arg)
346 {
347 volatile struct zschan *zc = arg;
348 int s, c;
349 uint8_t rr0;
350
351 s = splhigh();
352 /* Wait for a character to arrive. */
353 do {
354 rr0 = zc->zc_csr;
355 ZS_DELAY();
356 } while ((rr0 & ZSRR0_RX_READY) == 0);
357
358 c = zc->zc_data;
359 ZS_DELAY();
360 splx(s);
361
362 /*
363 * This is used by the kd driver to read scan codes,
364 * so don't translate '\r' ==> '\n' here...
365 */
366 return c;
367 }
368
369 /*
370 * Polled output char.
371 */
372 void
373 zs_putc(void *arg, int c)
374 {
375 volatile struct zschan *zc = arg;
376 int s;
377 uint8_t rr0;
378
379 s = splhigh();
380 /* Wait for transmitter to become ready. */
381 do {
382 rr0 = zc->zc_csr;
383 ZS_DELAY();
384 } while ((rr0 & ZSRR0_TX_READY) == 0);
385
386 zc->zc_data = c;
387 ZS_DELAY();
388 splx(s);
389 }
390
391 /*****************************************************************/
392
393 static void zscnprobe(struct consdev *);
394 static void zscninit(struct consdev *);
395 static int zscngetc(dev_t);
396 static void zscnputc(dev_t, int);
397
398 struct consdev consdev_zs_ap = {
399 zscnprobe,
400 zscninit,
401 zscngetc,
402 zscnputc,
403 nullcnpollc,
404 NULL,
405 NULL,
406 NULL,
407 NODEV,
408 CN_DEAD
409 };
410
411 static void
412 zscnprobe(struct consdev *cn)
413 {
414 }
415
416 static void
417 zscninit(struct consdev *cn)
418 {
419 extern const struct cdevsw zstty_cdevsw;
420
421 cn->cn_dev = makedev(cdevsw_lookup_major(&zstty_cdevsw), 0);
422 cn->cn_pri = CN_REMOTE;
423 zs_hwflags[0][0] = ZS_HWFLAG_CONSOLE;
424 }
425
426 static int
427 zscngetc(dev_t dev)
428 {
429
430 return zs_getc((void *)NEWS5000_SCCPORT0A);
431 }
432
433 static void
434 zscnputc(dev_t dev, int c)
435 {
436
437 zs_putc((void *)NEWS5000_SCCPORT0A, c);
438 }
439