xref: /rk3399_rockchip-uboot/drivers/serial/serial_meson.c (revision bfcef28ae4cf04e7c1fd3aea1d60a17bd046f153)
1*bfcef28aSBeniamino Galvani /*
2*bfcef28aSBeniamino Galvani  * (C) Copyright 2016 Beniamino Galvani <b.galvani@gmail.com>
3*bfcef28aSBeniamino Galvani  *
4*bfcef28aSBeniamino Galvani  * SPDX-License-Identifier:	GPL-2.0+
5*bfcef28aSBeniamino Galvani  */
6*bfcef28aSBeniamino Galvani 
7*bfcef28aSBeniamino Galvani #include <common.h>
8*bfcef28aSBeniamino Galvani #include <dm.h>
9*bfcef28aSBeniamino Galvani #include <errno.h>
10*bfcef28aSBeniamino Galvani #include <fdtdec.h>
11*bfcef28aSBeniamino Galvani #include <linux/compiler.h>
12*bfcef28aSBeniamino Galvani #include <serial.h>
13*bfcef28aSBeniamino Galvani 
14*bfcef28aSBeniamino Galvani DECLARE_GLOBAL_DATA_PTR;
15*bfcef28aSBeniamino Galvani 
16*bfcef28aSBeniamino Galvani struct meson_uart {
17*bfcef28aSBeniamino Galvani 	u32 wfifo;
18*bfcef28aSBeniamino Galvani 	u32 rfifo;
19*bfcef28aSBeniamino Galvani 	u32 control;
20*bfcef28aSBeniamino Galvani 	u32 status;
21*bfcef28aSBeniamino Galvani 	u32 misc;
22*bfcef28aSBeniamino Galvani };
23*bfcef28aSBeniamino Galvani 
24*bfcef28aSBeniamino Galvani struct meson_serial_platdata {
25*bfcef28aSBeniamino Galvani 	struct meson_uart *reg;
26*bfcef28aSBeniamino Galvani };
27*bfcef28aSBeniamino Galvani 
28*bfcef28aSBeniamino Galvani /* AML_UART_STATUS bits */
29*bfcef28aSBeniamino Galvani #define AML_UART_PARITY_ERR		BIT(16)
30*bfcef28aSBeniamino Galvani #define AML_UART_FRAME_ERR		BIT(17)
31*bfcef28aSBeniamino Galvani #define AML_UART_TX_FIFO_WERR		BIT(18)
32*bfcef28aSBeniamino Galvani #define AML_UART_RX_EMPTY		BIT(20)
33*bfcef28aSBeniamino Galvani #define AML_UART_TX_FULL		BIT(21)
34*bfcef28aSBeniamino Galvani #define AML_UART_TX_EMPTY		BIT(22)
35*bfcef28aSBeniamino Galvani #define AML_UART_XMIT_BUSY		BIT(25)
36*bfcef28aSBeniamino Galvani #define AML_UART_ERR			(AML_UART_PARITY_ERR | \
37*bfcef28aSBeniamino Galvani 					 AML_UART_FRAME_ERR  | \
38*bfcef28aSBeniamino Galvani 					 AML_UART_TX_FIFO_WERR)
39*bfcef28aSBeniamino Galvani 
40*bfcef28aSBeniamino Galvani /* AML_UART_CONTROL bits */
41*bfcef28aSBeniamino Galvani #define AML_UART_TX_EN			BIT(12)
42*bfcef28aSBeniamino Galvani #define AML_UART_RX_EN			BIT(13)
43*bfcef28aSBeniamino Galvani #define AML_UART_TX_RST			BIT(22)
44*bfcef28aSBeniamino Galvani #define AML_UART_RX_RST			BIT(23)
45*bfcef28aSBeniamino Galvani #define AML_UART_CLR_ERR		BIT(24)
46*bfcef28aSBeniamino Galvani 
47*bfcef28aSBeniamino Galvani static void meson_serial_init(struct meson_uart *uart)
48*bfcef28aSBeniamino Galvani {
49*bfcef28aSBeniamino Galvani 	u32 val;
50*bfcef28aSBeniamino Galvani 
51*bfcef28aSBeniamino Galvani 	val = readl(&uart->control);
52*bfcef28aSBeniamino Galvani 	val |= (AML_UART_RX_RST | AML_UART_TX_RST | AML_UART_CLR_ERR);
53*bfcef28aSBeniamino Galvani 	writel(val, &uart->control);
54*bfcef28aSBeniamino Galvani 	val &= ~(AML_UART_RX_RST | AML_UART_TX_RST | AML_UART_CLR_ERR);
55*bfcef28aSBeniamino Galvani 	writel(val, &uart->control);
56*bfcef28aSBeniamino Galvani 	val |= (AML_UART_RX_EN | AML_UART_TX_EN);
57*bfcef28aSBeniamino Galvani 	writel(val, &uart->control);
58*bfcef28aSBeniamino Galvani }
59*bfcef28aSBeniamino Galvani 
60*bfcef28aSBeniamino Galvani static int meson_serial_probe(struct udevice *dev)
61*bfcef28aSBeniamino Galvani {
62*bfcef28aSBeniamino Galvani 	struct meson_serial_platdata *plat = dev->platdata;
63*bfcef28aSBeniamino Galvani 	struct meson_uart *const uart = plat->reg;
64*bfcef28aSBeniamino Galvani 
65*bfcef28aSBeniamino Galvani 	meson_serial_init(uart);
66*bfcef28aSBeniamino Galvani 
67*bfcef28aSBeniamino Galvani 	return 0;
68*bfcef28aSBeniamino Galvani }
69*bfcef28aSBeniamino Galvani 
70*bfcef28aSBeniamino Galvani static int meson_serial_getc(struct udevice *dev)
71*bfcef28aSBeniamino Galvani {
72*bfcef28aSBeniamino Galvani 	struct meson_serial_platdata *plat = dev->platdata;
73*bfcef28aSBeniamino Galvani 	struct meson_uart *const uart = plat->reg;
74*bfcef28aSBeniamino Galvani 
75*bfcef28aSBeniamino Galvani 	if (readl(&uart->status) & AML_UART_RX_EMPTY)
76*bfcef28aSBeniamino Galvani 		return -EAGAIN;
77*bfcef28aSBeniamino Galvani 
78*bfcef28aSBeniamino Galvani 	return readl(&uart->rfifo) & 0xff;
79*bfcef28aSBeniamino Galvani }
80*bfcef28aSBeniamino Galvani 
81*bfcef28aSBeniamino Galvani static int meson_serial_putc(struct udevice *dev, const char ch)
82*bfcef28aSBeniamino Galvani {
83*bfcef28aSBeniamino Galvani 	struct meson_serial_platdata *plat = dev->platdata;
84*bfcef28aSBeniamino Galvani 	struct meson_uart *const uart = plat->reg;
85*bfcef28aSBeniamino Galvani 
86*bfcef28aSBeniamino Galvani 	if (readl(&uart->status) & AML_UART_TX_FULL)
87*bfcef28aSBeniamino Galvani 		return -EAGAIN;
88*bfcef28aSBeniamino Galvani 
89*bfcef28aSBeniamino Galvani 	writel(ch, &uart->wfifo);
90*bfcef28aSBeniamino Galvani 
91*bfcef28aSBeniamino Galvani 	return 0;
92*bfcef28aSBeniamino Galvani }
93*bfcef28aSBeniamino Galvani 
94*bfcef28aSBeniamino Galvani static int meson_serial_pending(struct udevice *dev, bool input)
95*bfcef28aSBeniamino Galvani {
96*bfcef28aSBeniamino Galvani 	struct meson_serial_platdata *plat = dev->platdata;
97*bfcef28aSBeniamino Galvani 	struct meson_uart *const uart = plat->reg;
98*bfcef28aSBeniamino Galvani 	uint32_t status = readl(&uart->status);
99*bfcef28aSBeniamino Galvani 
100*bfcef28aSBeniamino Galvani 	if (input)
101*bfcef28aSBeniamino Galvani 		return !(status & AML_UART_RX_EMPTY);
102*bfcef28aSBeniamino Galvani 	else
103*bfcef28aSBeniamino Galvani 		return !(status & AML_UART_TX_FULL);
104*bfcef28aSBeniamino Galvani }
105*bfcef28aSBeniamino Galvani 
106*bfcef28aSBeniamino Galvani static int meson_serial_ofdata_to_platdata(struct udevice *dev)
107*bfcef28aSBeniamino Galvani {
108*bfcef28aSBeniamino Galvani 	struct meson_serial_platdata *plat = dev->platdata;
109*bfcef28aSBeniamino Galvani 	fdt_addr_t addr;
110*bfcef28aSBeniamino Galvani 
111*bfcef28aSBeniamino Galvani 	addr = dev_get_addr(dev);
112*bfcef28aSBeniamino Galvani 	if (addr == FDT_ADDR_T_NONE)
113*bfcef28aSBeniamino Galvani 		return -EINVAL;
114*bfcef28aSBeniamino Galvani 
115*bfcef28aSBeniamino Galvani 	plat->reg = (struct meson_uart *)addr;
116*bfcef28aSBeniamino Galvani 
117*bfcef28aSBeniamino Galvani 	return 0;
118*bfcef28aSBeniamino Galvani }
119*bfcef28aSBeniamino Galvani 
120*bfcef28aSBeniamino Galvani static const struct dm_serial_ops meson_serial_ops = {
121*bfcef28aSBeniamino Galvani 	.putc = meson_serial_putc,
122*bfcef28aSBeniamino Galvani 	.pending = meson_serial_pending,
123*bfcef28aSBeniamino Galvani 	.getc = meson_serial_getc,
124*bfcef28aSBeniamino Galvani };
125*bfcef28aSBeniamino Galvani 
126*bfcef28aSBeniamino Galvani static const struct udevice_id meson_serial_ids[] = {
127*bfcef28aSBeniamino Galvani 	{ .compatible = "amlogic,meson-uart" },
128*bfcef28aSBeniamino Galvani 	{ }
129*bfcef28aSBeniamino Galvani };
130*bfcef28aSBeniamino Galvani 
131*bfcef28aSBeniamino Galvani U_BOOT_DRIVER(serial_meson) = {
132*bfcef28aSBeniamino Galvani 	.name		= "serial_meson",
133*bfcef28aSBeniamino Galvani 	.id		= UCLASS_SERIAL,
134*bfcef28aSBeniamino Galvani 	.of_match	= meson_serial_ids,
135*bfcef28aSBeniamino Galvani 	.probe		= meson_serial_probe,
136*bfcef28aSBeniamino Galvani 	.ops		= &meson_serial_ops,
137*bfcef28aSBeniamino Galvani 	.flags		= DM_FLAG_PRE_RELOC,
138*bfcef28aSBeniamino Galvani 	.ofdata_to_platdata = meson_serial_ofdata_to_platdata,
139*bfcef28aSBeniamino Galvani 	.platdata_auto_alloc_size = sizeof(struct meson_serial_platdata),
140*bfcef28aSBeniamino Galvani };
141*bfcef28aSBeniamino Galvani 
142*bfcef28aSBeniamino Galvani #ifdef CONFIG_DEBUG_UART_MESON
143*bfcef28aSBeniamino Galvani 
144*bfcef28aSBeniamino Galvani #include <debug_uart.h>
145*bfcef28aSBeniamino Galvani 
146*bfcef28aSBeniamino Galvani static inline void _debug_uart_init(void)
147*bfcef28aSBeniamino Galvani {
148*bfcef28aSBeniamino Galvani }
149*bfcef28aSBeniamino Galvani 
150*bfcef28aSBeniamino Galvani static inline void _debug_uart_putc(int ch)
151*bfcef28aSBeniamino Galvani {
152*bfcef28aSBeniamino Galvani 	struct meson_uart *regs = (struct meson_uart *)CONFIG_DEBUG_UART_BASE;
153*bfcef28aSBeniamino Galvani 
154*bfcef28aSBeniamino Galvani 	while (readl(&regs->status) & AML_UART_TX_FULL)
155*bfcef28aSBeniamino Galvani 		;
156*bfcef28aSBeniamino Galvani 
157*bfcef28aSBeniamino Galvani 	writel(ch, &regs->wfifo);
158*bfcef28aSBeniamino Galvani }
159*bfcef28aSBeniamino Galvani 
160*bfcef28aSBeniamino Galvani DEBUG_UART_FUNCS
161*bfcef28aSBeniamino Galvani 
162*bfcef28aSBeniamino Galvani #endif
163