1dc7717a8SGanbold Tsagaankhuu /*-
2dc7717a8SGanbold Tsagaankhuu * Copyright (c) 2014 Ganbold Tsagaankhuu <ganbold@freebsd.org>
3dc7717a8SGanbold Tsagaankhuu * All rights reserved.
4dc7717a8SGanbold Tsagaankhuu *
5dc7717a8SGanbold Tsagaankhuu * Redistribution and use in source and binary forms, with or without
6dc7717a8SGanbold Tsagaankhuu * modification, are permitted provided that the following conditions
7dc7717a8SGanbold Tsagaankhuu * are met:
8dc7717a8SGanbold Tsagaankhuu *
9dc7717a8SGanbold Tsagaankhuu * 1. Redistributions of source code must retain the above copyright
10dc7717a8SGanbold Tsagaankhuu * notice, this list of conditions and the following disclaimer.
11dc7717a8SGanbold Tsagaankhuu * 2. Redistributions in binary form must reproduce the above copyright
12dc7717a8SGanbold Tsagaankhuu * notice, this list of conditions and the following disclaimer in the
13dc7717a8SGanbold Tsagaankhuu * documentation and/or other materials provided with the distribution.
14dc7717a8SGanbold Tsagaankhuu *
15dc7717a8SGanbold Tsagaankhuu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16dc7717a8SGanbold Tsagaankhuu * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17dc7717a8SGanbold Tsagaankhuu * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18dc7717a8SGanbold Tsagaankhuu * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19dc7717a8SGanbold Tsagaankhuu * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20dc7717a8SGanbold Tsagaankhuu * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21dc7717a8SGanbold Tsagaankhuu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22dc7717a8SGanbold Tsagaankhuu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23dc7717a8SGanbold Tsagaankhuu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24dc7717a8SGanbold Tsagaankhuu * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25dc7717a8SGanbold Tsagaankhuu */
26dc7717a8SGanbold Tsagaankhuu
27dc7717a8SGanbold Tsagaankhuu /* Qualcomm MSM7K/8K uart driver */
28dc7717a8SGanbold Tsagaankhuu
29dc7717a8SGanbold Tsagaankhuu #include <sys/cdefs.h>
30dc7717a8SGanbold Tsagaankhuu #include "opt_ddb.h"
31dc7717a8SGanbold Tsagaankhuu
32dc7717a8SGanbold Tsagaankhuu #include <sys/param.h>
33dc7717a8SGanbold Tsagaankhuu #include <sys/systm.h>
34dc7717a8SGanbold Tsagaankhuu #include <sys/bus.h>
35dc7717a8SGanbold Tsagaankhuu #include <sys/conf.h>
36dc7717a8SGanbold Tsagaankhuu #include <sys/kdb.h>
37dc7717a8SGanbold Tsagaankhuu #include <machine/bus.h>
38dc7717a8SGanbold Tsagaankhuu
39dc7717a8SGanbold Tsagaankhuu #include <dev/uart/uart.h>
40dc7717a8SGanbold Tsagaankhuu #include <dev/uart/uart_cpu.h>
413bb693afSIan Lepore #include <dev/uart/uart_cpu_fdt.h>
42dc7717a8SGanbold Tsagaankhuu #include <dev/uart/uart_bus.h>
43dc7717a8SGanbold Tsagaankhuu #include <dev/uart/uart_dev_msm.h>
44dc7717a8SGanbold Tsagaankhuu
45dc7717a8SGanbold Tsagaankhuu #include "uart_if.h"
46dc7717a8SGanbold Tsagaankhuu
47dc7717a8SGanbold Tsagaankhuu #define DEF_CLK 7372800
48dc7717a8SGanbold Tsagaankhuu
49dc7717a8SGanbold Tsagaankhuu #define GETREG(bas, reg) \
50dc7717a8SGanbold Tsagaankhuu bus_space_read_4((bas)->bst, (bas)->bsh, (reg))
51dc7717a8SGanbold Tsagaankhuu #define SETREG(bas, reg, value) \
52dc7717a8SGanbold Tsagaankhuu bus_space_write_4((bas)->bst, (bas)->bsh, (reg), (value))
53dc7717a8SGanbold Tsagaankhuu
54dc7717a8SGanbold Tsagaankhuu static int msm_uart_param(struct uart_bas *, int, int, int, int);
55dc7717a8SGanbold Tsagaankhuu
56dc7717a8SGanbold Tsagaankhuu /*
57dc7717a8SGanbold Tsagaankhuu * Low-level UART interface.
58dc7717a8SGanbold Tsagaankhuu */
59dc7717a8SGanbold Tsagaankhuu static int msm_probe(struct uart_bas *bas);
60dc7717a8SGanbold Tsagaankhuu static void msm_init(struct uart_bas *bas, int, int, int, int);
61dc7717a8SGanbold Tsagaankhuu static void msm_term(struct uart_bas *bas);
62dc7717a8SGanbold Tsagaankhuu static void msm_putc(struct uart_bas *bas, int);
63dc7717a8SGanbold Tsagaankhuu static int msm_rxready(struct uart_bas *bas);
64dc7717a8SGanbold Tsagaankhuu static int msm_getc(struct uart_bas *bas, struct mtx *mtx);
65dc7717a8SGanbold Tsagaankhuu
66dc7717a8SGanbold Tsagaankhuu extern SLIST_HEAD(uart_devinfo_list, uart_devinfo) uart_sysdevs;
67dc7717a8SGanbold Tsagaankhuu
68dc7717a8SGanbold Tsagaankhuu static int
msm_uart_param(struct uart_bas * bas,int baudrate,int databits,int stopbits,int parity)69dc7717a8SGanbold Tsagaankhuu msm_uart_param(struct uart_bas *bas, int baudrate, int databits,
70dc7717a8SGanbold Tsagaankhuu int stopbits, int parity)
71dc7717a8SGanbold Tsagaankhuu {
72dc7717a8SGanbold Tsagaankhuu int ulcon;
73dc7717a8SGanbold Tsagaankhuu
74dc7717a8SGanbold Tsagaankhuu ulcon = 0;
75dc7717a8SGanbold Tsagaankhuu
76dc7717a8SGanbold Tsagaankhuu switch (databits) {
77dc7717a8SGanbold Tsagaankhuu case 5:
78dc7717a8SGanbold Tsagaankhuu ulcon |= (UART_DM_5_BPS << 4);
79dc7717a8SGanbold Tsagaankhuu break;
80dc7717a8SGanbold Tsagaankhuu case 6:
81dc7717a8SGanbold Tsagaankhuu ulcon |= (UART_DM_6_BPS << 4);
82dc7717a8SGanbold Tsagaankhuu break;
83dc7717a8SGanbold Tsagaankhuu case 7:
84dc7717a8SGanbold Tsagaankhuu ulcon |= (UART_DM_7_BPS << 4);
85dc7717a8SGanbold Tsagaankhuu break;
86dc7717a8SGanbold Tsagaankhuu case 8:
87dc7717a8SGanbold Tsagaankhuu ulcon |= (UART_DM_8_BPS << 4);
88dc7717a8SGanbold Tsagaankhuu break;
89dc7717a8SGanbold Tsagaankhuu default:
90dc7717a8SGanbold Tsagaankhuu return (EINVAL);
91dc7717a8SGanbold Tsagaankhuu }
92dc7717a8SGanbold Tsagaankhuu
93dc7717a8SGanbold Tsagaankhuu switch (parity) {
94dc7717a8SGanbold Tsagaankhuu case UART_PARITY_NONE:
95dc7717a8SGanbold Tsagaankhuu ulcon |= UART_DM_NO_PARITY;
96dc7717a8SGanbold Tsagaankhuu break;
97dc7717a8SGanbold Tsagaankhuu case UART_PARITY_ODD:
98dc7717a8SGanbold Tsagaankhuu ulcon |= UART_DM_ODD_PARITY;
99dc7717a8SGanbold Tsagaankhuu break;
100dc7717a8SGanbold Tsagaankhuu case UART_PARITY_EVEN:
101dc7717a8SGanbold Tsagaankhuu ulcon |= UART_DM_EVEN_PARITY;
102dc7717a8SGanbold Tsagaankhuu break;
103dc7717a8SGanbold Tsagaankhuu case UART_PARITY_SPACE:
104dc7717a8SGanbold Tsagaankhuu ulcon |= UART_DM_SPACE_PARITY;
105dc7717a8SGanbold Tsagaankhuu break;
106dc7717a8SGanbold Tsagaankhuu case UART_PARITY_MARK:
107dc7717a8SGanbold Tsagaankhuu default:
108dc7717a8SGanbold Tsagaankhuu return (EINVAL);
109dc7717a8SGanbold Tsagaankhuu }
110dc7717a8SGanbold Tsagaankhuu
111dc7717a8SGanbold Tsagaankhuu switch (stopbits) {
112dc7717a8SGanbold Tsagaankhuu case 1:
113dc7717a8SGanbold Tsagaankhuu ulcon |= (UART_DM_SBL_1 << 2);
114dc7717a8SGanbold Tsagaankhuu break;
115dc7717a8SGanbold Tsagaankhuu case 2:
116dc7717a8SGanbold Tsagaankhuu ulcon |= (UART_DM_SBL_2 << 2);
117dc7717a8SGanbold Tsagaankhuu break;
118dc7717a8SGanbold Tsagaankhuu default:
119dc7717a8SGanbold Tsagaankhuu return (EINVAL);
120dc7717a8SGanbold Tsagaankhuu }
121dc7717a8SGanbold Tsagaankhuu uart_setreg(bas, UART_DM_MR2, ulcon);
122dc7717a8SGanbold Tsagaankhuu uart_barrier(bas);
123dc7717a8SGanbold Tsagaankhuu
124dc7717a8SGanbold Tsagaankhuu return (0);
125dc7717a8SGanbold Tsagaankhuu }
126dc7717a8SGanbold Tsagaankhuu
127dc7717a8SGanbold Tsagaankhuu struct uart_ops uart_msm_ops = {
128dc7717a8SGanbold Tsagaankhuu .probe = msm_probe,
129dc7717a8SGanbold Tsagaankhuu .init = msm_init,
130dc7717a8SGanbold Tsagaankhuu .term = msm_term,
131dc7717a8SGanbold Tsagaankhuu .putc = msm_putc,
132dc7717a8SGanbold Tsagaankhuu .rxready = msm_rxready,
133dc7717a8SGanbold Tsagaankhuu .getc = msm_getc,
134dc7717a8SGanbold Tsagaankhuu };
135dc7717a8SGanbold Tsagaankhuu
136dc7717a8SGanbold Tsagaankhuu static int
msm_probe(struct uart_bas * bas)137dc7717a8SGanbold Tsagaankhuu msm_probe(struct uart_bas *bas)
138dc7717a8SGanbold Tsagaankhuu {
139dc7717a8SGanbold Tsagaankhuu
140*9f7743f2SRuslan Bukin bas->regiowidth = 4;
141*9f7743f2SRuslan Bukin
142dc7717a8SGanbold Tsagaankhuu return (0);
143dc7717a8SGanbold Tsagaankhuu }
144dc7717a8SGanbold Tsagaankhuu
145dc7717a8SGanbold Tsagaankhuu static void
msm_init(struct uart_bas * bas,int baudrate,int databits,int stopbits,int parity)146dc7717a8SGanbold Tsagaankhuu msm_init(struct uart_bas *bas, int baudrate, int databits, int stopbits,
147dc7717a8SGanbold Tsagaankhuu int parity)
148dc7717a8SGanbold Tsagaankhuu {
149dc7717a8SGanbold Tsagaankhuu
150dc7717a8SGanbold Tsagaankhuu if (bas->rclk == 0)
151dc7717a8SGanbold Tsagaankhuu bas->rclk = DEF_CLK;
152dc7717a8SGanbold Tsagaankhuu
153dc7717a8SGanbold Tsagaankhuu KASSERT(bas->rclk != 0, ("msm_init: Invalid rclk"));
154dc7717a8SGanbold Tsagaankhuu
155dc7717a8SGanbold Tsagaankhuu /* Set default parameters */
156dc7717a8SGanbold Tsagaankhuu msm_uart_param(bas, baudrate, databits, stopbits, parity);
157dc7717a8SGanbold Tsagaankhuu
158dc7717a8SGanbold Tsagaankhuu /*
159dc7717a8SGanbold Tsagaankhuu * Configure UART mode registers MR1 and MR2.
160dc7717a8SGanbold Tsagaankhuu * Hardware flow control isn't supported.
161dc7717a8SGanbold Tsagaankhuu */
162dc7717a8SGanbold Tsagaankhuu uart_setreg(bas, UART_DM_MR1, 0x0);
163dc7717a8SGanbold Tsagaankhuu
164dc7717a8SGanbold Tsagaankhuu /* Reset interrupt mask register. */
165dc7717a8SGanbold Tsagaankhuu uart_setreg(bas, UART_DM_IMR, 0);
166dc7717a8SGanbold Tsagaankhuu
167dc7717a8SGanbold Tsagaankhuu /*
168dc7717a8SGanbold Tsagaankhuu * Configure Tx and Rx watermarks configuration registers.
169dc7717a8SGanbold Tsagaankhuu * TX watermark value is set to 0 - interrupt is generated when
170dc7717a8SGanbold Tsagaankhuu * FIFO level is less than or equal to 0.
171dc7717a8SGanbold Tsagaankhuu */
172dc7717a8SGanbold Tsagaankhuu uart_setreg(bas, UART_DM_TFWR, UART_DM_TFW_VALUE);
173dc7717a8SGanbold Tsagaankhuu
174dc7717a8SGanbold Tsagaankhuu /* Set RX watermark value */
175dc7717a8SGanbold Tsagaankhuu uart_setreg(bas, UART_DM_RFWR, UART_DM_RFW_VALUE);
176dc7717a8SGanbold Tsagaankhuu
177dc7717a8SGanbold Tsagaankhuu /*
178dc7717a8SGanbold Tsagaankhuu * Configure Interrupt Programming Register.
179dc7717a8SGanbold Tsagaankhuu * Set initial Stale timeout value.
180dc7717a8SGanbold Tsagaankhuu */
181dc7717a8SGanbold Tsagaankhuu uart_setreg(bas, UART_DM_IPR, UART_DM_STALE_TIMEOUT_LSB);
182dc7717a8SGanbold Tsagaankhuu
183dc7717a8SGanbold Tsagaankhuu /* Disable IRDA mode */
184dc7717a8SGanbold Tsagaankhuu uart_setreg(bas, UART_DM_IRDA, 0x0);
185dc7717a8SGanbold Tsagaankhuu
186dc7717a8SGanbold Tsagaankhuu /*
187dc7717a8SGanbold Tsagaankhuu * Configure and enable sim interface if required.
188dc7717a8SGanbold Tsagaankhuu * Configure hunt character value in HCR register.
189dc7717a8SGanbold Tsagaankhuu * Keep it in reset state.
190dc7717a8SGanbold Tsagaankhuu */
191dc7717a8SGanbold Tsagaankhuu uart_setreg(bas, UART_DM_HCR, 0x0);
192dc7717a8SGanbold Tsagaankhuu
193dc7717a8SGanbold Tsagaankhuu /* Issue soft reset command */
194dc7717a8SGanbold Tsagaankhuu SETREG(bas, UART_DM_CR, UART_DM_RESET_TX);
195dc7717a8SGanbold Tsagaankhuu SETREG(bas, UART_DM_CR, UART_DM_RESET_RX);
196dc7717a8SGanbold Tsagaankhuu SETREG(bas, UART_DM_CR, UART_DM_RESET_ERROR_STATUS);
197dc7717a8SGanbold Tsagaankhuu SETREG(bas, UART_DM_CR, UART_DM_RESET_BREAK_INT);
198dc7717a8SGanbold Tsagaankhuu SETREG(bas, UART_DM_CR, UART_DM_RESET_STALE_INT);
199dc7717a8SGanbold Tsagaankhuu
200dc7717a8SGanbold Tsagaankhuu /* Enable/Disable Rx/Tx DM interfaces */
201*9f7743f2SRuslan Bukin uart_setreg(bas, UART_DM_DMEN, UART_DM_DMEN_RX_SC_ENABLE);
202dc7717a8SGanbold Tsagaankhuu
203dc7717a8SGanbold Tsagaankhuu /* Enable transmitter and receiver */
204dc7717a8SGanbold Tsagaankhuu uart_setreg(bas, UART_DM_CR, UART_DM_CR_RX_ENABLE);
205dc7717a8SGanbold Tsagaankhuu uart_setreg(bas, UART_DM_CR, UART_DM_CR_TX_ENABLE);
206dc7717a8SGanbold Tsagaankhuu
207dc7717a8SGanbold Tsagaankhuu uart_barrier(bas);
208dc7717a8SGanbold Tsagaankhuu }
209dc7717a8SGanbold Tsagaankhuu
210dc7717a8SGanbold Tsagaankhuu static void
msm_term(struct uart_bas * bas)211dc7717a8SGanbold Tsagaankhuu msm_term(struct uart_bas *bas)
212dc7717a8SGanbold Tsagaankhuu {
213dc7717a8SGanbold Tsagaankhuu
214dc7717a8SGanbold Tsagaankhuu /* XXX */
215dc7717a8SGanbold Tsagaankhuu }
216dc7717a8SGanbold Tsagaankhuu
217dc7717a8SGanbold Tsagaankhuu static void
msm_putc(struct uart_bas * bas,int c)218dc7717a8SGanbold Tsagaankhuu msm_putc(struct uart_bas *bas, int c)
219dc7717a8SGanbold Tsagaankhuu {
220dc7717a8SGanbold Tsagaankhuu int limit;
221dc7717a8SGanbold Tsagaankhuu
222dc7717a8SGanbold Tsagaankhuu /*
223dc7717a8SGanbold Tsagaankhuu * Write to NO_CHARS_FOR_TX register the number of characters
224dc7717a8SGanbold Tsagaankhuu * to be transmitted. However, before writing TX_FIFO must
225dc7717a8SGanbold Tsagaankhuu * be empty as indicated by TX_READY interrupt in IMR register
226dc7717a8SGanbold Tsagaankhuu */
227dc7717a8SGanbold Tsagaankhuu
228dc7717a8SGanbold Tsagaankhuu /*
229dc7717a8SGanbold Tsagaankhuu * Check if transmit FIFO is empty.
230dc7717a8SGanbold Tsagaankhuu * If not wait for TX_READY interrupt.
231dc7717a8SGanbold Tsagaankhuu */
232dc7717a8SGanbold Tsagaankhuu limit = 1000;
233dc7717a8SGanbold Tsagaankhuu if (!(uart_getreg(bas, UART_DM_SR) & UART_DM_SR_TXEMT)) {
234dc7717a8SGanbold Tsagaankhuu while ((uart_getreg(bas, UART_DM_ISR) & UART_DM_TX_READY) == 0
235dc7717a8SGanbold Tsagaankhuu && --limit)
236dc7717a8SGanbold Tsagaankhuu DELAY(4);
237*9f7743f2SRuslan Bukin SETREG(bas, UART_DM_CR, UART_DM_CLEAR_TX_READY);
238dc7717a8SGanbold Tsagaankhuu }
239dc7717a8SGanbold Tsagaankhuu /* FIFO is ready, write number of characters to be written */
240dc7717a8SGanbold Tsagaankhuu uart_setreg(bas, UART_DM_NO_CHARS_FOR_TX, 1);
241dc7717a8SGanbold Tsagaankhuu
242dc7717a8SGanbold Tsagaankhuu /* Wait till TX FIFO has space */
243dc7717a8SGanbold Tsagaankhuu while ((uart_getreg(bas, UART_DM_SR) & UART_DM_SR_TXRDY) == 0)
244dc7717a8SGanbold Tsagaankhuu DELAY(4);
245dc7717a8SGanbold Tsagaankhuu
246dc7717a8SGanbold Tsagaankhuu /* TX FIFO has space. Write char */
247dc7717a8SGanbold Tsagaankhuu SETREG(bas, UART_DM_TF(0), (c & 0xff));
248dc7717a8SGanbold Tsagaankhuu }
249dc7717a8SGanbold Tsagaankhuu
250dc7717a8SGanbold Tsagaankhuu static int
msm_rxready(struct uart_bas * bas)251dc7717a8SGanbold Tsagaankhuu msm_rxready(struct uart_bas *bas)
252dc7717a8SGanbold Tsagaankhuu {
253dc7717a8SGanbold Tsagaankhuu
254dc7717a8SGanbold Tsagaankhuu /* Wait for a character to come ready */
255dc7717a8SGanbold Tsagaankhuu return ((uart_getreg(bas, UART_DM_SR) & UART_DM_SR_RXRDY) ==
256dc7717a8SGanbold Tsagaankhuu UART_DM_SR_RXRDY);
257dc7717a8SGanbold Tsagaankhuu }
258dc7717a8SGanbold Tsagaankhuu
259dc7717a8SGanbold Tsagaankhuu static int
msm_getc(struct uart_bas * bas,struct mtx * mtx)260dc7717a8SGanbold Tsagaankhuu msm_getc(struct uart_bas *bas, struct mtx *mtx)
261dc7717a8SGanbold Tsagaankhuu {
262dc7717a8SGanbold Tsagaankhuu int c;
263dc7717a8SGanbold Tsagaankhuu
264dc7717a8SGanbold Tsagaankhuu uart_lock(mtx);
265dc7717a8SGanbold Tsagaankhuu
266dc7717a8SGanbold Tsagaankhuu /* Wait for a character to come ready */
267dc7717a8SGanbold Tsagaankhuu while ((uart_getreg(bas, UART_DM_SR) & UART_DM_SR_RXRDY) !=
268dc7717a8SGanbold Tsagaankhuu UART_DM_SR_RXRDY)
269dc7717a8SGanbold Tsagaankhuu DELAY(4);
270dc7717a8SGanbold Tsagaankhuu
271dc7717a8SGanbold Tsagaankhuu /* Check for Overrun error. If so reset Error Status */
272dc7717a8SGanbold Tsagaankhuu if (uart_getreg(bas, UART_DM_SR) & UART_DM_SR_UART_OVERRUN)
273dc7717a8SGanbold Tsagaankhuu uart_setreg(bas, UART_DM_CR, UART_DM_RESET_ERROR_STATUS);
274dc7717a8SGanbold Tsagaankhuu
275dc7717a8SGanbold Tsagaankhuu /* Read char */
276dc7717a8SGanbold Tsagaankhuu c = uart_getreg(bas, UART_DM_RF(0));
277dc7717a8SGanbold Tsagaankhuu
278dc7717a8SGanbold Tsagaankhuu uart_unlock(mtx);
279dc7717a8SGanbold Tsagaankhuu
280dc7717a8SGanbold Tsagaankhuu return (c);
281dc7717a8SGanbold Tsagaankhuu }
282dc7717a8SGanbold Tsagaankhuu
283dc7717a8SGanbold Tsagaankhuu /*
284dc7717a8SGanbold Tsagaankhuu * High-level UART interface.
285dc7717a8SGanbold Tsagaankhuu */
286dc7717a8SGanbold Tsagaankhuu struct msm_uart_softc {
287dc7717a8SGanbold Tsagaankhuu struct uart_softc base;
288dc7717a8SGanbold Tsagaankhuu uint32_t ier;
289dc7717a8SGanbold Tsagaankhuu };
290dc7717a8SGanbold Tsagaankhuu
291dc7717a8SGanbold Tsagaankhuu static int msm_bus_probe(struct uart_softc *sc);
292dc7717a8SGanbold Tsagaankhuu static int msm_bus_attach(struct uart_softc *sc);
293dc7717a8SGanbold Tsagaankhuu static int msm_bus_flush(struct uart_softc *, int);
294dc7717a8SGanbold Tsagaankhuu static int msm_bus_getsig(struct uart_softc *);
295dc7717a8SGanbold Tsagaankhuu static int msm_bus_ioctl(struct uart_softc *, int, intptr_t);
296dc7717a8SGanbold Tsagaankhuu static int msm_bus_ipend(struct uart_softc *);
297dc7717a8SGanbold Tsagaankhuu static int msm_bus_param(struct uart_softc *, int, int, int, int);
298dc7717a8SGanbold Tsagaankhuu static int msm_bus_receive(struct uart_softc *);
299dc7717a8SGanbold Tsagaankhuu static int msm_bus_setsig(struct uart_softc *, int);
300dc7717a8SGanbold Tsagaankhuu static int msm_bus_transmit(struct uart_softc *);
301dc7717a8SGanbold Tsagaankhuu static void msm_bus_grab(struct uart_softc *);
302dc7717a8SGanbold Tsagaankhuu static void msm_bus_ungrab(struct uart_softc *);
303dc7717a8SGanbold Tsagaankhuu
304dc7717a8SGanbold Tsagaankhuu static kobj_method_t msm_methods[] = {
305dc7717a8SGanbold Tsagaankhuu KOBJMETHOD(uart_probe, msm_bus_probe),
306dc7717a8SGanbold Tsagaankhuu KOBJMETHOD(uart_attach, msm_bus_attach),
307dc7717a8SGanbold Tsagaankhuu KOBJMETHOD(uart_flush, msm_bus_flush),
308dc7717a8SGanbold Tsagaankhuu KOBJMETHOD(uart_getsig, msm_bus_getsig),
309dc7717a8SGanbold Tsagaankhuu KOBJMETHOD(uart_ioctl, msm_bus_ioctl),
310dc7717a8SGanbold Tsagaankhuu KOBJMETHOD(uart_ipend, msm_bus_ipend),
311dc7717a8SGanbold Tsagaankhuu KOBJMETHOD(uart_param, msm_bus_param),
312dc7717a8SGanbold Tsagaankhuu KOBJMETHOD(uart_receive, msm_bus_receive),
313dc7717a8SGanbold Tsagaankhuu KOBJMETHOD(uart_setsig, msm_bus_setsig),
314dc7717a8SGanbold Tsagaankhuu KOBJMETHOD(uart_transmit, msm_bus_transmit),
315dc7717a8SGanbold Tsagaankhuu KOBJMETHOD(uart_grab, msm_bus_grab),
316dc7717a8SGanbold Tsagaankhuu KOBJMETHOD(uart_ungrab, msm_bus_ungrab),
317dc7717a8SGanbold Tsagaankhuu {0, 0 }
318dc7717a8SGanbold Tsagaankhuu };
319dc7717a8SGanbold Tsagaankhuu
320dc7717a8SGanbold Tsagaankhuu int
msm_bus_probe(struct uart_softc * sc)321dc7717a8SGanbold Tsagaankhuu msm_bus_probe(struct uart_softc *sc)
322dc7717a8SGanbold Tsagaankhuu {
323*9f7743f2SRuslan Bukin struct uart_bas *bas;
324*9f7743f2SRuslan Bukin
325*9f7743f2SRuslan Bukin bas = &sc->sc_bas;
326*9f7743f2SRuslan Bukin bas->regiowidth = 4;
327dc7717a8SGanbold Tsagaankhuu
328dc7717a8SGanbold Tsagaankhuu sc->sc_txfifosz = 64;
329dc7717a8SGanbold Tsagaankhuu sc->sc_rxfifosz = 64;
330dc7717a8SGanbold Tsagaankhuu
331dc7717a8SGanbold Tsagaankhuu device_set_desc(sc->sc_dev, "Qualcomm HSUART");
332dc7717a8SGanbold Tsagaankhuu
333dc7717a8SGanbold Tsagaankhuu return (0);
334dc7717a8SGanbold Tsagaankhuu }
335dc7717a8SGanbold Tsagaankhuu
336dc7717a8SGanbold Tsagaankhuu static int
msm_bus_attach(struct uart_softc * sc)337dc7717a8SGanbold Tsagaankhuu msm_bus_attach(struct uart_softc *sc)
338dc7717a8SGanbold Tsagaankhuu {
339dc7717a8SGanbold Tsagaankhuu struct msm_uart_softc *u = (struct msm_uart_softc *)sc;
340dc7717a8SGanbold Tsagaankhuu struct uart_bas *bas = &sc->sc_bas;
341dc7717a8SGanbold Tsagaankhuu
342dc7717a8SGanbold Tsagaankhuu sc->sc_hwiflow = 0;
343dc7717a8SGanbold Tsagaankhuu sc->sc_hwoflow = 0;
344dc7717a8SGanbold Tsagaankhuu
345dc7717a8SGanbold Tsagaankhuu /* Set TX_READY, TXLEV, RXLEV, RXSTALE */
346dc7717a8SGanbold Tsagaankhuu u->ier = UART_DM_IMR_ENABLED;
347dc7717a8SGanbold Tsagaankhuu
348dc7717a8SGanbold Tsagaankhuu /* Configure Interrupt Mask register IMR */
349dc7717a8SGanbold Tsagaankhuu uart_setreg(bas, UART_DM_IMR, u->ier);
350dc7717a8SGanbold Tsagaankhuu
351dc7717a8SGanbold Tsagaankhuu return (0);
352dc7717a8SGanbold Tsagaankhuu }
353dc7717a8SGanbold Tsagaankhuu
354dc7717a8SGanbold Tsagaankhuu /*
355dc7717a8SGanbold Tsagaankhuu * Write the current transmit buffer to the TX FIFO.
356dc7717a8SGanbold Tsagaankhuu */
357dc7717a8SGanbold Tsagaankhuu static int
msm_bus_transmit(struct uart_softc * sc)358dc7717a8SGanbold Tsagaankhuu msm_bus_transmit(struct uart_softc *sc)
359dc7717a8SGanbold Tsagaankhuu {
360dc7717a8SGanbold Tsagaankhuu struct msm_uart_softc *u = (struct msm_uart_softc *)sc;
361dc7717a8SGanbold Tsagaankhuu struct uart_bas *bas = &sc->sc_bas;
362dc7717a8SGanbold Tsagaankhuu int i;
363dc7717a8SGanbold Tsagaankhuu
364dc7717a8SGanbold Tsagaankhuu uart_lock(sc->sc_hwmtx);
365dc7717a8SGanbold Tsagaankhuu
366dc7717a8SGanbold Tsagaankhuu /* Write some data */
367dc7717a8SGanbold Tsagaankhuu for (i = 0; i < sc->sc_txdatasz; i++) {
368dc7717a8SGanbold Tsagaankhuu /* Write TX data */
369dc7717a8SGanbold Tsagaankhuu msm_putc(bas, sc->sc_txbuf[i]);
370dc7717a8SGanbold Tsagaankhuu uart_barrier(bas);
371dc7717a8SGanbold Tsagaankhuu }
372dc7717a8SGanbold Tsagaankhuu
373dc7717a8SGanbold Tsagaankhuu /* TX FIFO is empty now, enable TX_READY interrupt */
374dc7717a8SGanbold Tsagaankhuu u->ier |= UART_DM_TX_READY;
375dc7717a8SGanbold Tsagaankhuu SETREG(bas, UART_DM_IMR, u->ier);
376dc7717a8SGanbold Tsagaankhuu uart_barrier(bas);
377dc7717a8SGanbold Tsagaankhuu
378dc7717a8SGanbold Tsagaankhuu /*
379dc7717a8SGanbold Tsagaankhuu * Inform upper layer that it is transmitting data to hardware,
380dc7717a8SGanbold Tsagaankhuu * this will be cleared when TXIDLE interrupt occurs.
381dc7717a8SGanbold Tsagaankhuu */
382dc7717a8SGanbold Tsagaankhuu sc->sc_txbusy = 1;
383dc7717a8SGanbold Tsagaankhuu uart_unlock(sc->sc_hwmtx);
384dc7717a8SGanbold Tsagaankhuu
385dc7717a8SGanbold Tsagaankhuu return (0);
386dc7717a8SGanbold Tsagaankhuu }
387dc7717a8SGanbold Tsagaankhuu
388dc7717a8SGanbold Tsagaankhuu static int
msm_bus_setsig(struct uart_softc * sc,int sig)389dc7717a8SGanbold Tsagaankhuu msm_bus_setsig(struct uart_softc *sc, int sig)
390dc7717a8SGanbold Tsagaankhuu {
391dc7717a8SGanbold Tsagaankhuu
392dc7717a8SGanbold Tsagaankhuu return (0);
393dc7717a8SGanbold Tsagaankhuu }
394dc7717a8SGanbold Tsagaankhuu
395dc7717a8SGanbold Tsagaankhuu static int
msm_bus_receive(struct uart_softc * sc)396dc7717a8SGanbold Tsagaankhuu msm_bus_receive(struct uart_softc *sc)
397dc7717a8SGanbold Tsagaankhuu {
398dc7717a8SGanbold Tsagaankhuu struct msm_uart_softc *u = (struct msm_uart_softc *)sc;
399dc7717a8SGanbold Tsagaankhuu struct uart_bas *bas;
400dc7717a8SGanbold Tsagaankhuu int c;
401dc7717a8SGanbold Tsagaankhuu
402dc7717a8SGanbold Tsagaankhuu bas = &sc->sc_bas;
403dc7717a8SGanbold Tsagaankhuu uart_lock(sc->sc_hwmtx);
404dc7717a8SGanbold Tsagaankhuu
405dc7717a8SGanbold Tsagaankhuu /* Initialize Receive Path and interrupt */
406dc7717a8SGanbold Tsagaankhuu SETREG(bas, UART_DM_CR, UART_DM_RESET_STALE_INT);
407dc7717a8SGanbold Tsagaankhuu SETREG(bas, UART_DM_CR, UART_DM_STALE_EVENT_ENABLE);
408dc7717a8SGanbold Tsagaankhuu u->ier |= UART_DM_RXLEV;
409dc7717a8SGanbold Tsagaankhuu SETREG(bas, UART_DM_IMR, u->ier);
410dc7717a8SGanbold Tsagaankhuu
411dc7717a8SGanbold Tsagaankhuu /* Loop over until we are full, or no data is available */
412dc7717a8SGanbold Tsagaankhuu while (uart_getreg(bas, UART_DM_SR) & UART_DM_SR_RXRDY) {
413dc7717a8SGanbold Tsagaankhuu if (uart_rx_full(sc)) {
414dc7717a8SGanbold Tsagaankhuu /* No space left in input buffer */
415dc7717a8SGanbold Tsagaankhuu sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN;
416dc7717a8SGanbold Tsagaankhuu break;
417dc7717a8SGanbold Tsagaankhuu }
418dc7717a8SGanbold Tsagaankhuu
419dc7717a8SGanbold Tsagaankhuu /* Read RX FIFO */
420dc7717a8SGanbold Tsagaankhuu c = uart_getreg(bas, UART_DM_RF(0));
421dc7717a8SGanbold Tsagaankhuu uart_barrier(bas);
422dc7717a8SGanbold Tsagaankhuu
423dc7717a8SGanbold Tsagaankhuu uart_rx_put(sc, c);
424dc7717a8SGanbold Tsagaankhuu }
425dc7717a8SGanbold Tsagaankhuu
426dc7717a8SGanbold Tsagaankhuu uart_unlock(sc->sc_hwmtx);
427dc7717a8SGanbold Tsagaankhuu
428dc7717a8SGanbold Tsagaankhuu return (0);
429dc7717a8SGanbold Tsagaankhuu }
430dc7717a8SGanbold Tsagaankhuu
431dc7717a8SGanbold Tsagaankhuu static int
msm_bus_param(struct uart_softc * sc,int baudrate,int databits,int stopbits,int parity)432dc7717a8SGanbold Tsagaankhuu msm_bus_param(struct uart_softc *sc, int baudrate, int databits,
433dc7717a8SGanbold Tsagaankhuu int stopbits, int parity)
434dc7717a8SGanbold Tsagaankhuu {
435dc7717a8SGanbold Tsagaankhuu int error;
436dc7717a8SGanbold Tsagaankhuu
437dc7717a8SGanbold Tsagaankhuu if (sc->sc_bas.rclk == 0)
438dc7717a8SGanbold Tsagaankhuu sc->sc_bas.rclk = DEF_CLK;
439dc7717a8SGanbold Tsagaankhuu
440dc7717a8SGanbold Tsagaankhuu KASSERT(sc->sc_bas.rclk != 0, ("msm_init: Invalid rclk"));
441dc7717a8SGanbold Tsagaankhuu
442dc7717a8SGanbold Tsagaankhuu uart_lock(sc->sc_hwmtx);
443dc7717a8SGanbold Tsagaankhuu error = msm_uart_param(&sc->sc_bas, baudrate, databits, stopbits,
444dc7717a8SGanbold Tsagaankhuu parity);
445dc7717a8SGanbold Tsagaankhuu uart_unlock(sc->sc_hwmtx);
446dc7717a8SGanbold Tsagaankhuu
447dc7717a8SGanbold Tsagaankhuu return (error);
448dc7717a8SGanbold Tsagaankhuu }
449dc7717a8SGanbold Tsagaankhuu
450dc7717a8SGanbold Tsagaankhuu static int
msm_bus_ipend(struct uart_softc * sc)451dc7717a8SGanbold Tsagaankhuu msm_bus_ipend(struct uart_softc *sc)
452dc7717a8SGanbold Tsagaankhuu {
453dc7717a8SGanbold Tsagaankhuu struct msm_uart_softc *u = (struct msm_uart_softc *)sc;
454dc7717a8SGanbold Tsagaankhuu struct uart_bas *bas = &sc->sc_bas;
455dc7717a8SGanbold Tsagaankhuu uint32_t isr;
456dc7717a8SGanbold Tsagaankhuu int ipend;
457dc7717a8SGanbold Tsagaankhuu
458dc7717a8SGanbold Tsagaankhuu uart_lock(sc->sc_hwmtx);
459dc7717a8SGanbold Tsagaankhuu
460dc7717a8SGanbold Tsagaankhuu /* Get ISR status */
461dc7717a8SGanbold Tsagaankhuu isr = GETREG(bas, UART_DM_MISR);
462dc7717a8SGanbold Tsagaankhuu
463dc7717a8SGanbold Tsagaankhuu ipend = 0;
464dc7717a8SGanbold Tsagaankhuu
465dc7717a8SGanbold Tsagaankhuu /* Uart RX starting, notify upper layer */
466dc7717a8SGanbold Tsagaankhuu if (isr & UART_DM_RXLEV) {
467dc7717a8SGanbold Tsagaankhuu u->ier &= ~UART_DM_RXLEV;
468dc7717a8SGanbold Tsagaankhuu SETREG(bas, UART_DM_IMR, u->ier);
469dc7717a8SGanbold Tsagaankhuu uart_barrier(bas);
470dc7717a8SGanbold Tsagaankhuu ipend |= SER_INT_RXREADY;
471dc7717a8SGanbold Tsagaankhuu }
472dc7717a8SGanbold Tsagaankhuu
473dc7717a8SGanbold Tsagaankhuu /* Stale RX interrupt */
474dc7717a8SGanbold Tsagaankhuu if (isr & UART_DM_RXSTALE) {
475dc7717a8SGanbold Tsagaankhuu /* Disable and reset it */
476dc7717a8SGanbold Tsagaankhuu SETREG(bas, UART_DM_CR, UART_DM_STALE_EVENT_DISABLE);
477dc7717a8SGanbold Tsagaankhuu SETREG(bas, UART_DM_CR, UART_DM_RESET_STALE_INT);
478dc7717a8SGanbold Tsagaankhuu uart_barrier(bas);
479dc7717a8SGanbold Tsagaankhuu ipend |= SER_INT_RXREADY;
480dc7717a8SGanbold Tsagaankhuu }
481dc7717a8SGanbold Tsagaankhuu
482dc7717a8SGanbold Tsagaankhuu /* TX READY interrupt */
483dc7717a8SGanbold Tsagaankhuu if (isr & UART_DM_TX_READY) {
484dc7717a8SGanbold Tsagaankhuu /* Clear TX Ready */
485dc7717a8SGanbold Tsagaankhuu SETREG(bas, UART_DM_CR, UART_DM_CLEAR_TX_READY);
486dc7717a8SGanbold Tsagaankhuu
487dc7717a8SGanbold Tsagaankhuu /* Disable TX_READY */
488dc7717a8SGanbold Tsagaankhuu u->ier &= ~UART_DM_TX_READY;
489dc7717a8SGanbold Tsagaankhuu SETREG(bas, UART_DM_IMR, u->ier);
490dc7717a8SGanbold Tsagaankhuu uart_barrier(bas);
491dc7717a8SGanbold Tsagaankhuu
492dc7717a8SGanbold Tsagaankhuu if (sc->sc_txbusy != 0)
493dc7717a8SGanbold Tsagaankhuu ipend |= SER_INT_TXIDLE;
494dc7717a8SGanbold Tsagaankhuu }
495dc7717a8SGanbold Tsagaankhuu
496dc7717a8SGanbold Tsagaankhuu if (isr & UART_DM_TXLEV) {
497dc7717a8SGanbold Tsagaankhuu /* TX FIFO is empty */
498dc7717a8SGanbold Tsagaankhuu u->ier &= ~UART_DM_TXLEV;
499dc7717a8SGanbold Tsagaankhuu SETREG(bas, UART_DM_IMR, u->ier);
500dc7717a8SGanbold Tsagaankhuu uart_barrier(bas);
501dc7717a8SGanbold Tsagaankhuu
502dc7717a8SGanbold Tsagaankhuu if (sc->sc_txbusy != 0)
503dc7717a8SGanbold Tsagaankhuu ipend |= SER_INT_TXIDLE;
504dc7717a8SGanbold Tsagaankhuu }
505dc7717a8SGanbold Tsagaankhuu
506dc7717a8SGanbold Tsagaankhuu uart_unlock(sc->sc_hwmtx);
507dc7717a8SGanbold Tsagaankhuu return (ipend);
508dc7717a8SGanbold Tsagaankhuu }
509dc7717a8SGanbold Tsagaankhuu
510dc7717a8SGanbold Tsagaankhuu static int
msm_bus_flush(struct uart_softc * sc,int what)511dc7717a8SGanbold Tsagaankhuu msm_bus_flush(struct uart_softc *sc, int what)
512dc7717a8SGanbold Tsagaankhuu {
513dc7717a8SGanbold Tsagaankhuu
514dc7717a8SGanbold Tsagaankhuu return (0);
515dc7717a8SGanbold Tsagaankhuu }
516dc7717a8SGanbold Tsagaankhuu
517dc7717a8SGanbold Tsagaankhuu static int
msm_bus_getsig(struct uart_softc * sc)518dc7717a8SGanbold Tsagaankhuu msm_bus_getsig(struct uart_softc *sc)
519dc7717a8SGanbold Tsagaankhuu {
520dc7717a8SGanbold Tsagaankhuu
521dc7717a8SGanbold Tsagaankhuu return (0);
522dc7717a8SGanbold Tsagaankhuu }
523dc7717a8SGanbold Tsagaankhuu
524dc7717a8SGanbold Tsagaankhuu static int
msm_bus_ioctl(struct uart_softc * sc,int request,intptr_t data)525dc7717a8SGanbold Tsagaankhuu msm_bus_ioctl(struct uart_softc *sc, int request, intptr_t data)
526dc7717a8SGanbold Tsagaankhuu {
527dc7717a8SGanbold Tsagaankhuu
528dc7717a8SGanbold Tsagaankhuu return (EINVAL);
529dc7717a8SGanbold Tsagaankhuu }
530dc7717a8SGanbold Tsagaankhuu
531dc7717a8SGanbold Tsagaankhuu static void
msm_bus_grab(struct uart_softc * sc)532dc7717a8SGanbold Tsagaankhuu msm_bus_grab(struct uart_softc *sc)
533dc7717a8SGanbold Tsagaankhuu {
534dc7717a8SGanbold Tsagaankhuu struct uart_bas *bas = &sc->sc_bas;
535dc7717a8SGanbold Tsagaankhuu
536dc7717a8SGanbold Tsagaankhuu /*
537dc7717a8SGanbold Tsagaankhuu * XXX: Turn off all interrupts to enter polling mode. Leave the
538dc7717a8SGanbold Tsagaankhuu * saved mask alone. We'll restore whatever it was in ungrab.
539dc7717a8SGanbold Tsagaankhuu */
540dc7717a8SGanbold Tsagaankhuu uart_lock(sc->sc_hwmtx);
541dc7717a8SGanbold Tsagaankhuu SETREG(bas, UART_DM_CR, UART_DM_RESET_STALE_INT);
542dc7717a8SGanbold Tsagaankhuu SETREG(bas, UART_DM_IMR, 0);
543dc7717a8SGanbold Tsagaankhuu uart_barrier(bas);
544dc7717a8SGanbold Tsagaankhuu uart_unlock(sc->sc_hwmtx);
545dc7717a8SGanbold Tsagaankhuu }
546dc7717a8SGanbold Tsagaankhuu
547dc7717a8SGanbold Tsagaankhuu static void
msm_bus_ungrab(struct uart_softc * sc)548dc7717a8SGanbold Tsagaankhuu msm_bus_ungrab(struct uart_softc *sc)
549dc7717a8SGanbold Tsagaankhuu {
550dc7717a8SGanbold Tsagaankhuu struct msm_uart_softc *u = (struct msm_uart_softc *)sc;
551dc7717a8SGanbold Tsagaankhuu struct uart_bas *bas = &sc->sc_bas;
552dc7717a8SGanbold Tsagaankhuu
553dc7717a8SGanbold Tsagaankhuu /*
554dc7717a8SGanbold Tsagaankhuu * Restore previous interrupt mask
555dc7717a8SGanbold Tsagaankhuu */
556dc7717a8SGanbold Tsagaankhuu uart_lock(sc->sc_hwmtx);
557dc7717a8SGanbold Tsagaankhuu SETREG(bas, UART_DM_IMR, u->ier);
558dc7717a8SGanbold Tsagaankhuu uart_barrier(bas);
559dc7717a8SGanbold Tsagaankhuu uart_unlock(sc->sc_hwmtx);
560dc7717a8SGanbold Tsagaankhuu }
561dc7717a8SGanbold Tsagaankhuu
5623bb693afSIan Lepore static struct uart_class uart_msm_class = {
563dc7717a8SGanbold Tsagaankhuu "msm",
564dc7717a8SGanbold Tsagaankhuu msm_methods,
565dc7717a8SGanbold Tsagaankhuu sizeof(struct msm_uart_softc),
566dc7717a8SGanbold Tsagaankhuu .uc_ops = &uart_msm_ops,
567dc7717a8SGanbold Tsagaankhuu .uc_range = 8,
568dc7717a8SGanbold Tsagaankhuu .uc_rclk = DEF_CLK,
569405ada37SAndrew Turner .uc_rshift = 0
570dc7717a8SGanbold Tsagaankhuu };
5713bb693afSIan Lepore
5723bb693afSIan Lepore static struct ofw_compat_data compat_data[] = {
573*9f7743f2SRuslan Bukin {"qcom,msm-uartdm-v1.4", (uintptr_t)&uart_msm_class},
5743bb693afSIan Lepore {"qcom,msm-uartdm", (uintptr_t)&uart_msm_class},
5753bb693afSIan Lepore {NULL, (uintptr_t)NULL},
5763bb693afSIan Lepore };
5773bb693afSIan Lepore UART_FDT_CLASS_AND_DEVICE(compat_data);
578