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(®s, 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 ®s,
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