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