xref: /openbsd/sys/arch/octeon/dev/cn30xxuart.c (revision 9b7c3dbb)
1 /*	$OpenBSD: cn30xxuart.c,v 1.9 2016/04/14 13:51:58 visa Exp $	*/
2 
3 /*
4  * Copyright (c) 2001-2004 Opsycon AB  (www.opsycon.se / www.opsycon.com)
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  */
28 
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/device.h>
32 #include <sys/tty.h>
33 #include <sys/conf.h>
34 
35 #include <machine/octeonvar.h>
36 #include <machine/autoconf.h>
37 #include <machine/bus.h>
38 
39 #include <dev/ic/comreg.h>
40 #include <dev/ic/comvar.h>
41 #include <dev/cons.h>
42 
43 #include <octeon/dev/iobusvar.h>
44 #include <octeon/dev/uartbusvar.h>
45 #include <octeon/dev/cn30xxuartreg.h>
46 
47 #define OCTEON_UART_FIFO_SIZE		64
48 
49 int	cn30xxuart_probe(struct device *, void *, void *);
50 void	cn30xxuart_attach(struct device *, struct device *, void *);
51 int	cn30xxuart_intr(void *);
52 
53 struct cfattach cn30xxuart_ca = {
54 	sizeof(struct com_softc), cn30xxuart_probe, cn30xxuart_attach
55 };
56 
57 extern struct cfdriver com_cd;
58 
59 cons_decl(cn30xxuart);
60 
61 #define  USR_TXFIFO_NOTFULL		2
62 
63 /* XXX: What is this used for? Removed from stand/boot/uart.c -r1.2 */
64 static int delay_changed = 1;
65 int cn30xxuart_delay(void);
66 void cn30xxuart_wait_txhr_empty(int);
67 
68 int
69 cn30xxuart_probe(struct device *parent, void *match, void *aux)
70 {
71 	struct cfdata *cf = match;
72 	struct uartbus_attach_args *uba = aux;
73 	bus_space_tag_t iot = uba->uba_memt;
74 	bus_space_handle_t ioh;
75 	int rv = 0, console;
76 
77 	if (strcmp(uba->uba_name, com_cd.cd_name) != 0)
78 		return 0;
79 
80 	console = 1;
81 
82 	/* if it's in use as console, it's there. */
83 	if (!(console && !comconsattached)) {
84 		if (bus_space_map(iot, uba->uba_baseaddr, COM_NPORTS, 0, &ioh)) {
85 			printf(": can't map uart registers\n");
86 			return 1;
87 		}
88 		rv = comprobe1(iot, ioh);
89 	} else
90 		rv = 1;
91 
92 	/* make a config stanza with exact locators match over a generic line */
93 	if (cf->cf_loc[0] != -1)
94 		rv += rv;
95 
96 	return rv;
97 }
98 
99 void
100 cn30xxuart_attach(struct device *parent, struct device *self, void *aux)
101 {
102 	struct com_softc *sc = (void *)self;
103 	struct uartbus_attach_args *uba = aux;
104 	int console;
105 
106 	console = 1;
107 
108 	sc->sc_iot = uba->uba_memt;
109 	sc->sc_iobase = uba->uba_baseaddr;
110 	sc->sc_hwflags = 0;
111 	sc->sc_swflags = 0;
112 	sc->sc_frequency = octeon_ioclock_speed();
113 	sc->sc_uarttype = COM_UART_16550A;
114 	sc->sc_fifolen = OCTEON_UART_FIFO_SIZE;
115 
116 	/* if it's in use as console, it's there. */
117 	if (bus_space_map(sc->sc_iot, sc->sc_iobase, COM_NPORTS, 0, &sc->sc_ioh)) {
118 		printf(": can't map uart registers\n");
119 		return;
120 	}
121 
122 	if (console && !comconsattached) {
123 		/*
124 		 * If we are the console, reuse the existing bus_space
125 		 * information, so that comcnattach() invokes bus_space_map()
126 		 * with correct parameters.
127 		 */
128 
129 		if (comcnattach(sc->sc_iot, sc->sc_iobase, 115200,
130 		    sc->sc_frequency, (TTYDEF_CFLAG & ~(CSIZE | PARENB)) | CS8))
131 			panic("can't setup serial console");
132 	}
133 
134 	com_attach_subr(sc);
135 
136 	octeon_intr_establish(uba->uba_intr, IPL_TTY, cn30xxuart_intr,
137 	    (void *)sc, sc->sc_dev.dv_xname);
138 }
139 
140 int
141 cn30xxuart_intr(void *arg)
142 {
143 	comintr(arg);
144 
145 	/*
146 	 * Always return non-zero to prevent console clutter about spurious
147 	 * interrupts. comstart() enables the transmitter holding register
148 	 * empty interrupt before adding data to the FIFO, which can trigger
149 	 * a premature interrupt on the primary CPU in a multiprocessor system.
150 	 */
151 	return 1;
152 }
153 
154 /*
155  * Early console routines.
156  */
157 int
158 cn30xxuart_delay(void)
159 {
160 	int divisor;
161 	u_char lcr;
162 	static int d = 0;
163 
164 	if (!delay_changed)
165 		return d;
166 	delay_changed = 0;
167 	lcr = octeon_xkphys_read_8(MIO_UART0_LCR);
168 	octeon_xkphys_write_8(MIO_UART0_LCR, lcr | LCR_DLAB);
169 	divisor = octeon_xkphys_read_8(MIO_UART0_DLL) |
170 		octeon_xkphys_read_8(MIO_UART0_DLH) << 8;
171 	octeon_xkphys_write_8(MIO_UART0_LCR, lcr);
172 
173 	return 10; /* return an approx delay value */
174 }
175 
176 void
177 cn30xxuart_wait_txhr_empty(int d)
178 {
179 	while (((octeon_xkphys_read_8(MIO_UART0_LSR) & LSR_TXRDY) == 0) &&
180 	    ((octeon_xkphys_read_8(MIO_UART0_USR) & USR_TXFIFO_NOTFULL) == 0))
181 		delay(d);
182 }
183 
184 void
185 cn30xxuartcninit(struct consdev *consdev)
186 {
187 }
188 
189 void
190 cn30xxuartcnprobe(struct consdev *consdev)
191 {
192 }
193 
194 void
195 cn30xxuartcnpollc(dev_t dev, int c)
196 {
197 }
198 
199 void
200 cn30xxuartcnputc(dev_t dev, int c)
201 {
202 	int d;
203 
204 	/* 1/10th the time to transmit 1 character (estimate). */
205 	d = cn30xxuart_delay();
206 	cn30xxuart_wait_txhr_empty(d);
207 	octeon_xkphys_write_8(MIO_UART0_RBR, (uint8_t)c);
208 	cn30xxuart_wait_txhr_empty(d);
209 }
210 
211 int
212 cn30xxuartcngetc(dev_t dev)
213 {
214 	int c, d;
215 
216 	/* 1/10th the time to transmit 1 character (estimate). */
217 	d = cn30xxuart_delay();
218 
219 	while ((octeon_xkphys_read_8(MIO_UART0_LSR) & LSR_RXRDY) == 0)
220 		delay(d);
221 
222 	c = (uint8_t)octeon_xkphys_read_8(MIO_UART0_RBR);
223 
224 	return (c);
225 }
226