1 /*
2  * xen/drivers/char/mvebu3700-uart.c
3  *
4  * Driver for Marvell MVEBU UART.
5  *
6  * Copyright (c) 2018, Amit Singh Tomar <amittomer25@gmail.com>.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms and conditions of the GNU General Public
10  * License, version 2, as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public
18  * License along with this program; If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #include <xen/irq.h>
22 #include <xen/serial.h>
23 #include <xen/vmap.h>
24 #include <asm/io.h>
25 
26 /* Register offsets */
27 #define UART_RX_REG             0x00
28 
29 #define UART_TX_REG             0x04
30 
31 #define UART_CTRL_REG           0x08
32 #define CTRL_TXFIFO_RST         BIT(15, UL)
33 #define CTRL_RXFIFO_RST         BIT(14, UL)
34 #define CTRL_TX_RDY_INT         BIT(5, UL)
35 #define CTRL_RX_RDY_INT         BIT(4, UL)
36 #define CTRL_BRK_DET_INT        BIT(3, UL)
37 #define CTRL_FRM_ERR_INT        BIT(2, UL)
38 #define CTRL_PAR_ERR_INT        BIT(1, UL)
39 #define CTRL_OVR_ERR_INT        BIT(0, UL)
40 #define CTRL_ERR_INT            (CTRL_BRK_DET_INT | CTRL_FRM_ERR_INT | \
41                                  CTRL_PAR_ERR_INT | CTRL_OVR_ERR_INT)
42 
43 #define UART_STATUS_REG         0x0c
44 #define STATUS_TXFIFO_EMP       BIT(13, UL)
45 #define STATUS_TXFIFO_FUL       BIT(11, UL)
46 #define STATUS_TXFIFO_HFL       BIT(10, UL)
47 #define STATUS_TX_RDY           BIT(5, UL)
48 #define STATUS_RX_RDY           BIT(4, UL)
49 #define STATUS_BRK_DET          BIT(3, UL)
50 #define STATUS_FRM_ERR          BIT(2, UL)
51 #define STATUS_PAR_ERR          BIT(1, UL)
52 #define STATUS_OVR_ERR          BIT(0, UL)
53 #define STATUS_BRK_ERR          (STATUS_BRK_DET | STATUS_FRM_ERR | \
54                                  STATUS_PAR_ERR | STATUS_OVR_ERR)
55 
56 #define TX_FIFO_SIZE            32
57 
58 static struct mvebu3700_uart {
59     unsigned int irq;
60     void __iomem *regs;
61     struct irqaction irqaction;
62     struct vuart_info vuart;
63 } mvebu3700_com = {0};
64 
65 #define mvebu3700_read(uart, off)           readl((uart)->regs + off)
66 #define mvebu3700_write(uart, off, val)     writel(val, (uart->regs) + off)
67 
mvebu3700_uart_interrupt(int irq,void * data,struct cpu_user_regs * regs)68 static void mvebu3700_uart_interrupt(int irq, void *data,
69                                      struct cpu_user_regs *regs)
70 {
71     struct serial_port *port = data;
72     struct mvebu3700_uart *uart = port->uart;
73     uint32_t st = mvebu3700_read(uart, UART_STATUS_REG);
74 
75     if ( st & (STATUS_RX_RDY | STATUS_OVR_ERR | STATUS_FRM_ERR |
76                STATUS_BRK_DET) )
77         serial_rx_interrupt(port, regs);
78 
79     if ( st & STATUS_TX_RDY )
80         serial_tx_interrupt(port, regs);
81 }
82 
mvebu3700_uart_init_preirq(struct serial_port * port)83 static void __init mvebu3700_uart_init_preirq(struct serial_port *port)
84 {
85     struct mvebu3700_uart *uart = port->uart;
86     uint32_t reg;
87 
88     reg = mvebu3700_read(uart, UART_CTRL_REG);
89     reg |= (CTRL_TXFIFO_RST | CTRL_RXFIFO_RST);
90     mvebu3700_write(uart, UART_CTRL_REG, reg);
91 
92     /* Before we make IRQ request, clear the error bits of state register. */
93     reg = mvebu3700_read(uart, UART_STATUS_REG);
94     reg |= STATUS_BRK_ERR;
95     mvebu3700_write(uart, UART_STATUS_REG, reg);
96 
97     /* Clear error interrupts. */
98     mvebu3700_write(uart, UART_CTRL_REG, CTRL_ERR_INT);
99 
100     /* Disable Rx/Tx interrupts. */
101     reg = mvebu3700_read(uart, UART_CTRL_REG);
102     reg &= ~(CTRL_RX_RDY_INT | CTRL_TX_RDY_INT);
103     mvebu3700_write(uart, UART_CTRL_REG, reg);
104 }
105 
mvebu3700_uart_init_postirq(struct serial_port * port)106 static void __init mvebu3700_uart_init_postirq(struct serial_port *port)
107 {
108     struct mvebu3700_uart *uart = port->uart;
109     uint32_t reg;
110 
111     uart->irqaction.handler = mvebu3700_uart_interrupt;
112     uart->irqaction.name    = "mvebu3700_uart";
113     uart->irqaction.dev_id  = port;
114 
115     if ( setup_irq(uart->irq, 0, &uart->irqaction) != 0 )
116     {
117         printk("Failed to allocated mvebu3700_uart IRQ %d\n", uart->irq);
118         return;
119     }
120 
121     /* Make sure Rx/Tx interrupts are enabled now */
122     reg = mvebu3700_read(uart, UART_CTRL_REG);
123     reg |= (CTRL_RX_RDY_INT | CTRL_TX_RDY_INT);
124     mvebu3700_write(uart, UART_CTRL_REG, reg);
125 }
126 
mvebu3700_uart_suspend(struct serial_port * port)127 static void mvebu3700_uart_suspend(struct serial_port *port)
128 {
129     BUG();
130 }
131 
mvebu3700_uart_resume(struct serial_port * port)132 static void mvebu3700_uart_resume(struct serial_port *port)
133 {
134     BUG();
135 }
136 
mvebu3700_uart_putc(struct serial_port * port,char c)137 static void mvebu3700_uart_putc(struct serial_port *port, char c)
138 {
139     struct mvebu3700_uart *uart = port->uart;
140 
141     mvebu3700_write(uart, UART_TX_REG, c);
142 }
143 
mvebu3700_uart_getc(struct serial_port * port,char * c)144 static int mvebu3700_uart_getc(struct serial_port *port, char *c)
145 {
146     struct mvebu3700_uart *uart = port->uart;
147 
148     if ( !(mvebu3700_read(uart, UART_STATUS_REG) & STATUS_RX_RDY) )
149         return 0;
150 
151     *c = mvebu3700_read(uart, UART_RX_REG) & 0xff;
152 
153     return 1;
154 }
155 
mvebu3700_irq(struct serial_port * port)156 static int __init mvebu3700_irq(struct serial_port *port)
157 {
158     struct mvebu3700_uart *uart = port->uart;
159 
160     return uart->irq;
161 }
162 
mvebu3700_vuart_info(struct serial_port * port)163 static const struct vuart_info *mvebu3700_vuart_info(struct serial_port *port)
164 {
165     struct mvebu3700_uart *uart = port->uart;
166 
167     return &uart->vuart;
168 }
169 
mvebu3700_uart_stop_tx(struct serial_port * port)170 static void mvebu3700_uart_stop_tx(struct serial_port *port)
171 {
172     struct mvebu3700_uart *uart = port->uart;
173     uint32_t reg;
174 
175     reg = mvebu3700_read(uart, UART_CTRL_REG);
176     reg &= ~CTRL_TX_RDY_INT;
177     mvebu3700_write(uart, UART_CTRL_REG, reg);
178 }
179 
mvebu3700_uart_start_tx(struct serial_port * port)180 static void mvebu3700_uart_start_tx(struct serial_port *port)
181 {
182     struct mvebu3700_uart *uart = port->uart;
183     uint32_t reg;
184 
185     reg = mvebu3700_read(uart, UART_CTRL_REG);
186     reg |= CTRL_TX_RDY_INT;
187     mvebu3700_write(uart, UART_CTRL_REG, reg);
188 }
189 
mvebu3700_uart_tx_ready(struct serial_port * port)190 static int mvebu3700_uart_tx_ready(struct serial_port *port)
191 {
192     struct mvebu3700_uart *uart = port->uart;
193     uint32_t reg;
194 
195     reg = mvebu3700_read(uart, UART_STATUS_REG);
196 
197     if ( reg & STATUS_TXFIFO_EMP )
198         return TX_FIFO_SIZE;
199     if ( reg & STATUS_TXFIFO_FUL )
200         return 0;
201     if ( reg & STATUS_TXFIFO_HFL )
202         return TX_FIFO_SIZE / 2;
203 
204     /*
205      * If we reach here, we don't know the number of free char in FIFO
206      * but we are sure that neither the FIFO is full nor empty.
207      * So, let's just return at least 1.
208      */
209     return 1;
210 }
211 
212 static struct uart_driver __read_mostly mvebu3700_uart_driver = {
213     .init_preirq  = mvebu3700_uart_init_preirq,
214     .init_postirq = mvebu3700_uart_init_postirq,
215     .endboot      = NULL,
216     .suspend      = mvebu3700_uart_suspend,
217     .resume       = mvebu3700_uart_resume,
218     .putc         = mvebu3700_uart_putc,
219     .getc         = mvebu3700_uart_getc,
220     .tx_ready     = mvebu3700_uart_tx_ready,
221     .stop_tx      = mvebu3700_uart_stop_tx,
222     .start_tx     = mvebu3700_uart_start_tx,
223     .irq          = mvebu3700_irq,
224     .vuart_info   = mvebu3700_vuart_info,
225 };
226 
mvebu_uart_init(struct dt_device_node * dev,const void * data)227 static int __init mvebu_uart_init(struct dt_device_node *dev, const void *data)
228 {
229     const char *config = data;
230     struct mvebu3700_uart *uart;
231     int res;
232     u64 addr, size;
233 
234     if ( strcmp(config, "") )
235         printk("WARNING: UART configuration is not supported\n");
236 
237     uart = &mvebu3700_com;
238 
239     res = dt_device_get_address(dev, 0, &addr, &size);
240     if ( res )
241     {
242         printk("mvebu3700: Unable to retrieve the base address of the UART\n");
243         return res;
244     }
245 
246     res = platform_get_irq(dev, 0);
247     if ( res < 0 )
248     {
249         printk("mvebu3700: Unable to retrieve the IRQ\n");
250         return -EINVAL;
251     }
252 
253     uart->irq  = res;
254 
255     uart->regs = ioremap_nocache(addr, size);
256     if ( !uart->regs )
257     {
258         printk("mvebu3700: Unable to map the UART memory\n");
259         return -ENOMEM;
260     }
261 
262     uart->vuart.base_addr = addr;
263     uart->vuart.size = size;
264     uart->vuart.data_off = UART_CTRL_REG;
265     uart->vuart.status_off = UART_STATUS_REG;
266     uart->vuart.status = STATUS_TX_RDY | STATUS_RX_RDY;
267 
268     /* Register with generic serial driver. */
269     serial_register_uart(SERHND_DTUART, &mvebu3700_uart_driver, uart);
270 
271     dt_device_set_used_by(dev, DOMID_XEN);
272 
273     return 0;
274 }
275 
276 static const struct dt_device_match mvebu_dt_match[] __initconst =
277 {
278     DT_MATCH_COMPATIBLE("marvell,armada-3700-uart"),
279     { /* sentinel */ },
280 };
281 
282 DT_DEVICE_START(mvebu, "Marvell Armada-3700 UART", DEVICE_SERIAL)
283     .dt_match = mvebu_dt_match,
284     .init = mvebu_uart_init,
285 DT_DEVICE_END
286 
287 /*
288  * Local variables:
289  * mode: C
290  * c-file-style: "BSD"
291  * c-basic-offset: 4
292  * indent-tabs-mode: nil
293  * End:
294  */
295