xref: /openbmc/u-boot/drivers/serial/serial_owl.c (revision 1d6edcbfed2af33c748f2beb399810a0441888da)
1*6f9347f3SManivannan Sadhasivam // SPDX-License-Identifier: GPL-2.0+
2*6f9347f3SManivannan Sadhasivam /*
3*6f9347f3SManivannan Sadhasivam  * Actions Semi OWL SoCs UART driver
4*6f9347f3SManivannan Sadhasivam  *
5*6f9347f3SManivannan Sadhasivam  * Copyright (C) 2015 Actions Semi Co., Ltd.
6*6f9347f3SManivannan Sadhasivam  * Copyright (C) 2018 Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
7*6f9347f3SManivannan Sadhasivam  */
8*6f9347f3SManivannan Sadhasivam 
9*6f9347f3SManivannan Sadhasivam #include <common.h>
10*6f9347f3SManivannan Sadhasivam #include <clk.h>
11*6f9347f3SManivannan Sadhasivam #include <dm.h>
12*6f9347f3SManivannan Sadhasivam #include <errno.h>
13*6f9347f3SManivannan Sadhasivam #include <fdtdec.h>
14*6f9347f3SManivannan Sadhasivam #include <serial.h>
15*6f9347f3SManivannan Sadhasivam #include <asm/io.h>
16*6f9347f3SManivannan Sadhasivam #include <asm/types.h>
17*6f9347f3SManivannan Sadhasivam 
18*6f9347f3SManivannan Sadhasivam /* UART Registers */
19*6f9347f3SManivannan Sadhasivam #define	OWL_UART_CTL			(0x0000)
20*6f9347f3SManivannan Sadhasivam #define	OWL_UART_RXDAT			(0x0004)
21*6f9347f3SManivannan Sadhasivam #define	OWL_UART_TXDAT			(0x0008)
22*6f9347f3SManivannan Sadhasivam #define	OWL_UART_STAT			(0x000C)
23*6f9347f3SManivannan Sadhasivam 
24*6f9347f3SManivannan Sadhasivam /* UART_CTL Register Definitions */
25*6f9347f3SManivannan Sadhasivam #define	OWL_UART_CTL_PRS_NONE		GENMASK(6, 4)
26*6f9347f3SManivannan Sadhasivam #define	OWL_UART_CTL_STPS		BIT(2)
27*6f9347f3SManivannan Sadhasivam #define	OWL_UART_CTL_DWLS		3
28*6f9347f3SManivannan Sadhasivam 
29*6f9347f3SManivannan Sadhasivam /* UART_STAT Register Definitions */
30*6f9347f3SManivannan Sadhasivam #define	OWL_UART_STAT_TFES		BIT(10)	/* TX FIFO Empty Status	*/
31*6f9347f3SManivannan Sadhasivam #define	OWL_UART_STAT_RFFS		BIT(9)	/* RX FIFO full	Status */
32*6f9347f3SManivannan Sadhasivam #define	OWL_UART_STAT_TFFU		BIT(6)	/* TX FIFO full	Status */
33*6f9347f3SManivannan Sadhasivam #define	OWL_UART_STAT_RFEM		BIT(5)	/* RX FIFO Empty Status	*/
34*6f9347f3SManivannan Sadhasivam 
35*6f9347f3SManivannan Sadhasivam struct owl_serial_priv {
36*6f9347f3SManivannan Sadhasivam 	phys_addr_t base;
37*6f9347f3SManivannan Sadhasivam };
38*6f9347f3SManivannan Sadhasivam 
owl_serial_setbrg(struct udevice * dev,int baudrate)39*6f9347f3SManivannan Sadhasivam int owl_serial_setbrg(struct udevice *dev, int baudrate)
40*6f9347f3SManivannan Sadhasivam {
41*6f9347f3SManivannan Sadhasivam 	/* Driver supports only fixed baudrate */
42*6f9347f3SManivannan Sadhasivam 	return 0;
43*6f9347f3SManivannan Sadhasivam }
44*6f9347f3SManivannan Sadhasivam 
owl_serial_getc(struct udevice * dev)45*6f9347f3SManivannan Sadhasivam static int owl_serial_getc(struct udevice *dev)
46*6f9347f3SManivannan Sadhasivam {
47*6f9347f3SManivannan Sadhasivam 	struct owl_serial_priv *priv = dev_get_priv(dev);
48*6f9347f3SManivannan Sadhasivam 
49*6f9347f3SManivannan Sadhasivam 	if (readl(priv->base + OWL_UART_STAT) & OWL_UART_STAT_RFEM)
50*6f9347f3SManivannan Sadhasivam 		return -EAGAIN;
51*6f9347f3SManivannan Sadhasivam 
52*6f9347f3SManivannan Sadhasivam 	return (int)(readl(priv->base +	OWL_UART_RXDAT));
53*6f9347f3SManivannan Sadhasivam }
54*6f9347f3SManivannan Sadhasivam 
owl_serial_putc(struct udevice * dev,const char ch)55*6f9347f3SManivannan Sadhasivam static int owl_serial_putc(struct udevice *dev,	const char ch)
56*6f9347f3SManivannan Sadhasivam {
57*6f9347f3SManivannan Sadhasivam 	struct owl_serial_priv *priv = dev_get_priv(dev);
58*6f9347f3SManivannan Sadhasivam 
59*6f9347f3SManivannan Sadhasivam 	if (readl(priv->base + OWL_UART_STAT) & OWL_UART_STAT_TFFU)
60*6f9347f3SManivannan Sadhasivam 		return -EAGAIN;
61*6f9347f3SManivannan Sadhasivam 
62*6f9347f3SManivannan Sadhasivam 	writel(ch, priv->base +	OWL_UART_TXDAT);
63*6f9347f3SManivannan Sadhasivam 
64*6f9347f3SManivannan Sadhasivam 	return 0;
65*6f9347f3SManivannan Sadhasivam }
66*6f9347f3SManivannan Sadhasivam 
owl_serial_pending(struct udevice * dev,bool input)67*6f9347f3SManivannan Sadhasivam static int owl_serial_pending(struct udevice *dev, bool	input)
68*6f9347f3SManivannan Sadhasivam {
69*6f9347f3SManivannan Sadhasivam 	struct owl_serial_priv *priv = dev_get_priv(dev);
70*6f9347f3SManivannan Sadhasivam 	unsigned int stat = readl(priv->base + OWL_UART_STAT);
71*6f9347f3SManivannan Sadhasivam 
72*6f9347f3SManivannan Sadhasivam 	if (input)
73*6f9347f3SManivannan Sadhasivam 		return !(stat &	OWL_UART_STAT_RFEM);
74*6f9347f3SManivannan Sadhasivam 	else
75*6f9347f3SManivannan Sadhasivam 		return !(stat &	OWL_UART_STAT_TFES);
76*6f9347f3SManivannan Sadhasivam }
77*6f9347f3SManivannan Sadhasivam 
owl_serial_probe(struct udevice * dev)78*6f9347f3SManivannan Sadhasivam static int owl_serial_probe(struct udevice *dev)
79*6f9347f3SManivannan Sadhasivam {
80*6f9347f3SManivannan Sadhasivam 	struct owl_serial_priv *priv = dev_get_priv(dev);
81*6f9347f3SManivannan Sadhasivam 	struct clk clk;
82*6f9347f3SManivannan Sadhasivam 	u32 uart_ctl;
83*6f9347f3SManivannan Sadhasivam 	int ret;
84*6f9347f3SManivannan Sadhasivam 
85*6f9347f3SManivannan Sadhasivam 	/* Set data, parity and stop bits */
86*6f9347f3SManivannan Sadhasivam 	uart_ctl = readl(priv->base + OWL_UART_CTL);
87*6f9347f3SManivannan Sadhasivam 	uart_ctl &= ~(OWL_UART_CTL_PRS_NONE);
88*6f9347f3SManivannan Sadhasivam 	uart_ctl &= ~(OWL_UART_CTL_STPS);
89*6f9347f3SManivannan Sadhasivam 	uart_ctl |= OWL_UART_CTL_DWLS;
90*6f9347f3SManivannan Sadhasivam 	writel(uart_ctl, priv->base + OWL_UART_CTL);
91*6f9347f3SManivannan Sadhasivam 
92*6f9347f3SManivannan Sadhasivam 	/* Enable UART clock */
93*6f9347f3SManivannan Sadhasivam 	ret = clk_get_by_index(dev, 0, &clk);
94*6f9347f3SManivannan Sadhasivam 	if (ret < 0)
95*6f9347f3SManivannan Sadhasivam 		return ret;
96*6f9347f3SManivannan Sadhasivam 
97*6f9347f3SManivannan Sadhasivam 	ret = clk_enable(&clk);
98*6f9347f3SManivannan Sadhasivam 	if (ret < 0)
99*6f9347f3SManivannan Sadhasivam 		return ret;
100*6f9347f3SManivannan Sadhasivam 
101*6f9347f3SManivannan Sadhasivam 	return 0;
102*6f9347f3SManivannan Sadhasivam }
103*6f9347f3SManivannan Sadhasivam 
owl_serial_ofdata_to_platdata(struct udevice * dev)104*6f9347f3SManivannan Sadhasivam static int owl_serial_ofdata_to_platdata(struct	udevice	*dev)
105*6f9347f3SManivannan Sadhasivam {
106*6f9347f3SManivannan Sadhasivam 	struct owl_serial_priv *priv = dev_get_priv(dev);
107*6f9347f3SManivannan Sadhasivam 
108*6f9347f3SManivannan Sadhasivam 	priv->base = dev_read_addr(dev);
109*6f9347f3SManivannan Sadhasivam 	if (priv->base == FDT_ADDR_T_NONE)
110*6f9347f3SManivannan Sadhasivam 		return -EINVAL;
111*6f9347f3SManivannan Sadhasivam 
112*6f9347f3SManivannan Sadhasivam 	return 0;
113*6f9347f3SManivannan Sadhasivam }
114*6f9347f3SManivannan Sadhasivam 
115*6f9347f3SManivannan Sadhasivam static const struct dm_serial_ops owl_serial_ops = {
116*6f9347f3SManivannan Sadhasivam 	.putc =	owl_serial_putc,
117*6f9347f3SManivannan Sadhasivam 	.pending = owl_serial_pending,
118*6f9347f3SManivannan Sadhasivam 	.getc =	owl_serial_getc,
119*6f9347f3SManivannan Sadhasivam 	.setbrg	= owl_serial_setbrg,
120*6f9347f3SManivannan Sadhasivam };
121*6f9347f3SManivannan Sadhasivam 
122*6f9347f3SManivannan Sadhasivam static const struct udevice_id owl_serial_ids[] = {
123*6f9347f3SManivannan Sadhasivam 	{ .compatible =	"actions,s900-serial" },
124*6f9347f3SManivannan Sadhasivam 	{ }
125*6f9347f3SManivannan Sadhasivam };
126*6f9347f3SManivannan Sadhasivam 
127*6f9347f3SManivannan Sadhasivam U_BOOT_DRIVER(serial_owl) = {
128*6f9347f3SManivannan Sadhasivam 	.name = "serial_owl",
129*6f9347f3SManivannan Sadhasivam 	.id = UCLASS_SERIAL,
130*6f9347f3SManivannan Sadhasivam 	.of_match = owl_serial_ids,
131*6f9347f3SManivannan Sadhasivam 	.ofdata_to_platdata = owl_serial_ofdata_to_platdata,
132*6f9347f3SManivannan Sadhasivam 	.priv_auto_alloc_size =	sizeof(struct owl_serial_priv),
133*6f9347f3SManivannan Sadhasivam 	.probe = owl_serial_probe,
134*6f9347f3SManivannan Sadhasivam 	.ops = &owl_serial_ops,
135*6f9347f3SManivannan Sadhasivam };
136