]>
Commit | Line | Data |
---|---|---|
0de653d8 JL |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
3 | * (C) Copyright 2020 Cortina-Access Ltd. | |
4 | * Common UART Driver for Cortina Access CAxxxx line of SoCs | |
5 | * | |
6 | */ | |
7 | ||
8 | #include <common.h> | |
9 | #include <dm.h> | |
10 | #include <errno.h> | |
11 | #include <watchdog.h> | |
12 | #include <asm/io.h> | |
13 | #include <serial.h> | |
cd93d625 | 14 | #include <linux/bitops.h> |
0de653d8 JL |
15 | #include <linux/compiler.h> |
16 | ||
17 | /* Register definitions */ | |
18 | #define UCFG 0x00 /* UART config register */ | |
19 | #define UFC 0x04 /* Flow Control */ | |
20 | #define URX_SAMPLE 0x08 /* UART RX Sample register */ | |
21 | #define URT_TUNE 0x0C /* Fine tune of UART clk */ | |
22 | #define UTX_DATA 0x10 /* UART TX Character data */ | |
23 | #define URX_DATA 0x14 /* UART RX Character data */ | |
24 | #define UINFO 0x18 /* UART Info */ | |
25 | #define UINT_EN0 0x1C /* UART Interrupt enable 0 */ | |
26 | #define UINT_EN1 0x20 /* UART Interrupt enable 1 */ | |
27 | #define UINT0 0x24 /* UART Interrupt 0 setting/clearing */ | |
28 | #define UINT1 0x28 /* UART Interrupt 1 setting/clearing */ | |
29 | #define UINT_STAT 0x2C /* UART Interrupt Status */ | |
30 | ||
31 | /* UART Control Register Bit Fields */ | |
32 | #define UCFG_BAUD_COUNT_MASK 0xFFFFFF00 | |
33 | #define UCFG_BAUD_COUNT(x) ((x << 8) & UCFG_BAUD_COUNT_MASK) | |
34 | #define UCFG_EN BIT(7) | |
35 | #define UCFG_RX_EN BIT(6) | |
36 | #define UCFG_TX_EN BIT(5) | |
37 | #define UCFG_PARITY_EN BIT(4) | |
38 | #define UCFG_PARITY_SEL BIT(3) | |
39 | #define UCFG_2STOP_BIT BIT(2) | |
40 | #define UCFG_CNT1 BIT(1) | |
41 | #define UCFG_CNT0 BIT(0) | |
42 | #define UCFG_CHAR_5 0 | |
43 | #define UCFG_CHAR_6 1 | |
44 | #define UCFG_CHAR_7 2 | |
45 | #define UCFG_CHAR_8 3 | |
46 | ||
47 | #define UINFO_TX_FIFO_EMPTY BIT(3) | |
48 | #define UINFO_TX_FIFO_FULL BIT(2) | |
49 | #define UINFO_RX_FIFO_EMPTY BIT(1) | |
50 | #define UINFO_RX_FIFO_FULL BIT(0) | |
51 | ||
52 | #define UINT_RX_NON_EMPTY BIT(6) | |
53 | #define UINT_TX_EMPTY BIT(5) | |
54 | #define UINT_RX_UNDERRUN BIT(4) | |
55 | #define UINT_RX_OVERRUN BIT(3) | |
56 | #define UINT_RX_PARITY_ERR BIT(2) | |
57 | #define UINT_RX_STOP_ERR BIT(1) | |
58 | #define UINT_TX_OVERRUN BIT(0) | |
59 | #define UINT_MASK_ALL 0x7F | |
60 | ||
61 | struct ca_uart_priv { | |
62 | void __iomem *base; | |
63 | }; | |
64 | ||
65 | int ca_serial_setbrg(struct udevice *dev, int baudrate) | |
66 | { | |
67 | struct ca_uart_priv *priv = dev_get_priv(dev); | |
68 | unsigned int uart_ctrl, baud, sample; | |
69 | ||
70 | baud = CORTINA_UART_CLOCK / baudrate; | |
71 | ||
72 | uart_ctrl = readl(priv->base + UCFG); | |
73 | uart_ctrl &= ~UCFG_BAUD_COUNT_MASK; | |
74 | uart_ctrl |= UCFG_BAUD_COUNT(baud); | |
75 | writel(uart_ctrl, priv->base + UCFG); | |
76 | ||
77 | sample = baud / 2; | |
78 | sample = (sample < 7) ? 7 : sample; | |
79 | writel(sample, priv->base + URX_SAMPLE); | |
80 | ||
81 | return 0; | |
82 | } | |
83 | ||
84 | static int ca_serial_getc(struct udevice *dev) | |
85 | { | |
86 | struct ca_uart_priv *priv = dev_get_priv(dev); | |
87 | int ch; | |
88 | ||
89 | ch = readl(priv->base + URX_DATA) & 0xFF; | |
90 | ||
91 | return (int)ch; | |
92 | } | |
93 | ||
94 | static int ca_serial_putc(struct udevice *dev, const char ch) | |
95 | { | |
96 | struct ca_uart_priv *priv = dev_get_priv(dev); | |
97 | unsigned int status; | |
98 | ||
99 | /* Retry if TX FIFO full */ | |
100 | status = readl(priv->base + UINFO); | |
101 | if (status & UINFO_TX_FIFO_FULL) | |
102 | return -EAGAIN; | |
103 | ||
104 | writel(ch, priv->base + UTX_DATA); | |
105 | ||
106 | return 0; | |
107 | } | |
108 | ||
109 | static int ca_serial_pending(struct udevice *dev, bool input) | |
110 | { | |
111 | struct ca_uart_priv *priv = dev_get_priv(dev); | |
112 | unsigned int status; | |
113 | ||
114 | status = readl(priv->base + UINFO); | |
115 | ||
116 | if (input) | |
117 | return (status & UINFO_RX_FIFO_EMPTY) ? 0 : 1; | |
118 | else | |
119 | return (status & UINFO_TX_FIFO_FULL) ? 1 : 0; | |
120 | } | |
121 | ||
122 | static int ca_serial_probe(struct udevice *dev) | |
123 | { | |
124 | struct ca_uart_priv *priv = dev_get_priv(dev); | |
125 | u32 uart_ctrl; | |
126 | ||
127 | /* Set data, parity and stop bits */ | |
128 | uart_ctrl = UCFG_EN | UCFG_TX_EN | UCFG_RX_EN | UCFG_CHAR_8; | |
129 | writel(uart_ctrl, priv->base + UCFG); | |
130 | ||
131 | return 0; | |
132 | } | |
133 | ||
134 | static int ca_serial_ofdata_to_platdata(struct udevice *dev) | |
135 | { | |
136 | struct ca_uart_priv *priv = dev_get_priv(dev); | |
137 | ||
138 | priv->base = dev_remap_addr_index(dev, 0); | |
139 | if (!priv->base) | |
140 | return -ENOENT; | |
141 | ||
142 | return 0; | |
143 | } | |
144 | ||
145 | static const struct dm_serial_ops ca_serial_ops = { | |
146 | .putc = ca_serial_putc, | |
147 | .pending = ca_serial_pending, | |
148 | .getc = ca_serial_getc, | |
149 | .setbrg = ca_serial_setbrg, | |
150 | }; | |
151 | ||
152 | static const struct udevice_id ca_serial_ids[] = { | |
153 | {.compatible = "cortina,ca-uart"}, | |
154 | {} | |
155 | }; | |
156 | ||
157 | U_BOOT_DRIVER(serial_cortina) = { | |
158 | .name = "serial_cortina", | |
159 | .id = UCLASS_SERIAL, | |
160 | .of_match = ca_serial_ids, | |
161 | .ofdata_to_platdata = ca_serial_ofdata_to_platdata, | |
162 | .priv_auto_alloc_size = sizeof(struct ca_uart_priv), | |
163 | .probe = ca_serial_probe, | |
164 | .ops = &ca_serial_ops | |
165 | }; |