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