ingenic_com.c revision 1.5 1 /* $NetBSD: ingenic_com.c,v 1.5 2015/07/11 19:00:04 macallan Exp $ */
2
3 /*-
4 * Copyright (c) 2014 Michael Lorenz
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: ingenic_com.c,v 1.5 2015/07/11 19:00:04 macallan Exp $");
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/device.h>
35 #include <sys/kernel.h>
36 #include <sys/termios.h>
37 #include <sys/ttydefaults.h>
38 #include <sys/types.h>
39
40 #include <sys/bus.h>
41
42 #include <dev/cons.h>
43 #include <dev/ic/comreg.h>
44 #include <dev/ic/comvar.h>
45
46 #include <mips/cpuregs.h>
47
48 #include <mips/ingenic/ingenic_var.h>
49 #include <mips/ingenic/ingenic_regs.h>
50
51 #include "opt_com.h"
52
53 #ifndef COM_REGMAP
54 #error We need COM_REGMAP
55 #endif
56
57 volatile int32_t *com0addr = (int32_t *)MIPS_PHYS_TO_KSEG1(JZ_UART0);
58
59 void ingenic_putchar_init(void);
60 void ingenic_puts(const char *);
61 void ingenic_putchar(char);
62
63 #ifndef CONMODE
64 # define CONMODE ((TTYDEF_CFLAG & ~(CSIZE | CSTOPB | PARENB)) | CS8)
65 #endif
66
67
68 void ingenic_com_cnattach(void);
69
70 static int ingenic_com_match(device_t, cfdata_t , void *);
71 static void ingenic_com_attach(device_t, device_t, void *);
72
73 struct ingenic_com_softc {
74 struct com_softc sc_com;
75 bus_space_tag_t sc_tag;
76 bus_space_handle_t sc_regh;
77 };
78
79 CFATTACH_DECL_NEW(ingenic_com, sizeof(struct ingenic_com_softc),
80 ingenic_com_match, ingenic_com_attach, NULL, NULL);
81
82 static bus_space_handle_t regh = 0;
83 static bus_addr_t cons_com = 0;
84 static struct com_regs regs;
85 extern bus_space_tag_t apbus_memt;
86
87 void
88 ingenic_putchar_init(void)
89 {
90 /*
91 * XXX don't screw with the UART's speed until we know what clock
92 * we're on
93 */
94 #if 0
95 int rate;
96 #endif
97 extern int comspeed(long, long, int);
98
99 com0addr = (uint32_t *)MIPS_PHYS_TO_KSEG1(JZ_UART0);
100 #if 0
101 if (comcnfreq != -1) {
102 rate = comspeed(comcnspeed, comcnfreq, COM_TYPE_INGENIC);
103 if (rate < 0)
104 return; /* XXX */
105 #endif
106 com0addr[com_ier] = 0;
107 com0addr[com_lctl] = htole32(LCR_DLAB);
108 #if 0
109 com0addr[com_dlbl] = htole32(rate & 0xff);
110 com0addr[com_dlbh] = htole32(rate >> 8);
111 #endif
112 com0addr[com_lctl] = htole32(LCR_8BITS); /* XXX */
113 com0addr[com_mcr] = htole32(MCR_DTR|MCR_RTS);
114 com0addr[com_fifo] = htole32(
115 FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST |
116 FIFO_TRIGGER_1 | FIFO_UART_ON);
117 #if 0
118 }
119 #endif
120 }
121
122
123 void
124 ingenic_putchar(char c)
125 {
126 int timo = 150000;
127
128 while ((le32toh(com0addr[com_lsr]) & LSR_TXRDY) == 0)
129 if (--timo == 0)
130 break;
131
132 com0addr[com_data] = htole32((uint32_t)c);
133
134 while ((le32toh(com0addr[com_lsr]) & LSR_TSRE) == 0)
135 if (--timo == 0)
136 break;
137 }
138
139 void
140 ingenic_puts(const char *restrict s)
141 {
142 char c;
143
144 while ((c = *s++) != 0)
145 ingenic_putchar(c);
146 }
147
148 void
149 ingenic_com_cnattach(void)
150 {
151 int i;
152
153 bus_space_map(apbus_memt, JZ_UART0, 0x100, 0, ®h);
154 cons_com = JZ_UART0;
155 memset(®s, 0, sizeof(regs));
156 COM_INIT_REGS(regs, apbus_memt, regh, JZ_UART0);
157 for (i = 0; i < 16; i++) {
158 regs.cr_map[i] = regs.cr_map[i] << 2;
159 }
160 regs.cr_nports = 32;
161
162 comcnattach1(®s, 115200, 48000000, COM_TYPE_INGENIC, CONMODE);
163 }
164
165 static int
166 ingenic_com_match(device_t parent, cfdata_t cfdata, void *args)
167 {
168 struct mainbusdev {
169 const char *md_name;
170 } *aa = args;
171 if (strcmp(aa->md_name, "com") == 0) return 1;
172 return 0;
173 }
174
175
176 static void
177 ingenic_com_attach(device_t parent, device_t self, void *args)
178 {
179 struct ingenic_com_softc *isc = device_private(self);
180 struct com_softc *sc = &isc->sc_com;
181 struct apbus_attach_args *aa = args;
182 int i;
183
184 sc->sc_dev = self;
185 sc->sc_frequency = 48000000;
186 sc->sc_type = COM_TYPE_INGENIC;
187 isc->sc_tag = aa->aa_bst;
188
189 if (cons_com == aa->aa_addr) {
190 isc->sc_regh = regh;
191 } else {
192 bus_space_map(apbus_memt, aa->aa_addr, 0x1000, 0, &isc->sc_regh);
193 }
194 memset(&sc->sc_regs, 0, sizeof(sc->sc_regs));
195 COM_INIT_REGS(sc->sc_regs, aa->aa_bst, isc->sc_regh, aa->aa_addr);
196 for (i = 0; i < 16; i++)
197 sc->sc_regs.cr_map[i] = sc->sc_regs.cr_map[i] << 2;
198 sc->sc_regs.cr_nports = 32;
199
200 com_attach_subr(sc);
201 evbmips_intr_establish(aa->aa_irq, comintr, sc);
202 }
203