1/*-
2 * Copyright (c) 2012, 2013 The FreeBSD Foundation
3 *
4 * This software was developed by Oleksandr Rybalko under sponsorship
5 * from the FreeBSD Foundation.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1.	Redistributions of source code must retain the above copyright
11 *	notice, this list of conditions and the following disclaimer.
12 * 2.	Redistributions in binary form must reproduce the above copyright
13 *	notice, this list of conditions and the following disclaimer in the
14 *	documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29/* Simple UART console driver for Freescale i.MX515 */
30
31#include <sys/types.h>
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/cons.h>
35#include <sys/consio.h>
36#include <sys/kernel.h>
37
38/* Allow it to be predefined, to be able to use another UART for console */
39#ifndef	IMX_UART_BASE
40#define	IMX_UART_BASE	0xe3fbc000 /* imx51 UART1 */
41#endif
42
43#define	IMX_RXD			0x00
44#define	IMX_TXD			0x40
45
46#define	IMX_UFCR		0x90
47#define	IMX_USR1		0x94
48#define	IMX_USR1_TRDY		(1 << 13)
49
50#define	IMX_USR2		0x98
51#define	IMX_USR2_RDR		(1 << 0)
52#define	IMX_USR2_TXFE		(1 << 14)
53#define	IMX_USR2_TXDC		(1 << 3)
54
55#define	IMX_UTS			0xb4
56#define	IMX_UTS_TXFULL		(1 << 4)
57
58/*
59 * The base address of the uart registers.
60 *
61 * This is global so that it can be changed on the fly from the outside.  For
62 * example, set imx_uart_base=physaddr and then call cninit() as the first two
63 * lines of initarm() and enjoy printf() availability through the tricky bits of
64 * startup.  After initarm() switches from physical to virtual addressing, just
65 * set imx_uart_base=virtaddr and printf keeps working.
66 */
67uint32_t imx_uart_base = IMX_UART_BASE;
68
69/*
70 * uart related funcs
71 */
72static uint32_t
73ub_getreg(uint32_t off)
74{
75
76	return *((volatile uint32_t *)(imx_uart_base + off));
77}
78
79static void
80ub_setreg(uint32_t off, uint32_t val)
81{
82
83	*((volatile uint32_t *)(imx_uart_base + off)) = val;
84}
85
86static int
87ub_tstc(void)
88{
89
90	return ((ub_getreg(IMX_USR2) & IMX_USR2_RDR) ? 1 : 0);
91}
92
93static int
94ub_getc(void)
95{
96
97	while (!ub_tstc());
98		__asm __volatile("nop");
99
100	return (ub_getreg(IMX_RXD) & 0xff);
101}
102
103static void
104ub_putc(unsigned char c)
105{
106
107	if (c == '\n')
108		ub_putc('\r');
109
110	while (ub_getreg(IMX_UTS) & IMX_UTS_TXFULL)
111		__asm __volatile("nop");
112
113	ub_setreg(IMX_TXD, c);
114}
115
116static cn_probe_t	uart_cnprobe;
117static cn_init_t	uart_cninit;
118static cn_term_t	uart_cnterm;
119static cn_getc_t	uart_cngetc;
120static cn_putc_t	uart_cnputc;
121static cn_grab_t	uart_cngrab;
122static cn_ungrab_t	uart_cnungrab;
123
124static void
125uart_cngrab(struct consdev *cp)
126{
127
128}
129
130static void
131uart_cnungrab(struct consdev *cp)
132{
133
134}
135
136static void
137uart_cnprobe(struct consdev *cp)
138{
139
140        sprintf(cp->cn_name, "uart");
141        cp->cn_pri = CN_NORMAL;
142}
143
144static void
145uart_cninit(struct consdev *cp)
146{
147
148        /* Init fifo trigger levels to 32 bytes, refclock div to 2. */
149	ub_setreg(IMX_UFCR, 0x00004210);
150}
151
152static void
153uart_cnputc(struct consdev *cp, int c)
154{
155
156	ub_putc(c);
157}
158
159static int
160uart_cngetc(struct consdev * cp)
161{
162
163	return ub_getc();
164}
165
166static void
167uart_cnterm(struct consdev * cp)
168{
169
170}
171
172CONSOLE_DRIVER(uart);
173