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