1e3b3d0f5SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0+
2ab4382d2SGreg Kroah-Hartman /*
3ab4382d2SGreg Kroah-Hartman * Driver for AMBA serial ports
4ab4382d2SGreg Kroah-Hartman *
5ab4382d2SGreg Kroah-Hartman * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
6ab4382d2SGreg Kroah-Hartman *
7ab4382d2SGreg Kroah-Hartman * Copyright 1999 ARM Limited
8ab4382d2SGreg Kroah-Hartman * Copyright (C) 2000 Deep Blue Solutions Ltd.
9ab4382d2SGreg Kroah-Hartman * Copyright (C) 2010 ST-Ericsson SA
10ab4382d2SGreg Kroah-Hartman *
11ab4382d2SGreg Kroah-Hartman * This is a generic driver for ARM AMBA-type serial ports. They
12ab4382d2SGreg Kroah-Hartman * have a lot of 16550-like features, but are not register compatible.
13ab4382d2SGreg Kroah-Hartman * Note that although they do have CTS, DCD and DSR inputs, they do
14ab4382d2SGreg Kroah-Hartman * not have an RI input, nor do they have DTR or RTS outputs. If
15ab4382d2SGreg Kroah-Hartman * required, these have to be supplied via some other means (eg, GPIO)
16ab4382d2SGreg Kroah-Hartman * and hooked into this driver.
17ab4382d2SGreg Kroah-Hartman */
18ab4382d2SGreg Kroah-Hartman
19ab4382d2SGreg Kroah-Hartman #include <linux/module.h>
20ab4382d2SGreg Kroah-Hartman #include <linux/ioport.h>
21ab4382d2SGreg Kroah-Hartman #include <linux/init.h>
22ab4382d2SGreg Kroah-Hartman #include <linux/console.h>
2329e5c442SRob Herring #include <linux/platform_device.h>
24ab4382d2SGreg Kroah-Hartman #include <linux/sysrq.h>
25ab4382d2SGreg Kroah-Hartman #include <linux/device.h>
26ab4382d2SGreg Kroah-Hartman #include <linux/tty.h>
27ab4382d2SGreg Kroah-Hartman #include <linux/tty_flip.h>
28ab4382d2SGreg Kroah-Hartman #include <linux/serial_core.h>
29ab4382d2SGreg Kroah-Hartman #include <linux/serial.h>
30ab4382d2SGreg Kroah-Hartman #include <linux/amba/bus.h>
31ab4382d2SGreg Kroah-Hartman #include <linux/amba/serial.h>
32ab4382d2SGreg Kroah-Hartman #include <linux/clk.h>
33ab4382d2SGreg Kroah-Hartman #include <linux/slab.h>
34ab4382d2SGreg Kroah-Hartman #include <linux/dmaengine.h>
35ab4382d2SGreg Kroah-Hartman #include <linux/dma-mapping.h>
36ab4382d2SGreg Kroah-Hartman #include <linux/scatterlist.h>
37c16d51a3SShreshtha Kumar Sahu #include <linux/delay.h>
38258aea76SViresh Kumar #include <linux/types.h>
3932614aadSMatthew Leach #include <linux/of.h>
40258e0551SShawn Guo #include <linux/pinctrl/consumer.h>
41cb70706cSAlessandro Rubini #include <linux/sizes.h>
42de609582SLinus Walleij #include <linux/io.h>
433db9ab0bSGraeme Gregory #include <linux/acpi.h>
44ab4382d2SGreg Kroah-Hartman
45ab4382d2SGreg Kroah-Hartman #define UART_NR 14
46ab4382d2SGreg Kroah-Hartman
47ab4382d2SGreg Kroah-Hartman #define SERIAL_AMBA_MAJOR 204
48ab4382d2SGreg Kroah-Hartman #define SERIAL_AMBA_MINOR 64
49ab4382d2SGreg Kroah-Hartman #define SERIAL_AMBA_NR UART_NR
50ab4382d2SGreg Kroah-Hartman
51ab4382d2SGreg Kroah-Hartman #define AMBA_ISR_PASS_LIMIT 256
52ab4382d2SGreg Kroah-Hartman
53ab4382d2SGreg Kroah-Hartman #define UART_DR_ERROR (UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE)
54ab4382d2SGreg Kroah-Hartman #define UART_DUMMY_DR_RX (1 << 16)
55ab4382d2SGreg Kroah-Hartman
569bb13b2fSJiri Slaby enum {
579bb13b2fSJiri Slaby REG_DR,
589bb13b2fSJiri Slaby REG_ST_DMAWM,
599bb13b2fSJiri Slaby REG_ST_TIMEOUT,
609bb13b2fSJiri Slaby REG_FR,
619bb13b2fSJiri Slaby REG_LCRH_RX,
629bb13b2fSJiri Slaby REG_LCRH_TX,
639bb13b2fSJiri Slaby REG_IBRD,
649bb13b2fSJiri Slaby REG_FBRD,
659bb13b2fSJiri Slaby REG_CR,
669bb13b2fSJiri Slaby REG_IFLS,
679bb13b2fSJiri Slaby REG_IMSC,
689bb13b2fSJiri Slaby REG_RIS,
699bb13b2fSJiri Slaby REG_MIS,
709bb13b2fSJiri Slaby REG_ICR,
719bb13b2fSJiri Slaby REG_DMACR,
729bb13b2fSJiri Slaby REG_ST_XFCR,
739bb13b2fSJiri Slaby REG_ST_XON1,
749bb13b2fSJiri Slaby REG_ST_XON2,
759bb13b2fSJiri Slaby REG_ST_XOFF1,
769bb13b2fSJiri Slaby REG_ST_XOFF2,
779bb13b2fSJiri Slaby REG_ST_ITCR,
789bb13b2fSJiri Slaby REG_ST_ITIP,
799bb13b2fSJiri Slaby REG_ST_ABCR,
809bb13b2fSJiri Slaby REG_ST_ABIMSC,
819bb13b2fSJiri Slaby
829bb13b2fSJiri Slaby /* The size of the array - must be last */
839bb13b2fSJiri Slaby REG_ARRAY_SIZE,
849bb13b2fSJiri Slaby };
859bb13b2fSJiri Slaby
86debb7f64SRussell King static u16 pl011_std_offsets[REG_ARRAY_SIZE] = {
87debb7f64SRussell King [REG_DR] = UART01x_DR,
88debb7f64SRussell King [REG_FR] = UART01x_FR,
89e4df9a80SRussell King [REG_LCRH_RX] = UART011_LCRH,
90e4df9a80SRussell King [REG_LCRH_TX] = UART011_LCRH,
91debb7f64SRussell King [REG_IBRD] = UART011_IBRD,
92debb7f64SRussell King [REG_FBRD] = UART011_FBRD,
93debb7f64SRussell King [REG_CR] = UART011_CR,
94debb7f64SRussell King [REG_IFLS] = UART011_IFLS,
95debb7f64SRussell King [REG_IMSC] = UART011_IMSC,
96debb7f64SRussell King [REG_RIS] = UART011_RIS,
97debb7f64SRussell King [REG_MIS] = UART011_MIS,
98debb7f64SRussell King [REG_ICR] = UART011_ICR,
99debb7f64SRussell King [REG_DMACR] = UART011_DMACR,
100debb7f64SRussell King };
101debb7f64SRussell King
102ab4382d2SGreg Kroah-Hartman /* There is by now at least one vendor with differing details, so handle it */
103ab4382d2SGreg Kroah-Hartman struct vendor_data {
104439403bdSRussell King const u16 *reg_offset;
105ab4382d2SGreg Kroah-Hartman unsigned int ifls;
1060e125a5fSShawn Guo unsigned int fr_busy;
1070e125a5fSShawn Guo unsigned int fr_dsr;
1080e125a5fSShawn Guo unsigned int fr_cts;
1090e125a5fSShawn Guo unsigned int fr_ri;
110d8a4995bSChristopher Covington unsigned int inv_fr;
11184c3e03bSRussell King bool access_32b;
112ab4382d2SGreg Kroah-Hartman bool oversampling;
113ab4382d2SGreg Kroah-Hartman bool dma_threshold;
1144fd0690bSRajanikanth H.V bool cts_event_workaround;
11571eec483SAndre Przywara bool always_enabled;
116cefc2d1dSAndre Przywara bool fixed_options;
11778506f22SJongsung Kim
118ea33640aSJongsung Kim unsigned int (*get_fifosize)(struct amba_device *dev);
119ab4382d2SGreg Kroah-Hartman };
120ab4382d2SGreg Kroah-Hartman
get_fifosize_arm(struct amba_device * dev)121ea33640aSJongsung Kim static unsigned int get_fifosize_arm(struct amba_device *dev)
12278506f22SJongsung Kim {
123ea33640aSJongsung Kim return amba_rev(dev) < 3 ? 16 : 32;
12478506f22SJongsung Kim }
12578506f22SJongsung Kim
126ab4382d2SGreg Kroah-Hartman static struct vendor_data vendor_arm = {
127439403bdSRussell King .reg_offset = pl011_std_offsets,
128ab4382d2SGreg Kroah-Hartman .ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8,
1290e125a5fSShawn Guo .fr_busy = UART01x_FR_BUSY,
1300e125a5fSShawn Guo .fr_dsr = UART01x_FR_DSR,
1310e125a5fSShawn Guo .fr_cts = UART01x_FR_CTS,
1320e125a5fSShawn Guo .fr_ri = UART011_FR_RI,
133ab4382d2SGreg Kroah-Hartman .oversampling = false,
134ab4382d2SGreg Kroah-Hartman .dma_threshold = false,
1354fd0690bSRajanikanth H.V .cts_event_workaround = false,
13671eec483SAndre Przywara .always_enabled = false,
137cefc2d1dSAndre Przywara .fixed_options = false,
13878506f22SJongsung Kim .get_fifosize = get_fifosize_arm,
139ab4382d2SGreg Kroah-Hartman };
140ab4382d2SGreg Kroah-Hartman
141d054b3acSJulia Lawall static const struct vendor_data vendor_sbsa = {
142439403bdSRussell King .reg_offset = pl011_std_offsets,
1430e125a5fSShawn Guo .fr_busy = UART01x_FR_BUSY,
1440e125a5fSShawn Guo .fr_dsr = UART01x_FR_DSR,
1450e125a5fSShawn Guo .fr_cts = UART01x_FR_CTS,
1460e125a5fSShawn Guo .fr_ri = UART011_FR_RI,
1471aabf523SChristopher Covington .access_32b = true,
1480dd1e247SAndre Przywara .oversampling = false,
1490dd1e247SAndre Przywara .dma_threshold = false,
1500dd1e247SAndre Przywara .cts_event_workaround = false,
1510dd1e247SAndre Przywara .always_enabled = true,
1520dd1e247SAndre Przywara .fixed_options = true,
1530dd1e247SAndre Przywara };
1540dd1e247SAndre Przywara
15537ef38f3STimur Tabi #ifdef CONFIG_ACPI_SPCR_TABLE
156d054b3acSJulia Lawall static const struct vendor_data vendor_qdt_qdf2400_e44 = {
157d8a4995bSChristopher Covington .reg_offset = pl011_std_offsets,
158d8a4995bSChristopher Covington .fr_busy = UART011_FR_TXFE,
159d8a4995bSChristopher Covington .fr_dsr = UART01x_FR_DSR,
160d8a4995bSChristopher Covington .fr_cts = UART01x_FR_CTS,
161d8a4995bSChristopher Covington .fr_ri = UART011_FR_RI,
162d8a4995bSChristopher Covington .inv_fr = UART011_FR_TXFE,
163d8a4995bSChristopher Covington .access_32b = true,
164d8a4995bSChristopher Covington .oversampling = false,
165d8a4995bSChristopher Covington .dma_threshold = false,
166d8a4995bSChristopher Covington .cts_event_workaround = false,
167d8a4995bSChristopher Covington .always_enabled = true,
168d8a4995bSChristopher Covington .fixed_options = true,
169d8a4995bSChristopher Covington };
17037ef38f3STimur Tabi #endif
171d8a4995bSChristopher Covington
172bf69ff8aSRussell King static u16 pl011_st_offsets[REG_ARRAY_SIZE] = {
173bf69ff8aSRussell King [REG_DR] = UART01x_DR,
174bf69ff8aSRussell King [REG_ST_DMAWM] = ST_UART011_DMAWM,
175bf69ff8aSRussell King [REG_ST_TIMEOUT] = ST_UART011_TIMEOUT,
176bf69ff8aSRussell King [REG_FR] = UART01x_FR,
177e4df9a80SRussell King [REG_LCRH_RX] = ST_UART011_LCRH_RX,
178e4df9a80SRussell King [REG_LCRH_TX] = ST_UART011_LCRH_TX,
179bf69ff8aSRussell King [REG_IBRD] = UART011_IBRD,
180bf69ff8aSRussell King [REG_FBRD] = UART011_FBRD,
181bf69ff8aSRussell King [REG_CR] = UART011_CR,
182bf69ff8aSRussell King [REG_IFLS] = UART011_IFLS,
183bf69ff8aSRussell King [REG_IMSC] = UART011_IMSC,
184bf69ff8aSRussell King [REG_RIS] = UART011_RIS,
185bf69ff8aSRussell King [REG_MIS] = UART011_MIS,
186bf69ff8aSRussell King [REG_ICR] = UART011_ICR,
187bf69ff8aSRussell King [REG_DMACR] = UART011_DMACR,
188bf69ff8aSRussell King [REG_ST_XFCR] = ST_UART011_XFCR,
189bf69ff8aSRussell King [REG_ST_XON1] = ST_UART011_XON1,
190bf69ff8aSRussell King [REG_ST_XON2] = ST_UART011_XON2,
191bf69ff8aSRussell King [REG_ST_XOFF1] = ST_UART011_XOFF1,
192bf69ff8aSRussell King [REG_ST_XOFF2] = ST_UART011_XOFF2,
193bf69ff8aSRussell King [REG_ST_ITCR] = ST_UART011_ITCR,
194bf69ff8aSRussell King [REG_ST_ITIP] = ST_UART011_ITIP,
195bf69ff8aSRussell King [REG_ST_ABCR] = ST_UART011_ABCR,
196bf69ff8aSRussell King [REG_ST_ABIMSC] = ST_UART011_ABIMSC,
197bf69ff8aSRussell King };
198bf69ff8aSRussell King
get_fifosize_st(struct amba_device * dev)199ea33640aSJongsung Kim static unsigned int get_fifosize_st(struct amba_device *dev)
20078506f22SJongsung Kim {
20178506f22SJongsung Kim return 64;
20278506f22SJongsung Kim }
20378506f22SJongsung Kim
204ab4382d2SGreg Kroah-Hartman static struct vendor_data vendor_st = {
205bf69ff8aSRussell King .reg_offset = pl011_st_offsets,
206ab4382d2SGreg Kroah-Hartman .ifls = UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF,
2070e125a5fSShawn Guo .fr_busy = UART01x_FR_BUSY,
2080e125a5fSShawn Guo .fr_dsr = UART01x_FR_DSR,
2090e125a5fSShawn Guo .fr_cts = UART01x_FR_CTS,
2100e125a5fSShawn Guo .fr_ri = UART011_FR_RI,
211ab4382d2SGreg Kroah-Hartman .oversampling = true,
212ab4382d2SGreg Kroah-Hartman .dma_threshold = true,
2134fd0690bSRajanikanth H.V .cts_event_workaround = true,
21471eec483SAndre Przywara .always_enabled = false,
215cefc2d1dSAndre Przywara .fixed_options = false,
21678506f22SJongsung Kim .get_fifosize = get_fifosize_st,
217ab4382d2SGreg Kroah-Hartman };
218ab4382d2SGreg Kroah-Hartman
219ab4382d2SGreg Kroah-Hartman /* Deals with DMA transactions */
220ead76f32SLinus Walleij
221c865b77eSArnd Bergmann struct pl011_dmabuf {
222c865b77eSArnd Bergmann dma_addr_t dma;
223c865b77eSArnd Bergmann size_t len;
224ead76f32SLinus Walleij char *buf;
225ead76f32SLinus Walleij };
226ead76f32SLinus Walleij
227ead76f32SLinus Walleij struct pl011_dmarx_data {
228ead76f32SLinus Walleij struct dma_chan *chan;
229ead76f32SLinus Walleij struct completion complete;
230ead76f32SLinus Walleij bool use_buf_b;
231c865b77eSArnd Bergmann struct pl011_dmabuf dbuf_a;
232c865b77eSArnd Bergmann struct pl011_dmabuf dbuf_b;
233ead76f32SLinus Walleij dma_cookie_t cookie;
234ead76f32SLinus Walleij bool running;
235cb06ff10SChanho Min struct timer_list timer;
236cb06ff10SChanho Min unsigned int last_residue;
237cb06ff10SChanho Min unsigned long last_jiffies;
238cb06ff10SChanho Min bool auto_poll_rate;
239cb06ff10SChanho Min unsigned int poll_rate;
240cb06ff10SChanho Min unsigned int poll_timeout;
241ead76f32SLinus Walleij };
242ead76f32SLinus Walleij
243ab4382d2SGreg Kroah-Hartman struct pl011_dmatx_data {
244ab4382d2SGreg Kroah-Hartman struct dma_chan *chan;
245c865b77eSArnd Bergmann dma_addr_t dma;
246c865b77eSArnd Bergmann size_t len;
247ab4382d2SGreg Kroah-Hartman char *buf;
248ab4382d2SGreg Kroah-Hartman bool queued;
249ab4382d2SGreg Kroah-Hartman };
250ab4382d2SGreg Kroah-Hartman
251ab4382d2SGreg Kroah-Hartman /*
252ab4382d2SGreg Kroah-Hartman * We wrap our port structure around the generic uart_port.
253ab4382d2SGreg Kroah-Hartman */
254ab4382d2SGreg Kroah-Hartman struct uart_amba_port {
255ab4382d2SGreg Kroah-Hartman struct uart_port port;
256debb7f64SRussell King const u16 *reg_offset;
257ab4382d2SGreg Kroah-Hartman struct clk *clk;
258ab4382d2SGreg Kroah-Hartman const struct vendor_data *vendor;
259ab4382d2SGreg Kroah-Hartman unsigned int dmacr; /* dma control reg */
260ab4382d2SGreg Kroah-Hartman unsigned int im; /* interrupt mask */
261ab4382d2SGreg Kroah-Hartman unsigned int old_status;
262ab4382d2SGreg Kroah-Hartman unsigned int fifosize; /* vendor-specific */
263cefc2d1dSAndre Przywara unsigned int fixed_baud; /* vendor-set fixed baud rate */
264ab4382d2SGreg Kroah-Hartman char type[12];
2658d479237SLino Sanfilippo bool rs485_tx_started;
2668d479237SLino Sanfilippo unsigned int rs485_tx_drain_interval; /* usecs */
267ab4382d2SGreg Kroah-Hartman #ifdef CONFIG_DMA_ENGINE
268ab4382d2SGreg Kroah-Hartman /* DMA stuff */
269ead76f32SLinus Walleij bool using_tx_dma;
270ead76f32SLinus Walleij bool using_rx_dma;
271ead76f32SLinus Walleij struct pl011_dmarx_data dmarx;
272ab4382d2SGreg Kroah-Hartman struct pl011_dmatx_data dmatx;
2731c9be310SJorge Ramirez-Ortiz bool dma_probed;
274ab4382d2SGreg Kroah-Hartman #endif
275ab4382d2SGreg Kroah-Hartman };
276ab4382d2SGreg Kroah-Hartman
2778d479237SLino Sanfilippo static unsigned int pl011_tx_empty(struct uart_port *port);
2788d479237SLino Sanfilippo
pl011_reg_to_offset(const struct uart_amba_port * uap,unsigned int reg)2799f25bc51SRussell King static unsigned int pl011_reg_to_offset(const struct uart_amba_port *uap,
2809f25bc51SRussell King unsigned int reg)
2819f25bc51SRussell King {
282debb7f64SRussell King return uap->reg_offset[reg];
2839f25bc51SRussell King }
2849f25bc51SRussell King
pl011_read(const struct uart_amba_port * uap,unsigned int reg)285b2a4e24cSRussell King static unsigned int pl011_read(const struct uart_amba_port *uap,
286b2a4e24cSRussell King unsigned int reg)
28775836339SRussell King {
28884c3e03bSRussell King void __iomem *addr = uap->port.membase + pl011_reg_to_offset(uap, reg);
28984c3e03bSRussell King
2903b78fae7STimur Tabi return (uap->port.iotype == UPIO_MEM32) ?
2913b78fae7STimur Tabi readl_relaxed(addr) : readw_relaxed(addr);
29275836339SRussell King }
29375836339SRussell King
pl011_write(unsigned int val,const struct uart_amba_port * uap,unsigned int reg)294b2a4e24cSRussell King static void pl011_write(unsigned int val, const struct uart_amba_port *uap,
295b2a4e24cSRussell King unsigned int reg)
29675836339SRussell King {
29784c3e03bSRussell King void __iomem *addr = uap->port.membase + pl011_reg_to_offset(uap, reg);
29884c3e03bSRussell King
2993b78fae7STimur Tabi if (uap->port.iotype == UPIO_MEM32)
300f5ce6eddSRussell King writel_relaxed(val, addr);
30184c3e03bSRussell King else
302f5ce6eddSRussell King writew_relaxed(val, addr);
30375836339SRussell King }
30475836339SRussell King
305ab4382d2SGreg Kroah-Hartman /*
30629772c4eSLinus Walleij * Reads up to 256 characters from the FIFO or until it's empty and
30729772c4eSLinus Walleij * inserts them into the TTY layer. Returns the number of characters
30829772c4eSLinus Walleij * read from the FIFO.
30929772c4eSLinus Walleij */
pl011_fifo_to_tty(struct uart_amba_port * uap)31029772c4eSLinus Walleij static int pl011_fifo_to_tty(struct uart_amba_port *uap)
31129772c4eSLinus Walleij {
312fd2b55f8SJiri Slaby unsigned int ch, fifotaken;
313534cf755SPeter Zijlstra int sysrq;
314534cf755SPeter Zijlstra u16 status;
315fd2b55f8SJiri Slaby u8 flag;
31629772c4eSLinus Walleij
317e73be92dSLukas Wunner for (fifotaken = 0; fifotaken != 256; fifotaken++) {
3189f25bc51SRussell King status = pl011_read(uap, REG_FR);
31929772c4eSLinus Walleij if (status & UART01x_FR_RXFE)
32029772c4eSLinus Walleij break;
32129772c4eSLinus Walleij
32229772c4eSLinus Walleij /* Take chars from the FIFO and update status */
3239f25bc51SRussell King ch = pl011_read(uap, REG_DR) | UART_DUMMY_DR_RX;
32429772c4eSLinus Walleij flag = TTY_NORMAL;
32529772c4eSLinus Walleij uap->port.icount.rx++;
32629772c4eSLinus Walleij
32729772c4eSLinus Walleij if (unlikely(ch & UART_DR_ERROR)) {
32829772c4eSLinus Walleij if (ch & UART011_DR_BE) {
32929772c4eSLinus Walleij ch &= ~(UART011_DR_FE | UART011_DR_PE);
33029772c4eSLinus Walleij uap->port.icount.brk++;
33129772c4eSLinus Walleij if (uart_handle_break(&uap->port))
33229772c4eSLinus Walleij continue;
33329772c4eSLinus Walleij } else if (ch & UART011_DR_PE)
33429772c4eSLinus Walleij uap->port.icount.parity++;
33529772c4eSLinus Walleij else if (ch & UART011_DR_FE)
33629772c4eSLinus Walleij uap->port.icount.frame++;
33729772c4eSLinus Walleij if (ch & UART011_DR_OE)
33829772c4eSLinus Walleij uap->port.icount.overrun++;
33929772c4eSLinus Walleij
34029772c4eSLinus Walleij ch &= uap->port.read_status_mask;
34129772c4eSLinus Walleij
34229772c4eSLinus Walleij if (ch & UART011_DR_BE)
34329772c4eSLinus Walleij flag = TTY_BREAK;
34429772c4eSLinus Walleij else if (ch & UART011_DR_PE)
34529772c4eSLinus Walleij flag = TTY_PARITY;
34629772c4eSLinus Walleij else if (ch & UART011_DR_FE)
34729772c4eSLinus Walleij flag = TTY_FRAME;
34829772c4eSLinus Walleij }
34929772c4eSLinus Walleij
3505aea1229SThomas Gleixner uart_port_unlock(&uap->port);
351534cf755SPeter Zijlstra sysrq = uart_handle_sysrq_char(&uap->port, ch & 255);
3525aea1229SThomas Gleixner uart_port_lock(&uap->port);
35329772c4eSLinus Walleij
354534cf755SPeter Zijlstra if (!sysrq)
35529772c4eSLinus Walleij uart_insert_char(&uap->port, ch, UART011_DR_OE, ch, flag);
35629772c4eSLinus Walleij }
35729772c4eSLinus Walleij
35829772c4eSLinus Walleij return fifotaken;
35929772c4eSLinus Walleij }
36029772c4eSLinus Walleij
36129772c4eSLinus Walleij
36229772c4eSLinus Walleij /*
363ab4382d2SGreg Kroah-Hartman * All the DMA operation mode stuff goes inside this ifdef.
364ab4382d2SGreg Kroah-Hartman * This assumes that you have a generic DMA device interface,
365ab4382d2SGreg Kroah-Hartman * no custom DMA interfaces are supported.
366ab4382d2SGreg Kroah-Hartman */
367ab4382d2SGreg Kroah-Hartman #ifdef CONFIG_DMA_ENGINE
368ab4382d2SGreg Kroah-Hartman
369ab4382d2SGreg Kroah-Hartman #define PL011_DMA_BUFFER_SIZE PAGE_SIZE
370ab4382d2SGreg Kroah-Hartman
pl011_dmabuf_init(struct dma_chan * chan,struct pl011_dmabuf * db,enum dma_data_direction dir)371c865b77eSArnd Bergmann static int pl011_dmabuf_init(struct dma_chan *chan, struct pl011_dmabuf *db,
372ead76f32SLinus Walleij enum dma_data_direction dir)
373ead76f32SLinus Walleij {
374c865b77eSArnd Bergmann db->buf = dma_alloc_coherent(chan->device->dev, PL011_DMA_BUFFER_SIZE,
375c865b77eSArnd Bergmann &db->dma, GFP_KERNEL);
376c865b77eSArnd Bergmann if (!db->buf)
377ead76f32SLinus Walleij return -ENOMEM;
378c865b77eSArnd Bergmann db->len = PL011_DMA_BUFFER_SIZE;
379ead76f32SLinus Walleij
380ead76f32SLinus Walleij return 0;
381ead76f32SLinus Walleij }
382ead76f32SLinus Walleij
pl011_dmabuf_free(struct dma_chan * chan,struct pl011_dmabuf * db,enum dma_data_direction dir)383c865b77eSArnd Bergmann static void pl011_dmabuf_free(struct dma_chan *chan, struct pl011_dmabuf *db,
384ead76f32SLinus Walleij enum dma_data_direction dir)
385ead76f32SLinus Walleij {
386c865b77eSArnd Bergmann if (db->buf) {
387cb06ff10SChanho Min dma_free_coherent(chan->device->dev,
388c865b77eSArnd Bergmann PL011_DMA_BUFFER_SIZE, db->buf, db->dma);
389ead76f32SLinus Walleij }
390ead76f32SLinus Walleij }
391ead76f32SLinus Walleij
pl011_dma_probe(struct uart_amba_port * uap)3921c9be310SJorge Ramirez-Ortiz static void pl011_dma_probe(struct uart_amba_port *uap)
393ab4382d2SGreg Kroah-Hartman {
394ab4382d2SGreg Kroah-Hartman /* DMA is the sole user of the platform data right now */
395574de559SJingoo Han struct amba_pl011_data *plat = dev_get_platdata(uap->port.dev);
3961c9be310SJorge Ramirez-Ortiz struct device *dev = uap->port.dev;
397ab4382d2SGreg Kroah-Hartman struct dma_slave_config tx_conf = {
3989f25bc51SRussell King .dst_addr = uap->port.mapbase +
3999f25bc51SRussell King pl011_reg_to_offset(uap, REG_DR),
400ab4382d2SGreg Kroah-Hartman .dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
401a485df4bSVinod Koul .direction = DMA_MEM_TO_DEV,
402ab4382d2SGreg Kroah-Hartman .dst_maxburst = uap->fifosize >> 1,
403258aea76SViresh Kumar .device_fc = false,
404ab4382d2SGreg Kroah-Hartman };
405ab4382d2SGreg Kroah-Hartman struct dma_chan *chan;
406ab4382d2SGreg Kroah-Hartman dma_cap_mask_t mask;
407ab4382d2SGreg Kroah-Hartman
4081c9be310SJorge Ramirez-Ortiz uap->dma_probed = true;
40961b37b04SPeter Ujfalusi chan = dma_request_chan(dev, "tx");
4101c9be310SJorge Ramirez-Ortiz if (IS_ERR(chan)) {
4111c9be310SJorge Ramirez-Ortiz if (PTR_ERR(chan) == -EPROBE_DEFER) {
4121c9be310SJorge Ramirez-Ortiz uap->dma_probed = false;
4131c9be310SJorge Ramirez-Ortiz return;
4141c9be310SJorge Ramirez-Ortiz }
415787b0c1fSArnd Bergmann
416ab4382d2SGreg Kroah-Hartman /* We need platform data */
417ab4382d2SGreg Kroah-Hartman if (!plat || !plat->dma_filter) {
418ab4382d2SGreg Kroah-Hartman dev_info(uap->port.dev, "no DMA platform data\n");
419ab4382d2SGreg Kroah-Hartman return;
420ab4382d2SGreg Kroah-Hartman }
421ab4382d2SGreg Kroah-Hartman
422ead76f32SLinus Walleij /* Try to acquire a generic DMA engine slave TX channel */
423ab4382d2SGreg Kroah-Hartman dma_cap_zero(mask);
424ab4382d2SGreg Kroah-Hartman dma_cap_set(DMA_SLAVE, mask);
425ab4382d2SGreg Kroah-Hartman
426787b0c1fSArnd Bergmann chan = dma_request_channel(mask, plat->dma_filter,
427787b0c1fSArnd Bergmann plat->dma_tx_param);
428ab4382d2SGreg Kroah-Hartman if (!chan) {
429ab4382d2SGreg Kroah-Hartman dev_err(uap->port.dev, "no TX DMA channel!\n");
430ab4382d2SGreg Kroah-Hartman return;
431ab4382d2SGreg Kroah-Hartman }
432787b0c1fSArnd Bergmann }
433ab4382d2SGreg Kroah-Hartman
434ab4382d2SGreg Kroah-Hartman dmaengine_slave_config(chan, &tx_conf);
435ab4382d2SGreg Kroah-Hartman uap->dmatx.chan = chan;
436ab4382d2SGreg Kroah-Hartman
437ab4382d2SGreg Kroah-Hartman dev_info(uap->port.dev, "DMA channel TX %s\n",
438ab4382d2SGreg Kroah-Hartman dma_chan_name(uap->dmatx.chan));
439ead76f32SLinus Walleij
440ead76f32SLinus Walleij /* Optionally make use of an RX channel as well */
441787b0c1fSArnd Bergmann chan = dma_request_slave_channel(dev, "rx");
442787b0c1fSArnd Bergmann
443d9e105caSRobin Murphy if (!chan && plat && plat->dma_rx_param) {
444787b0c1fSArnd Bergmann chan = dma_request_channel(mask, plat->dma_filter, plat->dma_rx_param);
445787b0c1fSArnd Bergmann
446787b0c1fSArnd Bergmann if (!chan) {
447787b0c1fSArnd Bergmann dev_err(uap->port.dev, "no RX DMA channel!\n");
448787b0c1fSArnd Bergmann return;
449787b0c1fSArnd Bergmann }
450787b0c1fSArnd Bergmann }
451787b0c1fSArnd Bergmann
452787b0c1fSArnd Bergmann if (chan) {
453ead76f32SLinus Walleij struct dma_slave_config rx_conf = {
4549f25bc51SRussell King .src_addr = uap->port.mapbase +
4559f25bc51SRussell King pl011_reg_to_offset(uap, REG_DR),
456ead76f32SLinus Walleij .src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
457a485df4bSVinod Koul .direction = DMA_DEV_TO_MEM,
458b2aeb775SGuennadi Liakhovetski .src_maxburst = uap->fifosize >> 2,
459258aea76SViresh Kumar .device_fc = false,
460ead76f32SLinus Walleij };
4612d3b7d6eSAndrew Jackson struct dma_slave_caps caps;
462ead76f32SLinus Walleij
4632d3b7d6eSAndrew Jackson /*
4642d3b7d6eSAndrew Jackson * Some DMA controllers provide information on their capabilities.
4652d3b7d6eSAndrew Jackson * If the controller does, check for suitable residue processing
4662d3b7d6eSAndrew Jackson * otherwise assime all is well.
4672d3b7d6eSAndrew Jackson */
4682d3b7d6eSAndrew Jackson if (0 == dma_get_slave_caps(chan, &caps)) {
4692d3b7d6eSAndrew Jackson if (caps.residue_granularity ==
4702d3b7d6eSAndrew Jackson DMA_RESIDUE_GRANULARITY_DESCRIPTOR) {
4712d3b7d6eSAndrew Jackson dma_release_channel(chan);
4722d3b7d6eSAndrew Jackson dev_info(uap->port.dev,
4732d3b7d6eSAndrew Jackson "RX DMA disabled - no residue processing\n");
4742d3b7d6eSAndrew Jackson return;
4752d3b7d6eSAndrew Jackson }
4762d3b7d6eSAndrew Jackson }
477ead76f32SLinus Walleij dmaengine_slave_config(chan, &rx_conf);
478ead76f32SLinus Walleij uap->dmarx.chan = chan;
479ead76f32SLinus Walleij
48098267d33SAndrew Jackson uap->dmarx.auto_poll_rate = false;
4818f898bfdSGreg Kroah-Hartman if (plat && plat->dma_rx_poll_enable) {
482cb06ff10SChanho Min /* Set poll rate if specified. */
483cb06ff10SChanho Min if (plat->dma_rx_poll_rate) {
484cb06ff10SChanho Min uap->dmarx.auto_poll_rate = false;
485cb06ff10SChanho Min uap->dmarx.poll_rate = plat->dma_rx_poll_rate;
486cb06ff10SChanho Min } else {
487cb06ff10SChanho Min /*
488cb06ff10SChanho Min * 100 ms defaults to poll rate if not
489cb06ff10SChanho Min * specified. This will be adjusted with
490cb06ff10SChanho Min * the baud rate at set_termios.
491cb06ff10SChanho Min */
492cb06ff10SChanho Min uap->dmarx.auto_poll_rate = true;
493cb06ff10SChanho Min uap->dmarx.poll_rate = 100;
494cb06ff10SChanho Min }
495cb06ff10SChanho Min /* 3 secs defaults poll_timeout if not specified. */
496cb06ff10SChanho Min if (plat->dma_rx_poll_timeout)
497cb06ff10SChanho Min uap->dmarx.poll_timeout =
498cb06ff10SChanho Min plat->dma_rx_poll_timeout;
499cb06ff10SChanho Min else
500cb06ff10SChanho Min uap->dmarx.poll_timeout = 3000;
50198267d33SAndrew Jackson } else if (!plat && dev->of_node) {
50298267d33SAndrew Jackson uap->dmarx.auto_poll_rate = of_property_read_bool(
50398267d33SAndrew Jackson dev->of_node, "auto-poll");
50498267d33SAndrew Jackson if (uap->dmarx.auto_poll_rate) {
50598267d33SAndrew Jackson u32 x;
506cb06ff10SChanho Min
50798267d33SAndrew Jackson if (0 == of_property_read_u32(dev->of_node,
50898267d33SAndrew Jackson "poll-rate-ms", &x))
50998267d33SAndrew Jackson uap->dmarx.poll_rate = x;
51098267d33SAndrew Jackson else
51198267d33SAndrew Jackson uap->dmarx.poll_rate = 100;
51298267d33SAndrew Jackson if (0 == of_property_read_u32(dev->of_node,
51398267d33SAndrew Jackson "poll-timeout-ms", &x))
51498267d33SAndrew Jackson uap->dmarx.poll_timeout = x;
51598267d33SAndrew Jackson else
51698267d33SAndrew Jackson uap->dmarx.poll_timeout = 3000;
51798267d33SAndrew Jackson }
51898267d33SAndrew Jackson }
519ead76f32SLinus Walleij dev_info(uap->port.dev, "DMA channel RX %s\n",
520ead76f32SLinus Walleij dma_chan_name(uap->dmarx.chan));
521ead76f32SLinus Walleij }
522ab4382d2SGreg Kroah-Hartman }
523ab4382d2SGreg Kroah-Hartman
pl011_dma_remove(struct uart_amba_port * uap)524ab4382d2SGreg Kroah-Hartman static void pl011_dma_remove(struct uart_amba_port *uap)
525ab4382d2SGreg Kroah-Hartman {
526ab4382d2SGreg Kroah-Hartman if (uap->dmatx.chan)
527ab4382d2SGreg Kroah-Hartman dma_release_channel(uap->dmatx.chan);
528ead76f32SLinus Walleij if (uap->dmarx.chan)
529ead76f32SLinus Walleij dma_release_channel(uap->dmarx.chan);
530ab4382d2SGreg Kroah-Hartman }
531ab4382d2SGreg Kroah-Hartman
532734745caSDave Martin /* Forward declare these for the refill routine */
533ab4382d2SGreg Kroah-Hartman static int pl011_dma_tx_refill(struct uart_amba_port *uap);
534734745caSDave Martin static void pl011_start_tx_pio(struct uart_amba_port *uap);
535ab4382d2SGreg Kroah-Hartman
536ab4382d2SGreg Kroah-Hartman /*
537ab4382d2SGreg Kroah-Hartman * The current DMA TX buffer has been sent.
538ab4382d2SGreg Kroah-Hartman * Try to queue up another DMA buffer.
539ab4382d2SGreg Kroah-Hartman */
pl011_dma_tx_callback(void * data)540ab4382d2SGreg Kroah-Hartman static void pl011_dma_tx_callback(void *data)
541ab4382d2SGreg Kroah-Hartman {
542ab4382d2SGreg Kroah-Hartman struct uart_amba_port *uap = data;
543ab4382d2SGreg Kroah-Hartman struct pl011_dmatx_data *dmatx = &uap->dmatx;
544ab4382d2SGreg Kroah-Hartman unsigned long flags;
545ab4382d2SGreg Kroah-Hartman u16 dmacr;
546ab4382d2SGreg Kroah-Hartman
5475aea1229SThomas Gleixner uart_port_lock_irqsave(&uap->port, &flags);
548ab4382d2SGreg Kroah-Hartman if (uap->dmatx.queued)
549c865b77eSArnd Bergmann dma_unmap_single(dmatx->chan->device->dev, dmatx->dma,
550c865b77eSArnd Bergmann dmatx->len, DMA_TO_DEVICE);
551ab4382d2SGreg Kroah-Hartman
552ab4382d2SGreg Kroah-Hartman dmacr = uap->dmacr;
553ab4382d2SGreg Kroah-Hartman uap->dmacr = dmacr & ~UART011_TXDMAE;
5549f25bc51SRussell King pl011_write(uap->dmacr, uap, REG_DMACR);
555ab4382d2SGreg Kroah-Hartman
556ab4382d2SGreg Kroah-Hartman /*
557ab4382d2SGreg Kroah-Hartman * If TX DMA was disabled, it means that we've stopped the DMA for
558ab4382d2SGreg Kroah-Hartman * some reason (eg, XOFF received, or we want to send an X-char.)
559ab4382d2SGreg Kroah-Hartman *
560ab4382d2SGreg Kroah-Hartman * Note: we need to be careful here of a potential race between DMA
561ab4382d2SGreg Kroah-Hartman * and the rest of the driver - if the driver disables TX DMA while
562ab4382d2SGreg Kroah-Hartman * a TX buffer completing, we must update the tx queued status to
563ab4382d2SGreg Kroah-Hartman * get further refills (hence we check dmacr).
564ab4382d2SGreg Kroah-Hartman */
565ab4382d2SGreg Kroah-Hartman if (!(dmacr & UART011_TXDMAE) || uart_tx_stopped(&uap->port) ||
566ab4382d2SGreg Kroah-Hartman uart_circ_empty(&uap->port.state->xmit)) {
567ab4382d2SGreg Kroah-Hartman uap->dmatx.queued = false;
5685aea1229SThomas Gleixner uart_port_unlock_irqrestore(&uap->port, flags);
569ab4382d2SGreg Kroah-Hartman return;
570ab4382d2SGreg Kroah-Hartman }
571ab4382d2SGreg Kroah-Hartman
572734745caSDave Martin if (pl011_dma_tx_refill(uap) <= 0)
573ab4382d2SGreg Kroah-Hartman /*
574ab4382d2SGreg Kroah-Hartman * We didn't queue a DMA buffer for some reason, but we
575ab4382d2SGreg Kroah-Hartman * have data pending to be sent. Re-enable the TX IRQ.
576ab4382d2SGreg Kroah-Hartman */
577734745caSDave Martin pl011_start_tx_pio(uap);
578734745caSDave Martin
5795aea1229SThomas Gleixner uart_port_unlock_irqrestore(&uap->port, flags);
580ab4382d2SGreg Kroah-Hartman }
581ab4382d2SGreg Kroah-Hartman
582ab4382d2SGreg Kroah-Hartman /*
583ab4382d2SGreg Kroah-Hartman * Try to refill the TX DMA buffer.
584ab4382d2SGreg Kroah-Hartman * Locking: called with port lock held and IRQs disabled.
585ab4382d2SGreg Kroah-Hartman * Returns:
586ab4382d2SGreg Kroah-Hartman * 1 if we queued up a TX DMA buffer.
587ab4382d2SGreg Kroah-Hartman * 0 if we didn't want to handle this by DMA
588ab4382d2SGreg Kroah-Hartman * <0 on error
589ab4382d2SGreg Kroah-Hartman */
pl011_dma_tx_refill(struct uart_amba_port * uap)590ab4382d2SGreg Kroah-Hartman static int pl011_dma_tx_refill(struct uart_amba_port *uap)
591ab4382d2SGreg Kroah-Hartman {
592ab4382d2SGreg Kroah-Hartman struct pl011_dmatx_data *dmatx = &uap->dmatx;
593ab4382d2SGreg Kroah-Hartman struct dma_chan *chan = dmatx->chan;
594ab4382d2SGreg Kroah-Hartman struct dma_device *dma_dev = chan->device;
595ab4382d2SGreg Kroah-Hartman struct dma_async_tx_descriptor *desc;
596ab4382d2SGreg Kroah-Hartman struct circ_buf *xmit = &uap->port.state->xmit;
597ab4382d2SGreg Kroah-Hartman unsigned int count;
598ab4382d2SGreg Kroah-Hartman
599ab4382d2SGreg Kroah-Hartman /*
600ab4382d2SGreg Kroah-Hartman * Try to avoid the overhead involved in using DMA if the
601ab4382d2SGreg Kroah-Hartman * transaction fits in the first half of the FIFO, by using
602ab4382d2SGreg Kroah-Hartman * the standard interrupt handling. This ensures that we
603ab4382d2SGreg Kroah-Hartman * issue a uart_write_wakeup() at the appropriate time.
604ab4382d2SGreg Kroah-Hartman */
605ab4382d2SGreg Kroah-Hartman count = uart_circ_chars_pending(xmit);
606ab4382d2SGreg Kroah-Hartman if (count < (uap->fifosize >> 1)) {
607ab4382d2SGreg Kroah-Hartman uap->dmatx.queued = false;
608ab4382d2SGreg Kroah-Hartman return 0;
609ab4382d2SGreg Kroah-Hartman }
610ab4382d2SGreg Kroah-Hartman
611ab4382d2SGreg Kroah-Hartman /*
612ab4382d2SGreg Kroah-Hartman * Bodge: don't send the last character by DMA, as this
613ab4382d2SGreg Kroah-Hartman * will prevent XON from notifying us to restart DMA.
614ab4382d2SGreg Kroah-Hartman */
615ab4382d2SGreg Kroah-Hartman count -= 1;
616ab4382d2SGreg Kroah-Hartman
617ab4382d2SGreg Kroah-Hartman /* Else proceed to copy the TX chars to the DMA buffer and fire DMA */
618ab4382d2SGreg Kroah-Hartman if (count > PL011_DMA_BUFFER_SIZE)
619ab4382d2SGreg Kroah-Hartman count = PL011_DMA_BUFFER_SIZE;
620ab4382d2SGreg Kroah-Hartman
621ab4382d2SGreg Kroah-Hartman if (xmit->tail < xmit->head)
622ab4382d2SGreg Kroah-Hartman memcpy(&dmatx->buf[0], &xmit->buf[xmit->tail], count);
623ab4382d2SGreg Kroah-Hartman else {
624ab4382d2SGreg Kroah-Hartman size_t first = UART_XMIT_SIZE - xmit->tail;
625e2a545a6SAndrew Jackson size_t second;
626e2a545a6SAndrew Jackson
627e2a545a6SAndrew Jackson if (first > count)
628e2a545a6SAndrew Jackson first = count;
629e2a545a6SAndrew Jackson second = count - first;
630ab4382d2SGreg Kroah-Hartman
631ab4382d2SGreg Kroah-Hartman memcpy(&dmatx->buf[0], &xmit->buf[xmit->tail], first);
632ab4382d2SGreg Kroah-Hartman if (second)
633ab4382d2SGreg Kroah-Hartman memcpy(&dmatx->buf[first], &xmit->buf[0], second);
634ab4382d2SGreg Kroah-Hartman }
635ab4382d2SGreg Kroah-Hartman
636c865b77eSArnd Bergmann dmatx->len = count;
637c865b77eSArnd Bergmann dmatx->dma = dma_map_single(dma_dev->dev, dmatx->buf, count,
638c865b77eSArnd Bergmann DMA_TO_DEVICE);
639c865b77eSArnd Bergmann if (dmatx->dma == DMA_MAPPING_ERROR) {
640ab4382d2SGreg Kroah-Hartman uap->dmatx.queued = false;
641ab4382d2SGreg Kroah-Hartman dev_dbg(uap->port.dev, "unable to map TX DMA\n");
642ab4382d2SGreg Kroah-Hartman return -EBUSY;
643ab4382d2SGreg Kroah-Hartman }
644ab4382d2SGreg Kroah-Hartman
645c865b77eSArnd Bergmann desc = dmaengine_prep_slave_single(chan, dmatx->dma, dmatx->len, DMA_MEM_TO_DEV,
646ab4382d2SGreg Kroah-Hartman DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
647ab4382d2SGreg Kroah-Hartman if (!desc) {
648c865b77eSArnd Bergmann dma_unmap_single(dma_dev->dev, dmatx->dma, dmatx->len, DMA_TO_DEVICE);
649ab4382d2SGreg Kroah-Hartman uap->dmatx.queued = false;
650ab4382d2SGreg Kroah-Hartman /*
651ab4382d2SGreg Kroah-Hartman * If DMA cannot be used right now, we complete this
652ab4382d2SGreg Kroah-Hartman * transaction via IRQ and let the TTY layer retry.
653ab4382d2SGreg Kroah-Hartman */
654ab4382d2SGreg Kroah-Hartman dev_dbg(uap->port.dev, "TX DMA busy\n");
655ab4382d2SGreg Kroah-Hartman return -EBUSY;
656ab4382d2SGreg Kroah-Hartman }
657ab4382d2SGreg Kroah-Hartman
658ab4382d2SGreg Kroah-Hartman /* Some data to go along to the callback */
659ab4382d2SGreg Kroah-Hartman desc->callback = pl011_dma_tx_callback;
660ab4382d2SGreg Kroah-Hartman desc->callback_param = uap;
661ab4382d2SGreg Kroah-Hartman
662ab4382d2SGreg Kroah-Hartman /* All errors should happen at prepare time */
663ab4382d2SGreg Kroah-Hartman dmaengine_submit(desc);
664ab4382d2SGreg Kroah-Hartman
665ab4382d2SGreg Kroah-Hartman /* Fire the DMA transaction */
666ab4382d2SGreg Kroah-Hartman dma_dev->device_issue_pending(chan);
667ab4382d2SGreg Kroah-Hartman
668ab4382d2SGreg Kroah-Hartman uap->dmacr |= UART011_TXDMAE;
6699f25bc51SRussell King pl011_write(uap->dmacr, uap, REG_DMACR);
670ab4382d2SGreg Kroah-Hartman uap->dmatx.queued = true;
671ab4382d2SGreg Kroah-Hartman
672ab4382d2SGreg Kroah-Hartman /*
673ab4382d2SGreg Kroah-Hartman * Now we know that DMA will fire, so advance the ring buffer
674ab4382d2SGreg Kroah-Hartman * with the stuff we just dispatched.
675ab4382d2SGreg Kroah-Hartman */
67671a67573SIlpo Järvinen uart_xmit_advance(&uap->port, count);
677ab4382d2SGreg Kroah-Hartman
678ab4382d2SGreg Kroah-Hartman if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
679ab4382d2SGreg Kroah-Hartman uart_write_wakeup(&uap->port);
680ab4382d2SGreg Kroah-Hartman
681ab4382d2SGreg Kroah-Hartman return 1;
682ab4382d2SGreg Kroah-Hartman }
683ab4382d2SGreg Kroah-Hartman
684ab4382d2SGreg Kroah-Hartman /*
685ab4382d2SGreg Kroah-Hartman * We received a transmit interrupt without a pending X-char but with
686ab4382d2SGreg Kroah-Hartman * pending characters.
687ab4382d2SGreg Kroah-Hartman * Locking: called with port lock held and IRQs disabled.
688ab4382d2SGreg Kroah-Hartman * Returns:
689ab4382d2SGreg Kroah-Hartman * false if we want to use PIO to transmit
690ab4382d2SGreg Kroah-Hartman * true if we queued a DMA buffer
691ab4382d2SGreg Kroah-Hartman */
pl011_dma_tx_irq(struct uart_amba_port * uap)692ab4382d2SGreg Kroah-Hartman static bool pl011_dma_tx_irq(struct uart_amba_port *uap)
693ab4382d2SGreg Kroah-Hartman {
694ead76f32SLinus Walleij if (!uap->using_tx_dma)
695ab4382d2SGreg Kroah-Hartman return false;
696ab4382d2SGreg Kroah-Hartman
697ab4382d2SGreg Kroah-Hartman /*
698ab4382d2SGreg Kroah-Hartman * If we already have a TX buffer queued, but received a
699ab4382d2SGreg Kroah-Hartman * TX interrupt, it will be because we've just sent an X-char.
700ab4382d2SGreg Kroah-Hartman * Ensure the TX DMA is enabled and the TX IRQ is disabled.
701ab4382d2SGreg Kroah-Hartman */
702ab4382d2SGreg Kroah-Hartman if (uap->dmatx.queued) {
703ab4382d2SGreg Kroah-Hartman uap->dmacr |= UART011_TXDMAE;
7049f25bc51SRussell King pl011_write(uap->dmacr, uap, REG_DMACR);
705ab4382d2SGreg Kroah-Hartman uap->im &= ~UART011_TXIM;
7069f25bc51SRussell King pl011_write(uap->im, uap, REG_IMSC);
707ab4382d2SGreg Kroah-Hartman return true;
708ab4382d2SGreg Kroah-Hartman }
709ab4382d2SGreg Kroah-Hartman
710ab4382d2SGreg Kroah-Hartman /*
711ab4382d2SGreg Kroah-Hartman * We don't have a TX buffer queued, so try to queue one.
71225985edcSLucas De Marchi * If we successfully queued a buffer, mask the TX IRQ.
713ab4382d2SGreg Kroah-Hartman */
714ab4382d2SGreg Kroah-Hartman if (pl011_dma_tx_refill(uap) > 0) {
715ab4382d2SGreg Kroah-Hartman uap->im &= ~UART011_TXIM;
7169f25bc51SRussell King pl011_write(uap->im, uap, REG_IMSC);
717ab4382d2SGreg Kroah-Hartman return true;
718ab4382d2SGreg Kroah-Hartman }
719ab4382d2SGreg Kroah-Hartman return false;
720ab4382d2SGreg Kroah-Hartman }
721ab4382d2SGreg Kroah-Hartman
722ab4382d2SGreg Kroah-Hartman /*
723ab4382d2SGreg Kroah-Hartman * Stop the DMA transmit (eg, due to received XOFF).
724ab4382d2SGreg Kroah-Hartman * Locking: called with port lock held and IRQs disabled.
725ab4382d2SGreg Kroah-Hartman */
pl011_dma_tx_stop(struct uart_amba_port * uap)726ab4382d2SGreg Kroah-Hartman static inline void pl011_dma_tx_stop(struct uart_amba_port *uap)
727ab4382d2SGreg Kroah-Hartman {
728ab4382d2SGreg Kroah-Hartman if (uap->dmatx.queued) {
729ab4382d2SGreg Kroah-Hartman uap->dmacr &= ~UART011_TXDMAE;
7309f25bc51SRussell King pl011_write(uap->dmacr, uap, REG_DMACR);
731ab4382d2SGreg Kroah-Hartman }
732ab4382d2SGreg Kroah-Hartman }
733ab4382d2SGreg Kroah-Hartman
734ab4382d2SGreg Kroah-Hartman /*
735ab4382d2SGreg Kroah-Hartman * Try to start a DMA transmit, or in the case of an XON/OFF
736ab4382d2SGreg Kroah-Hartman * character queued for send, try to get that character out ASAP.
737ab4382d2SGreg Kroah-Hartman * Locking: called with port lock held and IRQs disabled.
738ab4382d2SGreg Kroah-Hartman * Returns:
739ab4382d2SGreg Kroah-Hartman * false if we want the TX IRQ to be enabled
740ab4382d2SGreg Kroah-Hartman * true if we have a buffer queued
741ab4382d2SGreg Kroah-Hartman */
pl011_dma_tx_start(struct uart_amba_port * uap)742ab4382d2SGreg Kroah-Hartman static inline bool pl011_dma_tx_start(struct uart_amba_port *uap)
743ab4382d2SGreg Kroah-Hartman {
744ab4382d2SGreg Kroah-Hartman u16 dmacr;
745ab4382d2SGreg Kroah-Hartman
746ead76f32SLinus Walleij if (!uap->using_tx_dma)
747ab4382d2SGreg Kroah-Hartman return false;
748ab4382d2SGreg Kroah-Hartman
749ab4382d2SGreg Kroah-Hartman if (!uap->port.x_char) {
750ab4382d2SGreg Kroah-Hartman /* no X-char, try to push chars out in DMA mode */
751ab4382d2SGreg Kroah-Hartman bool ret = true;
752ab4382d2SGreg Kroah-Hartman
753ab4382d2SGreg Kroah-Hartman if (!uap->dmatx.queued) {
754ab4382d2SGreg Kroah-Hartman if (pl011_dma_tx_refill(uap) > 0) {
755ab4382d2SGreg Kroah-Hartman uap->im &= ~UART011_TXIM;
7569f25bc51SRussell King pl011_write(uap->im, uap, REG_IMSC);
757734745caSDave Martin } else
758ab4382d2SGreg Kroah-Hartman ret = false;
759ab4382d2SGreg Kroah-Hartman } else if (!(uap->dmacr & UART011_TXDMAE)) {
760ab4382d2SGreg Kroah-Hartman uap->dmacr |= UART011_TXDMAE;
7619f25bc51SRussell King pl011_write(uap->dmacr, uap, REG_DMACR);
762ab4382d2SGreg Kroah-Hartman }
763ab4382d2SGreg Kroah-Hartman return ret;
764ab4382d2SGreg Kroah-Hartman }
765ab4382d2SGreg Kroah-Hartman
766ab4382d2SGreg Kroah-Hartman /*
767ab4382d2SGreg Kroah-Hartman * We have an X-char to send. Disable DMA to prevent it loading
768ab4382d2SGreg Kroah-Hartman * the TX fifo, and then see if we can stuff it into the FIFO.
769ab4382d2SGreg Kroah-Hartman */
770ab4382d2SGreg Kroah-Hartman dmacr = uap->dmacr;
771ab4382d2SGreg Kroah-Hartman uap->dmacr &= ~UART011_TXDMAE;
7729f25bc51SRussell King pl011_write(uap->dmacr, uap, REG_DMACR);
773ab4382d2SGreg Kroah-Hartman
7749f25bc51SRussell King if (pl011_read(uap, REG_FR) & UART01x_FR_TXFF) {
775ab4382d2SGreg Kroah-Hartman /*
776ab4382d2SGreg Kroah-Hartman * No space in the FIFO, so enable the transmit interrupt
777ab4382d2SGreg Kroah-Hartman * so we know when there is space. Note that once we've
778ab4382d2SGreg Kroah-Hartman * loaded the character, we should just re-enable DMA.
779ab4382d2SGreg Kroah-Hartman */
780ab4382d2SGreg Kroah-Hartman return false;
781ab4382d2SGreg Kroah-Hartman }
782ab4382d2SGreg Kroah-Hartman
7839f25bc51SRussell King pl011_write(uap->port.x_char, uap, REG_DR);
784ab4382d2SGreg Kroah-Hartman uap->port.icount.tx++;
785ab4382d2SGreg Kroah-Hartman uap->port.x_char = 0;
786ab4382d2SGreg Kroah-Hartman
787ab4382d2SGreg Kroah-Hartman /* Success - restore the DMA state */
788ab4382d2SGreg Kroah-Hartman uap->dmacr = dmacr;
7899f25bc51SRussell King pl011_write(dmacr, uap, REG_DMACR);
790ab4382d2SGreg Kroah-Hartman
791ab4382d2SGreg Kroah-Hartman return true;
792ab4382d2SGreg Kroah-Hartman }
793ab4382d2SGreg Kroah-Hartman
794ab4382d2SGreg Kroah-Hartman /*
795ab4382d2SGreg Kroah-Hartman * Flush the transmit buffer.
796ab4382d2SGreg Kroah-Hartman * Locking: called with port lock held and IRQs disabled.
797ab4382d2SGreg Kroah-Hartman */
pl011_dma_flush_buffer(struct uart_port * port)798ab4382d2SGreg Kroah-Hartman static void pl011_dma_flush_buffer(struct uart_port *port)
799b83286bfSFabio Estevam __releases(&uap->port.lock)
800b83286bfSFabio Estevam __acquires(&uap->port.lock)
801ab4382d2SGreg Kroah-Hartman {
802a5820c24SDaniel Thompson struct uart_amba_port *uap =
803a5820c24SDaniel Thompson container_of(port, struct uart_amba_port, port);
804ab4382d2SGreg Kroah-Hartman
805ead76f32SLinus Walleij if (!uap->using_tx_dma)
806ab4382d2SGreg Kroah-Hartman return;
807ab4382d2SGreg Kroah-Hartman
808f6a19647SVincent Whitchurch dmaengine_terminate_async(uap->dmatx.chan);
809f6a19647SVincent Whitchurch
810ab4382d2SGreg Kroah-Hartman if (uap->dmatx.queued) {
811c865b77eSArnd Bergmann dma_unmap_single(uap->dmatx.chan->device->dev, uap->dmatx.dma,
812c865b77eSArnd Bergmann uap->dmatx.len, DMA_TO_DEVICE);
813ab4382d2SGreg Kroah-Hartman uap->dmatx.queued = false;
814ab4382d2SGreg Kroah-Hartman uap->dmacr &= ~UART011_TXDMAE;
8159f25bc51SRussell King pl011_write(uap->dmacr, uap, REG_DMACR);
816ab4382d2SGreg Kroah-Hartman }
817ab4382d2SGreg Kroah-Hartman }
818ab4382d2SGreg Kroah-Hartman
819ead76f32SLinus Walleij static void pl011_dma_rx_callback(void *data);
820ead76f32SLinus Walleij
pl011_dma_rx_trigger_dma(struct uart_amba_port * uap)821ead76f32SLinus Walleij static int pl011_dma_rx_trigger_dma(struct uart_amba_port *uap)
822ead76f32SLinus Walleij {
823ead76f32SLinus Walleij struct dma_chan *rxchan = uap->dmarx.chan;
824ead76f32SLinus Walleij struct pl011_dmarx_data *dmarx = &uap->dmarx;
825ead76f32SLinus Walleij struct dma_async_tx_descriptor *desc;
826c865b77eSArnd Bergmann struct pl011_dmabuf *dbuf;
827ead76f32SLinus Walleij
828ead76f32SLinus Walleij if (!rxchan)
829ead76f32SLinus Walleij return -EIO;
830ead76f32SLinus Walleij
831ead76f32SLinus Walleij /* Start the RX DMA job */
832c865b77eSArnd Bergmann dbuf = uap->dmarx.use_buf_b ?
833c865b77eSArnd Bergmann &uap->dmarx.dbuf_b : &uap->dmarx.dbuf_a;
834c865b77eSArnd Bergmann desc = dmaengine_prep_slave_single(rxchan, dbuf->dma, dbuf->len,
835a485df4bSVinod Koul DMA_DEV_TO_MEM,
836ead76f32SLinus Walleij DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
837ead76f32SLinus Walleij /*
838ead76f32SLinus Walleij * If the DMA engine is busy and cannot prepare a
839ead76f32SLinus Walleij * channel, no big deal, the driver will fall back
840ead76f32SLinus Walleij * to interrupt mode as a result of this error code.
841ead76f32SLinus Walleij */
842ead76f32SLinus Walleij if (!desc) {
843ead76f32SLinus Walleij uap->dmarx.running = false;
844ead76f32SLinus Walleij dmaengine_terminate_all(rxchan);
845ead76f32SLinus Walleij return -EBUSY;
846ead76f32SLinus Walleij }
847ead76f32SLinus Walleij
848ead76f32SLinus Walleij /* Some data to go along to the callback */
849ead76f32SLinus Walleij desc->callback = pl011_dma_rx_callback;
850ead76f32SLinus Walleij desc->callback_param = uap;
851ead76f32SLinus Walleij dmarx->cookie = dmaengine_submit(desc);
852ead76f32SLinus Walleij dma_async_issue_pending(rxchan);
853ead76f32SLinus Walleij
854ead76f32SLinus Walleij uap->dmacr |= UART011_RXDMAE;
8559f25bc51SRussell King pl011_write(uap->dmacr, uap, REG_DMACR);
856ead76f32SLinus Walleij uap->dmarx.running = true;
857ead76f32SLinus Walleij
858ead76f32SLinus Walleij uap->im &= ~UART011_RXIM;
8599f25bc51SRussell King pl011_write(uap->im, uap, REG_IMSC);
860ead76f32SLinus Walleij
861ead76f32SLinus Walleij return 0;
862ead76f32SLinus Walleij }
863ead76f32SLinus Walleij
864ead76f32SLinus Walleij /*
865ead76f32SLinus Walleij * This is called when either the DMA job is complete, or
866ead76f32SLinus Walleij * the FIFO timeout interrupt occurred. This must be called
867ead76f32SLinus Walleij * with the port spinlock uap->port.lock held.
868ead76f32SLinus Walleij */
pl011_dma_rx_chars(struct uart_amba_port * uap,u32 pending,bool use_buf_b,bool readfifo)869ead76f32SLinus Walleij static void pl011_dma_rx_chars(struct uart_amba_port *uap,
870ead76f32SLinus Walleij u32 pending, bool use_buf_b,
871ead76f32SLinus Walleij bool readfifo)
872ead76f32SLinus Walleij {
87305c7cd39SJiri Slaby struct tty_port *port = &uap->port.state->port;
874c865b77eSArnd Bergmann struct pl011_dmabuf *dbuf = use_buf_b ?
875c865b77eSArnd Bergmann &uap->dmarx.dbuf_b : &uap->dmarx.dbuf_a;
876ead76f32SLinus Walleij int dma_count = 0;
877ead76f32SLinus Walleij u32 fifotaken = 0; /* only used for vdbg() */
878ead76f32SLinus Walleij
879cb06ff10SChanho Min struct pl011_dmarx_data *dmarx = &uap->dmarx;
880cb06ff10SChanho Min int dmataken = 0;
881cb06ff10SChanho Min
882cb06ff10SChanho Min if (uap->dmarx.poll_rate) {
883cb06ff10SChanho Min /* The data can be taken by polling */
884c865b77eSArnd Bergmann dmataken = dbuf->len - dmarx->last_residue;
885cb06ff10SChanho Min /* Recalculate the pending size */
886cb06ff10SChanho Min if (pending >= dmataken)
887cb06ff10SChanho Min pending -= dmataken;
888cb06ff10SChanho Min }
889cb06ff10SChanho Min
890cb06ff10SChanho Min /* Pick the remain data from the DMA */
891ead76f32SLinus Walleij if (pending) {
892ead76f32SLinus Walleij
893ead76f32SLinus Walleij /*
894ead76f32SLinus Walleij * First take all chars in the DMA pipe, then look in the FIFO.
895ead76f32SLinus Walleij * Note that tty_insert_flip_buf() tries to take as many chars
896ead76f32SLinus Walleij * as it can.
897ead76f32SLinus Walleij */
898c865b77eSArnd Bergmann dma_count = tty_insert_flip_string(port, dbuf->buf + dmataken,
899cb06ff10SChanho Min pending);
900ead76f32SLinus Walleij
901ead76f32SLinus Walleij uap->port.icount.rx += dma_count;
902ead76f32SLinus Walleij if (dma_count < pending)
903ead76f32SLinus Walleij dev_warn(uap->port.dev,
904ead76f32SLinus Walleij "couldn't insert all characters (TTY is full?)\n");
905ead76f32SLinus Walleij }
906ead76f32SLinus Walleij
907cb06ff10SChanho Min /* Reset the last_residue for Rx DMA poll */
908cb06ff10SChanho Min if (uap->dmarx.poll_rate)
909c865b77eSArnd Bergmann dmarx->last_residue = dbuf->len;
910cb06ff10SChanho Min
911ead76f32SLinus Walleij /*
912ead76f32SLinus Walleij * Only continue with trying to read the FIFO if all DMA chars have
913ead76f32SLinus Walleij * been taken first.
914ead76f32SLinus Walleij */
915ead76f32SLinus Walleij if (dma_count == pending && readfifo) {
916ead76f32SLinus Walleij /* Clear any error flags */
91775836339SRussell King pl011_write(UART011_OEIS | UART011_BEIS | UART011_PEIS |
9189f25bc51SRussell King UART011_FEIS, uap, REG_ICR);
919ead76f32SLinus Walleij
920ead76f32SLinus Walleij /*
921ead76f32SLinus Walleij * If we read all the DMA'd characters, and we had an
92229772c4eSLinus Walleij * incomplete buffer, that could be due to an rx error, or
92329772c4eSLinus Walleij * maybe we just timed out. Read any pending chars and check
92429772c4eSLinus Walleij * the error status.
92529772c4eSLinus Walleij *
92629772c4eSLinus Walleij * Error conditions will only occur in the FIFO, these will
92729772c4eSLinus Walleij * trigger an immediate interrupt and stop the DMA job, so we
92829772c4eSLinus Walleij * will always find the error in the FIFO, never in the DMA
92929772c4eSLinus Walleij * buffer.
930ead76f32SLinus Walleij */
93129772c4eSLinus Walleij fifotaken = pl011_fifo_to_tty(uap);
932ead76f32SLinus Walleij }
933ead76f32SLinus Walleij
934ead76f32SLinus Walleij dev_vdbg(uap->port.dev,
935ead76f32SLinus Walleij "Took %d chars from DMA buffer and %d chars from the FIFO\n",
936ead76f32SLinus Walleij dma_count, fifotaken);
9372e124b4aSJiri Slaby tty_flip_buffer_push(port);
938ead76f32SLinus Walleij }
939ead76f32SLinus Walleij
pl011_dma_rx_irq(struct uart_amba_port * uap)940ead76f32SLinus Walleij static void pl011_dma_rx_irq(struct uart_amba_port *uap)
941ead76f32SLinus Walleij {
942ead76f32SLinus Walleij struct pl011_dmarx_data *dmarx = &uap->dmarx;
943ead76f32SLinus Walleij struct dma_chan *rxchan = dmarx->chan;
944c865b77eSArnd Bergmann struct pl011_dmabuf *dbuf = dmarx->use_buf_b ?
945c865b77eSArnd Bergmann &dmarx->dbuf_b : &dmarx->dbuf_a;
946ead76f32SLinus Walleij size_t pending;
947ead76f32SLinus Walleij struct dma_tx_state state;
948ead76f32SLinus Walleij enum dma_status dmastat;
949ead76f32SLinus Walleij
950ead76f32SLinus Walleij /*
951ead76f32SLinus Walleij * Pause the transfer so we can trust the current counter,
952ead76f32SLinus Walleij * do this before we pause the PL011 block, else we may
953ead76f32SLinus Walleij * overflow the FIFO.
954ead76f32SLinus Walleij */
955ead76f32SLinus Walleij if (dmaengine_pause(rxchan))
956ead76f32SLinus Walleij dev_err(uap->port.dev, "unable to pause DMA transfer\n");
957ead76f32SLinus Walleij dmastat = rxchan->device->device_tx_status(rxchan,
958ead76f32SLinus Walleij dmarx->cookie, &state);
959ead76f32SLinus Walleij if (dmastat != DMA_PAUSED)
960ead76f32SLinus Walleij dev_err(uap->port.dev, "unable to pause DMA transfer\n");
961ead76f32SLinus Walleij
962ead76f32SLinus Walleij /* Disable RX DMA - incoming data will wait in the FIFO */
963ead76f32SLinus Walleij uap->dmacr &= ~UART011_RXDMAE;
9649f25bc51SRussell King pl011_write(uap->dmacr, uap, REG_DMACR);
965ead76f32SLinus Walleij uap->dmarx.running = false;
966ead76f32SLinus Walleij
967c865b77eSArnd Bergmann pending = dbuf->len - state.residue;
968ead76f32SLinus Walleij BUG_ON(pending > PL011_DMA_BUFFER_SIZE);
969ead76f32SLinus Walleij /* Then we terminate the transfer - we now know our residue */
970ead76f32SLinus Walleij dmaengine_terminate_all(rxchan);
971ead76f32SLinus Walleij
972ead76f32SLinus Walleij /*
973ead76f32SLinus Walleij * This will take the chars we have so far and insert
974ead76f32SLinus Walleij * into the framework.
975ead76f32SLinus Walleij */
976ead76f32SLinus Walleij pl011_dma_rx_chars(uap, pending, dmarx->use_buf_b, true);
977ead76f32SLinus Walleij
978ead76f32SLinus Walleij /* Switch buffer & re-trigger DMA job */
979ead76f32SLinus Walleij dmarx->use_buf_b = !dmarx->use_buf_b;
980ead76f32SLinus Walleij if (pl011_dma_rx_trigger_dma(uap)) {
981ead76f32SLinus Walleij dev_dbg(uap->port.dev, "could not retrigger RX DMA job "
982ead76f32SLinus Walleij "fall back to interrupt mode\n");
983ead76f32SLinus Walleij uap->im |= UART011_RXIM;
9849f25bc51SRussell King pl011_write(uap->im, uap, REG_IMSC);
985ead76f32SLinus Walleij }
986ead76f32SLinus Walleij }
987ead76f32SLinus Walleij
pl011_dma_rx_callback(void * data)988ead76f32SLinus Walleij static void pl011_dma_rx_callback(void *data)
989ead76f32SLinus Walleij {
990ead76f32SLinus Walleij struct uart_amba_port *uap = data;
991ead76f32SLinus Walleij struct pl011_dmarx_data *dmarx = &uap->dmarx;
9926dc01aa6SChanho Min struct dma_chan *rxchan = dmarx->chan;
993ead76f32SLinus Walleij bool lastbuf = dmarx->use_buf_b;
994c865b77eSArnd Bergmann struct pl011_dmabuf *dbuf = dmarx->use_buf_b ?
995c865b77eSArnd Bergmann &dmarx->dbuf_b : &dmarx->dbuf_a;
9966dc01aa6SChanho Min size_t pending;
9976dc01aa6SChanho Min struct dma_tx_state state;
998ead76f32SLinus Walleij int ret;
999ead76f32SLinus Walleij
1000ead76f32SLinus Walleij /*
1001ead76f32SLinus Walleij * This completion interrupt occurs typically when the
1002ead76f32SLinus Walleij * RX buffer is totally stuffed but no timeout has yet
1003ead76f32SLinus Walleij * occurred. When that happens, we just want the RX
1004ead76f32SLinus Walleij * routine to flush out the secondary DMA buffer while
1005ead76f32SLinus Walleij * we immediately trigger the next DMA job.
1006ead76f32SLinus Walleij */
10075aea1229SThomas Gleixner uart_port_lock_irq(&uap->port);
10086dc01aa6SChanho Min /*
10096dc01aa6SChanho Min * Rx data can be taken by the UART interrupts during
10106dc01aa6SChanho Min * the DMA irq handler. So we check the residue here.
10116dc01aa6SChanho Min */
10126dc01aa6SChanho Min rxchan->device->device_tx_status(rxchan, dmarx->cookie, &state);
1013c865b77eSArnd Bergmann pending = dbuf->len - state.residue;
10146dc01aa6SChanho Min BUG_ON(pending > PL011_DMA_BUFFER_SIZE);
10156dc01aa6SChanho Min /* Then we terminate the transfer - we now know our residue */
10166dc01aa6SChanho Min dmaengine_terminate_all(rxchan);
10176dc01aa6SChanho Min
1018ead76f32SLinus Walleij uap->dmarx.running = false;
1019ead76f32SLinus Walleij dmarx->use_buf_b = !lastbuf;
1020ead76f32SLinus Walleij ret = pl011_dma_rx_trigger_dma(uap);
1021ead76f32SLinus Walleij
10226dc01aa6SChanho Min pl011_dma_rx_chars(uap, pending, lastbuf, false);
10235aea1229SThomas Gleixner uart_port_unlock_irq(&uap->port);
1024ead76f32SLinus Walleij /*
1025ead76f32SLinus Walleij * Do this check after we picked the DMA chars so we don't
1026ead76f32SLinus Walleij * get some IRQ immediately from RX.
1027ead76f32SLinus Walleij */
1028ead76f32SLinus Walleij if (ret) {
1029ead76f32SLinus Walleij dev_dbg(uap->port.dev, "could not retrigger RX DMA job "
1030ead76f32SLinus Walleij "fall back to interrupt mode\n");
1031ead76f32SLinus Walleij uap->im |= UART011_RXIM;
10329f25bc51SRussell King pl011_write(uap->im, uap, REG_IMSC);
1033ead76f32SLinus Walleij }
1034ead76f32SLinus Walleij }
1035ead76f32SLinus Walleij
1036ead76f32SLinus Walleij /*
1037ead76f32SLinus Walleij * Stop accepting received characters, when we're shutting down or
1038ead76f32SLinus Walleij * suspending this port.
1039ead76f32SLinus Walleij * Locking: called with port lock held and IRQs disabled.
1040ead76f32SLinus Walleij */
pl011_dma_rx_stop(struct uart_amba_port * uap)1041ead76f32SLinus Walleij static inline void pl011_dma_rx_stop(struct uart_amba_port *uap)
1042ead76f32SLinus Walleij {
104394cdb9f3SJiamei Xie if (!uap->using_rx_dma)
104494cdb9f3SJiamei Xie return;
104594cdb9f3SJiamei Xie
1046ead76f32SLinus Walleij /* FIXME. Just disable the DMA enable */
1047ead76f32SLinus Walleij uap->dmacr &= ~UART011_RXDMAE;
10489f25bc51SRussell King pl011_write(uap->dmacr, uap, REG_DMACR);
1049ead76f32SLinus Walleij }
1050ab4382d2SGreg Kroah-Hartman
1051cb06ff10SChanho Min /*
1052cb06ff10SChanho Min * Timer handler for Rx DMA polling.
1053cb06ff10SChanho Min * Every polling, It checks the residue in the dma buffer and transfer
1054cb06ff10SChanho Min * data to the tty. Also, last_residue is updated for the next polling.
1055cb06ff10SChanho Min */
pl011_dma_rx_poll(struct timer_list * t)1056f7f73096SKees Cook static void pl011_dma_rx_poll(struct timer_list *t)
1057cb06ff10SChanho Min {
1058f7f73096SKees Cook struct uart_amba_port *uap = from_timer(uap, t, dmarx.timer);
1059cb06ff10SChanho Min struct tty_port *port = &uap->port.state->port;
1060cb06ff10SChanho Min struct pl011_dmarx_data *dmarx = &uap->dmarx;
1061cb06ff10SChanho Min struct dma_chan *rxchan = uap->dmarx.chan;
106218ee37e1SJohan Hovold unsigned long flags;
1063cb06ff10SChanho Min unsigned int dmataken = 0;
1064cb06ff10SChanho Min unsigned int size = 0;
1065c865b77eSArnd Bergmann struct pl011_dmabuf *dbuf;
1066cb06ff10SChanho Min int dma_count;
1067cb06ff10SChanho Min struct dma_tx_state state;
1068cb06ff10SChanho Min
1069c865b77eSArnd Bergmann dbuf = dmarx->use_buf_b ? &uap->dmarx.dbuf_b : &uap->dmarx.dbuf_a;
1070cb06ff10SChanho Min rxchan->device->device_tx_status(rxchan, dmarx->cookie, &state);
1071cb06ff10SChanho Min if (likely(state.residue < dmarx->last_residue)) {
1072c865b77eSArnd Bergmann dmataken = dbuf->len - dmarx->last_residue;
1073cb06ff10SChanho Min size = dmarx->last_residue - state.residue;
1074c865b77eSArnd Bergmann dma_count = tty_insert_flip_string(port, dbuf->buf + dmataken,
1075cb06ff10SChanho Min size);
1076cb06ff10SChanho Min if (dma_count == size)
1077cb06ff10SChanho Min dmarx->last_residue = state.residue;
1078cb06ff10SChanho Min dmarx->last_jiffies = jiffies;
1079cb06ff10SChanho Min }
1080cb06ff10SChanho Min tty_flip_buffer_push(port);
1081cb06ff10SChanho Min
1082cb06ff10SChanho Min /*
1083cb06ff10SChanho Min * If no data is received in poll_timeout, the driver will fall back
1084cb06ff10SChanho Min * to interrupt mode. We will retrigger DMA at the first interrupt.
1085cb06ff10SChanho Min */
1086cb06ff10SChanho Min if (jiffies_to_msecs(jiffies - dmarx->last_jiffies)
1087cb06ff10SChanho Min > uap->dmarx.poll_timeout) {
1088cb06ff10SChanho Min
10895aea1229SThomas Gleixner uart_port_lock_irqsave(&uap->port, &flags);
1090cb06ff10SChanho Min pl011_dma_rx_stop(uap);
1091c25a1ad7SGuennadi Liakhovetski uap->im |= UART011_RXIM;
10929f25bc51SRussell King pl011_write(uap->im, uap, REG_IMSC);
10935aea1229SThomas Gleixner uart_port_unlock_irqrestore(&uap->port, flags);
1094cb06ff10SChanho Min
1095cb06ff10SChanho Min uap->dmarx.running = false;
1096cb06ff10SChanho Min dmaengine_terminate_all(rxchan);
1097cb06ff10SChanho Min del_timer(&uap->dmarx.timer);
1098cb06ff10SChanho Min } else {
1099cb06ff10SChanho Min mod_timer(&uap->dmarx.timer,
1100cb06ff10SChanho Min jiffies + msecs_to_jiffies(uap->dmarx.poll_rate));
1101cb06ff10SChanho Min }
1102cb06ff10SChanho Min }
1103cb06ff10SChanho Min
pl011_dma_startup(struct uart_amba_port * uap)1104ab4382d2SGreg Kroah-Hartman static void pl011_dma_startup(struct uart_amba_port *uap)
1105ab4382d2SGreg Kroah-Hartman {
1106ead76f32SLinus Walleij int ret;
1107ead76f32SLinus Walleij
11081c9be310SJorge Ramirez-Ortiz if (!uap->dma_probed)
11091c9be310SJorge Ramirez-Ortiz pl011_dma_probe(uap);
11101c9be310SJorge Ramirez-Ortiz
1111ab4382d2SGreg Kroah-Hartman if (!uap->dmatx.chan)
1112ab4382d2SGreg Kroah-Hartman return;
1113ab4382d2SGreg Kroah-Hartman
11144c0be45bSAndrew Jackson uap->dmatx.buf = kmalloc(PL011_DMA_BUFFER_SIZE, GFP_KERNEL | __GFP_DMA);
1115ab4382d2SGreg Kroah-Hartman if (!uap->dmatx.buf) {
1116ab4382d2SGreg Kroah-Hartman dev_err(uap->port.dev, "no memory for DMA TX buffer\n");
1117ab4382d2SGreg Kroah-Hartman uap->port.fifosize = uap->fifosize;
1118ab4382d2SGreg Kroah-Hartman return;
1119ab4382d2SGreg Kroah-Hartman }
1120ab4382d2SGreg Kroah-Hartman
1121c865b77eSArnd Bergmann uap->dmatx.len = PL011_DMA_BUFFER_SIZE;
1122ab4382d2SGreg Kroah-Hartman
1123ab4382d2SGreg Kroah-Hartman /* The DMA buffer is now the FIFO the TTY subsystem can use */
1124ab4382d2SGreg Kroah-Hartman uap->port.fifosize = PL011_DMA_BUFFER_SIZE;
1125ead76f32SLinus Walleij uap->using_tx_dma = true;
1126ab4382d2SGreg Kroah-Hartman
1127ead76f32SLinus Walleij if (!uap->dmarx.chan)
1128ead76f32SLinus Walleij goto skip_rx;
1129ead76f32SLinus Walleij
1130ead76f32SLinus Walleij /* Allocate and map DMA RX buffers */
1131c865b77eSArnd Bergmann ret = pl011_dmabuf_init(uap->dmarx.chan, &uap->dmarx.dbuf_a,
1132ead76f32SLinus Walleij DMA_FROM_DEVICE);
1133ead76f32SLinus Walleij if (ret) {
1134ead76f32SLinus Walleij dev_err(uap->port.dev, "failed to init DMA %s: %d\n",
1135ead76f32SLinus Walleij "RX buffer A", ret);
1136ead76f32SLinus Walleij goto skip_rx;
1137ead76f32SLinus Walleij }
1138ead76f32SLinus Walleij
1139c865b77eSArnd Bergmann ret = pl011_dmabuf_init(uap->dmarx.chan, &uap->dmarx.dbuf_b,
1140ead76f32SLinus Walleij DMA_FROM_DEVICE);
1141ead76f32SLinus Walleij if (ret) {
1142ead76f32SLinus Walleij dev_err(uap->port.dev, "failed to init DMA %s: %d\n",
1143ead76f32SLinus Walleij "RX buffer B", ret);
1144c865b77eSArnd Bergmann pl011_dmabuf_free(uap->dmarx.chan, &uap->dmarx.dbuf_a,
1145ead76f32SLinus Walleij DMA_FROM_DEVICE);
1146ead76f32SLinus Walleij goto skip_rx;
1147ead76f32SLinus Walleij }
1148ead76f32SLinus Walleij
1149ead76f32SLinus Walleij uap->using_rx_dma = true;
1150ead76f32SLinus Walleij
1151ead76f32SLinus Walleij skip_rx:
1152ab4382d2SGreg Kroah-Hartman /* Turn on DMA error (RX/TX will be enabled on demand) */
1153ab4382d2SGreg Kroah-Hartman uap->dmacr |= UART011_DMAONERR;
11549f25bc51SRussell King pl011_write(uap->dmacr, uap, REG_DMACR);
1155ab4382d2SGreg Kroah-Hartman
1156ab4382d2SGreg Kroah-Hartman /*
1157ab4382d2SGreg Kroah-Hartman * ST Micro variants has some specific dma burst threshold
1158ab4382d2SGreg Kroah-Hartman * compensation. Set this to 16 bytes, so burst will only
1159ab4382d2SGreg Kroah-Hartman * be issued above/below 16 bytes.
1160ab4382d2SGreg Kroah-Hartman */
1161ab4382d2SGreg Kroah-Hartman if (uap->vendor->dma_threshold)
116275836339SRussell King pl011_write(ST_UART011_DMAWM_RX_16 | ST_UART011_DMAWM_TX_16,
11639f25bc51SRussell King uap, REG_ST_DMAWM);
1164ead76f32SLinus Walleij
1165ead76f32SLinus Walleij if (uap->using_rx_dma) {
1166ead76f32SLinus Walleij if (pl011_dma_rx_trigger_dma(uap))
1167ead76f32SLinus Walleij dev_dbg(uap->port.dev, "could not trigger initial "
1168ead76f32SLinus Walleij "RX DMA job, fall back to interrupt mode\n");
1169cb06ff10SChanho Min if (uap->dmarx.poll_rate) {
1170f7f73096SKees Cook timer_setup(&uap->dmarx.timer, pl011_dma_rx_poll, 0);
1171cb06ff10SChanho Min mod_timer(&uap->dmarx.timer,
1172cb06ff10SChanho Min jiffies +
1173cb06ff10SChanho Min msecs_to_jiffies(uap->dmarx.poll_rate));
1174cb06ff10SChanho Min uap->dmarx.last_residue = PL011_DMA_BUFFER_SIZE;
1175cb06ff10SChanho Min uap->dmarx.last_jiffies = jiffies;
1176cb06ff10SChanho Min }
1177ead76f32SLinus Walleij }
1178ab4382d2SGreg Kroah-Hartman }
1179ab4382d2SGreg Kroah-Hartman
pl011_dma_shutdown(struct uart_amba_port * uap)1180ab4382d2SGreg Kroah-Hartman static void pl011_dma_shutdown(struct uart_amba_port *uap)
1181ab4382d2SGreg Kroah-Hartman {
1182ead76f32SLinus Walleij if (!(uap->using_tx_dma || uap->using_rx_dma))
1183ab4382d2SGreg Kroah-Hartman return;
1184ab4382d2SGreg Kroah-Hartman
1185ab4382d2SGreg Kroah-Hartman /* Disable RX and TX DMA */
11860e125a5fSShawn Guo while (pl011_read(uap, REG_FR) & uap->vendor->fr_busy)
11872f2fd089STimur Tabi cpu_relax();
1188ab4382d2SGreg Kroah-Hartman
11895aea1229SThomas Gleixner uart_port_lock_irq(&uap->port);
1190ab4382d2SGreg Kroah-Hartman uap->dmacr &= ~(UART011_DMAONERR | UART011_RXDMAE | UART011_TXDMAE);
11919f25bc51SRussell King pl011_write(uap->dmacr, uap, REG_DMACR);
11925aea1229SThomas Gleixner uart_port_unlock_irq(&uap->port);
1193ab4382d2SGreg Kroah-Hartman
1194ead76f32SLinus Walleij if (uap->using_tx_dma) {
1195ab4382d2SGreg Kroah-Hartman /* In theory, this should already be done by pl011_dma_flush_buffer */
1196ab4382d2SGreg Kroah-Hartman dmaengine_terminate_all(uap->dmatx.chan);
1197ab4382d2SGreg Kroah-Hartman if (uap->dmatx.queued) {
1198c865b77eSArnd Bergmann dma_unmap_single(uap->dmatx.chan->device->dev,
1199c865b77eSArnd Bergmann uap->dmatx.dma, uap->dmatx.len,
1200ab4382d2SGreg Kroah-Hartman DMA_TO_DEVICE);
1201ab4382d2SGreg Kroah-Hartman uap->dmatx.queued = false;
1202ab4382d2SGreg Kroah-Hartman }
1203ab4382d2SGreg Kroah-Hartman
1204ab4382d2SGreg Kroah-Hartman kfree(uap->dmatx.buf);
1205ead76f32SLinus Walleij uap->using_tx_dma = false;
1206ab4382d2SGreg Kroah-Hartman }
1207ab4382d2SGreg Kroah-Hartman
1208ead76f32SLinus Walleij if (uap->using_rx_dma) {
1209ead76f32SLinus Walleij dmaengine_terminate_all(uap->dmarx.chan);
1210ead76f32SLinus Walleij /* Clean up the RX DMA */
1211c865b77eSArnd Bergmann pl011_dmabuf_free(uap->dmarx.chan, &uap->dmarx.dbuf_a, DMA_FROM_DEVICE);
1212c865b77eSArnd Bergmann pl011_dmabuf_free(uap->dmarx.chan, &uap->dmarx.dbuf_b, DMA_FROM_DEVICE);
1213cb06ff10SChanho Min if (uap->dmarx.poll_rate)
1214cb06ff10SChanho Min del_timer_sync(&uap->dmarx.timer);
1215ead76f32SLinus Walleij uap->using_rx_dma = false;
1216ead76f32SLinus Walleij }
1217ead76f32SLinus Walleij }
1218ead76f32SLinus Walleij
pl011_dma_rx_available(struct uart_amba_port * uap)1219ead76f32SLinus Walleij static inline bool pl011_dma_rx_available(struct uart_amba_port *uap)
1220ead76f32SLinus Walleij {
1221ead76f32SLinus Walleij return uap->using_rx_dma;
1222ead76f32SLinus Walleij }
1223ead76f32SLinus Walleij
pl011_dma_rx_running(struct uart_amba_port * uap)1224ead76f32SLinus Walleij static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
1225ead76f32SLinus Walleij {
1226ead76f32SLinus Walleij return uap->using_rx_dma && uap->dmarx.running;
1227ead76f32SLinus Walleij }
1228ead76f32SLinus Walleij
1229ab4382d2SGreg Kroah-Hartman #else
1230ab4382d2SGreg Kroah-Hartman /* Blank functions if the DMA engine is not available */
pl011_dma_remove(struct uart_amba_port * uap)1231ab4382d2SGreg Kroah-Hartman static inline void pl011_dma_remove(struct uart_amba_port *uap)
1232ab4382d2SGreg Kroah-Hartman {
1233ab4382d2SGreg Kroah-Hartman }
1234ab4382d2SGreg Kroah-Hartman
pl011_dma_startup(struct uart_amba_port * uap)1235ab4382d2SGreg Kroah-Hartman static inline void pl011_dma_startup(struct uart_amba_port *uap)
1236ab4382d2SGreg Kroah-Hartman {
1237ab4382d2SGreg Kroah-Hartman }
1238ab4382d2SGreg Kroah-Hartman
pl011_dma_shutdown(struct uart_amba_port * uap)1239ab4382d2SGreg Kroah-Hartman static inline void pl011_dma_shutdown(struct uart_amba_port *uap)
1240ab4382d2SGreg Kroah-Hartman {
1241ab4382d2SGreg Kroah-Hartman }
1242ab4382d2SGreg Kroah-Hartman
pl011_dma_tx_irq(struct uart_amba_port * uap)1243ab4382d2SGreg Kroah-Hartman static inline bool pl011_dma_tx_irq(struct uart_amba_port *uap)
1244ab4382d2SGreg Kroah-Hartman {
1245ab4382d2SGreg Kroah-Hartman return false;
1246ab4382d2SGreg Kroah-Hartman }
1247ab4382d2SGreg Kroah-Hartman
pl011_dma_tx_stop(struct uart_amba_port * uap)1248ab4382d2SGreg Kroah-Hartman static inline void pl011_dma_tx_stop(struct uart_amba_port *uap)
1249ab4382d2SGreg Kroah-Hartman {
1250ab4382d2SGreg Kroah-Hartman }
1251ab4382d2SGreg Kroah-Hartman
pl011_dma_tx_start(struct uart_amba_port * uap)1252ab4382d2SGreg Kroah-Hartman static inline bool pl011_dma_tx_start(struct uart_amba_port *uap)
1253ab4382d2SGreg Kroah-Hartman {
1254ab4382d2SGreg Kroah-Hartman return false;
1255ab4382d2SGreg Kroah-Hartman }
1256ab4382d2SGreg Kroah-Hartman
pl011_dma_rx_irq(struct uart_amba_port * uap)1257ead76f32SLinus Walleij static inline void pl011_dma_rx_irq(struct uart_amba_port *uap)
1258ead76f32SLinus Walleij {
1259ead76f32SLinus Walleij }
1260ead76f32SLinus Walleij
pl011_dma_rx_stop(struct uart_amba_port * uap)1261ead76f32SLinus Walleij static inline void pl011_dma_rx_stop(struct uart_amba_port *uap)
1262ead76f32SLinus Walleij {
1263ead76f32SLinus Walleij }
1264ead76f32SLinus Walleij
pl011_dma_rx_trigger_dma(struct uart_amba_port * uap)1265ead76f32SLinus Walleij static inline int pl011_dma_rx_trigger_dma(struct uart_amba_port *uap)
1266ead76f32SLinus Walleij {
1267ead76f32SLinus Walleij return -EIO;
1268ead76f32SLinus Walleij }
1269ead76f32SLinus Walleij
pl011_dma_rx_available(struct uart_amba_port * uap)1270ead76f32SLinus Walleij static inline bool pl011_dma_rx_available(struct uart_amba_port *uap)
1271ead76f32SLinus Walleij {
1272ead76f32SLinus Walleij return false;
1273ead76f32SLinus Walleij }
1274ead76f32SLinus Walleij
pl011_dma_rx_running(struct uart_amba_port * uap)1275ead76f32SLinus Walleij static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
1276ead76f32SLinus Walleij {
1277ead76f32SLinus Walleij return false;
1278ead76f32SLinus Walleij }
1279ead76f32SLinus Walleij
1280ab4382d2SGreg Kroah-Hartman #define pl011_dma_flush_buffer NULL
1281ab4382d2SGreg Kroah-Hartman #endif
1282ab4382d2SGreg Kroah-Hartman
pl011_rs485_tx_stop(struct uart_amba_port * uap)12838d479237SLino Sanfilippo static void pl011_rs485_tx_stop(struct uart_amba_port *uap)
12848d479237SLino Sanfilippo {
12850e4deb56SLino Sanfilippo /*
12860e4deb56SLino Sanfilippo * To be on the safe side only time out after twice as many iterations
12870e4deb56SLino Sanfilippo * as fifo size.
12880e4deb56SLino Sanfilippo */
12890e4deb56SLino Sanfilippo const int MAX_TX_DRAIN_ITERS = uap->port.fifosize * 2;
12908d479237SLino Sanfilippo struct uart_port *port = &uap->port;
12918d479237SLino Sanfilippo int i = 0;
12928d479237SLino Sanfilippo u32 cr;
12938d479237SLino Sanfilippo
12948d479237SLino Sanfilippo /* Wait until hardware tx queue is empty */
12958d479237SLino Sanfilippo while (!pl011_tx_empty(port)) {
12960e4deb56SLino Sanfilippo if (i > MAX_TX_DRAIN_ITERS) {
12978d479237SLino Sanfilippo dev_warn(port->dev,
12988d479237SLino Sanfilippo "timeout while draining hardware tx queue\n");
12998d479237SLino Sanfilippo break;
13008d479237SLino Sanfilippo }
13018d479237SLino Sanfilippo
13028d479237SLino Sanfilippo udelay(uap->rs485_tx_drain_interval);
13038d479237SLino Sanfilippo i++;
13048d479237SLino Sanfilippo }
13058d479237SLino Sanfilippo
13068d479237SLino Sanfilippo if (port->rs485.delay_rts_after_send)
13078d479237SLino Sanfilippo mdelay(port->rs485.delay_rts_after_send);
13088d479237SLino Sanfilippo
13098d479237SLino Sanfilippo cr = pl011_read(uap, REG_CR);
13108d479237SLino Sanfilippo
13118d479237SLino Sanfilippo if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
13128d479237SLino Sanfilippo cr &= ~UART011_CR_RTS;
13138d479237SLino Sanfilippo else
13148d479237SLino Sanfilippo cr |= UART011_CR_RTS;
13158d479237SLino Sanfilippo
13168d479237SLino Sanfilippo /* Disable the transmitter and reenable the transceiver */
13178d479237SLino Sanfilippo cr &= ~UART011_CR_TXE;
13188d479237SLino Sanfilippo cr |= UART011_CR_RXE;
13198d479237SLino Sanfilippo pl011_write(cr, uap, REG_CR);
13208d479237SLino Sanfilippo
13218d479237SLino Sanfilippo uap->rs485_tx_started = false;
13228d479237SLino Sanfilippo }
13238d479237SLino Sanfilippo
pl011_stop_tx(struct uart_port * port)1324ab4382d2SGreg Kroah-Hartman static void pl011_stop_tx(struct uart_port *port)
1325ab4382d2SGreg Kroah-Hartman {
1326a5820c24SDaniel Thompson struct uart_amba_port *uap =
1327a5820c24SDaniel Thompson container_of(port, struct uart_amba_port, port);
1328ab4382d2SGreg Kroah-Hartman
1329ab4382d2SGreg Kroah-Hartman uap->im &= ~UART011_TXIM;
13309f25bc51SRussell King pl011_write(uap->im, uap, REG_IMSC);
1331ab4382d2SGreg Kroah-Hartman pl011_dma_tx_stop(uap);
13328d479237SLino Sanfilippo
13338d479237SLino Sanfilippo if ((port->rs485.flags & SER_RS485_ENABLED) && uap->rs485_tx_started)
13348d479237SLino Sanfilippo pl011_rs485_tx_stop(uap);
1335ab4382d2SGreg Kroah-Hartman }
1336ab4382d2SGreg Kroah-Hartman
13377d05587cSJayachandran C static bool pl011_tx_chars(struct uart_amba_port *uap, bool from_irq);
1338734745caSDave Martin
1339734745caSDave Martin /* Start TX with programmed I/O only (no DMA) */
pl011_start_tx_pio(struct uart_amba_port * uap)1340734745caSDave Martin static void pl011_start_tx_pio(struct uart_amba_port *uap)
1341734745caSDave Martin {
13427d05587cSJayachandran C if (pl011_tx_chars(uap, false)) {
1343734745caSDave Martin uap->im |= UART011_TXIM;
13449f25bc51SRussell King pl011_write(uap->im, uap, REG_IMSC);
13457d05587cSJayachandran C }
1346734745caSDave Martin }
1347734745caSDave Martin
pl011_rs485_tx_start(struct uart_amba_port * uap)13489319ecb8SLino Sanfilippo static void pl011_rs485_tx_start(struct uart_amba_port *uap)
13499319ecb8SLino Sanfilippo {
13509319ecb8SLino Sanfilippo struct uart_port *port = &uap->port;
13519319ecb8SLino Sanfilippo u32 cr;
13529319ecb8SLino Sanfilippo
13539319ecb8SLino Sanfilippo /* Enable transmitter */
13549319ecb8SLino Sanfilippo cr = pl011_read(uap, REG_CR);
13559319ecb8SLino Sanfilippo cr |= UART011_CR_TXE;
13569319ecb8SLino Sanfilippo
13579319ecb8SLino Sanfilippo /* Disable receiver if half-duplex */
13589319ecb8SLino Sanfilippo if (!(port->rs485.flags & SER_RS485_RX_DURING_TX))
13599319ecb8SLino Sanfilippo cr &= ~UART011_CR_RXE;
13609319ecb8SLino Sanfilippo
13619319ecb8SLino Sanfilippo if (port->rs485.flags & SER_RS485_RTS_ON_SEND)
13629319ecb8SLino Sanfilippo cr &= ~UART011_CR_RTS;
13639319ecb8SLino Sanfilippo else
13649319ecb8SLino Sanfilippo cr |= UART011_CR_RTS;
13659319ecb8SLino Sanfilippo
13669319ecb8SLino Sanfilippo pl011_write(cr, uap, REG_CR);
13679319ecb8SLino Sanfilippo
13689319ecb8SLino Sanfilippo if (port->rs485.delay_rts_before_send)
13699319ecb8SLino Sanfilippo mdelay(port->rs485.delay_rts_before_send);
13709319ecb8SLino Sanfilippo
13719319ecb8SLino Sanfilippo uap->rs485_tx_started = true;
13729319ecb8SLino Sanfilippo }
13739319ecb8SLino Sanfilippo
pl011_start_tx(struct uart_port * port)1374ab4382d2SGreg Kroah-Hartman static void pl011_start_tx(struct uart_port *port)
1375ab4382d2SGreg Kroah-Hartman {
1376a5820c24SDaniel Thompson struct uart_amba_port *uap =
1377a5820c24SDaniel Thompson container_of(port, struct uart_amba_port, port);
1378ab4382d2SGreg Kroah-Hartman
13799319ecb8SLino Sanfilippo if ((uap->port.rs485.flags & SER_RS485_ENABLED) &&
13809319ecb8SLino Sanfilippo !uap->rs485_tx_started)
13819319ecb8SLino Sanfilippo pl011_rs485_tx_start(uap);
13829319ecb8SLino Sanfilippo
1383734745caSDave Martin if (!pl011_dma_tx_start(uap))
1384734745caSDave Martin pl011_start_tx_pio(uap);
1385ab4382d2SGreg Kroah-Hartman }
1386ab4382d2SGreg Kroah-Hartman
pl011_stop_rx(struct uart_port * port)1387ab4382d2SGreg Kroah-Hartman static void pl011_stop_rx(struct uart_port *port)
1388ab4382d2SGreg Kroah-Hartman {
1389a5820c24SDaniel Thompson struct uart_amba_port *uap =
1390a5820c24SDaniel Thompson container_of(port, struct uart_amba_port, port);
1391ab4382d2SGreg Kroah-Hartman
1392ab4382d2SGreg Kroah-Hartman uap->im &= ~(UART011_RXIM|UART011_RTIM|UART011_FEIM|
1393ab4382d2SGreg Kroah-Hartman UART011_PEIM|UART011_BEIM|UART011_OEIM);
13949f25bc51SRussell King pl011_write(uap->im, uap, REG_IMSC);
1395ead76f32SLinus Walleij
1396ead76f32SLinus Walleij pl011_dma_rx_stop(uap);
1397ab4382d2SGreg Kroah-Hartman }
1398ab4382d2SGreg Kroah-Hartman
pl011_throttle_rx(struct uart_port * port)1399211565b1SIlpo Järvinen static void pl011_throttle_rx(struct uart_port *port)
1400211565b1SIlpo Järvinen {
1401211565b1SIlpo Järvinen unsigned long flags;
1402211565b1SIlpo Järvinen
14035aea1229SThomas Gleixner uart_port_lock_irqsave(port, &flags);
1404211565b1SIlpo Järvinen pl011_stop_rx(port);
14055aea1229SThomas Gleixner uart_port_unlock_irqrestore(port, flags);
1406211565b1SIlpo Järvinen }
1407211565b1SIlpo Järvinen
pl011_enable_ms(struct uart_port * port)1408ab4382d2SGreg Kroah-Hartman static void pl011_enable_ms(struct uart_port *port)
1409ab4382d2SGreg Kroah-Hartman {
1410a5820c24SDaniel Thompson struct uart_amba_port *uap =
1411a5820c24SDaniel Thompson container_of(port, struct uart_amba_port, port);
1412ab4382d2SGreg Kroah-Hartman
1413ab4382d2SGreg Kroah-Hartman uap->im |= UART011_RIMIM|UART011_CTSMIM|UART011_DCDMIM|UART011_DSRMIM;
14149f25bc51SRussell King pl011_write(uap->im, uap, REG_IMSC);
1415ab4382d2SGreg Kroah-Hartman }
1416ab4382d2SGreg Kroah-Hartman
pl011_rx_chars(struct uart_amba_port * uap)1417ab4382d2SGreg Kroah-Hartman static void pl011_rx_chars(struct uart_amba_port *uap)
1418b83286bfSFabio Estevam __releases(&uap->port.lock)
1419b83286bfSFabio Estevam __acquires(&uap->port.lock)
1420ab4382d2SGreg Kroah-Hartman {
142129772c4eSLinus Walleij pl011_fifo_to_tty(uap);
1422ab4382d2SGreg Kroah-Hartman
14235aea1229SThomas Gleixner uart_port_unlock(&uap->port);
14242e124b4aSJiri Slaby tty_flip_buffer_push(&uap->port.state->port);
1425ead76f32SLinus Walleij /*
1426ead76f32SLinus Walleij * If we were temporarily out of DMA mode for a while,
1427ead76f32SLinus Walleij * attempt to switch back to DMA mode again.
1428ead76f32SLinus Walleij */
1429ead76f32SLinus Walleij if (pl011_dma_rx_available(uap)) {
1430ead76f32SLinus Walleij if (pl011_dma_rx_trigger_dma(uap)) {
1431ead76f32SLinus Walleij dev_dbg(uap->port.dev, "could not trigger RX DMA job "
1432ead76f32SLinus Walleij "fall back to interrupt mode again\n");
1433ead76f32SLinus Walleij uap->im |= UART011_RXIM;
14349f25bc51SRussell King pl011_write(uap->im, uap, REG_IMSC);
1435cb06ff10SChanho Min } else {
143689fa28dbSChanho Min #ifdef CONFIG_DMA_ENGINE
1437cb06ff10SChanho Min /* Start Rx DMA poll */
1438cb06ff10SChanho Min if (uap->dmarx.poll_rate) {
1439cb06ff10SChanho Min uap->dmarx.last_jiffies = jiffies;
1440cb06ff10SChanho Min uap->dmarx.last_residue = PL011_DMA_BUFFER_SIZE;
1441cb06ff10SChanho Min mod_timer(&uap->dmarx.timer,
1442cb06ff10SChanho Min jiffies +
1443cb06ff10SChanho Min msecs_to_jiffies(uap->dmarx.poll_rate));
1444cb06ff10SChanho Min }
144589fa28dbSChanho Min #endif
1446cb06ff10SChanho Min }
1447ead76f32SLinus Walleij }
14485aea1229SThomas Gleixner uart_port_lock(&uap->port);
1449ab4382d2SGreg Kroah-Hartman }
1450ab4382d2SGreg Kroah-Hartman
pl011_tx_char(struct uart_amba_port * uap,unsigned char c,bool from_irq)14511e84d223SDave Martin static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c,
14521e84d223SDave Martin bool from_irq)
1453734745caSDave Martin {
14541e84d223SDave Martin if (unlikely(!from_irq) &&
14559f25bc51SRussell King pl011_read(uap, REG_FR) & UART01x_FR_TXFF)
14561e84d223SDave Martin return false; /* unable to transmit character */
14571e84d223SDave Martin
14589f25bc51SRussell King pl011_write(c, uap, REG_DR);
1459734745caSDave Martin uap->port.icount.tx++;
1460734745caSDave Martin
1461734745caSDave Martin return true;
1462734745caSDave Martin }
1463734745caSDave Martin
14647d05587cSJayachandran C /* Returns true if tx interrupts have to be (kept) enabled */
pl011_tx_chars(struct uart_amba_port * uap,bool from_irq)14657d05587cSJayachandran C static bool pl011_tx_chars(struct uart_amba_port *uap, bool from_irq)
1466ab4382d2SGreg Kroah-Hartman {
1467ab4382d2SGreg Kroah-Hartman struct circ_buf *xmit = &uap->port.state->xmit;
14681e84d223SDave Martin int count = uap->fifosize >> 1;
1469734745caSDave Martin
1470ab4382d2SGreg Kroah-Hartman if (uap->port.x_char) {
14711e84d223SDave Martin if (!pl011_tx_char(uap, uap->port.x_char, from_irq))
14727d05587cSJayachandran C return true;
1473ab4382d2SGreg Kroah-Hartman uap->port.x_char = 0;
1474734745caSDave Martin --count;
1475ab4382d2SGreg Kroah-Hartman }
1476ab4382d2SGreg Kroah-Hartman if (uart_circ_empty(xmit) || uart_tx_stopped(&uap->port)) {
1477ab4382d2SGreg Kroah-Hartman pl011_stop_tx(&uap->port);
14787d05587cSJayachandran C return false;
1479ab4382d2SGreg Kroah-Hartman }
1480ab4382d2SGreg Kroah-Hartman
1481ab4382d2SGreg Kroah-Hartman /* If we are using DMA mode, try to send some characters. */
1482ab4382d2SGreg Kroah-Hartman if (pl011_dma_tx_irq(uap))
14837d05587cSJayachandran C return true;
1484ab4382d2SGreg Kroah-Hartman
14851e84d223SDave Martin do {
14861e84d223SDave Martin if (likely(from_irq) && count-- == 0)
1487ab4382d2SGreg Kroah-Hartman break;
14881e84d223SDave Martin
14891e84d223SDave Martin if (!pl011_tx_char(uap, xmit->buf[xmit->tail], from_irq))
14901e84d223SDave Martin break;
14911e84d223SDave Martin
14921e84d223SDave Martin xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
14931e84d223SDave Martin } while (!uart_circ_empty(xmit));
1494ab4382d2SGreg Kroah-Hartman
1495ab4382d2SGreg Kroah-Hartman if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
1496ab4382d2SGreg Kroah-Hartman uart_write_wakeup(&uap->port);
1497ab4382d2SGreg Kroah-Hartman
14987d05587cSJayachandran C if (uart_circ_empty(xmit)) {
1499ab4382d2SGreg Kroah-Hartman pl011_stop_tx(&uap->port);
15007d05587cSJayachandran C return false;
15017d05587cSJayachandran C }
15027d05587cSJayachandran C return true;
1503ab4382d2SGreg Kroah-Hartman }
1504ab4382d2SGreg Kroah-Hartman
pl011_modem_status(struct uart_amba_port * uap)1505ab4382d2SGreg Kroah-Hartman static void pl011_modem_status(struct uart_amba_port *uap)
1506ab4382d2SGreg Kroah-Hartman {
1507ab4382d2SGreg Kroah-Hartman unsigned int status, delta;
1508ab4382d2SGreg Kroah-Hartman
15099f25bc51SRussell King status = pl011_read(uap, REG_FR) & UART01x_FR_MODEM_ANY;
1510ab4382d2SGreg Kroah-Hartman
1511ab4382d2SGreg Kroah-Hartman delta = status ^ uap->old_status;
1512ab4382d2SGreg Kroah-Hartman uap->old_status = status;
1513ab4382d2SGreg Kroah-Hartman
1514ab4382d2SGreg Kroah-Hartman if (!delta)
1515ab4382d2SGreg Kroah-Hartman return;
1516ab4382d2SGreg Kroah-Hartman
1517ab4382d2SGreg Kroah-Hartman if (delta & UART01x_FR_DCD)
1518ab4382d2SGreg Kroah-Hartman uart_handle_dcd_change(&uap->port, status & UART01x_FR_DCD);
1519ab4382d2SGreg Kroah-Hartman
15200e125a5fSShawn Guo if (delta & uap->vendor->fr_dsr)
1521ab4382d2SGreg Kroah-Hartman uap->port.icount.dsr++;
1522ab4382d2SGreg Kroah-Hartman
15230e125a5fSShawn Guo if (delta & uap->vendor->fr_cts)
15240e125a5fSShawn Guo uart_handle_cts_change(&uap->port,
15250e125a5fSShawn Guo status & uap->vendor->fr_cts);
1526ab4382d2SGreg Kroah-Hartman
1527ab4382d2SGreg Kroah-Hartman wake_up_interruptible(&uap->port.state->port.delta_msr_wait);
1528ab4382d2SGreg Kroah-Hartman }
1529ab4382d2SGreg Kroah-Hartman
check_apply_cts_event_workaround(struct uart_amba_port * uap)15309c4ef4b0SAndre Przywara static void check_apply_cts_event_workaround(struct uart_amba_port *uap)
1531ab4382d2SGreg Kroah-Hartman {
15329c4ef4b0SAndre Przywara if (!uap->vendor->cts_event_workaround)
15339c4ef4b0SAndre Przywara return;
15349c4ef4b0SAndre Przywara
15354fd0690bSRajanikanth H.V /* workaround to make sure that all bits are unlocked.. */
15369f25bc51SRussell King pl011_write(0x00, uap, REG_ICR);
15374fd0690bSRajanikanth H.V
15384fd0690bSRajanikanth H.V /*
15394fd0690bSRajanikanth H.V * WA: introduce 26ns(1 uart clk) delay before W1C;
15404fd0690bSRajanikanth H.V * single apb access will incur 2 pclk(133.12Mhz) delay,
15414fd0690bSRajanikanth H.V * so add 2 dummy reads
15424fd0690bSRajanikanth H.V */
154394345aeeSXiongfeng Wang pl011_read(uap, REG_ICR);
154494345aeeSXiongfeng Wang pl011_read(uap, REG_ICR);
15454fd0690bSRajanikanth H.V }
15464fd0690bSRajanikanth H.V
pl011_int(int irq,void * dev_id)15479c4ef4b0SAndre Przywara static irqreturn_t pl011_int(int irq, void *dev_id)
15489c4ef4b0SAndre Przywara {
15499c4ef4b0SAndre Przywara struct uart_amba_port *uap = dev_id;
15509c4ef4b0SAndre Przywara unsigned long flags;
15519c4ef4b0SAndre Przywara unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
15529c4ef4b0SAndre Przywara int handled = 0;
15539c4ef4b0SAndre Przywara
15545aea1229SThomas Gleixner uart_port_lock_irqsave(&uap->port, &flags);
1555d3a96c94SLukas Wunner status = pl011_read(uap, REG_RIS) & uap->im;
15569c4ef4b0SAndre Przywara if (status) {
15579c4ef4b0SAndre Przywara do {
15589c4ef4b0SAndre Przywara check_apply_cts_event_workaround(uap);
1559f11c9841SGreg Kroah-Hartman
156075836339SRussell King pl011_write(status & ~(UART011_TXIS|UART011_RTIS|
1561f11c9841SGreg Kroah-Hartman UART011_RXIS),
15629f25bc51SRussell King uap, REG_ICR);
1563ab4382d2SGreg Kroah-Hartman
1564ead76f32SLinus Walleij if (status & (UART011_RTIS|UART011_RXIS)) {
1565ead76f32SLinus Walleij if (pl011_dma_rx_running(uap))
1566ead76f32SLinus Walleij pl011_dma_rx_irq(uap);
1567ead76f32SLinus Walleij else
1568ab4382d2SGreg Kroah-Hartman pl011_rx_chars(uap);
1569ead76f32SLinus Walleij }
1570ab4382d2SGreg Kroah-Hartman if (status & (UART011_DSRMIS|UART011_DCDMIS|
1571ab4382d2SGreg Kroah-Hartman UART011_CTSMIS|UART011_RIMIS))
1572ab4382d2SGreg Kroah-Hartman pl011_modem_status(uap);
15731e84d223SDave Martin if (status & UART011_TXIS)
15741e84d223SDave Martin pl011_tx_chars(uap, true);
1575ab4382d2SGreg Kroah-Hartman
15764fd0690bSRajanikanth H.V if (pass_counter-- == 0)
1577ab4382d2SGreg Kroah-Hartman break;
1578ab4382d2SGreg Kroah-Hartman
1579d3a96c94SLukas Wunner status = pl011_read(uap, REG_RIS) & uap->im;
1580ab4382d2SGreg Kroah-Hartman } while (status != 0);
1581ab4382d2SGreg Kroah-Hartman handled = 1;
1582ab4382d2SGreg Kroah-Hartman }
1583ab4382d2SGreg Kroah-Hartman
15845aea1229SThomas Gleixner uart_port_unlock_irqrestore(&uap->port, flags);
1585ab4382d2SGreg Kroah-Hartman
1586ab4382d2SGreg Kroah-Hartman return IRQ_RETVAL(handled);
1587ab4382d2SGreg Kroah-Hartman }
1588ab4382d2SGreg Kroah-Hartman
pl011_tx_empty(struct uart_port * port)1589e643f87fSLinus Walleij static unsigned int pl011_tx_empty(struct uart_port *port)
1590ab4382d2SGreg Kroah-Hartman {
1591a5820c24SDaniel Thompson struct uart_amba_port *uap =
1592a5820c24SDaniel Thompson container_of(port, struct uart_amba_port, port);
1593d8a4995bSChristopher Covington
1594d8a4995bSChristopher Covington /* Allow feature register bits to be inverted to work around errata */
1595d8a4995bSChristopher Covington unsigned int status = pl011_read(uap, REG_FR) ^ uap->vendor->inv_fr;
1596d8a4995bSChristopher Covington
15970e125a5fSShawn Guo return status & (uap->vendor->fr_busy | UART01x_FR_TXFF) ?
15980e125a5fSShawn Guo 0 : TIOCSER_TEMT;
1599ab4382d2SGreg Kroah-Hartman }
1600ab4382d2SGreg Kroah-Hartman
pl011_get_mctrl(struct uart_port * port)1601e643f87fSLinus Walleij static unsigned int pl011_get_mctrl(struct uart_port *port)
1602ab4382d2SGreg Kroah-Hartman {
1603a5820c24SDaniel Thompson struct uart_amba_port *uap =
1604a5820c24SDaniel Thompson container_of(port, struct uart_amba_port, port);
1605ab4382d2SGreg Kroah-Hartman unsigned int result = 0;
16069f25bc51SRussell King unsigned int status = pl011_read(uap, REG_FR);
1607ab4382d2SGreg Kroah-Hartman
1608ab4382d2SGreg Kroah-Hartman #define TIOCMBIT(uartbit, tiocmbit) \
1609ab4382d2SGreg Kroah-Hartman if (status & uartbit) \
1610ab4382d2SGreg Kroah-Hartman result |= tiocmbit
1611ab4382d2SGreg Kroah-Hartman
1612ab4382d2SGreg Kroah-Hartman TIOCMBIT(UART01x_FR_DCD, TIOCM_CAR);
16130e125a5fSShawn Guo TIOCMBIT(uap->vendor->fr_dsr, TIOCM_DSR);
16140e125a5fSShawn Guo TIOCMBIT(uap->vendor->fr_cts, TIOCM_CTS);
16150e125a5fSShawn Guo TIOCMBIT(uap->vendor->fr_ri, TIOCM_RNG);
1616ab4382d2SGreg Kroah-Hartman #undef TIOCMBIT
1617ab4382d2SGreg Kroah-Hartman return result;
1618ab4382d2SGreg Kroah-Hartman }
1619ab4382d2SGreg Kroah-Hartman
pl011_set_mctrl(struct uart_port * port,unsigned int mctrl)1620ab4382d2SGreg Kroah-Hartman static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl)
1621ab4382d2SGreg Kroah-Hartman {
1622a5820c24SDaniel Thompson struct uart_amba_port *uap =
1623a5820c24SDaniel Thompson container_of(port, struct uart_amba_port, port);
1624ab4382d2SGreg Kroah-Hartman unsigned int cr;
1625ab4382d2SGreg Kroah-Hartman
16269f25bc51SRussell King cr = pl011_read(uap, REG_CR);
1627ab4382d2SGreg Kroah-Hartman
1628ab4382d2SGreg Kroah-Hartman #define TIOCMBIT(tiocmbit, uartbit) \
1629ab4382d2SGreg Kroah-Hartman if (mctrl & tiocmbit) \
1630ab4382d2SGreg Kroah-Hartman cr |= uartbit; \
1631ab4382d2SGreg Kroah-Hartman else \
1632ab4382d2SGreg Kroah-Hartman cr &= ~uartbit
1633ab4382d2SGreg Kroah-Hartman
1634ab4382d2SGreg Kroah-Hartman TIOCMBIT(TIOCM_RTS, UART011_CR_RTS);
1635ab4382d2SGreg Kroah-Hartman TIOCMBIT(TIOCM_DTR, UART011_CR_DTR);
1636ab4382d2SGreg Kroah-Hartman TIOCMBIT(TIOCM_OUT1, UART011_CR_OUT1);
1637ab4382d2SGreg Kroah-Hartman TIOCMBIT(TIOCM_OUT2, UART011_CR_OUT2);
1638ab4382d2SGreg Kroah-Hartman TIOCMBIT(TIOCM_LOOP, UART011_CR_LBE);
1639ab4382d2SGreg Kroah-Hartman
16402a76fa28SLukas Wunner if (port->status & UPSTAT_AUTORTS) {
1641ab4382d2SGreg Kroah-Hartman /* We need to disable auto-RTS if we want to turn RTS off */
1642ab4382d2SGreg Kroah-Hartman TIOCMBIT(TIOCM_RTS, UART011_CR_RTSEN);
1643ab4382d2SGreg Kroah-Hartman }
1644ab4382d2SGreg Kroah-Hartman #undef TIOCMBIT
1645ab4382d2SGreg Kroah-Hartman
16469f25bc51SRussell King pl011_write(cr, uap, REG_CR);
1647ab4382d2SGreg Kroah-Hartman }
1648ab4382d2SGreg Kroah-Hartman
pl011_break_ctl(struct uart_port * port,int break_state)1649ab4382d2SGreg Kroah-Hartman static void pl011_break_ctl(struct uart_port *port, int break_state)
1650ab4382d2SGreg Kroah-Hartman {
1651a5820c24SDaniel Thompson struct uart_amba_port *uap =
1652a5820c24SDaniel Thompson container_of(port, struct uart_amba_port, port);
1653ab4382d2SGreg Kroah-Hartman unsigned long flags;
1654ab4382d2SGreg Kroah-Hartman unsigned int lcr_h;
1655ab4382d2SGreg Kroah-Hartman
16565aea1229SThomas Gleixner uart_port_lock_irqsave(&uap->port, &flags);
1657e4df9a80SRussell King lcr_h = pl011_read(uap, REG_LCRH_TX);
1658ab4382d2SGreg Kroah-Hartman if (break_state == -1)
1659ab4382d2SGreg Kroah-Hartman lcr_h |= UART01x_LCRH_BRK;
1660ab4382d2SGreg Kroah-Hartman else
1661ab4382d2SGreg Kroah-Hartman lcr_h &= ~UART01x_LCRH_BRK;
1662e4df9a80SRussell King pl011_write(lcr_h, uap, REG_LCRH_TX);
16635aea1229SThomas Gleixner uart_port_unlock_irqrestore(&uap->port, flags);
1664ab4382d2SGreg Kroah-Hartman }
1665ab4382d2SGreg Kroah-Hartman
1666ab4382d2SGreg Kroah-Hartman #ifdef CONFIG_CONSOLE_POLL
16675c8124a0SAnton Vorontsov
pl011_quiesce_irqs(struct uart_port * port)16685c8124a0SAnton Vorontsov static void pl011_quiesce_irqs(struct uart_port *port)
16695c8124a0SAnton Vorontsov {
1670a5820c24SDaniel Thompson struct uart_amba_port *uap =
1671a5820c24SDaniel Thompson container_of(port, struct uart_amba_port, port);
16725c8124a0SAnton Vorontsov
16739f25bc51SRussell King pl011_write(pl011_read(uap, REG_MIS), uap, REG_ICR);
16745c8124a0SAnton Vorontsov /*
16755c8124a0SAnton Vorontsov * There is no way to clear TXIM as this is "ready to transmit IRQ", so
16765c8124a0SAnton Vorontsov * we simply mask it. start_tx() will unmask it.
16775c8124a0SAnton Vorontsov *
16785c8124a0SAnton Vorontsov * Note we can race with start_tx(), and if the race happens, the
16795c8124a0SAnton Vorontsov * polling user might get another interrupt just after we clear it.
16805c8124a0SAnton Vorontsov * But it should be OK and can happen even w/o the race, e.g.
16815c8124a0SAnton Vorontsov * controller immediately got some new data and raised the IRQ.
16825c8124a0SAnton Vorontsov *
16835c8124a0SAnton Vorontsov * And whoever uses polling routines assumes that it manages the device
16845c8124a0SAnton Vorontsov * (including tx queue), so we're also fine with start_tx()'s caller
16855c8124a0SAnton Vorontsov * side.
16865c8124a0SAnton Vorontsov */
16879f25bc51SRussell King pl011_write(pl011_read(uap, REG_IMSC) & ~UART011_TXIM, uap,
16889f25bc51SRussell King REG_IMSC);
16895c8124a0SAnton Vorontsov }
16905c8124a0SAnton Vorontsov
pl011_get_poll_char(struct uart_port * port)1691e643f87fSLinus Walleij static int pl011_get_poll_char(struct uart_port *port)
1692ab4382d2SGreg Kroah-Hartman {
1693a5820c24SDaniel Thompson struct uart_amba_port *uap =
1694a5820c24SDaniel Thompson container_of(port, struct uart_amba_port, port);
1695ab4382d2SGreg Kroah-Hartman unsigned int status;
1696ab4382d2SGreg Kroah-Hartman
16975c8124a0SAnton Vorontsov /*
16985c8124a0SAnton Vorontsov * The caller might need IRQs lowered, e.g. if used with KDB NMI
16995c8124a0SAnton Vorontsov * debugger.
17005c8124a0SAnton Vorontsov */
17015c8124a0SAnton Vorontsov pl011_quiesce_irqs(port);
17025c8124a0SAnton Vorontsov
17039f25bc51SRussell King status = pl011_read(uap, REG_FR);
1704ab4382d2SGreg Kroah-Hartman if (status & UART01x_FR_RXFE)
1705ab4382d2SGreg Kroah-Hartman return NO_POLL_CHAR;
1706ab4382d2SGreg Kroah-Hartman
17079f25bc51SRussell King return pl011_read(uap, REG_DR);
1708ab4382d2SGreg Kroah-Hartman }
1709ab4382d2SGreg Kroah-Hartman
pl011_put_poll_char(struct uart_port * port,unsigned char ch)1710e643f87fSLinus Walleij static void pl011_put_poll_char(struct uart_port *port,
1711ab4382d2SGreg Kroah-Hartman unsigned char ch)
1712ab4382d2SGreg Kroah-Hartman {
1713a5820c24SDaniel Thompson struct uart_amba_port *uap =
1714a5820c24SDaniel Thompson container_of(port, struct uart_amba_port, port);
1715ab4382d2SGreg Kroah-Hartman
17169f25bc51SRussell King while (pl011_read(uap, REG_FR) & UART01x_FR_TXFF)
17172f2fd089STimur Tabi cpu_relax();
1718ab4382d2SGreg Kroah-Hartman
17199f25bc51SRussell King pl011_write(ch, uap, REG_DR);
1720ab4382d2SGreg Kroah-Hartman }
1721ab4382d2SGreg Kroah-Hartman
1722ab4382d2SGreg Kroah-Hartman #endif /* CONFIG_CONSOLE_POLL */
1723ab4382d2SGreg Kroah-Hartman
pl011_hwinit(struct uart_port * port)1724b3564c2cSAnton Vorontsov static int pl011_hwinit(struct uart_port *port)
1725ab4382d2SGreg Kroah-Hartman {
1726a5820c24SDaniel Thompson struct uart_amba_port *uap =
1727a5820c24SDaniel Thompson container_of(port, struct uart_amba_port, port);
1728ab4382d2SGreg Kroah-Hartman int retval;
1729ab4382d2SGreg Kroah-Hartman
173078d80c5aSLinus Walleij /* Optionaly enable pins to be muxed in and configured */
17312b996fc5SLinus Walleij pinctrl_pm_select_default_state(port->dev);
173278d80c5aSLinus Walleij
1733ab4382d2SGreg Kroah-Hartman /*
1734ab4382d2SGreg Kroah-Hartman * Try to enable the clock producer.
1735ab4382d2SGreg Kroah-Hartman */
17361c4c4394SJulia Lawall retval = clk_prepare_enable(uap->clk);
1737ab4382d2SGreg Kroah-Hartman if (retval)
17387f6d942aSTushar Behera return retval;
1739ab4382d2SGreg Kroah-Hartman
1740ab4382d2SGreg Kroah-Hartman uap->port.uartclk = clk_get_rate(uap->clk);
1741ab4382d2SGreg Kroah-Hartman
17429b96fbacSLinus Walleij /* Clear pending error and receive interrupts */
174375836339SRussell King pl011_write(UART011_OEIS | UART011_BEIS | UART011_PEIS |
174475836339SRussell King UART011_FEIS | UART011_RTIS | UART011_RXIS,
17459f25bc51SRussell King uap, REG_ICR);
17469b96fbacSLinus Walleij
1747ab4382d2SGreg Kroah-Hartman /*
1748b3564c2cSAnton Vorontsov * Save interrupts enable mask, and enable RX interrupts in case if
1749b3564c2cSAnton Vorontsov * the interrupt is used for NMI entry.
1750b3564c2cSAnton Vorontsov */
17519f25bc51SRussell King uap->im = pl011_read(uap, REG_IMSC);
17529f25bc51SRussell King pl011_write(UART011_RTIM | UART011_RXIM, uap, REG_IMSC);
1753b3564c2cSAnton Vorontsov
1754574de559SJingoo Han if (dev_get_platdata(uap->port.dev)) {
1755b3564c2cSAnton Vorontsov struct amba_pl011_data *plat;
1756b3564c2cSAnton Vorontsov
1757574de559SJingoo Han plat = dev_get_platdata(uap->port.dev);
1758b3564c2cSAnton Vorontsov if (plat->init)
1759b3564c2cSAnton Vorontsov plat->init();
1760b3564c2cSAnton Vorontsov }
1761b3564c2cSAnton Vorontsov return 0;
1762b3564c2cSAnton Vorontsov }
1763b3564c2cSAnton Vorontsov
pl011_split_lcrh(const struct uart_amba_port * uap)17647fe9a5a9SRussell King static bool pl011_split_lcrh(const struct uart_amba_port *uap)
17657fe9a5a9SRussell King {
1766e4df9a80SRussell King return pl011_reg_to_offset(uap, REG_LCRH_RX) !=
1767e4df9a80SRussell King pl011_reg_to_offset(uap, REG_LCRH_TX);
17687fe9a5a9SRussell King }
17697fe9a5a9SRussell King
pl011_write_lcr_h(struct uart_amba_port * uap,unsigned int lcr_h)1770b60f2f66SJon Medhurst static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h)
1771b60f2f66SJon Medhurst {
1772e4df9a80SRussell King pl011_write(lcr_h, uap, REG_LCRH_RX);
17737fe9a5a9SRussell King if (pl011_split_lcrh(uap)) {
1774b60f2f66SJon Medhurst int i;
1775b60f2f66SJon Medhurst /*
1776b60f2f66SJon Medhurst * Wait 10 PCLKs before writing LCRH_TX register,
1777b60f2f66SJon Medhurst * to get this delay write read only register 10 times
1778b60f2f66SJon Medhurst */
1779b60f2f66SJon Medhurst for (i = 0; i < 10; ++i)
17809f25bc51SRussell King pl011_write(0xff, uap, REG_MIS);
1781e4df9a80SRussell King pl011_write(lcr_h, uap, REG_LCRH_TX);
1782b60f2f66SJon Medhurst }
1783b60f2f66SJon Medhurst }
1784b60f2f66SJon Medhurst
pl011_allocate_irq(struct uart_amba_port * uap)1785867b8e8eSAndre Przywara static int pl011_allocate_irq(struct uart_amba_port *uap)
1786867b8e8eSAndre Przywara {
17879f25bc51SRussell King pl011_write(uap->im, uap, REG_IMSC);
1788867b8e8eSAndre Przywara
178994560f61SQian Cai return request_irq(uap->port.irq, pl011_int, IRQF_SHARED, "uart-pl011", uap);
1790867b8e8eSAndre Przywara }
1791867b8e8eSAndre Przywara
1792867b8e8eSAndre Przywara /*
1793867b8e8eSAndre Przywara * Enable interrupts, only timeouts when using DMA
1794867b8e8eSAndre Przywara * if initial RX DMA job failed, start in interrupt mode
1795867b8e8eSAndre Przywara * as well.
1796867b8e8eSAndre Przywara */
pl011_enable_interrupts(struct uart_amba_port * uap)1797867b8e8eSAndre Przywara static void pl011_enable_interrupts(struct uart_amba_port *uap)
1798867b8e8eSAndre Przywara {
1799211565b1SIlpo Järvinen unsigned long flags;
18004a7e625cSDave Martin unsigned int i;
18014a7e625cSDave Martin
18025aea1229SThomas Gleixner uart_port_lock_irqsave(&uap->port, &flags);
1803867b8e8eSAndre Przywara
1804867b8e8eSAndre Przywara /* Clear out any spuriously appearing RX interrupts */
18059f25bc51SRussell King pl011_write(UART011_RTIS | UART011_RXIS, uap, REG_ICR);
18064a7e625cSDave Martin
18074a7e625cSDave Martin /*
18084a7e625cSDave Martin * RXIS is asserted only when the RX FIFO transitions from below
18094a7e625cSDave Martin * to above the trigger threshold. If the RX FIFO is already
18104a7e625cSDave Martin * full to the threshold this can't happen and RXIS will now be
18114a7e625cSDave Martin * stuck off. Drain the RX FIFO explicitly to fix this:
18124a7e625cSDave Martin */
18134a7e625cSDave Martin for (i = 0; i < uap->fifosize * 2; ++i) {
18144a7e625cSDave Martin if (pl011_read(uap, REG_FR) & UART01x_FR_RXFE)
18154a7e625cSDave Martin break;
18164a7e625cSDave Martin
18174a7e625cSDave Martin pl011_read(uap, REG_DR);
18184a7e625cSDave Martin }
18194a7e625cSDave Martin
1820867b8e8eSAndre Przywara uap->im = UART011_RTIM;
1821867b8e8eSAndre Przywara if (!pl011_dma_rx_running(uap))
1822867b8e8eSAndre Przywara uap->im |= UART011_RXIM;
18239f25bc51SRussell King pl011_write(uap->im, uap, REG_IMSC);
18245aea1229SThomas Gleixner uart_port_unlock_irqrestore(&uap->port, flags);
1825211565b1SIlpo Järvinen }
1826211565b1SIlpo Järvinen
pl011_unthrottle_rx(struct uart_port * port)1827211565b1SIlpo Järvinen static void pl011_unthrottle_rx(struct uart_port *port)
1828211565b1SIlpo Järvinen {
1829211565b1SIlpo Järvinen struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port);
1830032d5a71Sdelisun unsigned long flags;
1831211565b1SIlpo Järvinen
18325aea1229SThomas Gleixner uart_port_lock_irqsave(&uap->port, &flags);
1833032d5a71Sdelisun
1834032d5a71Sdelisun uap->im = UART011_RTIM;
1835032d5a71Sdelisun if (!pl011_dma_rx_running(uap))
1836032d5a71Sdelisun uap->im |= UART011_RXIM;
1837032d5a71Sdelisun
1838032d5a71Sdelisun pl011_write(uap->im, uap, REG_IMSC);
1839032d5a71Sdelisun
1840*1baed369SArnd Bergmann #ifdef CONFIG_DMA_ENGINE
18412eb983f6SKartik Rajput if (uap->using_rx_dma) {
18422eb983f6SKartik Rajput uap->dmacr |= UART011_RXDMAE;
18432eb983f6SKartik Rajput pl011_write(uap->dmacr, uap, REG_DMACR);
18442eb983f6SKartik Rajput }
1845*1baed369SArnd Bergmann #endif
18462eb983f6SKartik Rajput
18475aea1229SThomas Gleixner uart_port_unlock_irqrestore(&uap->port, flags);
1848867b8e8eSAndre Przywara }
1849867b8e8eSAndre Przywara
pl011_startup(struct uart_port * port)1850b3564c2cSAnton Vorontsov static int pl011_startup(struct uart_port *port)
1851b3564c2cSAnton Vorontsov {
1852a5820c24SDaniel Thompson struct uart_amba_port *uap =
1853a5820c24SDaniel Thompson container_of(port, struct uart_amba_port, port);
1854734745caSDave Martin unsigned int cr;
1855b3564c2cSAnton Vorontsov int retval;
1856b3564c2cSAnton Vorontsov
1857b3564c2cSAnton Vorontsov retval = pl011_hwinit(port);
1858b3564c2cSAnton Vorontsov if (retval)
1859b3564c2cSAnton Vorontsov goto clk_dis;
1860b3564c2cSAnton Vorontsov
1861867b8e8eSAndre Przywara retval = pl011_allocate_irq(uap);
1862ab4382d2SGreg Kroah-Hartman if (retval)
1863ab4382d2SGreg Kroah-Hartman goto clk_dis;
1864ab4382d2SGreg Kroah-Hartman
18659f25bc51SRussell King pl011_write(uap->vendor->ifls, uap, REG_IFLS);
1866ab4382d2SGreg Kroah-Hartman
18675aea1229SThomas Gleixner uart_port_lock_irq(&uap->port);
1868fe433907SJon Medhurst
186949a80424SLukas Wunner cr = pl011_read(uap, REG_CR);
187049a80424SLukas Wunner cr &= UART011_CR_RTS | UART011_CR_DTR;
18718d479237SLino Sanfilippo cr |= UART01x_CR_UARTEN | UART011_CR_RXE;
18728d479237SLino Sanfilippo
18732dd8a74fSLukas Wunner if (!(port->rs485.flags & SER_RS485_ENABLED))
18748d479237SLino Sanfilippo cr |= UART011_CR_TXE;
18758d479237SLino Sanfilippo
18769f25bc51SRussell King pl011_write(cr, uap, REG_CR);
1877ab4382d2SGreg Kroah-Hartman
18785aea1229SThomas Gleixner uart_port_unlock_irq(&uap->port);
1879fe433907SJon Medhurst
1880ab4382d2SGreg Kroah-Hartman /*
1881ab4382d2SGreg Kroah-Hartman * initialise the old status of the modem signals
1882ab4382d2SGreg Kroah-Hartman */
18839f25bc51SRussell King uap->old_status = pl011_read(uap, REG_FR) & UART01x_FR_MODEM_ANY;
1884ab4382d2SGreg Kroah-Hartman
1885ab4382d2SGreg Kroah-Hartman /* Startup DMA */
1886ab4382d2SGreg Kroah-Hartman pl011_dma_startup(uap);
1887ab4382d2SGreg Kroah-Hartman
1888867b8e8eSAndre Przywara pl011_enable_interrupts(uap);
1889ab4382d2SGreg Kroah-Hartman
1890ab4382d2SGreg Kroah-Hartman return 0;
1891ab4382d2SGreg Kroah-Hartman
1892ab4382d2SGreg Kroah-Hartman clk_dis:
18931c4c4394SJulia Lawall clk_disable_unprepare(uap->clk);
1894ab4382d2SGreg Kroah-Hartman return retval;
1895ab4382d2SGreg Kroah-Hartman }
1896ab4382d2SGreg Kroah-Hartman
sbsa_uart_startup(struct uart_port * port)18970dd1e247SAndre Przywara static int sbsa_uart_startup(struct uart_port *port)
18980dd1e247SAndre Przywara {
18990dd1e247SAndre Przywara struct uart_amba_port *uap =
19000dd1e247SAndre Przywara container_of(port, struct uart_amba_port, port);
19010dd1e247SAndre Przywara int retval;
19020dd1e247SAndre Przywara
19030dd1e247SAndre Przywara retval = pl011_hwinit(port);
19040dd1e247SAndre Przywara if (retval)
19050dd1e247SAndre Przywara return retval;
19060dd1e247SAndre Przywara
19070dd1e247SAndre Przywara retval = pl011_allocate_irq(uap);
19080dd1e247SAndre Przywara if (retval)
19090dd1e247SAndre Przywara return retval;
19100dd1e247SAndre Przywara
19110dd1e247SAndre Przywara /* The SBSA UART does not support any modem status lines. */
19120dd1e247SAndre Przywara uap->old_status = 0;
19130dd1e247SAndre Przywara
19140dd1e247SAndre Przywara pl011_enable_interrupts(uap);
19150dd1e247SAndre Przywara
19160dd1e247SAndre Przywara return 0;
19170dd1e247SAndre Przywara }
19180dd1e247SAndre Przywara
pl011_shutdown_channel(struct uart_amba_port * uap,unsigned int lcrh)1919ab4382d2SGreg Kroah-Hartman static void pl011_shutdown_channel(struct uart_amba_port *uap,
1920ab4382d2SGreg Kroah-Hartman unsigned int lcrh)
1921ab4382d2SGreg Kroah-Hartman {
1922ab4382d2SGreg Kroah-Hartman unsigned long val;
1923ab4382d2SGreg Kroah-Hartman
1924b2a4e24cSRussell King val = pl011_read(uap, lcrh);
1925ab4382d2SGreg Kroah-Hartman val &= ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN);
1926b2a4e24cSRussell King pl011_write(val, uap, lcrh);
1927ab4382d2SGreg Kroah-Hartman }
1928ab4382d2SGreg Kroah-Hartman
1929ab4382d2SGreg Kroah-Hartman /*
1930d8d8ffa4SShreshtha Kumar Sahu * disable the port. It should not disable RTS and DTR.
1931d8d8ffa4SShreshtha Kumar Sahu * Also RTS and DTR state should be preserved to restore
1932d8d8ffa4SShreshtha Kumar Sahu * it during startup().
1933ab4382d2SGreg Kroah-Hartman */
pl011_disable_uart(struct uart_amba_port * uap)193495166a3fSAndre Przywara static void pl011_disable_uart(struct uart_amba_port *uap)
193595166a3fSAndre Przywara {
193695166a3fSAndre Przywara unsigned int cr;
193795166a3fSAndre Przywara
19382a76fa28SLukas Wunner uap->port.status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS);
19395aea1229SThomas Gleixner uart_port_lock_irq(&uap->port);
19409f25bc51SRussell King cr = pl011_read(uap, REG_CR);
1941d8d8ffa4SShreshtha Kumar Sahu cr &= UART011_CR_RTS | UART011_CR_DTR;
1942d8d8ffa4SShreshtha Kumar Sahu cr |= UART01x_CR_UARTEN | UART011_CR_TXE;
19439f25bc51SRussell King pl011_write(cr, uap, REG_CR);
19445aea1229SThomas Gleixner uart_port_unlock_irq(&uap->port);
1945ab4382d2SGreg Kroah-Hartman
1946ab4382d2SGreg Kroah-Hartman /*
1947ab4382d2SGreg Kroah-Hartman * disable break condition and fifos
1948ab4382d2SGreg Kroah-Hartman */
1949e4df9a80SRussell King pl011_shutdown_channel(uap, REG_LCRH_RX);
19507fe9a5a9SRussell King if (pl011_split_lcrh(uap))
1951e4df9a80SRussell King pl011_shutdown_channel(uap, REG_LCRH_TX);
195295166a3fSAndre Przywara }
195395166a3fSAndre Przywara
pl011_disable_interrupts(struct uart_amba_port * uap)195495166a3fSAndre Przywara static void pl011_disable_interrupts(struct uart_amba_port *uap)
195595166a3fSAndre Przywara {
19565aea1229SThomas Gleixner uart_port_lock_irq(&uap->port);
195795166a3fSAndre Przywara
195895166a3fSAndre Przywara /* mask all interrupts and clear all pending ones */
195995166a3fSAndre Przywara uap->im = 0;
19609f25bc51SRussell King pl011_write(uap->im, uap, REG_IMSC);
19619f25bc51SRussell King pl011_write(0xffff, uap, REG_ICR);
196295166a3fSAndre Przywara
19635aea1229SThomas Gleixner uart_port_unlock_irq(&uap->port);
196495166a3fSAndre Przywara }
196595166a3fSAndre Przywara
pl011_shutdown(struct uart_port * port)196695166a3fSAndre Przywara static void pl011_shutdown(struct uart_port *port)
196795166a3fSAndre Przywara {
196895166a3fSAndre Przywara struct uart_amba_port *uap =
196995166a3fSAndre Przywara container_of(port, struct uart_amba_port, port);
197095166a3fSAndre Przywara
197195166a3fSAndre Przywara pl011_disable_interrupts(uap);
197295166a3fSAndre Przywara
197395166a3fSAndre Przywara pl011_dma_shutdown(uap);
197495166a3fSAndre Przywara
19758d479237SLino Sanfilippo if ((port->rs485.flags & SER_RS485_ENABLED) && uap->rs485_tx_started)
19768d479237SLino Sanfilippo pl011_rs485_tx_stop(uap);
19778d479237SLino Sanfilippo
197894560f61SQian Cai free_irq(uap->port.irq, uap);
197995166a3fSAndre Przywara
198095166a3fSAndre Przywara pl011_disable_uart(uap);
1981ab4382d2SGreg Kroah-Hartman
1982ab4382d2SGreg Kroah-Hartman /*
1983ab4382d2SGreg Kroah-Hartman * Shut down the clock producer
1984ab4382d2SGreg Kroah-Hartman */
19851c4c4394SJulia Lawall clk_disable_unprepare(uap->clk);
198678d80c5aSLinus Walleij /* Optionally let pins go into sleep states */
19872b996fc5SLinus Walleij pinctrl_pm_select_sleep_state(port->dev);
1988c16d51a3SShreshtha Kumar Sahu
1989574de559SJingoo Han if (dev_get_platdata(uap->port.dev)) {
1990c16d51a3SShreshtha Kumar Sahu struct amba_pl011_data *plat;
1991c16d51a3SShreshtha Kumar Sahu
1992574de559SJingoo Han plat = dev_get_platdata(uap->port.dev);
1993c16d51a3SShreshtha Kumar Sahu if (plat->exit)
1994c16d51a3SShreshtha Kumar Sahu plat->exit();
1995c16d51a3SShreshtha Kumar Sahu }
1996c16d51a3SShreshtha Kumar Sahu
199736f339d1SPeter Hurley if (uap->port.ops->flush_buffer)
199836f339d1SPeter Hurley uap->port.ops->flush_buffer(port);
1999ab4382d2SGreg Kroah-Hartman }
2000ab4382d2SGreg Kroah-Hartman
sbsa_uart_shutdown(struct uart_port * port)20010dd1e247SAndre Przywara static void sbsa_uart_shutdown(struct uart_port *port)
20020dd1e247SAndre Przywara {
20030dd1e247SAndre Przywara struct uart_amba_port *uap =
20040dd1e247SAndre Przywara container_of(port, struct uart_amba_port, port);
20050dd1e247SAndre Przywara
20060dd1e247SAndre Przywara pl011_disable_interrupts(uap);
20070dd1e247SAndre Przywara
200894560f61SQian Cai free_irq(uap->port.irq, uap);
20090dd1e247SAndre Przywara
20100dd1e247SAndre Przywara if (uap->port.ops->flush_buffer)
20110dd1e247SAndre Przywara uap->port.ops->flush_buffer(port);
20120dd1e247SAndre Przywara }
20130dd1e247SAndre Przywara
2014ab4382d2SGreg Kroah-Hartman static void
pl011_setup_status_masks(struct uart_port * port,struct ktermios * termios)2015ef5a9358SAndre Przywara pl011_setup_status_masks(struct uart_port *port, struct ktermios *termios)
2016ef5a9358SAndre Przywara {
2017ef5a9358SAndre Przywara port->read_status_mask = UART011_DR_OE | 255;
2018ef5a9358SAndre Przywara if (termios->c_iflag & INPCK)
2019ef5a9358SAndre Przywara port->read_status_mask |= UART011_DR_FE | UART011_DR_PE;
2020ef5a9358SAndre Przywara if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
2021ef5a9358SAndre Przywara port->read_status_mask |= UART011_DR_BE;
2022ef5a9358SAndre Przywara
2023ef5a9358SAndre Przywara /*
2024ef5a9358SAndre Przywara * Characters to ignore
2025ef5a9358SAndre Przywara */
2026ef5a9358SAndre Przywara port->ignore_status_mask = 0;
2027ef5a9358SAndre Przywara if (termios->c_iflag & IGNPAR)
2028ef5a9358SAndre Przywara port->ignore_status_mask |= UART011_DR_FE | UART011_DR_PE;
2029ef5a9358SAndre Przywara if (termios->c_iflag & IGNBRK) {
2030ef5a9358SAndre Przywara port->ignore_status_mask |= UART011_DR_BE;
2031ef5a9358SAndre Przywara /*
2032ef5a9358SAndre Przywara * If we're ignoring parity and break indicators,
2033ef5a9358SAndre Przywara * ignore overruns too (for real raw support).
2034ef5a9358SAndre Przywara */
2035ef5a9358SAndre Przywara if (termios->c_iflag & IGNPAR)
2036ef5a9358SAndre Przywara port->ignore_status_mask |= UART011_DR_OE;
2037ef5a9358SAndre Przywara }
2038ef5a9358SAndre Przywara
2039ef5a9358SAndre Przywara /*
2040ef5a9358SAndre Przywara * Ignore all characters if CREAD is not set.
2041ef5a9358SAndre Przywara */
2042ef5a9358SAndre Przywara if ((termios->c_cflag & CREAD) == 0)
2043ef5a9358SAndre Przywara port->ignore_status_mask |= UART_DUMMY_DR_RX;
2044ef5a9358SAndre Przywara }
2045ef5a9358SAndre Przywara
2046ef5a9358SAndre Przywara static void
pl011_set_termios(struct uart_port * port,struct ktermios * termios,const struct ktermios * old)2047ab4382d2SGreg Kroah-Hartman pl011_set_termios(struct uart_port *port, struct ktermios *termios,
2048bec5b814SIlpo Järvinen const struct ktermios *old)
2049ab4382d2SGreg Kroah-Hartman {
2050a5820c24SDaniel Thompson struct uart_amba_port *uap =
2051a5820c24SDaniel Thompson container_of(port, struct uart_amba_port, port);
2052ab4382d2SGreg Kroah-Hartman unsigned int lcr_h, old_cr;
2053ab4382d2SGreg Kroah-Hartman unsigned long flags;
2054ab4382d2SGreg Kroah-Hartman unsigned int baud, quot, clkdiv;
20558d479237SLino Sanfilippo unsigned int bits;
2056ab4382d2SGreg Kroah-Hartman
2057ab4382d2SGreg Kroah-Hartman if (uap->vendor->oversampling)
2058ab4382d2SGreg Kroah-Hartman clkdiv = 8;
2059ab4382d2SGreg Kroah-Hartman else
2060ab4382d2SGreg Kroah-Hartman clkdiv = 16;
2061ab4382d2SGreg Kroah-Hartman
2062ab4382d2SGreg Kroah-Hartman /*
2063ab4382d2SGreg Kroah-Hartman * Ask the core to calculate the divisor for us.
2064ab4382d2SGreg Kroah-Hartman */
2065ab4382d2SGreg Kroah-Hartman baud = uart_get_baud_rate(port, termios, old, 0,
2066ab4382d2SGreg Kroah-Hartman port->uartclk / clkdiv);
206789fa28dbSChanho Min #ifdef CONFIG_DMA_ENGINE
2068cb06ff10SChanho Min /*
2069cb06ff10SChanho Min * Adjust RX DMA polling rate with baud rate if not specified.
2070cb06ff10SChanho Min */
2071cb06ff10SChanho Min if (uap->dmarx.auto_poll_rate)
2072cb06ff10SChanho Min uap->dmarx.poll_rate = DIV_ROUND_UP(10000000, baud);
207389fa28dbSChanho Min #endif
2074ab4382d2SGreg Kroah-Hartman
2075ab4382d2SGreg Kroah-Hartman if (baud > port->uartclk/16)
2076ab4382d2SGreg Kroah-Hartman quot = DIV_ROUND_CLOSEST(port->uartclk * 8, baud);
2077ab4382d2SGreg Kroah-Hartman else
2078ab4382d2SGreg Kroah-Hartman quot = DIV_ROUND_CLOSEST(port->uartclk * 4, baud);
2079ab4382d2SGreg Kroah-Hartman
2080ab4382d2SGreg Kroah-Hartman switch (termios->c_cflag & CSIZE) {
2081ab4382d2SGreg Kroah-Hartman case CS5:
2082ab4382d2SGreg Kroah-Hartman lcr_h = UART01x_LCRH_WLEN_5;
2083ab4382d2SGreg Kroah-Hartman break;
2084ab4382d2SGreg Kroah-Hartman case CS6:
2085ab4382d2SGreg Kroah-Hartman lcr_h = UART01x_LCRH_WLEN_6;
2086ab4382d2SGreg Kroah-Hartman break;
2087ab4382d2SGreg Kroah-Hartman case CS7:
2088ab4382d2SGreg Kroah-Hartman lcr_h = UART01x_LCRH_WLEN_7;
2089ab4382d2SGreg Kroah-Hartman break;
2090ab4382d2SGreg Kroah-Hartman default: // CS8
2091ab4382d2SGreg Kroah-Hartman lcr_h = UART01x_LCRH_WLEN_8;
2092ab4382d2SGreg Kroah-Hartman break;
2093ab4382d2SGreg Kroah-Hartman }
2094ab4382d2SGreg Kroah-Hartman if (termios->c_cflag & CSTOPB)
2095ab4382d2SGreg Kroah-Hartman lcr_h |= UART01x_LCRH_STP2;
2096ab4382d2SGreg Kroah-Hartman if (termios->c_cflag & PARENB) {
2097ab4382d2SGreg Kroah-Hartman lcr_h |= UART01x_LCRH_PEN;
2098ab4382d2SGreg Kroah-Hartman if (!(termios->c_cflag & PARODD))
2099ab4382d2SGreg Kroah-Hartman lcr_h |= UART01x_LCRH_EPS;
2100bb70002cSEd Spiridonov if (termios->c_cflag & CMSPAR)
2101bb70002cSEd Spiridonov lcr_h |= UART011_LCRH_SPS;
2102ab4382d2SGreg Kroah-Hartman }
2103ab4382d2SGreg Kroah-Hartman if (uap->fifosize > 1)
2104ab4382d2SGreg Kroah-Hartman lcr_h |= UART01x_LCRH_FEN;
2105ab4382d2SGreg Kroah-Hartman
21068d479237SLino Sanfilippo bits = tty_get_frame_size(termios->c_cflag);
21078d479237SLino Sanfilippo
21085aea1229SThomas Gleixner uart_port_lock_irqsave(port, &flags);
2109ab4382d2SGreg Kroah-Hartman
2110ab4382d2SGreg Kroah-Hartman /*
2111ab4382d2SGreg Kroah-Hartman * Update the per-port timeout.
2112ab4382d2SGreg Kroah-Hartman */
2113ab4382d2SGreg Kroah-Hartman uart_update_timeout(port, termios->c_cflag, baud);
2114ab4382d2SGreg Kroah-Hartman
21158d479237SLino Sanfilippo /*
21168d479237SLino Sanfilippo * Calculate the approximated time it takes to transmit one character
21178d479237SLino Sanfilippo * with the given baud rate. We use this as the poll interval when we
21188d479237SLino Sanfilippo * wait for the tx queue to empty.
21198d479237SLino Sanfilippo */
21200e4deb56SLino Sanfilippo uap->rs485_tx_drain_interval = DIV_ROUND_UP(bits * 1000 * 1000, baud);
21218d479237SLino Sanfilippo
2122ef5a9358SAndre Przywara pl011_setup_status_masks(port, termios);
2123ab4382d2SGreg Kroah-Hartman
2124ab4382d2SGreg Kroah-Hartman if (UART_ENABLE_MS(port, termios->c_cflag))
2125ab4382d2SGreg Kroah-Hartman pl011_enable_ms(port);
2126ab4382d2SGreg Kroah-Hartman
21278d479237SLino Sanfilippo if (port->rs485.flags & SER_RS485_ENABLED)
21288d479237SLino Sanfilippo termios->c_cflag &= ~CRTSCTS;
21298d479237SLino Sanfilippo
21309f25bc51SRussell King old_cr = pl011_read(uap, REG_CR);
2131ab4382d2SGreg Kroah-Hartman
2132ab4382d2SGreg Kroah-Hartman if (termios->c_cflag & CRTSCTS) {
2133ab4382d2SGreg Kroah-Hartman if (old_cr & UART011_CR_RTS)
2134ab4382d2SGreg Kroah-Hartman old_cr |= UART011_CR_RTSEN;
2135ab4382d2SGreg Kroah-Hartman
2136ab4382d2SGreg Kroah-Hartman old_cr |= UART011_CR_CTSEN;
21372a76fa28SLukas Wunner port->status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS;
2138ab4382d2SGreg Kroah-Hartman } else {
2139ab4382d2SGreg Kroah-Hartman old_cr &= ~(UART011_CR_CTSEN | UART011_CR_RTSEN);
21402a76fa28SLukas Wunner port->status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS);
2141ab4382d2SGreg Kroah-Hartman }
2142ab4382d2SGreg Kroah-Hartman
2143ab4382d2SGreg Kroah-Hartman if (uap->vendor->oversampling) {
2144ab4382d2SGreg Kroah-Hartman if (baud > port->uartclk / 16)
2145ab4382d2SGreg Kroah-Hartman old_cr |= ST_UART011_CR_OVSFACT;
2146ab4382d2SGreg Kroah-Hartman else
2147ab4382d2SGreg Kroah-Hartman old_cr &= ~ST_UART011_CR_OVSFACT;
2148ab4382d2SGreg Kroah-Hartman }
2149ab4382d2SGreg Kroah-Hartman
2150c5dd553bSLinus Walleij /*
2151c5dd553bSLinus Walleij * Workaround for the ST Micro oversampling variants to
2152c5dd553bSLinus Walleij * increase the bitrate slightly, by lowering the divisor,
2153c5dd553bSLinus Walleij * to avoid delayed sampling of start bit at high speeds,
2154c5dd553bSLinus Walleij * else we see data corruption.
2155c5dd553bSLinus Walleij */
2156c5dd553bSLinus Walleij if (uap->vendor->oversampling) {
2157c5dd553bSLinus Walleij if ((baud >= 3000000) && (baud < 3250000) && (quot > 1))
2158c5dd553bSLinus Walleij quot -= 1;
2159c5dd553bSLinus Walleij else if ((baud > 3250000) && (quot > 2))
2160c5dd553bSLinus Walleij quot -= 2;
2161c5dd553bSLinus Walleij }
2162ab4382d2SGreg Kroah-Hartman /* Set baud rate */
21639f25bc51SRussell King pl011_write(quot & 0x3f, uap, REG_FBRD);
21649f25bc51SRussell King pl011_write(quot >> 6, uap, REG_IBRD);
2165ab4382d2SGreg Kroah-Hartman
2166ab4382d2SGreg Kroah-Hartman /*
2167ab4382d2SGreg Kroah-Hartman * ----------v----------v----------v----------v-----
2168e4df9a80SRussell King * NOTE: REG_LCRH_TX and REG_LCRH_RX MUST BE WRITTEN AFTER
21699f25bc51SRussell King * REG_FBRD & REG_IBRD.
2170ab4382d2SGreg Kroah-Hartman * ----------^----------^----------^----------^-----
2171ab4382d2SGreg Kroah-Hartman */
2172b60f2f66SJon Medhurst pl011_write_lcr_h(uap, lcr_h);
21736d8c1fcaSHongyu Xie
21746d8c1fcaSHongyu Xie /*
21756d8c1fcaSHongyu Xie * Receive was disabled by pl011_disable_uart during shutdown.
21766d8c1fcaSHongyu Xie * Need to reenable receive if you need to use a tty_driver
21776d8c1fcaSHongyu Xie * returns from tty_find_polling_driver() after a port shutdown.
21786d8c1fcaSHongyu Xie */
21796d8c1fcaSHongyu Xie old_cr |= UART011_CR_RXE;
21809f25bc51SRussell King pl011_write(old_cr, uap, REG_CR);
2181ab4382d2SGreg Kroah-Hartman
21825aea1229SThomas Gleixner uart_port_unlock_irqrestore(port, flags);
2183ab4382d2SGreg Kroah-Hartman }
2184ab4382d2SGreg Kroah-Hartman
21850dd1e247SAndre Przywara static void
sbsa_uart_set_termios(struct uart_port * port,struct ktermios * termios,const struct ktermios * old)21860dd1e247SAndre Przywara sbsa_uart_set_termios(struct uart_port *port, struct ktermios *termios,
2187bec5b814SIlpo Järvinen const struct ktermios *old)
21880dd1e247SAndre Przywara {
21890dd1e247SAndre Przywara struct uart_amba_port *uap =
21900dd1e247SAndre Przywara container_of(port, struct uart_amba_port, port);
21910dd1e247SAndre Przywara unsigned long flags;
21920dd1e247SAndre Przywara
21930dd1e247SAndre Przywara tty_termios_encode_baud_rate(termios, uap->fixed_baud, uap->fixed_baud);
21940dd1e247SAndre Przywara
21950dd1e247SAndre Przywara /* The SBSA UART only supports 8n1 without hardware flow control. */
21960dd1e247SAndre Przywara termios->c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD);
21970dd1e247SAndre Przywara termios->c_cflag &= ~(CMSPAR | CRTSCTS);
21980dd1e247SAndre Przywara termios->c_cflag |= CS8 | CLOCAL;
21990dd1e247SAndre Przywara
22005aea1229SThomas Gleixner uart_port_lock_irqsave(port, &flags);
22010dd1e247SAndre Przywara uart_update_timeout(port, CS8, uap->fixed_baud);
22020dd1e247SAndre Przywara pl011_setup_status_masks(port, termios);
22035aea1229SThomas Gleixner uart_port_unlock_irqrestore(port, flags);
22040dd1e247SAndre Przywara }
22050dd1e247SAndre Przywara
pl011_type(struct uart_port * port)2206ab4382d2SGreg Kroah-Hartman static const char *pl011_type(struct uart_port *port)
2207ab4382d2SGreg Kroah-Hartman {
2208a5820c24SDaniel Thompson struct uart_amba_port *uap =
2209a5820c24SDaniel Thompson container_of(port, struct uart_amba_port, port);
2210ab4382d2SGreg Kroah-Hartman return uap->port.type == PORT_AMBA ? uap->type : NULL;
2211ab4382d2SGreg Kroah-Hartman }
2212ab4382d2SGreg Kroah-Hartman
2213ab4382d2SGreg Kroah-Hartman /*
2214ab4382d2SGreg Kroah-Hartman * Configure/autoconfigure the port.
2215ab4382d2SGreg Kroah-Hartman */
pl011_config_port(struct uart_port * port,int flags)2216e643f87fSLinus Walleij static void pl011_config_port(struct uart_port *port, int flags)
2217ab4382d2SGreg Kroah-Hartman {
2218d1180405SLino Sanfilippo if (flags & UART_CONFIG_TYPE)
2219ab4382d2SGreg Kroah-Hartman port->type = PORT_AMBA;
2220ab4382d2SGreg Kroah-Hartman }
2221ab4382d2SGreg Kroah-Hartman
2222ab4382d2SGreg Kroah-Hartman /*
2223ab4382d2SGreg Kroah-Hartman * verify the new serial_struct (for TIOCSSERIAL).
2224ab4382d2SGreg Kroah-Hartman */
pl011_verify_port(struct uart_port * port,struct serial_struct * ser)2225e643f87fSLinus Walleij static int pl011_verify_port(struct uart_port *port, struct serial_struct *ser)
2226ab4382d2SGreg Kroah-Hartman {
2227ab4382d2SGreg Kroah-Hartman int ret = 0;
2228ab4382d2SGreg Kroah-Hartman if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA)
2229ab4382d2SGreg Kroah-Hartman ret = -EINVAL;
2230ab4382d2SGreg Kroah-Hartman if (ser->irq < 0 || ser->irq >= nr_irqs)
2231ab4382d2SGreg Kroah-Hartman ret = -EINVAL;
2232ab4382d2SGreg Kroah-Hartman if (ser->baud_base < 9600)
2233ab4382d2SGreg Kroah-Hartman ret = -EINVAL;
2234d1180405SLino Sanfilippo if (port->mapbase != (unsigned long) ser->iomem_base)
2235d1180405SLino Sanfilippo ret = -EINVAL;
2236ab4382d2SGreg Kroah-Hartman return ret;
2237ab4382d2SGreg Kroah-Hartman }
2238ab4382d2SGreg Kroah-Hartman
pl011_rs485_config(struct uart_port * port,struct ktermios * termios,struct serial_rs485 * rs485)2239ae50bb27SIlpo Järvinen static int pl011_rs485_config(struct uart_port *port, struct ktermios *termios,
22408d479237SLino Sanfilippo struct serial_rs485 *rs485)
22418d479237SLino Sanfilippo {
22428d479237SLino Sanfilippo struct uart_amba_port *uap =
22438d479237SLino Sanfilippo container_of(port, struct uart_amba_port, port);
22448d479237SLino Sanfilippo
22458d479237SLino Sanfilippo if (port->rs485.flags & SER_RS485_ENABLED)
22468d479237SLino Sanfilippo pl011_rs485_tx_stop(uap);
22478d479237SLino Sanfilippo
22488d479237SLino Sanfilippo /* Make sure auto RTS is disabled */
2249a9efa452SLino Sanfilippo if (rs485->flags & SER_RS485_ENABLED) {
22508d479237SLino Sanfilippo u32 cr = pl011_read(uap, REG_CR);
22518d479237SLino Sanfilippo
22528d479237SLino Sanfilippo cr &= ~UART011_CR_RTSEN;
22538d479237SLino Sanfilippo pl011_write(cr, uap, REG_CR);
22548d479237SLino Sanfilippo port->status &= ~UPSTAT_AUTORTS;
22558d479237SLino Sanfilippo }
22568d479237SLino Sanfilippo
22578d479237SLino Sanfilippo return 0;
22588d479237SLino Sanfilippo }
22598d479237SLino Sanfilippo
22602331e068SBhumika Goyal static const struct uart_ops amba_pl011_pops = {
2261e643f87fSLinus Walleij .tx_empty = pl011_tx_empty,
2262ab4382d2SGreg Kroah-Hartman .set_mctrl = pl011_set_mctrl,
2263e643f87fSLinus Walleij .get_mctrl = pl011_get_mctrl,
2264ab4382d2SGreg Kroah-Hartman .stop_tx = pl011_stop_tx,
2265ab4382d2SGreg Kroah-Hartman .start_tx = pl011_start_tx,
2266ab4382d2SGreg Kroah-Hartman .stop_rx = pl011_stop_rx,
2267211565b1SIlpo Järvinen .throttle = pl011_throttle_rx,
2268211565b1SIlpo Järvinen .unthrottle = pl011_unthrottle_rx,
2269ab4382d2SGreg Kroah-Hartman .enable_ms = pl011_enable_ms,
2270ab4382d2SGreg Kroah-Hartman .break_ctl = pl011_break_ctl,
2271ab4382d2SGreg Kroah-Hartman .startup = pl011_startup,
2272ab4382d2SGreg Kroah-Hartman .shutdown = pl011_shutdown,
2273ab4382d2SGreg Kroah-Hartman .flush_buffer = pl011_dma_flush_buffer,
2274ab4382d2SGreg Kroah-Hartman .set_termios = pl011_set_termios,
2275ab4382d2SGreg Kroah-Hartman .type = pl011_type,
2276e643f87fSLinus Walleij .config_port = pl011_config_port,
2277e643f87fSLinus Walleij .verify_port = pl011_verify_port,
2278ab4382d2SGreg Kroah-Hartman #ifdef CONFIG_CONSOLE_POLL
2279b3564c2cSAnton Vorontsov .poll_init = pl011_hwinit,
2280e643f87fSLinus Walleij .poll_get_char = pl011_get_poll_char,
2281e643f87fSLinus Walleij .poll_put_char = pl011_put_poll_char,
2282ab4382d2SGreg Kroah-Hartman #endif
2283ab4382d2SGreg Kroah-Hartman };
2284ab4382d2SGreg Kroah-Hartman
sbsa_uart_set_mctrl(struct uart_port * port,unsigned int mctrl)22850dd1e247SAndre Przywara static void sbsa_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
22860dd1e247SAndre Przywara {
22870dd1e247SAndre Przywara }
22880dd1e247SAndre Przywara
sbsa_uart_get_mctrl(struct uart_port * port)22890dd1e247SAndre Przywara static unsigned int sbsa_uart_get_mctrl(struct uart_port *port)
22900dd1e247SAndre Przywara {
22910dd1e247SAndre Przywara return 0;
22920dd1e247SAndre Przywara }
22930dd1e247SAndre Przywara
22940dd1e247SAndre Przywara static const struct uart_ops sbsa_uart_pops = {
22950dd1e247SAndre Przywara .tx_empty = pl011_tx_empty,
22960dd1e247SAndre Przywara .set_mctrl = sbsa_uart_set_mctrl,
22970dd1e247SAndre Przywara .get_mctrl = sbsa_uart_get_mctrl,
22980dd1e247SAndre Przywara .stop_tx = pl011_stop_tx,
22990dd1e247SAndre Przywara .start_tx = pl011_start_tx,
23000dd1e247SAndre Przywara .stop_rx = pl011_stop_rx,
23010dd1e247SAndre Przywara .startup = sbsa_uart_startup,
23020dd1e247SAndre Przywara .shutdown = sbsa_uart_shutdown,
23030dd1e247SAndre Przywara .set_termios = sbsa_uart_set_termios,
23040dd1e247SAndre Przywara .type = pl011_type,
23050dd1e247SAndre Przywara .config_port = pl011_config_port,
23060dd1e247SAndre Przywara .verify_port = pl011_verify_port,
23070dd1e247SAndre Przywara #ifdef CONFIG_CONSOLE_POLL
23080dd1e247SAndre Przywara .poll_init = pl011_hwinit,
23090dd1e247SAndre Przywara .poll_get_char = pl011_get_poll_char,
23100dd1e247SAndre Przywara .poll_put_char = pl011_put_poll_char,
23110dd1e247SAndre Przywara #endif
23120dd1e247SAndre Przywara };
23130dd1e247SAndre Przywara
2314ab4382d2SGreg Kroah-Hartman static struct uart_amba_port *amba_ports[UART_NR];
2315ab4382d2SGreg Kroah-Hartman
2316ab4382d2SGreg Kroah-Hartman #ifdef CONFIG_SERIAL_AMBA_PL011_CONSOLE
2317ab4382d2SGreg Kroah-Hartman
pl011_console_putchar(struct uart_port * port,unsigned char ch)23183f8bab17SJiri Slaby static void pl011_console_putchar(struct uart_port *port, unsigned char ch)
2319ab4382d2SGreg Kroah-Hartman {
2320a5820c24SDaniel Thompson struct uart_amba_port *uap =
2321a5820c24SDaniel Thompson container_of(port, struct uart_amba_port, port);
2322ab4382d2SGreg Kroah-Hartman
23239f25bc51SRussell King while (pl011_read(uap, REG_FR) & UART01x_FR_TXFF)
23242f2fd089STimur Tabi cpu_relax();
23259f25bc51SRussell King pl011_write(ch, uap, REG_DR);
2326ab4382d2SGreg Kroah-Hartman }
2327ab4382d2SGreg Kroah-Hartman
2328ab4382d2SGreg Kroah-Hartman static void
pl011_console_write(struct console * co,const char * s,unsigned int count)2329ab4382d2SGreg Kroah-Hartman pl011_console_write(struct console *co, const char *s, unsigned int count)
2330ab4382d2SGreg Kroah-Hartman {
2331ab4382d2SGreg Kroah-Hartman struct uart_amba_port *uap = amba_ports[co->index];
23322f2fd089STimur Tabi unsigned int old_cr = 0, new_cr;
2333ef605fdbSRabin Vincent unsigned long flags;
2334ef605fdbSRabin Vincent int locked = 1;
2335ab4382d2SGreg Kroah-Hartman
2336ab4382d2SGreg Kroah-Hartman clk_enable(uap->clk);
2337ab4382d2SGreg Kroah-Hartman
2338ef605fdbSRabin Vincent local_irq_save(flags);
2339ef605fdbSRabin Vincent if (uap->port.sysrq)
2340ef605fdbSRabin Vincent locked = 0;
2341ef605fdbSRabin Vincent else if (oops_in_progress)
23425aea1229SThomas Gleixner locked = uart_port_trylock(&uap->port);
2343ef605fdbSRabin Vincent else
23445aea1229SThomas Gleixner uart_port_lock(&uap->port);
2345ef605fdbSRabin Vincent
2346ab4382d2SGreg Kroah-Hartman /*
2347ab4382d2SGreg Kroah-Hartman * First save the CR then disable the interrupts
2348ab4382d2SGreg Kroah-Hartman */
234971eec483SAndre Przywara if (!uap->vendor->always_enabled) {
23509f25bc51SRussell King old_cr = pl011_read(uap, REG_CR);
2351ab4382d2SGreg Kroah-Hartman new_cr = old_cr & ~UART011_CR_CTSEN;
2352ab4382d2SGreg Kroah-Hartman new_cr |= UART01x_CR_UARTEN | UART011_CR_TXE;
23539f25bc51SRussell King pl011_write(new_cr, uap, REG_CR);
235471eec483SAndre Przywara }
2355ab4382d2SGreg Kroah-Hartman
2356ab4382d2SGreg Kroah-Hartman uart_console_write(&uap->port, s, count, pl011_console_putchar);
2357ab4382d2SGreg Kroah-Hartman
2358ab4382d2SGreg Kroah-Hartman /*
2359d8a4995bSChristopher Covington * Finally, wait for transmitter to become empty and restore the
2360d8a4995bSChristopher Covington * TCR. Allow feature register bits to be inverted to work around
2361d8a4995bSChristopher Covington * errata.
2362ab4382d2SGreg Kroah-Hartman */
2363d8a4995bSChristopher Covington while ((pl011_read(uap, REG_FR) ^ uap->vendor->inv_fr)
2364d8a4995bSChristopher Covington & uap->vendor->fr_busy)
23652f2fd089STimur Tabi cpu_relax();
236671eec483SAndre Przywara if (!uap->vendor->always_enabled)
23679f25bc51SRussell King pl011_write(old_cr, uap, REG_CR);
2368ab4382d2SGreg Kroah-Hartman
2369ef605fdbSRabin Vincent if (locked)
23705aea1229SThomas Gleixner uart_port_unlock(&uap->port);
2371ef605fdbSRabin Vincent local_irq_restore(flags);
2372ef605fdbSRabin Vincent
2373ab4382d2SGreg Kroah-Hartman clk_disable(uap->clk);
2374ab4382d2SGreg Kroah-Hartman }
2375ab4382d2SGreg Kroah-Hartman
pl011_console_get_options(struct uart_amba_port * uap,int * baud,int * parity,int * bits)237627afac93SLukas Wunner static void pl011_console_get_options(struct uart_amba_port *uap, int *baud,
2377ab4382d2SGreg Kroah-Hartman int *parity, int *bits)
2378ab4382d2SGreg Kroah-Hartman {
23799f25bc51SRussell King if (pl011_read(uap, REG_CR) & UART01x_CR_UARTEN) {
2380ab4382d2SGreg Kroah-Hartman unsigned int lcr_h, ibrd, fbrd;
2381ab4382d2SGreg Kroah-Hartman
2382e4df9a80SRussell King lcr_h = pl011_read(uap, REG_LCRH_TX);
2383ab4382d2SGreg Kroah-Hartman
2384ab4382d2SGreg Kroah-Hartman *parity = 'n';
2385ab4382d2SGreg Kroah-Hartman if (lcr_h & UART01x_LCRH_PEN) {
2386ab4382d2SGreg Kroah-Hartman if (lcr_h & UART01x_LCRH_EPS)
2387ab4382d2SGreg Kroah-Hartman *parity = 'e';
2388ab4382d2SGreg Kroah-Hartman else
2389ab4382d2SGreg Kroah-Hartman *parity = 'o';
2390ab4382d2SGreg Kroah-Hartman }
2391ab4382d2SGreg Kroah-Hartman
2392ab4382d2SGreg Kroah-Hartman if ((lcr_h & 0x60) == UART01x_LCRH_WLEN_7)
2393ab4382d2SGreg Kroah-Hartman *bits = 7;
2394ab4382d2SGreg Kroah-Hartman else
2395ab4382d2SGreg Kroah-Hartman *bits = 8;
2396ab4382d2SGreg Kroah-Hartman
23979f25bc51SRussell King ibrd = pl011_read(uap, REG_IBRD);
23989f25bc51SRussell King fbrd = pl011_read(uap, REG_FBRD);
2399ab4382d2SGreg Kroah-Hartman
2400ab4382d2SGreg Kroah-Hartman *baud = uap->port.uartclk * 4 / (64 * ibrd + fbrd);
2401ab4382d2SGreg Kroah-Hartman
2402ab4382d2SGreg Kroah-Hartman if (uap->vendor->oversampling) {
24039f25bc51SRussell King if (pl011_read(uap, REG_CR)
2404ab4382d2SGreg Kroah-Hartman & ST_UART011_CR_OVSFACT)
2405ab4382d2SGreg Kroah-Hartman *baud *= 2;
2406ab4382d2SGreg Kroah-Hartman }
2407ab4382d2SGreg Kroah-Hartman }
2408ab4382d2SGreg Kroah-Hartman }
2409ab4382d2SGreg Kroah-Hartman
pl011_console_setup(struct console * co,char * options)241027afac93SLukas Wunner static int pl011_console_setup(struct console *co, char *options)
2411ab4382d2SGreg Kroah-Hartman {
2412ab4382d2SGreg Kroah-Hartman struct uart_amba_port *uap;
2413ab4382d2SGreg Kroah-Hartman int baud = 38400;
2414ab4382d2SGreg Kroah-Hartman int bits = 8;
2415ab4382d2SGreg Kroah-Hartman int parity = 'n';
2416ab4382d2SGreg Kroah-Hartman int flow = 'n';
24174b4851c6SRussell King int ret;
2418ab4382d2SGreg Kroah-Hartman
2419ab4382d2SGreg Kroah-Hartman /*
2420ab4382d2SGreg Kroah-Hartman * Check whether an invalid uart number has been specified, and
2421ab4382d2SGreg Kroah-Hartman * if so, search for the first available port that does have
2422ab4382d2SGreg Kroah-Hartman * console support.
2423ab4382d2SGreg Kroah-Hartman */
2424ab4382d2SGreg Kroah-Hartman if (co->index >= UART_NR)
2425ab4382d2SGreg Kroah-Hartman co->index = 0;
2426ab4382d2SGreg Kroah-Hartman uap = amba_ports[co->index];
2427ab4382d2SGreg Kroah-Hartman if (!uap)
2428ab4382d2SGreg Kroah-Hartman return -ENODEV;
2429ab4382d2SGreg Kroah-Hartman
243078d80c5aSLinus Walleij /* Allow pins to be muxed in and configured */
24312b996fc5SLinus Walleij pinctrl_pm_select_default_state(uap->port.dev);
243278d80c5aSLinus Walleij
24334b4851c6SRussell King ret = clk_prepare(uap->clk);
24344b4851c6SRussell King if (ret)
24354b4851c6SRussell King return ret;
24364b4851c6SRussell King
2437574de559SJingoo Han if (dev_get_platdata(uap->port.dev)) {
2438c16d51a3SShreshtha Kumar Sahu struct amba_pl011_data *plat;
2439c16d51a3SShreshtha Kumar Sahu
2440574de559SJingoo Han plat = dev_get_platdata(uap->port.dev);
2441c16d51a3SShreshtha Kumar Sahu if (plat->init)
2442c16d51a3SShreshtha Kumar Sahu plat->init();
2443c16d51a3SShreshtha Kumar Sahu }
2444c16d51a3SShreshtha Kumar Sahu
2445ab4382d2SGreg Kroah-Hartman uap->port.uartclk = clk_get_rate(uap->clk);
2446ab4382d2SGreg Kroah-Hartman
2447cefc2d1dSAndre Przywara if (uap->vendor->fixed_options) {
2448cefc2d1dSAndre Przywara baud = uap->fixed_baud;
2449cefc2d1dSAndre Przywara } else {
2450ab4382d2SGreg Kroah-Hartman if (options)
2451cefc2d1dSAndre Przywara uart_parse_options(options,
2452cefc2d1dSAndre Przywara &baud, &parity, &bits, &flow);
2453ab4382d2SGreg Kroah-Hartman else
2454ab4382d2SGreg Kroah-Hartman pl011_console_get_options(uap, &baud, &parity, &bits);
2455cefc2d1dSAndre Przywara }
2456ab4382d2SGreg Kroah-Hartman
2457ab4382d2SGreg Kroah-Hartman return uart_set_options(&uap->port, co, baud, parity, bits, flow);
2458ab4382d2SGreg Kroah-Hartman }
2459ab4382d2SGreg Kroah-Hartman
246010879ae5SAleksey Makarov /**
246110879ae5SAleksey Makarov * pl011_console_match - non-standard console matching
246210879ae5SAleksey Makarov * @co: registering console
246310879ae5SAleksey Makarov * @name: name from console command line
246410879ae5SAleksey Makarov * @idx: index from console command line
246510879ae5SAleksey Makarov * @options: ptr to option string from console command line
246610879ae5SAleksey Makarov *
246710879ae5SAleksey Makarov * Only attempts to match console command lines of the form:
246810879ae5SAleksey Makarov * console=pl011,mmio|mmio32,<addr>[,<options>]
246910879ae5SAleksey Makarov * console=pl011,0x<addr>[,<options>]
247010879ae5SAleksey Makarov * This form is used to register an initial earlycon boot console and
247110879ae5SAleksey Makarov * replace it with the amba_console at pl011 driver init.
247210879ae5SAleksey Makarov *
247310879ae5SAleksey Makarov * Performs console setup for a match (as required by interface)
247410879ae5SAleksey Makarov * If no <options> are specified, then assume the h/w is already setup.
247510879ae5SAleksey Makarov *
247610879ae5SAleksey Makarov * Returns 0 if console matches; otherwise non-zero to use default matching
247710879ae5SAleksey Makarov */
pl011_console_match(struct console * co,char * name,int idx,char * options)247827afac93SLukas Wunner static int pl011_console_match(struct console *co, char *name, int idx,
247910879ae5SAleksey Makarov char *options)
248010879ae5SAleksey Makarov {
248110879ae5SAleksey Makarov unsigned char iotype;
248210879ae5SAleksey Makarov resource_size_t addr;
248310879ae5SAleksey Makarov int i;
248410879ae5SAleksey Makarov
248537ef38f3STimur Tabi /*
248637ef38f3STimur Tabi * Systems affected by the Qualcomm Technologies QDF2400 E44 erratum
248737ef38f3STimur Tabi * have a distinct console name, so make sure we check for that.
248837ef38f3STimur Tabi * The actual implementation of the erratum occurs in the probe
248937ef38f3STimur Tabi * function.
249037ef38f3STimur Tabi */
249137ef38f3STimur Tabi if ((strcmp(name, "qdf2400_e44") != 0) && (strcmp(name, "pl011") != 0))
249210879ae5SAleksey Makarov return -ENODEV;
249310879ae5SAleksey Makarov
249410879ae5SAleksey Makarov if (uart_parse_earlycon(options, &iotype, &addr, &options))
249510879ae5SAleksey Makarov return -ENODEV;
249610879ae5SAleksey Makarov
249710879ae5SAleksey Makarov if (iotype != UPIO_MEM && iotype != UPIO_MEM32)
249810879ae5SAleksey Makarov return -ENODEV;
249910879ae5SAleksey Makarov
250010879ae5SAleksey Makarov /* try to match the port specified on the command line */
250110879ae5SAleksey Makarov for (i = 0; i < ARRAY_SIZE(amba_ports); i++) {
250210879ae5SAleksey Makarov struct uart_port *port;
250310879ae5SAleksey Makarov
250410879ae5SAleksey Makarov if (!amba_ports[i])
250510879ae5SAleksey Makarov continue;
250610879ae5SAleksey Makarov
250710879ae5SAleksey Makarov port = &amba_ports[i]->port;
250810879ae5SAleksey Makarov
250910879ae5SAleksey Makarov if (port->mapbase != addr)
251010879ae5SAleksey Makarov continue;
251110879ae5SAleksey Makarov
251210879ae5SAleksey Makarov co->index = i;
251310879ae5SAleksey Makarov port->cons = co;
251410879ae5SAleksey Makarov return pl011_console_setup(co, options);
251510879ae5SAleksey Makarov }
251610879ae5SAleksey Makarov
251710879ae5SAleksey Makarov return -ENODEV;
251810879ae5SAleksey Makarov }
251910879ae5SAleksey Makarov
2520ab4382d2SGreg Kroah-Hartman static struct uart_driver amba_reg;
2521ab4382d2SGreg Kroah-Hartman static struct console amba_console = {
2522ab4382d2SGreg Kroah-Hartman .name = "ttyAMA",
2523ab4382d2SGreg Kroah-Hartman .write = pl011_console_write,
2524ab4382d2SGreg Kroah-Hartman .device = uart_console_device,
2525ab4382d2SGreg Kroah-Hartman .setup = pl011_console_setup,
252610879ae5SAleksey Makarov .match = pl011_console_match,
25277951ffc9SAlexander Sverdlin .flags = CON_PRINTBUFFER | CON_ANYTIME,
2528ab4382d2SGreg Kroah-Hartman .index = -1,
2529ab4382d2SGreg Kroah-Hartman .data = &amba_reg,
2530ab4382d2SGreg Kroah-Hartman };
2531ab4382d2SGreg Kroah-Hartman
2532ab4382d2SGreg Kroah-Hartman #define AMBA_CONSOLE (&amba_console)
25330d3c673eSRob Herring
qdf2400_e44_putc(struct uart_port * port,unsigned char c)25343f8bab17SJiri Slaby static void qdf2400_e44_putc(struct uart_port *port, unsigned char c)
2535d8a4995bSChristopher Covington {
2536d8a4995bSChristopher Covington while (readl(port->membase + UART01x_FR) & UART01x_FR_TXFF)
2537d8a4995bSChristopher Covington cpu_relax();
2538d8a4995bSChristopher Covington writel(c, port->membase + UART01x_DR);
2539d8a4995bSChristopher Covington while (!(readl(port->membase + UART01x_FR) & UART011_FR_TXFE))
2540d8a4995bSChristopher Covington cpu_relax();
2541d8a4995bSChristopher Covington }
2542d8a4995bSChristopher Covington
qdf2400_e44_early_write(struct console * con,const char * s,unsigned n)2543d8a4995bSChristopher Covington static void qdf2400_e44_early_write(struct console *con, const char *s, unsigned n)
2544d8a4995bSChristopher Covington {
2545d8a4995bSChristopher Covington struct earlycon_device *dev = con->data;
2546d8a4995bSChristopher Covington
2547d8a4995bSChristopher Covington uart_console_write(&dev->port, s, n, qdf2400_e44_putc);
2548d8a4995bSChristopher Covington }
2549d8a4995bSChristopher Covington
pl011_putc(struct uart_port * port,unsigned char c)25503f8bab17SJiri Slaby static void pl011_putc(struct uart_port *port, unsigned char c)
25510d3c673eSRob Herring {
2552cdf091caSRussell King while (readl(port->membase + UART01x_FR) & UART01x_FR_TXFF)
25532f2fd089STimur Tabi cpu_relax();
25543b78fae7STimur Tabi if (port->iotype == UPIO_MEM32)
25553b78fae7STimur Tabi writel(c, port->membase + UART01x_DR);
25563b78fae7STimur Tabi else
2557cdf091caSRussell King writeb(c, port->membase + UART01x_DR);
2558e06690bfSShawn Guo while (readl(port->membase + UART01x_FR) & UART01x_FR_BUSY)
25592f2fd089STimur Tabi cpu_relax();
25600d3c673eSRob Herring }
25610d3c673eSRob Herring
pl011_early_write(struct console * con,const char * s,unsigned n)25620d3c673eSRob Herring static void pl011_early_write(struct console *con, const char *s, unsigned n)
25630d3c673eSRob Herring {
25640d3c673eSRob Herring struct earlycon_device *dev = con->data;
25650d3c673eSRob Herring
25660d3c673eSRob Herring uart_console_write(&dev->port, s, n, pl011_putc);
25670d3c673eSRob Herring }
25680d3c673eSRob Herring
2569195867ffSSumit Garg #ifdef CONFIG_CONSOLE_POLL
pl011_getc(struct uart_port * port)2570195867ffSSumit Garg static int pl011_getc(struct uart_port *port)
2571195867ffSSumit Garg {
2572195867ffSSumit Garg if (readl(port->membase + UART01x_FR) & UART01x_FR_RXFE)
2573195867ffSSumit Garg return NO_POLL_CHAR;
2574195867ffSSumit Garg
2575195867ffSSumit Garg if (port->iotype == UPIO_MEM32)
2576195867ffSSumit Garg return readl(port->membase + UART01x_DR);
2577195867ffSSumit Garg else
2578195867ffSSumit Garg return readb(port->membase + UART01x_DR);
2579195867ffSSumit Garg }
2580195867ffSSumit Garg
pl011_early_read(struct console * con,char * s,unsigned int n)2581195867ffSSumit Garg static int pl011_early_read(struct console *con, char *s, unsigned int n)
2582195867ffSSumit Garg {
2583195867ffSSumit Garg struct earlycon_device *dev = con->data;
2584195867ffSSumit Garg int ch, num_read = 0;
2585195867ffSSumit Garg
2586195867ffSSumit Garg while (num_read < n) {
2587195867ffSSumit Garg ch = pl011_getc(&dev->port);
2588195867ffSSumit Garg if (ch == NO_POLL_CHAR)
2589195867ffSSumit Garg break;
2590195867ffSSumit Garg
2591195867ffSSumit Garg s[num_read++] = ch;
2592195867ffSSumit Garg }
2593195867ffSSumit Garg
2594195867ffSSumit Garg return num_read;
2595195867ffSSumit Garg }
2596195867ffSSumit Garg #else
2597195867ffSSumit Garg #define pl011_early_read NULL
2598195867ffSSumit Garg #endif
2599195867ffSSumit Garg
2600e53e597fSTimur Tabi /*
2601e53e597fSTimur Tabi * On non-ACPI systems, earlycon is enabled by specifying
2602e53e597fSTimur Tabi * "earlycon=pl011,<address>" on the kernel command line.
2603e53e597fSTimur Tabi *
2604e53e597fSTimur Tabi * On ACPI ARM64 systems, an "early" console is enabled via the SPCR table,
2605e53e597fSTimur Tabi * by specifying only "earlycon" on the command line. Because it requires
2606e53e597fSTimur Tabi * SPCR, the console starts after ACPI is parsed, which is later than a
2607e53e597fSTimur Tabi * traditional early console.
2608e53e597fSTimur Tabi *
2609e53e597fSTimur Tabi * To get the traditional early console that starts before ACPI is parsed,
2610e53e597fSTimur Tabi * specify the full "earlycon=pl011,<address>" option.
2611e53e597fSTimur Tabi */
pl011_early_console_setup(struct earlycon_device * device,const char * opt)26120d3c673eSRob Herring static int __init pl011_early_console_setup(struct earlycon_device *device,
26130d3c673eSRob Herring const char *opt)
26140d3c673eSRob Herring {
26150d3c673eSRob Herring if (!device->port.membase)
26160d3c673eSRob Herring return -ENODEV;
26170d3c673eSRob Herring
2618e53e597fSTimur Tabi device->con->write = pl011_early_write;
2619195867ffSSumit Garg device->con->read = pl011_early_read;
2620e53e597fSTimur Tabi
26210d3c673eSRob Herring return 0;
26220d3c673eSRob Herring }
262345e0f0f5SRob Herring OF_EARLYCON_DECLARE(pl011, "arm,pl011", pl011_early_console_setup);
2624fcb32159SKefeng Wang OF_EARLYCON_DECLARE(pl011, "arm,sbsa-uart", pl011_early_console_setup);
26255a0722b8STimur Tabi
26265a0722b8STimur Tabi /*
26275a0722b8STimur Tabi * On Qualcomm Datacenter Technologies QDF2400 SOCs affected by
26285a0722b8STimur Tabi * Erratum 44, traditional earlycon can be enabled by specifying
26295a0722b8STimur Tabi * "earlycon=qdf2400_e44,<address>". Any options are ignored.
26305a0722b8STimur Tabi *
26315a0722b8STimur Tabi * Alternatively, you can just specify "earlycon", and the early console
26325a0722b8STimur Tabi * will be enabled with the information from the SPCR table. In this
26335a0722b8STimur Tabi * case, the SPCR code will detect the need for the E44 work-around,
26345a0722b8STimur Tabi * and set the console name to "qdf2400_e44".
26355a0722b8STimur Tabi */
26365a0722b8STimur Tabi static int __init
qdf2400_e44_early_console_setup(struct earlycon_device * device,const char * opt)26375a0722b8STimur Tabi qdf2400_e44_early_console_setup(struct earlycon_device *device,
26385a0722b8STimur Tabi const char *opt)
26395a0722b8STimur Tabi {
26405a0722b8STimur Tabi if (!device->port.membase)
26415a0722b8STimur Tabi return -ENODEV;
26425a0722b8STimur Tabi
26435a0722b8STimur Tabi device->con->write = qdf2400_e44_early_write;
26445a0722b8STimur Tabi return 0;
26455a0722b8STimur Tabi }
26465a0722b8STimur Tabi EARLYCON_DECLARE(qdf2400_e44, qdf2400_e44_early_console_setup);
26470d3c673eSRob Herring
2648ab4382d2SGreg Kroah-Hartman #else
2649ab4382d2SGreg Kroah-Hartman #define AMBA_CONSOLE NULL
2650ab4382d2SGreg Kroah-Hartman #endif
2651ab4382d2SGreg Kroah-Hartman
2652ab4382d2SGreg Kroah-Hartman static struct uart_driver amba_reg = {
2653ab4382d2SGreg Kroah-Hartman .owner = THIS_MODULE,
2654ab4382d2SGreg Kroah-Hartman .driver_name = "ttyAMA",
2655ab4382d2SGreg Kroah-Hartman .dev_name = "ttyAMA",
2656ab4382d2SGreg Kroah-Hartman .major = SERIAL_AMBA_MAJOR,
2657ab4382d2SGreg Kroah-Hartman .minor = SERIAL_AMBA_MINOR,
2658ab4382d2SGreg Kroah-Hartman .nr = UART_NR,
2659ab4382d2SGreg Kroah-Hartman .cons = AMBA_CONSOLE,
2660ab4382d2SGreg Kroah-Hartman };
2661ab4382d2SGreg Kroah-Hartman
pl011_probe_dt_alias(int index,struct device * dev)266232614aadSMatthew Leach static int pl011_probe_dt_alias(int index, struct device *dev)
266332614aadSMatthew Leach {
266432614aadSMatthew Leach struct device_node *np;
266532614aadSMatthew Leach static bool seen_dev_with_alias = false;
266632614aadSMatthew Leach static bool seen_dev_without_alias = false;
266732614aadSMatthew Leach int ret = index;
266832614aadSMatthew Leach
266932614aadSMatthew Leach if (!IS_ENABLED(CONFIG_OF))
267032614aadSMatthew Leach return ret;
267132614aadSMatthew Leach
267232614aadSMatthew Leach np = dev->of_node;
267332614aadSMatthew Leach if (!np)
267432614aadSMatthew Leach return ret;
267532614aadSMatthew Leach
267632614aadSMatthew Leach ret = of_alias_get_id(np, "serial");
2677287980e4SArnd Bergmann if (ret < 0) {
267832614aadSMatthew Leach seen_dev_without_alias = true;
267932614aadSMatthew Leach ret = index;
268032614aadSMatthew Leach } else {
268132614aadSMatthew Leach seen_dev_with_alias = true;
268232614aadSMatthew Leach if (ret >= ARRAY_SIZE(amba_ports) || amba_ports[ret] != NULL) {
268332614aadSMatthew Leach dev_warn(dev, "requested serial port %d not available.\n", ret);
268432614aadSMatthew Leach ret = index;
268532614aadSMatthew Leach }
268632614aadSMatthew Leach }
268732614aadSMatthew Leach
268832614aadSMatthew Leach if (seen_dev_with_alias && seen_dev_without_alias)
268932614aadSMatthew Leach dev_warn(dev, "aliased and non-aliased serial devices found in device tree. Serial port enumeration may be unpredictable.\n");
269032614aadSMatthew Leach
269132614aadSMatthew Leach return ret;
269232614aadSMatthew Leach }
269332614aadSMatthew Leach
269449bb3c86SAndre Przywara /* unregisters the driver also if no more ports are left */
pl011_unregister_port(struct uart_amba_port * uap)269549bb3c86SAndre Przywara static void pl011_unregister_port(struct uart_amba_port *uap)
269649bb3c86SAndre Przywara {
269749bb3c86SAndre Przywara int i;
269849bb3c86SAndre Przywara bool busy = false;
269949bb3c86SAndre Przywara
270049bb3c86SAndre Przywara for (i = 0; i < ARRAY_SIZE(amba_ports); i++) {
270149bb3c86SAndre Przywara if (amba_ports[i] == uap)
270249bb3c86SAndre Przywara amba_ports[i] = NULL;
270349bb3c86SAndre Przywara else if (amba_ports[i])
270449bb3c86SAndre Przywara busy = true;
270549bb3c86SAndre Przywara }
270649bb3c86SAndre Przywara pl011_dma_remove(uap);
270749bb3c86SAndre Przywara if (!busy)
270849bb3c86SAndre Przywara uart_unregister_driver(&amba_reg);
270949bb3c86SAndre Przywara }
271049bb3c86SAndre Przywara
pl011_find_free_port(void)27113873e2d7SAndre Przywara static int pl011_find_free_port(void)
2712ab4382d2SGreg Kroah-Hartman {
27133873e2d7SAndre Przywara int i;
2714ab4382d2SGreg Kroah-Hartman
2715ab4382d2SGreg Kroah-Hartman for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
2716ab4382d2SGreg Kroah-Hartman if (amba_ports[i] == NULL)
27173873e2d7SAndre Przywara return i;
2718ab4382d2SGreg Kroah-Hartman
27197f6d942aSTushar Behera return -EBUSY;
27203873e2d7SAndre Przywara }
2721ab4382d2SGreg Kroah-Hartman
pl011_get_rs485_mode(struct uart_amba_port * uap)27228d479237SLino Sanfilippo static int pl011_get_rs485_mode(struct uart_amba_port *uap)
27238d479237SLino Sanfilippo {
27248d479237SLino Sanfilippo struct uart_port *port = &uap->port;
27258d479237SLino Sanfilippo int ret;
27268d479237SLino Sanfilippo
27278d479237SLino Sanfilippo ret = uart_get_rs485_mode(port);
27288d479237SLino Sanfilippo if (ret)
27298d479237SLino Sanfilippo return ret;
27308d479237SLino Sanfilippo
27318d479237SLino Sanfilippo return 0;
27328d479237SLino Sanfilippo }
27338d479237SLino Sanfilippo
pl011_setup_port(struct device * dev,struct uart_amba_port * uap,struct resource * mmiobase,int index)27343873e2d7SAndre Przywara static int pl011_setup_port(struct device *dev, struct uart_amba_port *uap,
27353873e2d7SAndre Przywara struct resource *mmiobase, int index)
27363873e2d7SAndre Przywara {
27373873e2d7SAndre Przywara void __iomem *base;
27388d479237SLino Sanfilippo int ret;
2739ab4382d2SGreg Kroah-Hartman
27403873e2d7SAndre Przywara base = devm_ioremap_resource(dev, mmiobase);
274197a60eacSKrzysztof Kozlowski if (IS_ERR(base))
274297a60eacSKrzysztof Kozlowski return PTR_ERR(base);
2743ab4382d2SGreg Kroah-Hartman
27443873e2d7SAndre Przywara index = pl011_probe_dt_alias(index, dev);
2745ab4382d2SGreg Kroah-Hartman
27463873e2d7SAndre Przywara uap->port.dev = dev;
27473873e2d7SAndre Przywara uap->port.mapbase = mmiobase->start;
2748ab4382d2SGreg Kroah-Hartman uap->port.membase = base;
2749ab4382d2SGreg Kroah-Hartman uap->port.fifosize = uap->fifosize;
27505f99fca9SDmitry Safonov uap->port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_AMBA_PL011_CONSOLE);
2751ab4382d2SGreg Kroah-Hartman uap->port.flags = UPF_BOOT_AUTOCONF;
27523873e2d7SAndre Przywara uap->port.line = index;
27533873e2d7SAndre Przywara
27548d479237SLino Sanfilippo ret = pl011_get_rs485_mode(uap);
27558d479237SLino Sanfilippo if (ret)
27568d479237SLino Sanfilippo return ret;
27578d479237SLino Sanfilippo
27583873e2d7SAndre Przywara amba_ports[index] = uap;
27593873e2d7SAndre Przywara
27603873e2d7SAndre Przywara return 0;
27613873e2d7SAndre Przywara }
27623873e2d7SAndre Przywara
pl011_register_port(struct uart_amba_port * uap)27633873e2d7SAndre Przywara static int pl011_register_port(struct uart_amba_port *uap)
27643873e2d7SAndre Przywara {
276589efbe70SLukas Wunner int ret, i;
2766ab4382d2SGreg Kroah-Hartman
2767c3d8b76fSLinus Walleij /* Ensure interrupts from this UART are masked and cleared */
27689f25bc51SRussell King pl011_write(0, uap, REG_IMSC);
27699f25bc51SRussell King pl011_write(0xffff, uap, REG_ICR);
2770c3d8b76fSLinus Walleij
2771ef2889f7STushar Behera if (!amba_reg.state) {
2772ef2889f7STushar Behera ret = uart_register_driver(&amba_reg);
2773ef2889f7STushar Behera if (ret < 0) {
27743873e2d7SAndre Przywara dev_err(uap->port.dev,
27751c9be310SJorge Ramirez-Ortiz "Failed to register AMBA-PL011 driver\n");
277689efbe70SLukas Wunner for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
277789efbe70SLukas Wunner if (amba_ports[i] == uap)
277889efbe70SLukas Wunner amba_ports[i] = NULL;
2779ef2889f7STushar Behera return ret;
2780ef2889f7STushar Behera }
2781ef2889f7STushar Behera }
2782ef2889f7STushar Behera
2783ab4382d2SGreg Kroah-Hartman ret = uart_add_one_port(&amba_reg, &uap->port);
278449bb3c86SAndre Przywara if (ret)
278549bb3c86SAndre Przywara pl011_unregister_port(uap);
27867f6d942aSTushar Behera
2787ab4382d2SGreg Kroah-Hartman return ret;
2788ab4382d2SGreg Kroah-Hartman }
2789ab4382d2SGreg Kroah-Hartman
2790ebe2cf73SIlpo Järvinen static const struct serial_rs485 pl011_rs485_supported = {
2791ebe2cf73SIlpo Järvinen .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND |
2792ebe2cf73SIlpo Järvinen SER_RS485_RX_DURING_TX,
2793ebe2cf73SIlpo Järvinen .delay_rts_before_send = 1,
2794ebe2cf73SIlpo Järvinen .delay_rts_after_send = 1,
2795ebe2cf73SIlpo Järvinen };
2796ebe2cf73SIlpo Järvinen
pl011_probe(struct amba_device * dev,const struct amba_id * id)27973873e2d7SAndre Przywara static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
27983873e2d7SAndre Przywara {
27993873e2d7SAndre Przywara struct uart_amba_port *uap;
28003873e2d7SAndre Przywara struct vendor_data *vendor = id->data;
28013873e2d7SAndre Przywara int portnr, ret;
280281db9e8eSShubhrajyoti Datta u32 val;
28033873e2d7SAndre Przywara
28043873e2d7SAndre Przywara portnr = pl011_find_free_port();
28053873e2d7SAndre Przywara if (portnr < 0)
28063873e2d7SAndre Przywara return portnr;
28073873e2d7SAndre Przywara
28083873e2d7SAndre Przywara uap = devm_kzalloc(&dev->dev, sizeof(struct uart_amba_port),
28093873e2d7SAndre Przywara GFP_KERNEL);
28103873e2d7SAndre Przywara if (!uap)
28113873e2d7SAndre Przywara return -ENOMEM;
28123873e2d7SAndre Przywara
28133873e2d7SAndre Przywara uap->clk = devm_clk_get(&dev->dev, NULL);
28143873e2d7SAndre Przywara if (IS_ERR(uap->clk))
28153873e2d7SAndre Przywara return PTR_ERR(uap->clk);
28163873e2d7SAndre Przywara
2817439403bdSRussell King uap->reg_offset = vendor->reg_offset;
28183873e2d7SAndre Przywara uap->vendor = vendor;
28193873e2d7SAndre Przywara uap->fifosize = vendor->get_fifosize(dev);
28203b78fae7STimur Tabi uap->port.iotype = vendor->access_32b ? UPIO_MEM32 : UPIO_MEM;
28213873e2d7SAndre Przywara uap->port.irq = dev->irq[0];
28223873e2d7SAndre Przywara uap->port.ops = &amba_pl011_pops;
28238d479237SLino Sanfilippo uap->port.rs485_config = pl011_rs485_config;
28240139da50SIlpo Järvinen uap->port.rs485_supported = pl011_rs485_supported;
28253873e2d7SAndre Przywara snprintf(uap->type, sizeof(uap->type), "PL011 rev%u", amba_rev(dev));
28263873e2d7SAndre Przywara
282781db9e8eSShubhrajyoti Datta if (device_property_read_u32(&dev->dev, "reg-io-width", &val) == 0) {
282881db9e8eSShubhrajyoti Datta switch (val) {
282981db9e8eSShubhrajyoti Datta case 1:
283081db9e8eSShubhrajyoti Datta uap->port.iotype = UPIO_MEM;
283181db9e8eSShubhrajyoti Datta break;
283281db9e8eSShubhrajyoti Datta case 4:
283381db9e8eSShubhrajyoti Datta uap->port.iotype = UPIO_MEM32;
283481db9e8eSShubhrajyoti Datta break;
283581db9e8eSShubhrajyoti Datta default:
283681db9e8eSShubhrajyoti Datta dev_warn(&dev->dev, "unsupported reg-io-width (%d)\n",
283781db9e8eSShubhrajyoti Datta val);
283881db9e8eSShubhrajyoti Datta return -EINVAL;
283981db9e8eSShubhrajyoti Datta }
284081db9e8eSShubhrajyoti Datta }
284181db9e8eSShubhrajyoti Datta
28423873e2d7SAndre Przywara ret = pl011_setup_port(&dev->dev, uap, &dev->res, portnr);
28433873e2d7SAndre Przywara if (ret)
28443873e2d7SAndre Przywara return ret;
28453873e2d7SAndre Przywara
28463873e2d7SAndre Przywara amba_set_drvdata(dev, uap);
28473873e2d7SAndre Przywara
28483873e2d7SAndre Przywara return pl011_register_port(uap);
28493873e2d7SAndre Przywara }
28503873e2d7SAndre Przywara
pl011_remove(struct amba_device * dev)28513fd269e7SUwe Kleine-König static void pl011_remove(struct amba_device *dev)
2852ab4382d2SGreg Kroah-Hartman {
2853ab4382d2SGreg Kroah-Hartman struct uart_amba_port *uap = amba_get_drvdata(dev);
2854ab4382d2SGreg Kroah-Hartman
2855ab4382d2SGreg Kroah-Hartman uart_remove_one_port(&amba_reg, &uap->port);
285649bb3c86SAndre Przywara pl011_unregister_port(uap);
2857ab4382d2SGreg Kroah-Hartman }
2858ab4382d2SGreg Kroah-Hartman
2859d0ce850dSUlf Hansson #ifdef CONFIG_PM_SLEEP
pl011_suspend(struct device * dev)2860d0ce850dSUlf Hansson static int pl011_suspend(struct device *dev)
2861ab4382d2SGreg Kroah-Hartman {
2862d0ce850dSUlf Hansson struct uart_amba_port *uap = dev_get_drvdata(dev);
2863ab4382d2SGreg Kroah-Hartman
2864ab4382d2SGreg Kroah-Hartman if (!uap)
2865ab4382d2SGreg Kroah-Hartman return -EINVAL;
2866ab4382d2SGreg Kroah-Hartman
2867ab4382d2SGreg Kroah-Hartman return uart_suspend_port(&amba_reg, &uap->port);
2868ab4382d2SGreg Kroah-Hartman }
2869ab4382d2SGreg Kroah-Hartman
pl011_resume(struct device * dev)2870d0ce850dSUlf Hansson static int pl011_resume(struct device *dev)
2871ab4382d2SGreg Kroah-Hartman {
2872d0ce850dSUlf Hansson struct uart_amba_port *uap = dev_get_drvdata(dev);
2873ab4382d2SGreg Kroah-Hartman
2874ab4382d2SGreg Kroah-Hartman if (!uap)
2875ab4382d2SGreg Kroah-Hartman return -EINVAL;
2876ab4382d2SGreg Kroah-Hartman
2877ab4382d2SGreg Kroah-Hartman return uart_resume_port(&amba_reg, &uap->port);
2878ab4382d2SGreg Kroah-Hartman }
2879ab4382d2SGreg Kroah-Hartman #endif
2880ab4382d2SGreg Kroah-Hartman
2881d0ce850dSUlf Hansson static SIMPLE_DEV_PM_OPS(pl011_dev_pm_ops, pl011_suspend, pl011_resume);
2882d0ce850dSUlf Hansson
sbsa_uart_probe(struct platform_device * pdev)28830dd1e247SAndre Przywara static int sbsa_uart_probe(struct platform_device *pdev)
28840dd1e247SAndre Przywara {
28850dd1e247SAndre Przywara struct uart_amba_port *uap;
28860dd1e247SAndre Przywara struct resource *r;
28870dd1e247SAndre Przywara int portnr, ret;
28880dd1e247SAndre Przywara int baudrate;
28890dd1e247SAndre Przywara
28900dd1e247SAndre Przywara /*
28910dd1e247SAndre Przywara * Check the mandatory baud rate parameter in the DT node early
28920dd1e247SAndre Przywara * so that we can easily exit with the error.
28930dd1e247SAndre Przywara */
28940dd1e247SAndre Przywara if (pdev->dev.of_node) {
28950dd1e247SAndre Przywara struct device_node *np = pdev->dev.of_node;
28960dd1e247SAndre Przywara
28970dd1e247SAndre Przywara ret = of_property_read_u32(np, "current-speed", &baudrate);
28980dd1e247SAndre Przywara if (ret)
28990dd1e247SAndre Przywara return ret;
29000dd1e247SAndre Przywara } else {
29010dd1e247SAndre Przywara baudrate = 115200;
29020dd1e247SAndre Przywara }
29030dd1e247SAndre Przywara
29040dd1e247SAndre Przywara portnr = pl011_find_free_port();
29050dd1e247SAndre Przywara if (portnr < 0)
29060dd1e247SAndre Przywara return portnr;
29070dd1e247SAndre Przywara
29080dd1e247SAndre Przywara uap = devm_kzalloc(&pdev->dev, sizeof(struct uart_amba_port),
29090dd1e247SAndre Przywara GFP_KERNEL);
29100dd1e247SAndre Przywara if (!uap)
29110dd1e247SAndre Przywara return -ENOMEM;
29120dd1e247SAndre Przywara
2913394a9e2cSJiri Slaby ret = platform_get_irq(pdev, 0);
29141df21786SStephen Boyd if (ret < 0)
2915394a9e2cSJiri Slaby return ret;
2916394a9e2cSJiri Slaby uap->port.irq = ret;
2917394a9e2cSJiri Slaby
291837ef38f3STimur Tabi #ifdef CONFIG_ACPI_SPCR_TABLE
291937ef38f3STimur Tabi if (qdf2400_e44_present) {
292037ef38f3STimur Tabi dev_info(&pdev->dev, "working around QDF2400 SoC erratum 44\n");
292137ef38f3STimur Tabi uap->vendor = &vendor_qdt_qdf2400_e44;
292237ef38f3STimur Tabi } else
292337ef38f3STimur Tabi #endif
292437ef38f3STimur Tabi uap->vendor = &vendor_sbsa;
292537ef38f3STimur Tabi
292637ef38f3STimur Tabi uap->reg_offset = uap->vendor->reg_offset;
29270dd1e247SAndre Przywara uap->fifosize = 32;
292837ef38f3STimur Tabi uap->port.iotype = uap->vendor->access_32b ? UPIO_MEM32 : UPIO_MEM;
29290dd1e247SAndre Przywara uap->port.ops = &sbsa_uart_pops;
29300dd1e247SAndre Przywara uap->fixed_baud = baudrate;
29310dd1e247SAndre Przywara
29320dd1e247SAndre Przywara snprintf(uap->type, sizeof(uap->type), "SBSA");
29330dd1e247SAndre Przywara
29340dd1e247SAndre Przywara r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
29350dd1e247SAndre Przywara
29360dd1e247SAndre Przywara ret = pl011_setup_port(&pdev->dev, uap, r, portnr);
29370dd1e247SAndre Przywara if (ret)
29380dd1e247SAndre Przywara return ret;
29390dd1e247SAndre Przywara
29400dd1e247SAndre Przywara platform_set_drvdata(pdev, uap);
29410dd1e247SAndre Przywara
29420dd1e247SAndre Przywara return pl011_register_port(uap);
29430dd1e247SAndre Przywara }
29440dd1e247SAndre Przywara
sbsa_uart_remove(struct platform_device * pdev)29450dd1e247SAndre Przywara static int sbsa_uart_remove(struct platform_device *pdev)
29460dd1e247SAndre Przywara {
29470dd1e247SAndre Przywara struct uart_amba_port *uap = platform_get_drvdata(pdev);
29480dd1e247SAndre Przywara
29490dd1e247SAndre Przywara uart_remove_one_port(&amba_reg, &uap->port);
29500dd1e247SAndre Przywara pl011_unregister_port(uap);
29510dd1e247SAndre Przywara return 0;
29520dd1e247SAndre Przywara }
29530dd1e247SAndre Przywara
29540dd1e247SAndre Przywara static const struct of_device_id sbsa_uart_of_match[] = {
29550dd1e247SAndre Przywara { .compatible = "arm,sbsa-uart", },
29560dd1e247SAndre Przywara {},
29570dd1e247SAndre Przywara };
29580dd1e247SAndre Przywara MODULE_DEVICE_TABLE(of, sbsa_uart_of_match);
29590dd1e247SAndre Przywara
29607789c1f1SLee Jones static const struct acpi_device_id __maybe_unused sbsa_uart_acpi_match[] = {
29613db9ab0bSGraeme Gregory { "ARMH0011", 0 },
2962ac442a07SPierre Gondois { "ARMHB000", 0 },
29633db9ab0bSGraeme Gregory {},
29643db9ab0bSGraeme Gregory };
29653db9ab0bSGraeme Gregory MODULE_DEVICE_TABLE(acpi, sbsa_uart_acpi_match);
29663db9ab0bSGraeme Gregory
29670dd1e247SAndre Przywara static struct platform_driver arm_sbsa_uart_platform_driver = {
29680dd1e247SAndre Przywara .probe = sbsa_uart_probe,
29690dd1e247SAndre Przywara .remove = sbsa_uart_remove,
29700dd1e247SAndre Przywara .driver = {
29710dd1e247SAndre Przywara .name = "sbsa-uart",
29722301ec36SShubhrajyoti Datta .pm = &pl011_dev_pm_ops,
29730dd1e247SAndre Przywara .of_match_table = of_match_ptr(sbsa_uart_of_match),
29743db9ab0bSGraeme Gregory .acpi_match_table = ACPI_PTR(sbsa_uart_acpi_match),
297564609794SAnders Roxell .suppress_bind_attrs = IS_BUILTIN(CONFIG_SERIAL_AMBA_PL011),
29760dd1e247SAndre Przywara },
29770dd1e247SAndre Przywara };
29780dd1e247SAndre Przywara
2979a704ddc2SArvind Yadav static const struct amba_id pl011_ids[] = {
2980ab4382d2SGreg Kroah-Hartman {
2981ab4382d2SGreg Kroah-Hartman .id = 0x00041011,
2982ab4382d2SGreg Kroah-Hartman .mask = 0x000fffff,
2983ab4382d2SGreg Kroah-Hartman .data = &vendor_arm,
2984ab4382d2SGreg Kroah-Hartman },
2985ab4382d2SGreg Kroah-Hartman {
2986ab4382d2SGreg Kroah-Hartman .id = 0x00380802,
2987ab4382d2SGreg Kroah-Hartman .mask = 0x00ffffff,
2988ab4382d2SGreg Kroah-Hartman .data = &vendor_st,
2989ab4382d2SGreg Kroah-Hartman },
2990ab4382d2SGreg Kroah-Hartman { 0, 0 },
2991ab4382d2SGreg Kroah-Hartman };
2992ab4382d2SGreg Kroah-Hartman
299360f7a33bSDave Martin MODULE_DEVICE_TABLE(amba, pl011_ids);
299460f7a33bSDave Martin
2995ab4382d2SGreg Kroah-Hartman static struct amba_driver pl011_driver = {
2996ab4382d2SGreg Kroah-Hartman .drv = {
2997ab4382d2SGreg Kroah-Hartman .name = "uart-pl011",
2998d0ce850dSUlf Hansson .pm = &pl011_dev_pm_ops,
299964609794SAnders Roxell .suppress_bind_attrs = IS_BUILTIN(CONFIG_SERIAL_AMBA_PL011),
3000ab4382d2SGreg Kroah-Hartman },
3001ab4382d2SGreg Kroah-Hartman .id_table = pl011_ids,
3002ab4382d2SGreg Kroah-Hartman .probe = pl011_probe,
3003ab4382d2SGreg Kroah-Hartman .remove = pl011_remove,
3004ab4382d2SGreg Kroah-Hartman };
3005ab4382d2SGreg Kroah-Hartman
pl011_init(void)3006ab4382d2SGreg Kroah-Hartman static int __init pl011_init(void)
3007ab4382d2SGreg Kroah-Hartman {
3008ab4382d2SGreg Kroah-Hartman printk(KERN_INFO "Serial: AMBA PL011 UART driver\n");
3009ab4382d2SGreg Kroah-Hartman
30100dd1e247SAndre Przywara if (platform_driver_register(&arm_sbsa_uart_platform_driver))
30110dd1e247SAndre Przywara pr_warn("could not register SBSA UART platform driver\n");
3012062a68a5SGreg Kroah-Hartman return amba_driver_register(&pl011_driver);
3013ab4382d2SGreg Kroah-Hartman }
3014ab4382d2SGreg Kroah-Hartman
pl011_exit(void)3015ab4382d2SGreg Kroah-Hartman static void __exit pl011_exit(void)
3016ab4382d2SGreg Kroah-Hartman {
30170dd1e247SAndre Przywara platform_driver_unregister(&arm_sbsa_uart_platform_driver);
3018ab4382d2SGreg Kroah-Hartman amba_driver_unregister(&pl011_driver);
3019ab4382d2SGreg Kroah-Hartman }
3020ab4382d2SGreg Kroah-Hartman
3021ab4382d2SGreg Kroah-Hartman /*
3022ab4382d2SGreg Kroah-Hartman * While this can be a module, if builtin it's most likely the console
3023ab4382d2SGreg Kroah-Hartman * So let's leave module_exit but move module_init to an earlier place
3024ab4382d2SGreg Kroah-Hartman */
3025ab4382d2SGreg Kroah-Hartman arch_initcall(pl011_init);
3026ab4382d2SGreg Kroah-Hartman module_exit(pl011_exit);
3027ab4382d2SGreg Kroah-Hartman
3028ab4382d2SGreg Kroah-Hartman MODULE_AUTHOR("ARM Ltd/Deep Blue Solutions Ltd");
3029ab4382d2SGreg Kroah-Hartman MODULE_DESCRIPTION("ARM AMBA serial port driver");
3030ab4382d2SGreg Kroah-Hartman MODULE_LICENSE("GPL");
3031