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