xref: /netbsd-src/sys/arch/mips/cavium/dev/octeon_uart.c (revision 39930c1fd3550972780e61d81a5ace47896cdc65)
1*39930c1fSmartin /*	$NetBSD: octeon_uart.c,v 1.10 2022/01/26 18:57:55 martin Exp $	*/
2f693c922Shikaru 
3f693c922Shikaru /*
4f693c922Shikaru  * Copyright (c) 2007 Internet Initiative Japan, Inc.
5f693c922Shikaru  * All rights reserved.
6f693c922Shikaru  *
7f693c922Shikaru  * Redistribution and use in source and binary forms, with or without
8f693c922Shikaru  * modification, are permitted provided that the following conditions
9f693c922Shikaru  * are met:
10f693c922Shikaru  * 1. Redistributions of source code must retain the above copyright
11f693c922Shikaru  *    notice, this list of conditions and the following disclaimer.
12f693c922Shikaru  * 2. Redistributions in binary form must reproduce the above copyright
13f693c922Shikaru  *    notice, this list of conditions and the following disclaimer in the
14f693c922Shikaru  *    documentation and/or other materials provided with the distribution.
15f693c922Shikaru  *
16f693c922Shikaru  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
17f693c922Shikaru  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18f693c922Shikaru  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19f693c922Shikaru  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
20f693c922Shikaru  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21f693c922Shikaru  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22f693c922Shikaru  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23f693c922Shikaru  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24f693c922Shikaru  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25f693c922Shikaru  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26f693c922Shikaru  * SUCH DAMAGE.
27f693c922Shikaru  */
28f693c922Shikaru 
29f693c922Shikaru #include <sys/cdefs.h>
30*39930c1fSmartin __KERNEL_RCSID(0, "$NetBSD: octeon_uart.c,v 1.10 2022/01/26 18:57:55 martin Exp $");
31f693c922Shikaru 
32f693c922Shikaru #include <sys/param.h>
33f693c922Shikaru #include <sys/systm.h>
34f693c922Shikaru #include <sys/types.h>
35f693c922Shikaru #include <sys/device.h>
36f693c922Shikaru #include <sys/tty.h>
37f693c922Shikaru 
38f693c922Shikaru #include <sys/bus.h>
39f693c922Shikaru #include <sys/cpu.h>
40f693c922Shikaru #include <machine/intr.h>
41f693c922Shikaru 
428acfb7e9Ssimonb #include <dev/cons.h>
43f693c922Shikaru #include <dev/ic/comreg.h>
44f693c922Shikaru #include <dev/ic/comvar.h>
45f693c922Shikaru 
46f693c922Shikaru #include <mips/cavium/include/iobusvar.h>
47f693c922Shikaru #include <mips/cavium/dev/octeon_uartreg.h>
488acfb7e9Ssimonb #include <mips/cavium/dev/octeon_uartvar.h>
49f693c922Shikaru #include <mips/cavium/dev/octeon_ciureg.h>
50f693c922Shikaru 
51d6f10032Ssimonb struct octuart_iobus_softc {
52f693c922Shikaru 	struct com_softc sc_com;
53f693c922Shikaru 	int sc_irq;
54f693c922Shikaru 	void *sc_ih;
55f693c922Shikaru };
56f693c922Shikaru 
57d6f10032Ssimonb static int	octuart_iobus_match(device_t, struct cfdata *, void *);
58d6f10032Ssimonb static void	octuart_iobus_attach(device_t, device_t, void *);
59d6f10032Ssimonb static int	octuart_com_enable(struct com_softc *);
60d6f10032Ssimonb static void	octuart_com_disable(struct com_softc *);
61f693c922Shikaru 
628acfb7e9Ssimonb /* octputc() is not declared static so it can be used for debugging elsewhere */
638acfb7e9Ssimonb void		octputc(dev_t, int);
64f693c922Shikaru 
65f693c922Shikaru /* XXX */
66d6f10032Ssimonb const bus_addr_t octuart_com_bases[] = {
67f693c922Shikaru 	MIO_UART0_BASE,
68f693c922Shikaru 	MIO_UART1_BASE
69f693c922Shikaru };
70d6f10032Ssimonb const struct com_regs octuart_com_regs = {
71f693c922Shikaru 	.cr_map = {
72f693c922Shikaru 		[COM_REG_RXDATA] =	MIO_UART_RBR_OFFSET,
73f693c922Shikaru 		[COM_REG_TXDATA] =	MIO_UART_THR_OFFSET,
74f693c922Shikaru 		[COM_REG_DLBL] =	MIO_UART_DLL_OFFSET,
75f693c922Shikaru 		[COM_REG_DLBH] =	MIO_UART_DLH_OFFSET,
76f693c922Shikaru 		[COM_REG_IER] =		MIO_UART_IER_OFFSET,
77f693c922Shikaru 		[COM_REG_IIR] =		MIO_UART_IIR_OFFSET,
78f693c922Shikaru 		[COM_REG_FIFO] =	MIO_UART_FCR_OFFSET,
79f693c922Shikaru 		[COM_REG_EFR] =		0,
80f693c922Shikaru 		[COM_REG_LCR] =		MIO_UART_LCR_OFFSET,
81f693c922Shikaru 		[COM_REG_MCR] =		MIO_UART_MCR_OFFSET,
82f693c922Shikaru 		[COM_REG_LSR] =		MIO_UART_LSR_OFFSET,
83f693c922Shikaru 		[COM_REG_MSR] =		MIO_UART_MSR_OFFSET,
84f693c922Shikaru #if 0 /* XXX COM_TYPE_16750_NOERS */
85f693c922Shikaru 		[COM_REG_USR] =		MIO_UART_USR_OFFSET,
86f693c922Shikaru 		[COM_REG_SRR] =		MIO_UART_SRR_OFFSET
87f693c922Shikaru #endif
88f693c922Shikaru 	}
89f693c922Shikaru };
90f693c922Shikaru 
91d6f10032Ssimonb CFATTACH_DECL_NEW(com_iobus, sizeof(struct octuart_iobus_softc),
92d6f10032Ssimonb     octuart_iobus_match, octuart_iobus_attach, NULL, NULL);
93f693c922Shikaru 
948acfb7e9Ssimonb static int
octuart_iobus_match(device_t parent,struct cfdata * cf,void * aux)95d6f10032Ssimonb octuart_iobus_match(device_t parent, struct cfdata *cf, void *aux)
96f693c922Shikaru {
97f693c922Shikaru 	struct iobus_attach_args *aa = aux;
98f693c922Shikaru 	int result = 0;
99f693c922Shikaru 
100f693c922Shikaru 	if (strcmp(cf->cf_name, aa->aa_name) != 0)
101f693c922Shikaru 		goto out;
102f693c922Shikaru 	if (cf->cf_unit != aa->aa_unitno)
103f693c922Shikaru 		goto out;
104f693c922Shikaru 	result = 1;
105f693c922Shikaru 
106f693c922Shikaru out:
107f693c922Shikaru 	return result;
108f693c922Shikaru }
109f693c922Shikaru 
1108acfb7e9Ssimonb static void
octuart_iobus_attach(device_t parent,device_t self,void * aux)111d6f10032Ssimonb octuart_iobus_attach(device_t parent, device_t self, void *aux)
112f693c922Shikaru {
113d6f10032Ssimonb 	struct octuart_iobus_softc *sc = device_private(self);
114f693c922Shikaru 	struct com_softc *sc_com = &sc->sc_com;
115f693c922Shikaru 	struct iobus_attach_args *aa = aux;
116f693c922Shikaru 	int status;
117f693c922Shikaru 
118f693c922Shikaru 	sc_com->sc_dev = self;
119*39930c1fSmartin 	com_init_regs(&sc_com->sc_regs, aa->aa_bust, 0, aa->aa_unit->addr);
120*39930c1fSmartin 	memcpy(sc_com->sc_regs.cr_map, octuart_com_regs.cr_map,
121*39930c1fSmartin 	    sizeof(octuart_com_regs.cr_map));
122f693c922Shikaru 
123f693c922Shikaru 	sc->sc_irq = aa->aa_unit->irq;
124f693c922Shikaru 
125f693c922Shikaru 	status = bus_space_map(
126f693c922Shikaru 		aa->aa_bust,
127f693c922Shikaru 		aa->aa_unit->addr,
128f693c922Shikaru 		COM_NPORTS,
129f693c922Shikaru 		0,
130f693c922Shikaru 		&sc_com->sc_regs.cr_ioh);
131f693c922Shikaru 	if (status != 0) {
132f693c922Shikaru 		aprint_error(": can't map i/o space\n");
133f693c922Shikaru 		return;
134f693c922Shikaru 	}
135f693c922Shikaru 
136f693c922Shikaru 	sc_com->sc_type = COM_TYPE_16550_NOERS;
1377beb3ab7Ssimonb 	sc_com->sc_frequency = octeon_ioclock_speed();
138d6f10032Ssimonb 	sc_com->enable = octuart_com_enable;
139d6f10032Ssimonb 	sc_com->disable = octuart_com_disable;
140f693c922Shikaru 
141d6f10032Ssimonb 	octuart_com_enable(sc_com);
142f693c922Shikaru 	sc_com->enabled = 1;
143f693c922Shikaru 
144f693c922Shikaru 	com_attach_subr(sc_com);
145f693c922Shikaru 
14682a25ec3Ssimonb 	sc->sc_ih = octeon_intr_establish(CIU_INT_UART_0 + device_unit(self),
1472d299731Smatt 	    IPL_SERIAL, comintr, sc_com);
148f693c922Shikaru 	if (sc->sc_ih == NULL)
149f693c922Shikaru 		panic("%s: can't establish interrupt\n",
150f693c922Shikaru 		    device_xname(self));
151f693c922Shikaru 
152f693c922Shikaru 	/* XXX disable if kgdb? */
153f693c922Shikaru }
154f693c922Shikaru 
1558acfb7e9Ssimonb static int
octuart_com_enable(struct com_softc * sc_com)156d6f10032Ssimonb octuart_com_enable(struct com_softc *sc_com)
157f693c922Shikaru {
158f693c922Shikaru 	struct com_regs *regsp = &sc_com->sc_regs;
159f693c922Shikaru 
160f693c922Shikaru 	/* XXX Clear old busy detect interrupts */
161f693c922Shikaru 	bus_space_read_1(regsp->cr_iot, regsp->cr_ioh,
162f693c922Shikaru 	    MIO_UART_USR_OFFSET);
163f693c922Shikaru 
164f693c922Shikaru 	return 0;
165f693c922Shikaru }
166f693c922Shikaru 
1678acfb7e9Ssimonb static void
octuart_com_disable(struct com_softc * sc_com)168d6f10032Ssimonb octuart_com_disable(struct com_softc *sc_com)
169f693c922Shikaru {
170f693c922Shikaru 	/*
171f693c922Shikaru 	 * XXX chip specific procedure
172f693c922Shikaru 	 */
173f693c922Shikaru }
174f693c922Shikaru 
175f693c922Shikaru 
176f693c922Shikaru #ifndef CONMODE
177f693c922Shikaru #define	CONMODE	((TTYDEF_CFLAG & ~(CSIZE | CSTOPB | PARENB)) | CS8) /* 8N1 */
178f693c922Shikaru #endif
179f693c922Shikaru 
180f693c922Shikaru int
octuart_com_cnattach(bus_space_tag_t bust,int portno,int speed)181d6f10032Ssimonb octuart_com_cnattach(bus_space_tag_t bust, int portno, int speed)
182f693c922Shikaru {
183f693c922Shikaru 	struct com_regs regs;
184f693c922Shikaru 
185*39930c1fSmartin 	com_init_regs(&regs, bust, 0, octuart_com_bases[portno]);
186*39930c1fSmartin 	memcpy(regs.cr_map, octuart_com_regs.cr_map,
187*39930c1fSmartin 	    sizeof(octuart_com_regs.cr_map));
188f693c922Shikaru 
189f693c922Shikaru 	return comcnattach1(
190f693c922Shikaru 		&regs,
191f693c922Shikaru 		speed,
1927beb3ab7Ssimonb 		octeon_ioclock_speed(),
193f693c922Shikaru 		COM_TYPE_16550_NOERS,
194f693c922Shikaru 		CONMODE);
195f693c922Shikaru }
1968acfb7e9Ssimonb 
1978acfb7e9Ssimonb 
1988acfb7e9Ssimonb /*
1998acfb7e9Ssimonb  * A very simple output-only console so early printf() can work.
2008acfb7e9Ssimonb  */
2018acfb7e9Ssimonb struct consdev early_console = {
2028acfb7e9Ssimonb 	.cn_putc = octputc,
2038acfb7e9Ssimonb 	.cn_pollc = nullcnpollc,
2048acfb7e9Ssimonb 	.cn_dev = makedev(0, 0),
2058acfb7e9Ssimonb 	.cn_pri = CN_DEAD
2068acfb7e9Ssimonb };
2078acfb7e9Ssimonb static int early_comcnrate;
2088acfb7e9Ssimonb 
2098acfb7e9Ssimonb void
octputc(dev_t dev,int c)2108acfb7e9Ssimonb octputc(dev_t dev, int c)
2118acfb7e9Ssimonb {
2128acfb7e9Ssimonb 
2138acfb7e9Ssimonb 	octeon_xkphys_write_8(MIO_UART0_RBR, (uint8_t)c);
2148acfb7e9Ssimonb 	delay(1000000 / (early_comcnrate / 10)); /* wait for char to drain */
2158acfb7e9Ssimonb }
2168acfb7e9Ssimonb 
2178acfb7e9Ssimonb void
octuart_early_cnattach(int rate)2188acfb7e9Ssimonb octuart_early_cnattach(int rate)
2198acfb7e9Ssimonb {
2208acfb7e9Ssimonb 
2218acfb7e9Ssimonb 	early_comcnrate = rate;
2228acfb7e9Ssimonb 	cn_tab = &early_console;
2238acfb7e9Ssimonb }
224