| @@ -1,488 +1,445 @@ | | | @@ -1,488 +1,445 @@ |
1 | /* $NetBSD: amlogic_com.c,v 1.3 2015/03/01 23:39:28 jmcneill Exp $ */ | | 1 | /* $NetBSD: amlogic_com.c,v 1.4 2015/03/03 21:56:25 jmcneill Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2013 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 2013 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Matt Thomas of 3am Software Foundry. | | 8 | * by Matt Thomas of 3am Software Foundry. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright | | 15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the | | 16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. | | 17 | * documentation and/or other materials provided with the distribution. |
18 | * | | 18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | | 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. | | 29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | #include "locators.h" | | 32 | #include "locators.h" |
33 | | | 33 | |
34 | #include <sys/cdefs.h> | | 34 | #include <sys/cdefs.h> |
35 | | | 35 | |
36 | __KERNEL_RCSID(1, "$NetBSD: amlogic_com.c,v 1.3 2015/03/01 23:39:28 jmcneill Exp $"); | | 36 | __KERNEL_RCSID(1, "$NetBSD: amlogic_com.c,v 1.4 2015/03/03 21:56:25 jmcneill Exp $"); |
37 | | | | |
38 | #define AMLOGIC_COM_INTRPOLL | | | |
39 | #define AMLOGIC_COM_INTRPOLL_RATE 10 | | | |
40 | | | 37 | |
41 | #include <sys/param.h> | | 38 | #include <sys/param.h> |
42 | #include <sys/bus.h> | | 39 | #include <sys/bus.h> |
43 | #include <sys/device.h> | | 40 | #include <sys/device.h> |
44 | #include <sys/conf.h> | | 41 | #include <sys/conf.h> |
45 | #include <sys/intr.h> | | 42 | #include <sys/intr.h> |
46 | #include <sys/systm.h> | | 43 | #include <sys/systm.h> |
47 | #include <sys/time.h> | | 44 | #include <sys/time.h> |
48 | #include <sys/termios.h> | | 45 | #include <sys/termios.h> |
49 | #include <sys/kauth.h> | | 46 | #include <sys/kauth.h> |
50 | #include <sys/lwp.h> | | 47 | #include <sys/lwp.h> |
51 | #include <sys/tty.h> | | 48 | #include <sys/tty.h> |
52 | | | 49 | |
53 | #include <dev/cons.h> | | 50 | #include <dev/cons.h> |
54 | | | 51 | |
55 | #include <arm/amlogic/amlogic_reg.h> | | 52 | #include <arm/amlogic/amlogic_reg.h> |
56 | #include <arm/amlogic/amlogic_var.h> | | 53 | #include <arm/amlogic/amlogic_var.h> |
57 | #include <arm/amlogic/amlogic_comreg.h> | | 54 | #include <arm/amlogic/amlogic_comreg.h> |
58 | #include <arm/amlogic/amlogic_comvar.h> | | 55 | #include <arm/amlogic/amlogic_comvar.h> |
59 | | | 56 | |
60 | static int amlogic_com_match(device_t, cfdata_t, void *); | | 57 | static int amlogic_com_match(device_t, cfdata_t, void *); |
61 | static void amlogic_com_attach(device_t, device_t, void *); | | 58 | static void amlogic_com_attach(device_t, device_t, void *); |
62 | | | 59 | |
63 | static int amlogic_com_intr(void *); | | 60 | static int amlogic_com_intr(void *); |
64 | | | 61 | |
65 | #ifdef AMLOGIC_COM_INTRPOLL | | | |
66 | static void amlogic_com_intrpoll(void *); | | | |
67 | #endif | | | |
68 | | | | |
69 | static int amlogic_com_cngetc(dev_t); | | 62 | static int amlogic_com_cngetc(dev_t); |
70 | static void amlogic_com_cnputc(dev_t, int); | | 63 | static void amlogic_com_cnputc(dev_t, int); |
71 | static void amlogic_com_cnpollc(dev_t, int); | | 64 | static void amlogic_com_cnpollc(dev_t, int); |
72 | | | 65 | |
73 | static void amlogic_com_start(struct tty *); | | 66 | static void amlogic_com_start(struct tty *); |
74 | static int amlogic_com_param(struct tty *, struct termios *); | | 67 | static int amlogic_com_param(struct tty *, struct termios *); |
75 | | | 68 | |
76 | extern struct cfdriver amlogiccom_cd; | | 69 | extern struct cfdriver amlogiccom_cd; |
77 | | | 70 | |
78 | struct amlogic_com_softc { | | 71 | struct amlogic_com_softc { |
79 | device_t sc_dev; | | 72 | device_t sc_dev; |
80 | bus_space_tag_t sc_bst; | | 73 | bus_space_tag_t sc_bst; |
81 | bus_space_handle_t sc_bsh; | | 74 | bus_space_handle_t sc_bsh; |
82 | void *sc_ih; | | 75 | void *sc_ih; |
83 | | | 76 | |
84 | struct tty *sc_tty; | | 77 | struct tty *sc_tty; |
85 | | | 78 | |
86 | int sc_ospeed; | | 79 | int sc_ospeed; |
87 | tcflag_t sc_cflag; | | 80 | tcflag_t sc_cflag; |
88 | | | 81 | |
89 | u_char sc_buf[1024]; | | 82 | u_char sc_buf[1024]; |
90 | | | | |
91 | #ifdef AMLOGIC_COM_INTRPOLL | | | |
92 | callout_t sc_intrpoll_ch; | | | |
93 | #endif | | | |
94 | }; | | 83 | }; |
95 | | | 84 | |
96 | static struct amlogic_com_softc amlogic_com_cnsc; | | 85 | static struct amlogic_com_softc amlogic_com_cnsc; |
97 | | | 86 | |
98 | static struct cnm_state amlogic_com_cnm_state; | | 87 | static struct cnm_state amlogic_com_cnm_state; |
99 | | | 88 | |
100 | struct consdev amlogic_com_consdev = { | | 89 | struct consdev amlogic_com_consdev = { |
101 | .cn_getc = amlogic_com_cngetc, | | 90 | .cn_getc = amlogic_com_cngetc, |
102 | .cn_putc = amlogic_com_cnputc, | | 91 | .cn_putc = amlogic_com_cnputc, |
103 | .cn_pollc = amlogic_com_cnpollc, | | 92 | .cn_pollc = amlogic_com_cnpollc, |
104 | .cn_dev = NODEV, | | 93 | .cn_dev = NODEV, |
105 | .cn_pri = CN_NORMAL, | | 94 | .cn_pri = CN_NORMAL, |
106 | }; | | 95 | }; |
107 | | | 96 | |
108 | static dev_type_open(amlogic_com_open); | | 97 | static dev_type_open(amlogic_com_open); |
109 | static dev_type_open(amlogic_com_close); | | 98 | static dev_type_open(amlogic_com_close); |
110 | static dev_type_read(amlogic_com_read); | | 99 | static dev_type_read(amlogic_com_read); |
111 | static dev_type_write(amlogic_com_write); | | 100 | static dev_type_write(amlogic_com_write); |
112 | static dev_type_ioctl(amlogic_com_ioctl); | | 101 | static dev_type_ioctl(amlogic_com_ioctl); |
113 | static dev_type_tty(amlogic_com_tty); | | 102 | static dev_type_tty(amlogic_com_tty); |
114 | static dev_type_poll(amlogic_com_poll); | | 103 | static dev_type_poll(amlogic_com_poll); |
115 | static dev_type_stop(amlogic_com_stop); | | 104 | static dev_type_stop(amlogic_com_stop); |
116 | | | 105 | |
117 | const struct cdevsw amlogiccom_cdevsw = { | | 106 | const struct cdevsw amlogiccom_cdevsw = { |
118 | .d_open = amlogic_com_open, | | 107 | .d_open = amlogic_com_open, |
119 | .d_close = amlogic_com_close, | | 108 | .d_close = amlogic_com_close, |
120 | .d_read = amlogic_com_read, | | 109 | .d_read = amlogic_com_read, |
121 | .d_write = amlogic_com_write, | | 110 | .d_write = amlogic_com_write, |
122 | .d_ioctl = amlogic_com_ioctl, | | 111 | .d_ioctl = amlogic_com_ioctl, |
123 | .d_stop = amlogic_com_stop, | | 112 | .d_stop = amlogic_com_stop, |
124 | .d_tty = amlogic_com_tty, | | 113 | .d_tty = amlogic_com_tty, |
125 | .d_poll = amlogic_com_poll, | | 114 | .d_poll = amlogic_com_poll, |
126 | .d_mmap = nommap, | | 115 | .d_mmap = nommap, |
127 | .d_kqfilter = ttykqfilter, | | 116 | .d_kqfilter = ttykqfilter, |
128 | .d_discard = nodiscard, | | 117 | .d_discard = nodiscard, |
129 | .d_flag = D_TTY | | 118 | .d_flag = D_TTY |
130 | }; | | 119 | }; |
131 | | | 120 | |
132 | static int amlogic_com_cmajor = -1; | | 121 | static int amlogic_com_cmajor = -1; |
133 | | | 122 | |
134 | CFATTACH_DECL_NEW(amlogic_com, sizeof(struct amlogic_com_softc), | | 123 | CFATTACH_DECL_NEW(amlogic_com, sizeof(struct amlogic_com_softc), |
135 | amlogic_com_match, amlogic_com_attach, NULL, NULL); | | 124 | amlogic_com_match, amlogic_com_attach, NULL, NULL); |
136 | | | 125 | |
137 | static int | | 126 | static int |
138 | amlogic_com_match(device_t parent, cfdata_t cf, void *aux) | | 127 | amlogic_com_match(device_t parent, cfdata_t cf, void *aux) |
139 | { | | 128 | { |
140 | return 1; | | 129 | return 1; |
141 | } | | 130 | } |
142 | | | 131 | |
143 | static void | | 132 | static void |
144 | amlogic_com_attach(device_t parent, device_t self, void *aux) | | 133 | amlogic_com_attach(device_t parent, device_t self, void *aux) |
145 | { | | 134 | { |
146 | struct amlogic_com_softc * const sc = device_private(self); | | 135 | struct amlogic_com_softc * const sc = device_private(self); |
147 | struct amlogicio_attach_args * const aio = aux; | | 136 | struct amlogicio_attach_args * const aio = aux; |
148 | const struct amlogic_locators * const loc = &aio->aio_loc; | | 137 | const struct amlogic_locators * const loc = &aio->aio_loc; |
149 | const bus_addr_t iobase = AMLOGIC_CORE_BASE + loc->loc_offset; | | 138 | const bus_addr_t iobase = AMLOGIC_CORE_BASE + loc->loc_offset; |
150 | struct tty *tp; | | 139 | struct tty *tp; |
151 | int major, minor; | | 140 | int major, minor; |
152 | uint32_t misc, control; | | 141 | uint32_t misc, control; |
153 | | | 142 | |
154 | sc->sc_dev = self; | | 143 | sc->sc_dev = self; |
155 | sc->sc_bst = aio->aio_core_bst; | | 144 | sc->sc_bst = aio->aio_core_bst; |
156 | bus_space_subregion(aio->aio_core_bst, aio->aio_bsh, | | 145 | bus_space_subregion(aio->aio_core_bst, aio->aio_bsh, |
157 | loc->loc_offset, loc->loc_size, &sc->sc_bsh); | | 146 | loc->loc_offset, loc->loc_size, &sc->sc_bsh); |
158 | | | 147 | |
159 | #ifdef AMLOGIC_COM_INTRPOLL | | | |
160 | callout_init(&sc->sc_intrpoll_ch, CALLOUT_MPSAFE); | | | |
161 | callout_setfunc(&sc->sc_intrpoll_ch, amlogic_com_intrpoll, sc); | | | |
162 | #else | | | |
163 | sc->sc_ih = intr_establish(loc->loc_intr, IPL_SERIAL, | | 148 | sc->sc_ih = intr_establish(loc->loc_intr, IPL_SERIAL, |
164 | IST_EDGE | IST_MPSAFE, amlogic_com_intr, sc); | | 149 | IST_EDGE | IST_MPSAFE, amlogic_com_intr, sc); |
165 | if (sc->sc_ih == NULL) { | | 150 | if (sc->sc_ih == NULL) { |
166 | aprint_error(": failed to establish interrupt %d\n", | | 151 | aprint_error(": failed to establish interrupt %d\n", |
167 | loc->loc_intr); | | 152 | loc->loc_intr); |
168 | return; | | 153 | return; |
169 | } | | 154 | } |
170 | #endif | | | |
171 | | | 155 | |
172 | if (amlogic_com_cmajor == -1) { | | 156 | if (amlogic_com_cmajor == -1) { |
173 | /* allocate a major number */ | | 157 | /* allocate a major number */ |
174 | int bmajor = -1, cmajor = -1; | | 158 | int bmajor = -1, cmajor = -1; |
175 | int error = devsw_attach("amlogiccom", NULL, &bmajor, | | 159 | int error = devsw_attach("amlogiccom", NULL, &bmajor, |
176 | &amlogiccom_cdevsw, &cmajor); | | 160 | &amlogiccom_cdevsw, &cmajor); |
177 | if (error) { | | 161 | if (error) { |
178 | aprint_error(": couldn't allocate major number\n"); | | 162 | aprint_error(": couldn't allocate major number\n"); |
179 | return; | | 163 | return; |
180 | } | | 164 | } |
181 | amlogic_com_cmajor = cmajor; | | 165 | amlogic_com_cmajor = cmajor; |
182 | } | | 166 | } |
183 | | | 167 | |
184 | major = cdevsw_lookup_major(&amlogiccom_cdevsw); | | 168 | major = cdevsw_lookup_major(&amlogiccom_cdevsw); |
185 | minor = device_unit(self); | | 169 | minor = device_unit(self); |
186 | | | 170 | |
187 | tp = sc->sc_tty = tty_alloc(); | | 171 | tp = sc->sc_tty = tty_alloc(); |
188 | tp->t_oproc = amlogic_com_start; | | 172 | tp->t_oproc = amlogic_com_start; |
189 | tp->t_param = amlogic_com_param; | | 173 | tp->t_param = amlogic_com_param; |
190 | tp->t_dev = makedev(major, minor); | | 174 | tp->t_dev = makedev(major, minor); |
191 | tp->t_sc = sc; | | 175 | tp->t_sc = sc; |
192 | tty_attach(tp); | | 176 | tty_attach(tp); |
193 | | | 177 | |
194 | aprint_naive("\n"); | | 178 | aprint_naive("\n"); |
195 | if (amlogic_com_is_console(iobase)) { | | 179 | if (amlogic_com_is_console(iobase)) { |
196 | cn_tab->cn_dev = tp->t_dev; | | 180 | cn_tab->cn_dev = tp->t_dev; |
197 | aprint_normal(": console"); | | 181 | aprint_normal(": console"); |
198 | } | | 182 | } |
199 | aprint_normal("\n"); | | 183 | aprint_normal("\n"); |
200 | | | 184 | |
201 | #ifdef AMLOGIC_COM_INTRPOLL | | | |
202 | aprint_normal_dev(self, "polling\n"); | | | |
203 | #else | | | |
204 | aprint_normal_dev(self, "interrupting at irq %d\n", loc->loc_intr); | | 185 | aprint_normal_dev(self, "interrupting at irq %d\n", loc->loc_intr); |
205 | #endif | | | |
206 | | | 186 | |
207 | misc = bus_space_read_4(sc->sc_bst, sc->sc_bsh, UART_MISC_REG); | | 187 | misc = bus_space_read_4(sc->sc_bst, sc->sc_bsh, UART_MISC_REG); |
208 | misc &= ~UART_MISC_TX_IRQ_CNT; | | 188 | misc &= ~UART_MISC_TX_IRQ_CNT; |
209 | misc |= __SHIFTIN(0, UART_MISC_TX_IRQ_CNT); | | 189 | misc |= __SHIFTIN(0, UART_MISC_TX_IRQ_CNT); |
210 | misc &= ~UART_MISC_RX_IRQ_CNT; | | 190 | misc &= ~UART_MISC_RX_IRQ_CNT; |
211 | misc |= __SHIFTIN(1, UART_MISC_RX_IRQ_CNT); | | 191 | misc |= __SHIFTIN(1, UART_MISC_RX_IRQ_CNT); |
212 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, UART_MISC_REG, misc); | | 192 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, UART_MISC_REG, misc); |
213 | | | 193 | |
214 | control = bus_space_read_4(sc->sc_bst, sc->sc_bsh, UART_CONTROL_REG); | | 194 | control = bus_space_read_4(sc->sc_bst, sc->sc_bsh, UART_CONTROL_REG); |
215 | control &= ~UART_CONTROL_TX_INT_EN; | | 195 | control &= ~UART_CONTROL_TX_INT_EN; |
216 | #ifdef AMLOGIC_COM_INTRPOLL | | | |
217 | control &= ~UART_CONTROL_RX_INT_EN; | | | |
218 | #else | | | |
219 | control |= UART_CONTROL_RX_INT_EN; | | 196 | control |= UART_CONTROL_RX_INT_EN; |
220 | #endif | | | |
221 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, UART_CONTROL_REG, control); | | 197 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, UART_CONTROL_REG, control); |
222 | | | | |
223 | #ifdef AMLOGIC_COM_INTRPOLL | | | |
224 | callout_schedule(&sc->sc_intrpoll_ch, AMLOGIC_COM_INTRPOLL_RATE); | | | |
225 | #endif | | | |
226 | } | | 198 | } |
227 | | | 199 | |
228 | static int | | 200 | static int |
229 | amlogic_com_cngetc(dev_t dev) | | 201 | amlogic_com_cngetc(dev_t dev) |
230 | { | | 202 | { |
231 | bus_space_tag_t bst = amlogic_com_cnsc.sc_bst; | | 203 | bus_space_tag_t bst = amlogic_com_cnsc.sc_bst; |
232 | bus_space_handle_t bsh = amlogic_com_cnsc.sc_bsh; | | 204 | bus_space_handle_t bsh = amlogic_com_cnsc.sc_bsh; |
233 | uint32_t status; | | 205 | uint32_t status; |
234 | int s, c; | | 206 | int s, c; |
235 | | | 207 | |
236 | s = splserial(); | | 208 | s = splserial(); |
237 | | | 209 | |
238 | status = bus_space_read_4(bst, bsh, UART_STATUS_REG); | | 210 | status = bus_space_read_4(bst, bsh, UART_STATUS_REG); |
239 | if (status & UART_STATUS_RX_EMPTY) { | | 211 | if (status & UART_STATUS_RX_EMPTY) { |
240 | splx(s); | | 212 | splx(s); |
241 | return -1; | | 213 | return -1; |
242 | } | | 214 | } |
243 | | | 215 | |
244 | c = bus_space_read_4(bst, bsh, UART_RFIFO_REG); | | 216 | c = bus_space_read_4(bst, bsh, UART_RFIFO_REG); |
245 | #if defined(DDB) | | 217 | #if defined(DDB) |
246 | extern int db_active; | | 218 | extern int db_active; |
247 | if (!db_active) | | 219 | if (!db_active) |
248 | #endif | | 220 | #endif |
249 | { | | 221 | { |
250 | int cn_trapped __unused = 0; | | 222 | int cn_trapped __unused = 0; |
251 | cn_check_magic(dev, c, amlogic_com_cnm_state); | | 223 | cn_check_magic(dev, c, amlogic_com_cnm_state); |
252 | } | | 224 | } |
253 | | | 225 | |
254 | splx(s); | | 226 | splx(s); |
255 | | | 227 | |
256 | return c & 0xff; | | 228 | return c & 0xff; |
257 | } | | 229 | } |
258 | | | 230 | |
259 | static void | | 231 | static void |
260 | amlogic_com_cnputc(dev_t dev, int c) | | 232 | amlogic_com_cnputc(dev_t dev, int c) |
261 | { | | 233 | { |
262 | bus_space_tag_t bst = amlogic_com_cnsc.sc_bst; | | 234 | bus_space_tag_t bst = amlogic_com_cnsc.sc_bst; |
263 | bus_space_handle_t bsh = amlogic_com_cnsc.sc_bsh; | | 235 | bus_space_handle_t bsh = amlogic_com_cnsc.sc_bsh; |
264 | int s; | | 236 | int s; |
265 | | | 237 | |
266 | s = splserial(); | | 238 | s = splserial(); |
267 | | | 239 | |
268 | while ((bus_space_read_4(bst, bsh, UART_STATUS_REG) & UART_STATUS_TX_FULL) != 0) | | 240 | while ((bus_space_read_4(bst, bsh, UART_STATUS_REG) & UART_STATUS_TX_FULL) != 0) |
269 | ; | | 241 | ; |
270 | | | 242 | |
271 | bus_space_write_4(bst, bsh, UART_WFIFO_REG, c); | | 243 | bus_space_write_4(bst, bsh, UART_WFIFO_REG, c); |
272 | | | 244 | |
273 | splx(s); | | 245 | splx(s); |
274 | } | | 246 | } |
275 | | | 247 | |
276 | | | 248 | |
277 | static void | | 249 | static void |
278 | amlogic_com_cnpollc(dev_t dev, int on) | | 250 | amlogic_com_cnpollc(dev_t dev, int on) |
279 | { | | 251 | { |
280 | } | | 252 | } |
281 | | | 253 | |
282 | bool | | 254 | bool |
283 | amlogic_com_cnattach(bus_space_tag_t bst, bus_space_handle_t bsh, | | 255 | amlogic_com_cnattach(bus_space_tag_t bst, bus_space_handle_t bsh, |
284 | int ospeed, tcflag_t cflag) | | 256 | int ospeed, tcflag_t cflag) |
285 | { | | 257 | { |
286 | struct amlogic_com_softc *sc = &amlogic_com_cnsc; | | 258 | struct amlogic_com_softc *sc = &amlogic_com_cnsc; |
287 | | | 259 | |
288 | cn_tab = &amlogic_com_consdev; | | 260 | cn_tab = &amlogic_com_consdev; |
289 | cn_init_magic(&amlogic_com_cnm_state); | | 261 | cn_init_magic(&amlogic_com_cnm_state); |
290 | cn_set_magic("\047\001"); | | 262 | cn_set_magic("\047\001"); |
291 | | | 263 | |
292 | sc->sc_bst = bst; | | 264 | sc->sc_bst = bst; |
293 | sc->sc_bsh = bsh; | | 265 | sc->sc_bsh = bsh; |
294 | sc->sc_ospeed = ospeed; | | 266 | sc->sc_ospeed = ospeed; |
295 | sc->sc_cflag = cflag; | | 267 | sc->sc_cflag = cflag; |
296 | | | 268 | |
297 | return true; | | 269 | return true; |
298 | } | | 270 | } |
299 | | | 271 | |
300 | bool | | 272 | bool |
301 | amlogic_com_is_console(bus_addr_t iobase) | | 273 | amlogic_com_is_console(bus_addr_t iobase) |
302 | { | | 274 | { |
303 | return iobase == CONSADDR; | | 275 | return iobase == CONSADDR; |
304 | } | | 276 | } |
305 | | | 277 | |
306 | static int | | 278 | static int |
307 | amlogic_com_open(dev_t dev, int flag, int mode, lwp_t *l) | | 279 | amlogic_com_open(dev_t dev, int flag, int mode, lwp_t *l) |
308 | { | | 280 | { |
309 | struct amlogic_com_softc *sc = | | 281 | struct amlogic_com_softc *sc = |
310 | device_lookup_private(&amlogiccom_cd, minor(dev)); | | 282 | device_lookup_private(&amlogiccom_cd, minor(dev)); |
311 | struct tty *tp = sc->sc_tty; | | 283 | struct tty *tp = sc->sc_tty; |
312 | | | 284 | |
313 | if (kauth_authorize_device_tty(l->l_cred, | | 285 | if (kauth_authorize_device_tty(l->l_cred, |
314 | KAUTH_DEVICE_TTY_OPEN, tp) != 0) { | | 286 | KAUTH_DEVICE_TTY_OPEN, tp) != 0) { |
315 | return EBUSY; | | 287 | return EBUSY; |
316 | } | | 288 | } |
317 | | | 289 | |
318 | if ((tp->t_state & TS_ISOPEN) == 0 && tp->t_wopen == 0) { | | 290 | if ((tp->t_state & TS_ISOPEN) == 0 && tp->t_wopen == 0) { |
319 | tp->t_dev = dev; | | 291 | tp->t_dev = dev; |
320 | ttychars(tp); | | 292 | ttychars(tp); |
321 | tp->t_iflag = TTYDEF_IFLAG; | | 293 | tp->t_iflag = TTYDEF_IFLAG; |
322 | tp->t_oflag = TTYDEF_OFLAG; | | 294 | tp->t_oflag = TTYDEF_OFLAG; |
323 | tp->t_cflag = TTYDEF_CFLAG; | | 295 | tp->t_cflag = TTYDEF_CFLAG; |
324 | tp->t_lflag = TTYDEF_LFLAG; | | 296 | tp->t_lflag = TTYDEF_LFLAG; |
325 | tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; | | 297 | tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; |
326 | ttsetwater(tp); | | 298 | ttsetwater(tp); |
327 | } | | 299 | } |
328 | tp->t_state |= TS_CARR_ON; | | 300 | tp->t_state |= TS_CARR_ON; |
329 | | | 301 | |
330 | return tp->t_linesw->l_open(dev, tp); | | 302 | return tp->t_linesw->l_open(dev, tp); |
331 | } | | 303 | } |
332 | | | 304 | |
333 | static int | | 305 | static int |
334 | amlogic_com_close(dev_t dev, int flag, int mode, lwp_t *l) | | 306 | amlogic_com_close(dev_t dev, int flag, int mode, lwp_t *l) |
335 | { | | 307 | { |
336 | struct amlogic_com_softc *sc = | | 308 | struct amlogic_com_softc *sc = |
337 | device_lookup_private(&amlogiccom_cd, minor(dev)); | | 309 | device_lookup_private(&amlogiccom_cd, minor(dev)); |
338 | struct tty *tp = sc->sc_tty; | | 310 | struct tty *tp = sc->sc_tty; |
339 | | | 311 | |
340 | tp->t_linesw->l_close(tp, flag); | | 312 | tp->t_linesw->l_close(tp, flag); |
341 | ttyclose(tp); | | 313 | ttyclose(tp); |
342 | | | 314 | |
343 | return 0; | | 315 | return 0; |
344 | } | | 316 | } |
345 | | | 317 | |
346 | static int | | 318 | static int |
347 | amlogic_com_read(dev_t dev, struct uio *uio, int flag) | | 319 | amlogic_com_read(dev_t dev, struct uio *uio, int flag) |
348 | { | | 320 | { |
349 | struct amlogic_com_softc *sc = | | 321 | struct amlogic_com_softc *sc = |
350 | device_lookup_private(&amlogiccom_cd, minor(dev)); | | 322 | device_lookup_private(&amlogiccom_cd, minor(dev)); |
351 | struct tty *tp = sc->sc_tty; | | 323 | struct tty *tp = sc->sc_tty; |
352 | | | 324 | |
353 | return tp->t_linesw->l_read(tp, uio, flag); | | 325 | return tp->t_linesw->l_read(tp, uio, flag); |
354 | } | | 326 | } |
355 | | | 327 | |
356 | static int | | 328 | static int |
357 | amlogic_com_write(dev_t dev, struct uio *uio, int flag) | | 329 | amlogic_com_write(dev_t dev, struct uio *uio, int flag) |
358 | { | | 330 | { |
359 | struct amlogic_com_softc *sc = | | 331 | struct amlogic_com_softc *sc = |
360 | device_lookup_private(&amlogiccom_cd, minor(dev)); | | 332 | device_lookup_private(&amlogiccom_cd, minor(dev)); |
361 | struct tty *tp = sc->sc_tty; | | 333 | struct tty *tp = sc->sc_tty; |
362 | | | 334 | |
363 | return tp->t_linesw->l_write(tp, uio, flag); | | 335 | return tp->t_linesw->l_write(tp, uio, flag); |
364 | } | | 336 | } |
365 | | | 337 | |
366 | static int | | 338 | static int |
367 | amlogic_com_poll(dev_t dev, int events, lwp_t *l) | | 339 | amlogic_com_poll(dev_t dev, int events, lwp_t *l) |
368 | { | | 340 | { |
369 | struct amlogic_com_softc *sc = | | 341 | struct amlogic_com_softc *sc = |
370 | device_lookup_private(&amlogiccom_cd, minor(dev)); | | 342 | device_lookup_private(&amlogiccom_cd, minor(dev)); |
371 | struct tty *tp = sc->sc_tty; | | 343 | struct tty *tp = sc->sc_tty; |
372 | | | 344 | |
373 | return tp->t_linesw->l_poll(tp, events, l); | | 345 | return tp->t_linesw->l_poll(tp, events, l); |
374 | } | | 346 | } |
375 | | | 347 | |
376 | static int | | 348 | static int |
377 | amlogic_com_ioctl(dev_t dev, u_long cmd, void *data, int flag, lwp_t *l) | | 349 | amlogic_com_ioctl(dev_t dev, u_long cmd, void *data, int flag, lwp_t *l) |
378 | { | | 350 | { |
379 | struct amlogic_com_softc *sc = | | 351 | struct amlogic_com_softc *sc = |
380 | device_lookup_private(&amlogiccom_cd, minor(dev)); | | 352 | device_lookup_private(&amlogiccom_cd, minor(dev)); |
381 | struct tty *tp = sc->sc_tty; | | 353 | struct tty *tp = sc->sc_tty; |
382 | int error; | | 354 | int error; |
383 | | | 355 | |
384 | error = tp->t_linesw->l_ioctl(tp, cmd, data, flag, l); | | 356 | error = tp->t_linesw->l_ioctl(tp, cmd, data, flag, l); |
385 | if (error != EPASSTHROUGH) | | 357 | if (error != EPASSTHROUGH) |
386 | return error; | | 358 | return error; |
387 | | | 359 | |
388 | return ttioctl(tp, cmd, data, flag, l); | | 360 | return ttioctl(tp, cmd, data, flag, l); |
389 | } | | 361 | } |
390 | | | 362 | |
391 | static struct tty * | | 363 | static struct tty * |
392 | amlogic_com_tty(dev_t dev) | | 364 | amlogic_com_tty(dev_t dev) |
393 | { | | 365 | { |
394 | struct amlogic_com_softc *sc = | | 366 | struct amlogic_com_softc *sc = |
395 | device_lookup_private(&amlogiccom_cd, minor(dev)); | | 367 | device_lookup_private(&amlogiccom_cd, minor(dev)); |
396 | | | 368 | |
397 | return sc->sc_tty; | | 369 | return sc->sc_tty; |
398 | } | | 370 | } |
399 | | | 371 | |
400 | static void | | 372 | static void |
401 | amlogic_com_stop(struct tty *tp, int flag) | | 373 | amlogic_com_stop(struct tty *tp, int flag) |
402 | { | | 374 | { |
403 | } | | 375 | } |
404 | | | 376 | |
405 | static void | | 377 | static void |
406 | amlogic_com_start(struct tty *tp) | | 378 | amlogic_com_start(struct tty *tp) |
407 | { | | 379 | { |
408 | struct amlogic_com_softc *sc = tp->t_sc; | | 380 | struct amlogic_com_softc *sc = tp->t_sc; |
409 | u_char *p = sc->sc_buf; | | 381 | u_char *p = sc->sc_buf; |
410 | int s, brem; | | 382 | int s, brem; |
411 | | | 383 | |
412 | s = spltty(); | | 384 | s = spltty(); |
413 | | | 385 | |
414 | if (tp->t_state & (TS_TTSTOP | TS_BUSY | TS_TIMEOUT)) { | | 386 | if (tp->t_state & (TS_TTSTOP | TS_BUSY | TS_TIMEOUT)) { |
415 | splx(s); | | 387 | splx(s); |
416 | return; | | 388 | return; |
417 | } | | 389 | } |
418 | tp->t_state |= TS_BUSY; | | 390 | tp->t_state |= TS_BUSY; |
419 | | | 391 | |
420 | splx(s); | | 392 | splx(s); |
421 | | | 393 | |
422 | for (brem = q_to_b(&tp->t_outq, sc->sc_buf, sizeof(sc->sc_buf)); | | 394 | for (brem = q_to_b(&tp->t_outq, sc->sc_buf, sizeof(sc->sc_buf)); |
423 | brem > 0; | | 395 | brem > 0; |
424 | brem--, p++) { | | 396 | brem--, p++) { |
425 | while ((bus_space_read_4(sc->sc_bst, sc->sc_bsh, | | 397 | while ((bus_space_read_4(sc->sc_bst, sc->sc_bsh, |
426 | UART_STATUS_REG) & UART_STATUS_TX_FULL) != 0) | | 398 | UART_STATUS_REG) & UART_STATUS_TX_FULL) != 0) |
427 | ; | | 399 | ; |
428 | | | 400 | |
429 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, | | 401 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, |
430 | UART_WFIFO_REG, *p); | | 402 | UART_WFIFO_REG, *p); |
431 | } | | 403 | } |
432 | | | 404 | |
433 | s = spltty(); | | 405 | s = spltty(); |
434 | tp->t_state &= ~TS_BUSY; | | 406 | tp->t_state &= ~TS_BUSY; |
435 | if (ttypull(tp)) { | | 407 | if (ttypull(tp)) { |
436 | tp->t_state |= TS_TIMEOUT; | | 408 | tp->t_state |= TS_TIMEOUT; |
437 | callout_schedule(&tp->t_rstrt_ch, 1); | | 409 | callout_schedule(&tp->t_rstrt_ch, 1); |
438 | } | | 410 | } |
439 | splx(s); | | 411 | splx(s); |
440 | } | | 412 | } |
441 | | | 413 | |
442 | static int | | 414 | static int |
443 | amlogic_com_param(struct tty *tp, struct termios *t) | | 415 | amlogic_com_param(struct tty *tp, struct termios *t) |
444 | { | | 416 | { |
445 | | | 417 | |
446 | tp->t_ispeed = t->c_ispeed; | | 418 | tp->t_ispeed = t->c_ispeed; |
447 | tp->t_ospeed = t->c_ospeed; | | 419 | tp->t_ospeed = t->c_ospeed; |
448 | tp->t_cflag = t->c_cflag; | | 420 | tp->t_cflag = t->c_cflag; |
449 | | | 421 | |
450 | return 0; | | 422 | return 0; |
451 | } | | 423 | } |
452 | | | 424 | |
453 | static int | | 425 | static int |
454 | amlogic_com_intr(void *priv) | | 426 | amlogic_com_intr(void *priv) |
455 | { | | 427 | { |
456 | struct amlogic_com_softc *sc = priv; | | 428 | struct amlogic_com_softc *sc = priv; |
457 | struct tty *tp = sc->sc_tty; | | 429 | struct tty *tp = sc->sc_tty; |
458 | uint32_t status, c; | | 430 | uint32_t status, c; |
459 | | | 431 | |
460 | for (;;) { | | 432 | for (;;) { |
461 | status = bus_space_read_4(sc->sc_bst, sc->sc_bsh, | | 433 | status = bus_space_read_4(sc->sc_bst, sc->sc_bsh, |
462 | UART_STATUS_REG); | | 434 | UART_STATUS_REG); |
463 | if (status & UART_STATUS_RX_EMPTY) { | | 435 | if (status & UART_STATUS_RX_EMPTY) { |
464 | break; | | 436 | break; |
465 | } | | 437 | } |
466 | | | 438 | |
467 | c = bus_space_read_4(sc->sc_bst, sc->sc_bsh, UART_RFIFO_REG); | | 439 | c = bus_space_read_4(sc->sc_bst, sc->sc_bsh, UART_RFIFO_REG); |
468 | cn_check_magic(tp->t_dev, c, amlogic_com_cnm_state); | | 440 | cn_check_magic(tp->t_dev, c, amlogic_com_cnm_state); |
469 | tp->t_linesw->l_rint(c & 0xff, tp); | | 441 | tp->t_linesw->l_rint(c & 0xff, tp); |
470 | } | | 442 | } |
471 | | | 443 | |
472 | return 0; | | 444 | return 0; |
473 | } | | 445 | } |
474 | | | | |
475 | #ifdef AMLOGIC_COM_INTRPOLL | | | |
476 | static void | | | |
477 | amlogic_com_intrpoll(void *priv) | | | |
478 | { | | | |
479 | struct amlogic_com_softc *sc = priv; | | | |
480 | int s; | | | |
481 | | | | |
482 | s = splserial(); | | | |
483 | amlogic_com_intr(sc); | | | |
484 | splx(s); | | | |
485 | | | | |
486 | callout_schedule(&sc->sc_intrpoll_ch, AMLOGIC_COM_INTRPOLL_RATE); | | | |
487 | } | | | |
488 | #endif | | | |