1139749Simp/*-
2119815Smarcel * Copyright (c) 2003 Marcel Moolenaar
3119815Smarcel * All rights reserved.
4119815Smarcel *
5119815Smarcel * Redistribution and use in source and binary forms, with or without
6119815Smarcel * modification, are permitted provided that the following conditions
7119815Smarcel * are met:
8119815Smarcel *
9119815Smarcel * 1. Redistributions of source code must retain the above copyright
10119815Smarcel *    notice, this list of conditions and the following disclaimer.
11119815Smarcel * 2. Redistributions in binary form must reproduce the above copyright
12119815Smarcel *    notice, this list of conditions and the following disclaimer in the
13119815Smarcel *    documentation and/or other materials provided with the distribution.
14119815Smarcel *
15119815Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16119815Smarcel * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17119815Smarcel * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18119815Smarcel * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19119815Smarcel * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20119815Smarcel * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21119815Smarcel * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22119815Smarcel * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23119815Smarcel * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24119815Smarcel * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25119815Smarcel */
26119815Smarcel
27119815Smarcel#include <sys/cdefs.h>
28119815Smarcel__FBSDID("$FreeBSD$");
29119815Smarcel
30119815Smarcel#include <sys/param.h>
31119815Smarcel#include <sys/systm.h>
32119815Smarcel#include <sys/bus.h>
33119815Smarcel#include <sys/conf.h>
34119815Smarcel#include <machine/bus.h>
35119815Smarcel
36119815Smarcel#include <dev/uart/uart.h>
37119815Smarcel#include <dev/uart/uart_cpu.h>
38119815Smarcel#include <dev/uart/uart_bus.h>
39119815Smarcel
40137956Smarcel#include <dev/ic/sab82532.h>
41137956Smarcel
42119815Smarcel#include "uart_if.h"
43119815Smarcel
44119815Smarcel#define	DEFAULT_RCLK	29491200
45119815Smarcel
46119815Smarcel/*
47119815Smarcel * NOTE: To allow us to read the baudrate divisor from the chip, we
48119815Smarcel * copy the value written to the write-only BGR register to an unused
49119815Smarcel * read-write register. We use TCR for that.
50119815Smarcel */
51119815Smarcel
52119815Smarcelstatic int
53119815Smarcelsab82532_delay(struct uart_bas *bas)
54119815Smarcel{
55119815Smarcel	int divisor, m, n;
56119815Smarcel	uint8_t bgr, ccr2;
57119815Smarcel
58119815Smarcel	bgr = uart_getreg(bas, SAB_TCR);
59119815Smarcel	ccr2 = uart_getreg(bas, SAB_CCR2);
60119815Smarcel	n = (bgr & 0x3f) + 1;
61119815Smarcel	m = (bgr >> 6) | ((ccr2 >> 4) & 0xC);
62119815Smarcel	divisor = n * (1<<m);
63119815Smarcel
64119815Smarcel	/* 1/10th the time to transmit 1 character (estimate). */
65119815Smarcel	return (16000000 * divisor / bas->rclk);
66119815Smarcel}
67119815Smarcel
68119815Smarcelstatic int
69119815Smarcelsab82532_divisor(int rclk, int baudrate)
70119815Smarcel{
71119815Smarcel	int act_baud, act_div, divisor;
72119815Smarcel	int error, m, n;
73119815Smarcel
74119815Smarcel	if (baudrate == 0)
75119815Smarcel		return (0);
76119815Smarcel
77119815Smarcel	divisor = (rclk / (baudrate << 3) + 1) >> 1;
78119815Smarcel	if (divisor < 2 || divisor >= 1048576)
79119815Smarcel		return (0);
80119815Smarcel
81119815Smarcel	/* Find the best (N+1,M) pair. */
82119815Smarcel	for (m = 1; m < 15; m++) {
83119815Smarcel		n = divisor / (1<<m);
84119815Smarcel		if (n < 1 || n > 63)
85119815Smarcel			continue;
86119815Smarcel		act_div = n * (1<<m);
87119815Smarcel		act_baud = rclk / (act_div << 4);
88119815Smarcel
89119815Smarcel		/* 10 times error in percent: */
90119815Smarcel		error = ((act_baud - baudrate) * 2000 / baudrate + 1) >> 1;
91119815Smarcel
92119815Smarcel		/* 3.0% maximum error tolerance: */
93119815Smarcel		if (error < -30 || error > 30)
94119815Smarcel			continue;
95119815Smarcel
96119815Smarcel		/* Got it. */
97119815Smarcel		return ((n - 1) | (m << 6));
98119815Smarcel	}
99119815Smarcel
100119815Smarcel	return (0);
101119815Smarcel}
102119815Smarcel
103119815Smarcelstatic void
104119815Smarcelsab82532_flush(struct uart_bas *bas, int what)
105119815Smarcel{
106119815Smarcel
107119815Smarcel	if (what & UART_FLUSH_TRANSMITTER) {
108119815Smarcel		while (uart_getreg(bas, SAB_STAR) & SAB_STAR_CEC)
109119815Smarcel			;
110119815Smarcel		uart_setreg(bas, SAB_CMDR, SAB_CMDR_XRES);
111119815Smarcel		uart_barrier(bas);
112119815Smarcel	}
113119815Smarcel	if (what & UART_FLUSH_RECEIVER) {
114119815Smarcel		while (uart_getreg(bas, SAB_STAR) & SAB_STAR_CEC)
115119815Smarcel			;
116119815Smarcel		uart_setreg(bas, SAB_CMDR, SAB_CMDR_RRES);
117119815Smarcel		uart_barrier(bas);
118119815Smarcel	}
119119815Smarcel}
120119815Smarcel
121119815Smarcelstatic int
122119815Smarcelsab82532_param(struct uart_bas *bas, int baudrate, int databits, int stopbits,
123119815Smarcel    int parity)
124119815Smarcel{
125119815Smarcel	int divisor;
126119815Smarcel	uint8_t ccr2, dafo;
127119815Smarcel
128119815Smarcel	if (databits >= 8)
129119815Smarcel		dafo = SAB_DAFO_CHL_CS8;
130119815Smarcel	else if (databits == 7)
131119815Smarcel		dafo = SAB_DAFO_CHL_CS7;
132119815Smarcel	else if (databits == 6)
133119815Smarcel		dafo = SAB_DAFO_CHL_CS6;
134119815Smarcel	else
135119815Smarcel		dafo = SAB_DAFO_CHL_CS5;
136119815Smarcel	if (stopbits > 1)
137119815Smarcel		dafo |= SAB_DAFO_STOP;
138119815Smarcel	switch (parity) {
139119815Smarcel	case UART_PARITY_EVEN:	dafo |= SAB_DAFO_PAR_EVEN; break;
140119815Smarcel	case UART_PARITY_MARK:	dafo |= SAB_DAFO_PAR_MARK; break;
141119815Smarcel	case UART_PARITY_NONE:	dafo |= SAB_DAFO_PAR_NONE; break;
142119815Smarcel	case UART_PARITY_ODD:	dafo |= SAB_DAFO_PAR_ODD; break;
143119815Smarcel	case UART_PARITY_SPACE:	dafo |= SAB_DAFO_PAR_SPACE; break;
144119815Smarcel	default:		return (EINVAL);
145119815Smarcel	}
146119815Smarcel
147119815Smarcel	/* Set baudrate. */
148119815Smarcel	if (baudrate > 0) {
149119815Smarcel		divisor = sab82532_divisor(bas->rclk, baudrate);
150119815Smarcel		if (divisor == 0)
151119815Smarcel			return (EINVAL);
152119815Smarcel		uart_setreg(bas, SAB_BGR, divisor & 0xff);
153119815Smarcel		uart_barrier(bas);
154119815Smarcel		/* Allow reading the (n-1,m) tuple from the chip. */
155119815Smarcel		uart_setreg(bas, SAB_TCR, divisor & 0xff);
156119815Smarcel		uart_barrier(bas);
157119815Smarcel		ccr2 = uart_getreg(bas, SAB_CCR2);
158119815Smarcel		ccr2 &= ~(SAB_CCR2_BR9 | SAB_CCR2_BR8);
159119815Smarcel		ccr2 |= (divisor >> 2) & (SAB_CCR2_BR9 | SAB_CCR2_BR8);
160119815Smarcel		uart_setreg(bas, SAB_CCR2, ccr2);
161119815Smarcel		uart_barrier(bas);
162119815Smarcel	}
163119815Smarcel
164119815Smarcel	uart_setreg(bas, SAB_DAFO, dafo);
165119815Smarcel	uart_barrier(bas);
166119815Smarcel	return (0);
167119815Smarcel}
168119815Smarcel
169119815Smarcel/*
170119815Smarcel * Low-level UART interface.
171119815Smarcel */
172119815Smarcelstatic int sab82532_probe(struct uart_bas *bas);
173119815Smarcelstatic void sab82532_init(struct uart_bas *bas, int, int, int, int);
174119815Smarcelstatic void sab82532_term(struct uart_bas *bas);
175119815Smarcelstatic void sab82532_putc(struct uart_bas *bas, int);
176166100Smariusstatic int sab82532_rxready(struct uart_bas *bas);
177157380Smarcelstatic int sab82532_getc(struct uart_bas *bas, struct mtx *);
178119815Smarcel
179168281Smarcelstatic struct uart_ops uart_sab82532_ops = {
180119815Smarcel	.probe = sab82532_probe,
181119815Smarcel	.init = sab82532_init,
182119815Smarcel	.term = sab82532_term,
183119815Smarcel	.putc = sab82532_putc,
184166100Smarius	.rxready = sab82532_rxready,
185119815Smarcel	.getc = sab82532_getc,
186119815Smarcel};
187119815Smarcel
188119815Smarcelstatic int
189119815Smarcelsab82532_probe(struct uart_bas *bas)
190119815Smarcel{
191119815Smarcel
192119815Smarcel	return (0);
193119815Smarcel}
194119815Smarcel
195119815Smarcelstatic void
196119815Smarcelsab82532_init(struct uart_bas *bas, int baudrate, int databits, int stopbits,
197119815Smarcel    int parity)
198119815Smarcel{
199119815Smarcel	uint8_t ccr0, pvr;
200119815Smarcel
201119815Smarcel	if (bas->rclk == 0)
202119815Smarcel		bas->rclk = DEFAULT_RCLK;
203119815Smarcel
204119815Smarcel	/*
205119815Smarcel	 * Set all pins, except the DTR pins (pin 1 and 2) to be inputs.
206119815Smarcel	 * Pin 4 is magical, meaning that I don't know what it does, but
207119815Smarcel	 * it too has to be set to output.
208119815Smarcel	 */
209119815Smarcel	uart_setreg(bas, SAB_PCR,
210119815Smarcel	    ~(SAB_PVR_DTR_A|SAB_PVR_DTR_B|SAB_PVR_MAGIC));
211119815Smarcel	uart_barrier(bas);
212119815Smarcel	/* Disable port interrupts. */
213119815Smarcel	uart_setreg(bas, SAB_PIM, 0xff);
214119815Smarcel	uart_barrier(bas);
215119815Smarcel	/* Interrupts are active low. */
216119815Smarcel	uart_setreg(bas, SAB_IPC, SAB_IPC_ICPL);
217119815Smarcel	uart_barrier(bas);
218119815Smarcel	/* Set DTR. */
219119815Smarcel	pvr = uart_getreg(bas, SAB_PVR);
220120452Smarcel	switch (bas->chan) {
221120452Smarcel	case 1:
222120452Smarcel		pvr &= ~SAB_PVR_DTR_A;
223120452Smarcel		break;
224120452Smarcel	case 2:
225120452Smarcel		pvr &= ~SAB_PVR_DTR_B;
226120452Smarcel		break;
227120452Smarcel	}
228119815Smarcel	uart_setreg(bas, SAB_PVR, pvr | SAB_PVR_MAGIC);
229119815Smarcel	uart_barrier(bas);
230119815Smarcel
231119815Smarcel	/* power down */
232119815Smarcel	uart_setreg(bas, SAB_CCR0, 0);
233119815Smarcel	uart_barrier(bas);
234119815Smarcel
235119815Smarcel	/* set basic configuration */
236119815Smarcel	ccr0 = SAB_CCR0_MCE|SAB_CCR0_SC_NRZ|SAB_CCR0_SM_ASYNC;
237119815Smarcel	uart_setreg(bas, SAB_CCR0, ccr0);
238119815Smarcel	uart_barrier(bas);
239119815Smarcel	uart_setreg(bas, SAB_CCR1, SAB_CCR1_ODS|SAB_CCR1_BCR|SAB_CCR1_CM_7);
240119815Smarcel	uart_barrier(bas);
241119815Smarcel	uart_setreg(bas, SAB_CCR2, SAB_CCR2_BDF|SAB_CCR2_SSEL|SAB_CCR2_TOE);
242119815Smarcel	uart_barrier(bas);
243119815Smarcel	uart_setreg(bas, SAB_CCR3, 0);
244119815Smarcel	uart_barrier(bas);
245119815Smarcel	uart_setreg(bas, SAB_CCR4, SAB_CCR4_MCK4|SAB_CCR4_EBRG|SAB_CCR4_ICD);
246119815Smarcel	uart_barrier(bas);
247119815Smarcel	uart_setreg(bas, SAB_MODE, SAB_MODE_FCTS|SAB_MODE_RTS|SAB_MODE_RAC);
248119815Smarcel	uart_barrier(bas);
249119815Smarcel	uart_setreg(bas, SAB_RFC, SAB_RFC_DPS|SAB_RFC_RFDF|
250119815Smarcel	    SAB_RFC_RFTH_32CHAR);
251119815Smarcel	uart_barrier(bas);
252119815Smarcel
253119815Smarcel	sab82532_param(bas, baudrate, databits, stopbits, parity);
254119815Smarcel
255119815Smarcel	/* Clear interrupts. */
256128631Smarcel	uart_setreg(bas, SAB_IMR0, (unsigned char)~SAB_IMR0_TCD);
257119815Smarcel	uart_setreg(bas, SAB_IMR1, 0xff);
258119815Smarcel	uart_barrier(bas);
259119815Smarcel	uart_getreg(bas, SAB_ISR0);
260119815Smarcel	uart_getreg(bas, SAB_ISR1);
261119815Smarcel	uart_barrier(bas);
262119815Smarcel
263119815Smarcel	sab82532_flush(bas, UART_FLUSH_TRANSMITTER|UART_FLUSH_RECEIVER);
264119815Smarcel
265119815Smarcel	/* Power up. */
266119815Smarcel	uart_setreg(bas, SAB_CCR0, ccr0|SAB_CCR0_PU);
267119815Smarcel	uart_barrier(bas);
268119815Smarcel}
269119815Smarcel
270119815Smarcelstatic void
271119815Smarcelsab82532_term(struct uart_bas *bas)
272119815Smarcel{
273119815Smarcel	uint8_t pvr;
274119815Smarcel
275119815Smarcel	pvr = uart_getreg(bas, SAB_PVR);
276120452Smarcel	switch (bas->chan) {
277120452Smarcel	case 1:
278120452Smarcel		pvr |= SAB_PVR_DTR_A;
279120452Smarcel		break;
280120452Smarcel	case 2:
281120452Smarcel		pvr |= SAB_PVR_DTR_B;
282120452Smarcel		break;
283120452Smarcel	}
284119815Smarcel	uart_setreg(bas, SAB_PVR, pvr);
285119815Smarcel	uart_barrier(bas);
286119815Smarcel}
287119815Smarcel
288119815Smarcelstatic void
289119815Smarcelsab82532_putc(struct uart_bas *bas, int c)
290119815Smarcel{
291119815Smarcel	int delay, limit;
292119815Smarcel
293119815Smarcel	/* 1/10th the time to transmit 1 character (estimate). */
294119815Smarcel	delay = sab82532_delay(bas);
295119815Smarcel
296119815Smarcel	limit = 20;
297119815Smarcel	while ((uart_getreg(bas, SAB_STAR) & SAB_STAR_TEC) && --limit)
298119815Smarcel		DELAY(delay);
299119815Smarcel	uart_setreg(bas, SAB_TIC, c);
300119815Smarcel	limit = 20;
301119815Smarcel	while ((uart_getreg(bas, SAB_STAR) & SAB_STAR_TEC) && --limit)
302119815Smarcel		DELAY(delay);
303119815Smarcel}
304119815Smarcel
305119815Smarcelstatic int
306166100Smariussab82532_rxready(struct uart_bas *bas)
307119815Smarcel{
308119815Smarcel
309166100Smarius	return ((uart_getreg(bas, SAB_STAR) & SAB_STAR_RFNE) != 0 ? 1 : 0);
310119815Smarcel}
311119815Smarcel
312119815Smarcelstatic int
313157380Smarcelsab82532_getc(struct uart_bas *bas, struct mtx *hwmtx)
314119815Smarcel{
315119815Smarcel	int c, delay;
316119815Smarcel
317157380Smarcel	uart_lock(hwmtx);
318157380Smarcel
319119815Smarcel	/* 1/10th the time to transmit 1 character (estimate). */
320119815Smarcel	delay = sab82532_delay(bas);
321119815Smarcel
322157380Smarcel	while (!(uart_getreg(bas, SAB_STAR) & SAB_STAR_RFNE)) {
323157380Smarcel		uart_unlock(hwmtx);
324119815Smarcel		DELAY(delay);
325157380Smarcel		uart_lock(hwmtx);
326157380Smarcel	}
327119815Smarcel
328119815Smarcel	while (uart_getreg(bas, SAB_STAR) & SAB_STAR_CEC)
329119815Smarcel		;
330119815Smarcel	uart_setreg(bas, SAB_CMDR, SAB_CMDR_RFRD);
331119815Smarcel	uart_barrier(bas);
332119815Smarcel
333119815Smarcel	while (!(uart_getreg(bas, SAB_ISR0) & SAB_ISR0_TCD))
334119815Smarcel		DELAY(delay);
335119815Smarcel
336119815Smarcel	c = uart_getreg(bas, SAB_RFIFO);
337119815Smarcel	uart_barrier(bas);
338119815Smarcel
339119815Smarcel	/* Blow away everything left in the FIFO... */
340119815Smarcel	while (uart_getreg(bas, SAB_STAR) & SAB_STAR_CEC)
341119815Smarcel		;
342119815Smarcel	uart_setreg(bas, SAB_CMDR, SAB_CMDR_RMC);
343119815Smarcel	uart_barrier(bas);
344157380Smarcel
345157380Smarcel	uart_unlock(hwmtx);
346157380Smarcel
347119815Smarcel	return (c);
348119815Smarcel}
349119815Smarcel
350119815Smarcel/*
351119815Smarcel * High-level UART interface.
352119815Smarcel */
353119815Smarcelstruct sab82532_softc {
354119815Smarcel	struct uart_softc base;
355119815Smarcel};
356119815Smarcel
357119815Smarcelstatic int sab82532_bus_attach(struct uart_softc *);
358119815Smarcelstatic int sab82532_bus_detach(struct uart_softc *);
359119815Smarcelstatic int sab82532_bus_flush(struct uart_softc *, int);
360119815Smarcelstatic int sab82532_bus_getsig(struct uart_softc *);
361119815Smarcelstatic int sab82532_bus_ioctl(struct uart_softc *, int, intptr_t);
362119815Smarcelstatic int sab82532_bus_ipend(struct uart_softc *);
363119815Smarcelstatic int sab82532_bus_param(struct uart_softc *, int, int, int, int);
364119815Smarcelstatic int sab82532_bus_probe(struct uart_softc *);
365119815Smarcelstatic int sab82532_bus_receive(struct uart_softc *);
366119815Smarcelstatic int sab82532_bus_setsig(struct uart_softc *, int);
367119815Smarcelstatic int sab82532_bus_transmit(struct uart_softc *);
368119815Smarcel
369119815Smarcelstatic kobj_method_t sab82532_methods[] = {
370119815Smarcel	KOBJMETHOD(uart_attach,		sab82532_bus_attach),
371119815Smarcel	KOBJMETHOD(uart_detach,		sab82532_bus_detach),
372119815Smarcel	KOBJMETHOD(uart_flush,		sab82532_bus_flush),
373119815Smarcel	KOBJMETHOD(uart_getsig,		sab82532_bus_getsig),
374119815Smarcel	KOBJMETHOD(uart_ioctl,		sab82532_bus_ioctl),
375119815Smarcel	KOBJMETHOD(uart_ipend,		sab82532_bus_ipend),
376119815Smarcel	KOBJMETHOD(uart_param,		sab82532_bus_param),
377119815Smarcel	KOBJMETHOD(uart_probe,		sab82532_bus_probe),
378119815Smarcel	KOBJMETHOD(uart_receive,	sab82532_bus_receive),
379119815Smarcel	KOBJMETHOD(uart_setsig,		sab82532_bus_setsig),
380119815Smarcel	KOBJMETHOD(uart_transmit,	sab82532_bus_transmit),
381119815Smarcel	{ 0, 0 }
382119815Smarcel};
383119815Smarcel
384119815Smarcelstruct uart_class uart_sab82532_class = {
385168281Smarcel	"sab82532",
386119815Smarcel	sab82532_methods,
387119815Smarcel	sizeof(struct sab82532_softc),
388168281Smarcel	.uc_ops = &uart_sab82532_ops,
389119815Smarcel	.uc_range = 64,
390119815Smarcel	.uc_rclk = DEFAULT_RCLK
391119815Smarcel};
392119815Smarcel
393119815Smarcel#define	SIGCHG(c, i, s, d)				\
394119815Smarcel	if (c) {					\
395119815Smarcel		i |= (i & s) ? s : s | d;		\
396119815Smarcel	} else {					\
397119815Smarcel		i = (i & s) ? (i & ~s) | d : i;		\
398119815Smarcel	}
399119815Smarcel
400119815Smarcelstatic int
401119815Smarcelsab82532_bus_attach(struct uart_softc *sc)
402119815Smarcel{
403119815Smarcel	struct uart_bas *bas;
404119815Smarcel	uint8_t imr0, imr1;
405119815Smarcel
406119815Smarcel	bas = &sc->sc_bas;
407119815Smarcel	if (sc->sc_sysdev == NULL)
408119815Smarcel		sab82532_init(bas, 9600, 8, 1, UART_PARITY_NONE);
409119815Smarcel
410119815Smarcel	imr0 = SAB_IMR0_TCD|SAB_IMR0_TIME|SAB_IMR0_CDSC|SAB_IMR0_RFO|
411119815Smarcel	    SAB_IMR0_RPF;
412119815Smarcel	uart_setreg(bas, SAB_IMR0, 0xff & ~imr0);
413119815Smarcel	imr1 = SAB_IMR1_BRKT|SAB_IMR1_ALLS|SAB_IMR1_CSC;
414119815Smarcel	uart_setreg(bas, SAB_IMR1, 0xff & ~imr1);
415119815Smarcel	uart_barrier(bas);
416119815Smarcel
417119815Smarcel	if (sc->sc_sysdev == NULL)
418131043Sphk		sab82532_bus_setsig(sc, SER_DDTR|SER_DRTS);
419119815Smarcel	(void)sab82532_bus_getsig(sc);
420119815Smarcel	return (0);
421119815Smarcel}
422119815Smarcel
423119815Smarcelstatic int
424119815Smarcelsab82532_bus_detach(struct uart_softc *sc)
425119815Smarcel{
426119815Smarcel	struct uart_bas *bas;
427119815Smarcel
428119815Smarcel	bas = &sc->sc_bas;
429119815Smarcel	uart_setreg(bas, SAB_IMR0, 0xff);
430119815Smarcel	uart_setreg(bas, SAB_IMR1, 0xff);
431119815Smarcel	uart_barrier(bas);
432119815Smarcel	uart_getreg(bas, SAB_ISR0);
433119815Smarcel	uart_getreg(bas, SAB_ISR1);
434119815Smarcel	uart_barrier(bas);
435119815Smarcel	uart_setreg(bas, SAB_CCR0, 0);
436119815Smarcel	uart_barrier(bas);
437119815Smarcel	return (0);
438119815Smarcel}
439119815Smarcel
440119815Smarcelstatic int
441119815Smarcelsab82532_bus_flush(struct uart_softc *sc, int what)
442119815Smarcel{
443119815Smarcel
444157300Smarcel	uart_lock(sc->sc_hwmtx);
445119815Smarcel	sab82532_flush(&sc->sc_bas, what);
446157300Smarcel	uart_unlock(sc->sc_hwmtx);
447119815Smarcel	return (0);
448119815Smarcel}
449119815Smarcel
450119815Smarcelstatic int
451119815Smarcelsab82532_bus_getsig(struct uart_softc *sc)
452119815Smarcel{
453119815Smarcel	struct uart_bas *bas;
454119815Smarcel	uint32_t new, old, sig;
455119815Smarcel	uint8_t pvr, star, vstr;
456119815Smarcel
457119815Smarcel	bas = &sc->sc_bas;
458119815Smarcel	do {
459119815Smarcel		old = sc->sc_hwsig;
460119815Smarcel		sig = old;
461157300Smarcel		uart_lock(sc->sc_hwmtx);
462119815Smarcel		star = uart_getreg(bas, SAB_STAR);
463131043Sphk		SIGCHG(star & SAB_STAR_CTS, sig, SER_CTS, SER_DCTS);
464119815Smarcel		vstr = uart_getreg(bas, SAB_VSTR);
465131043Sphk		SIGCHG(vstr & SAB_VSTR_CD, sig, SER_DCD, SER_DDCD);
466141069Smarcel		pvr = ~uart_getreg(bas, SAB_PVR);
467120452Smarcel		switch (bas->chan) {
468120452Smarcel		case 1:
469120452Smarcel			pvr &= SAB_PVR_DSR_A;
470120452Smarcel			break;
471120452Smarcel		case 2:
472120452Smarcel			pvr &= SAB_PVR_DSR_B;
473120452Smarcel			break;
474120452Smarcel		}
475141069Smarcel		SIGCHG(pvr, sig, SER_DSR, SER_DDSR);
476157300Smarcel		uart_unlock(sc->sc_hwmtx);
477155973Smarcel		new = sig & ~SER_MASK_DELTA;
478119815Smarcel	} while (!atomic_cmpset_32(&sc->sc_hwsig, old, new));
479119815Smarcel	return (sig);
480119815Smarcel}
481119815Smarcel
482119815Smarcelstatic int
483119815Smarcelsab82532_bus_ioctl(struct uart_softc *sc, int request, intptr_t data)
484119815Smarcel{
485119815Smarcel	struct uart_bas *bas;
486119815Smarcel	uint8_t dafo, mode;
487120143Smarcel	int error;
488119815Smarcel
489119815Smarcel	bas = &sc->sc_bas;
490120143Smarcel	error = 0;
491157300Smarcel	uart_lock(sc->sc_hwmtx);
492119815Smarcel	switch (request) {
493119815Smarcel	case UART_IOCTL_BREAK:
494119815Smarcel		dafo = uart_getreg(bas, SAB_DAFO);
495119815Smarcel		if (data)
496119815Smarcel			dafo |= SAB_DAFO_XBRK;
497119815Smarcel		else
498119815Smarcel			dafo &= ~SAB_DAFO_XBRK;
499119815Smarcel		uart_setreg(bas, SAB_DAFO, dafo);
500119815Smarcel		uart_barrier(bas);
501119815Smarcel		break;
502119815Smarcel	case UART_IOCTL_IFLOW:
503119815Smarcel		mode = uart_getreg(bas, SAB_MODE);
504119815Smarcel		if (data) {
505119815Smarcel			mode &= ~SAB_MODE_RTS;
506119815Smarcel			mode |= SAB_MODE_FRTS;
507119815Smarcel		} else {
508119815Smarcel			mode |= SAB_MODE_RTS;
509119815Smarcel			mode &= ~SAB_MODE_FRTS;
510119815Smarcel		}
511119815Smarcel		uart_setreg(bas, SAB_MODE, mode);
512119815Smarcel		uart_barrier(bas);
513119815Smarcel		break;
514119815Smarcel	case UART_IOCTL_OFLOW:
515119815Smarcel		mode = uart_getreg(bas, SAB_MODE);
516119815Smarcel		if (data)
517119815Smarcel			mode &= ~SAB_MODE_FCTS;
518119815Smarcel		else
519119815Smarcel			mode |= SAB_MODE_FCTS;
520119815Smarcel		uart_setreg(bas, SAB_MODE, mode);
521119815Smarcel		uart_barrier(bas);
522119815Smarcel		break;
523119815Smarcel	default:
524120143Smarcel		error = EINVAL;
525120143Smarcel		break;
526119815Smarcel	}
527157300Smarcel	uart_unlock(sc->sc_hwmtx);
528120143Smarcel	return (error);
529119815Smarcel}
530119815Smarcel
531119815Smarcelstatic int
532119815Smarcelsab82532_bus_ipend(struct uart_softc *sc)
533119815Smarcel{
534119815Smarcel	struct uart_bas *bas;
535119815Smarcel	int ipend;
536119815Smarcel	uint8_t isr0, isr1;
537119815Smarcel
538119815Smarcel	bas = &sc->sc_bas;
539157300Smarcel	uart_lock(sc->sc_hwmtx);
540119815Smarcel	isr0 = uart_getreg(bas, SAB_ISR0);
541119815Smarcel	isr1 = uart_getreg(bas, SAB_ISR1);
542119815Smarcel	uart_barrier(bas);
543119815Smarcel	if (isr0 & SAB_ISR0_TIME) {
544119815Smarcel		while (uart_getreg(bas, SAB_STAR) & SAB_STAR_CEC)
545119815Smarcel			;
546119815Smarcel		uart_setreg(bas, SAB_CMDR, SAB_CMDR_RFRD);
547119815Smarcel		uart_barrier(bas);
548119815Smarcel	}
549157300Smarcel	uart_unlock(sc->sc_hwmtx);
550119815Smarcel
551119815Smarcel	ipend = 0;
552119815Smarcel	if (isr1 & SAB_ISR1_BRKT)
553155971Smarcel		ipend |= SER_INT_BREAK;
554119815Smarcel	if (isr0 & SAB_ISR0_RFO)
555155971Smarcel		ipend |= SER_INT_OVERRUN;
556119815Smarcel	if (isr0 & (SAB_ISR0_TCD|SAB_ISR0_RPF))
557155971Smarcel		ipend |= SER_INT_RXREADY;
558119815Smarcel	if ((isr0 & SAB_ISR0_CDSC) || (isr1 & SAB_ISR1_CSC))
559155971Smarcel		ipend |= SER_INT_SIGCHG;
560119815Smarcel	if (isr1 & SAB_ISR1_ALLS)
561155971Smarcel		ipend |= SER_INT_TXIDLE;
562119815Smarcel
563119815Smarcel	return (ipend);
564119815Smarcel}
565119815Smarcel
566119815Smarcelstatic int
567119815Smarcelsab82532_bus_param(struct uart_softc *sc, int baudrate, int databits,
568119815Smarcel    int stopbits, int parity)
569119815Smarcel{
570119815Smarcel	struct uart_bas *bas;
571120143Smarcel	int error;
572119815Smarcel
573119815Smarcel	bas = &sc->sc_bas;
574157300Smarcel	uart_lock(sc->sc_hwmtx);
575120143Smarcel	error = sab82532_param(bas, baudrate, databits, stopbits, parity);
576157300Smarcel	uart_unlock(sc->sc_hwmtx);
577120143Smarcel	return (error);
578119815Smarcel}
579119815Smarcel
580119815Smarcelstatic int
581119815Smarcelsab82532_bus_probe(struct uart_softc *sc)
582119815Smarcel{
583119815Smarcel	char buf[80];
584120452Smarcel	const char *vstr;
585119815Smarcel	int error;
586120452Smarcel	char ch;
587119815Smarcel
588119815Smarcel	error = sab82532_probe(&sc->sc_bas);
589119815Smarcel	if (error)
590119815Smarcel		return (error);
591119815Smarcel
592248965Sian	sc->sc_rxfifosz = 32;
593248965Sian	sc->sc_txfifosz = 32;
594248965Sian
595120452Smarcel	ch = sc->sc_bas.chan - 1 + 'A';
596119815Smarcel
597119815Smarcel	switch (uart_getreg(&sc->sc_bas, SAB_VSTR) & SAB_VSTR_VMASK) {
598119815Smarcel	case SAB_VSTR_V_1:
599119815Smarcel		vstr = "v1";
600119815Smarcel		break;
601119815Smarcel	case SAB_VSTR_V_2:
602119815Smarcel		vstr = "v2";
603119815Smarcel		break;
604119815Smarcel	case SAB_VSTR_V_32:
605119815Smarcel		vstr = "v3.2";
606119815Smarcel		sc->sc_hwiflow = 0;	/* CTS doesn't work with RFC:RFDF. */
607119815Smarcel		sc->sc_hwoflow = 1;
608119815Smarcel		break;
609119815Smarcel	default:
610119815Smarcel		vstr = "v4?";
611119815Smarcel		break;
612119815Smarcel	}
613119815Smarcel
614120452Smarcel	snprintf(buf, sizeof(buf), "SAB 82532 %s, channel %c", vstr, ch);
615119815Smarcel	device_set_desc_copy(sc->sc_dev, buf);
616119815Smarcel	return (0);
617119815Smarcel}
618119815Smarcel
619119815Smarcelstatic int
620119815Smarcelsab82532_bus_receive(struct uart_softc *sc)
621119815Smarcel{
622119815Smarcel	struct uart_bas *bas;
623119815Smarcel	int i, rbcl, xc;
624119815Smarcel	uint8_t s;
625119815Smarcel
626119815Smarcel	bas = &sc->sc_bas;
627157300Smarcel	uart_lock(sc->sc_hwmtx);
628119815Smarcel	if (uart_getreg(bas, SAB_STAR) & SAB_STAR_RFNE) {
629119815Smarcel		rbcl = uart_getreg(bas, SAB_RBCL) & 31;
630119815Smarcel		if (rbcl == 0)
631119815Smarcel			rbcl = 32;
632119815Smarcel		for (i = 0; i < rbcl; i += 2) {
633119815Smarcel			if (uart_rx_full(sc)) {
634119815Smarcel				sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN;
635119815Smarcel				break;
636119815Smarcel			}
637119815Smarcel			xc = uart_getreg(bas, SAB_RFIFO);
638119815Smarcel			s = uart_getreg(bas, SAB_RFIFO + 1);
639119815Smarcel			if (s & SAB_RSTAT_FE)
640119815Smarcel				xc |= UART_STAT_FRAMERR;
641119815Smarcel			if (s & SAB_RSTAT_PE)
642119815Smarcel				xc |= UART_STAT_PARERR;
643119815Smarcel			uart_rx_put(sc, xc);
644119815Smarcel		}
645119815Smarcel	}
646119815Smarcel
647119815Smarcel	while (uart_getreg(bas, SAB_STAR) & SAB_STAR_CEC)
648119815Smarcel		;
649119815Smarcel	uart_setreg(bas, SAB_CMDR, SAB_CMDR_RMC);
650119815Smarcel	uart_barrier(bas);
651157300Smarcel	uart_unlock(sc->sc_hwmtx);
652119815Smarcel	return (0);
653119815Smarcel}
654119815Smarcel
655119815Smarcelstatic int
656119815Smarcelsab82532_bus_setsig(struct uart_softc *sc, int sig)
657119815Smarcel{
658119815Smarcel	struct uart_bas *bas;
659119815Smarcel	uint32_t new, old;
660119815Smarcel	uint8_t mode, pvr;
661119815Smarcel
662119815Smarcel	bas = &sc->sc_bas;
663119815Smarcel	do {
664119815Smarcel		old = sc->sc_hwsig;
665119815Smarcel		new = old;
666131043Sphk		if (sig & SER_DDTR) {
667131043Sphk			SIGCHG(sig & SER_DTR, new, SER_DTR,
668131043Sphk			    SER_DDTR);
669119815Smarcel		}
670131043Sphk		if (sig & SER_DRTS) {
671131043Sphk			SIGCHG(sig & SER_RTS, new, SER_RTS,
672131043Sphk			    SER_DRTS);
673119815Smarcel		}
674119815Smarcel	} while (!atomic_cmpset_32(&sc->sc_hwsig, old, new));
675119815Smarcel
676157300Smarcel	uart_lock(sc->sc_hwmtx);
677119815Smarcel	/* Set DTR pin. */
678119815Smarcel	pvr = uart_getreg(bas, SAB_PVR);
679120452Smarcel	switch (bas->chan) {
680120452Smarcel	case 1:
681131043Sphk		if (new & SER_DTR)
682120452Smarcel			pvr &= ~SAB_PVR_DTR_A;
683120452Smarcel		else
684120452Smarcel			pvr |= SAB_PVR_DTR_A;
685120452Smarcel		break;
686120452Smarcel	case 2:
687131043Sphk		if (new & SER_DTR)
688120452Smarcel			pvr &= ~SAB_PVR_DTR_B;
689120452Smarcel		else
690120452Smarcel			pvr |= SAB_PVR_DTR_B;
691120452Smarcel		break;
692120452Smarcel	}
693119815Smarcel	uart_setreg(bas, SAB_PVR, pvr);
694119815Smarcel
695119815Smarcel	/* Set RTS pin. */
696119815Smarcel	mode = uart_getreg(bas, SAB_MODE);
697131043Sphk	if (new & SER_RTS)
698119815Smarcel		mode &= ~SAB_MODE_FRTS;
699119815Smarcel	else
700119815Smarcel		mode |= SAB_MODE_FRTS;
701119815Smarcel	uart_setreg(bas, SAB_MODE, mode);
702119815Smarcel	uart_barrier(bas);
703157300Smarcel	uart_unlock(sc->sc_hwmtx);
704119815Smarcel	return (0);
705119815Smarcel}
706119815Smarcel
707119815Smarcelstatic int
708119815Smarcelsab82532_bus_transmit(struct uart_softc *sc)
709119815Smarcel{
710119815Smarcel	struct uart_bas *bas;
711119815Smarcel	int i;
712119815Smarcel
713119815Smarcel	bas = &sc->sc_bas;
714157300Smarcel	uart_lock(sc->sc_hwmtx);
715119815Smarcel	while (!(uart_getreg(bas, SAB_STAR) & SAB_STAR_XFW))
716119815Smarcel		;
717119815Smarcel	for (i = 0; i < sc->sc_txdatasz; i++)
718119815Smarcel		uart_setreg(bas, SAB_XFIFO + i, sc->sc_txbuf[i]);
719119815Smarcel	uart_barrier(bas);
720119815Smarcel	while (uart_getreg(bas, SAB_STAR) & SAB_STAR_CEC)
721119815Smarcel		;
722119815Smarcel	uart_setreg(bas, SAB_CMDR, SAB_CMDR_XF);
723119815Smarcel	sc->sc_txbusy = 1;
724157300Smarcel	uart_unlock(sc->sc_hwmtx);
725119815Smarcel	return (0);
726119815Smarcel}
727