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