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