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)
54826bd77aSThéo Lebrun #define UART_DUMMY_DR_RX BIT(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
22158ac1b37SArnd Bergmann struct pl011_dmabuf {
22258ac1b37SArnd Bergmann dma_addr_t dma;
22358ac1b37SArnd 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;
23158ac1b37SArnd Bergmann struct pl011_dmabuf dbuf_a;
23258ac1b37SArnd 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;
24558ac1b37SArnd Bergmann dma_addr_t dma;
24658ac1b37SArnd 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 im; /* interrupt mask */
260ab4382d2SGreg Kroah-Hartman unsigned int old_status;
261ab4382d2SGreg Kroah-Hartman unsigned int fifosize; /* vendor-specific */
262cefc2d1dSAndre Przywara unsigned int fixed_baud; /* vendor-set fixed baud rate */
263ab4382d2SGreg Kroah-Hartman char type[12];
2648d479237SLino Sanfilippo bool rs485_tx_started;
2658d479237SLino Sanfilippo unsigned int rs485_tx_drain_interval; /* usecs */
266ab4382d2SGreg Kroah-Hartman #ifdef CONFIG_DMA_ENGINE
267ab4382d2SGreg Kroah-Hartman /* DMA stuff */
268*255abd49SLino Sanfilippo unsigned int dmacr; /* dma control reg */
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;
33328a7ec8cSThéo Lebrun } else if (ch & UART011_DR_PE) {
33429772c4eSLinus Walleij uap->port.icount.parity++;
33528a7ec8cSThéo Lebrun } else if (ch & UART011_DR_FE) {
33629772c4eSLinus Walleij uap->port.icount.frame++;
33728a7ec8cSThéo Lebrun }
33829772c4eSLinus Walleij if (ch & UART011_DR_OE)
33929772c4eSLinus Walleij uap->port.icount.overrun++;
34029772c4eSLinus Walleij
34129772c4eSLinus Walleij ch &= uap->port.read_status_mask;
34229772c4eSLinus Walleij
34329772c4eSLinus Walleij if (ch & UART011_DR_BE)
34429772c4eSLinus Walleij flag = TTY_BREAK;
34529772c4eSLinus Walleij else if (ch & UART011_DR_PE)
34629772c4eSLinus Walleij flag = TTY_PARITY;
34729772c4eSLinus Walleij else if (ch & UART011_DR_FE)
34829772c4eSLinus Walleij flag = TTY_FRAME;
34929772c4eSLinus Walleij }
35029772c4eSLinus Walleij
3512432f71cSSebastian Andrzej Siewior sysrq = uart_prepare_sysrq_char(&uap->port, ch & 255);
352534cf755SPeter Zijlstra if (!sysrq)
35329772c4eSLinus Walleij uart_insert_char(&uap->port, ch, UART011_DR_OE, ch, flag);
35429772c4eSLinus Walleij }
35529772c4eSLinus Walleij
35629772c4eSLinus Walleij return fifotaken;
35729772c4eSLinus Walleij }
35829772c4eSLinus Walleij
35929772c4eSLinus Walleij /*
360ab4382d2SGreg Kroah-Hartman * All the DMA operation mode stuff goes inside this ifdef.
361ab4382d2SGreg Kroah-Hartman * This assumes that you have a generic DMA device interface,
362ab4382d2SGreg Kroah-Hartman * no custom DMA interfaces are supported.
363ab4382d2SGreg Kroah-Hartman */
364ab4382d2SGreg Kroah-Hartman #ifdef CONFIG_DMA_ENGINE
365ab4382d2SGreg Kroah-Hartman
366ab4382d2SGreg Kroah-Hartman #define PL011_DMA_BUFFER_SIZE PAGE_SIZE
367ab4382d2SGreg Kroah-Hartman
pl011_dmabuf_init(struct dma_chan * chan,struct pl011_dmabuf * db,enum dma_data_direction dir)36858ac1b37SArnd Bergmann static int pl011_dmabuf_init(struct dma_chan *chan, struct pl011_dmabuf *db,
369ead76f32SLinus Walleij enum dma_data_direction dir)
370ead76f32SLinus Walleij {
37158ac1b37SArnd Bergmann db->buf = dma_alloc_coherent(chan->device->dev, PL011_DMA_BUFFER_SIZE,
37258ac1b37SArnd Bergmann &db->dma, GFP_KERNEL);
37358ac1b37SArnd Bergmann if (!db->buf)
374ead76f32SLinus Walleij return -ENOMEM;
37558ac1b37SArnd Bergmann db->len = PL011_DMA_BUFFER_SIZE;
376ead76f32SLinus Walleij
377ead76f32SLinus Walleij return 0;
378ead76f32SLinus Walleij }
379ead76f32SLinus Walleij
pl011_dmabuf_free(struct dma_chan * chan,struct pl011_dmabuf * db,enum dma_data_direction dir)38058ac1b37SArnd Bergmann static void pl011_dmabuf_free(struct dma_chan *chan, struct pl011_dmabuf *db,
381ead76f32SLinus Walleij enum dma_data_direction dir)
382ead76f32SLinus Walleij {
38358ac1b37SArnd Bergmann if (db->buf) {
384cb06ff10SChanho Min dma_free_coherent(chan->device->dev,
38558ac1b37SArnd Bergmann PL011_DMA_BUFFER_SIZE, db->buf, db->dma);
386ead76f32SLinus Walleij }
387ead76f32SLinus Walleij }
388ead76f32SLinus Walleij
pl011_dma_probe(struct uart_amba_port * uap)3891c9be310SJorge Ramirez-Ortiz static void pl011_dma_probe(struct uart_amba_port *uap)
390ab4382d2SGreg Kroah-Hartman {
391ab4382d2SGreg Kroah-Hartman /* DMA is the sole user of the platform data right now */
392574de559SJingoo Han struct amba_pl011_data *plat = dev_get_platdata(uap->port.dev);
3931c9be310SJorge Ramirez-Ortiz struct device *dev = uap->port.dev;
394ab4382d2SGreg Kroah-Hartman struct dma_slave_config tx_conf = {
3959f25bc51SRussell King .dst_addr = uap->port.mapbase +
3969f25bc51SRussell King pl011_reg_to_offset(uap, REG_DR),
397ab4382d2SGreg Kroah-Hartman .dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
398a485df4bSVinod Koul .direction = DMA_MEM_TO_DEV,
399ab4382d2SGreg Kroah-Hartman .dst_maxburst = uap->fifosize >> 1,
400258aea76SViresh Kumar .device_fc = false,
401ab4382d2SGreg Kroah-Hartman };
402ab4382d2SGreg Kroah-Hartman struct dma_chan *chan;
403ab4382d2SGreg Kroah-Hartman dma_cap_mask_t mask;
404ab4382d2SGreg Kroah-Hartman
4051c9be310SJorge Ramirez-Ortiz uap->dma_probed = true;
40661b37b04SPeter Ujfalusi chan = dma_request_chan(dev, "tx");
4071c9be310SJorge Ramirez-Ortiz if (IS_ERR(chan)) {
4081c9be310SJorge Ramirez-Ortiz if (PTR_ERR(chan) == -EPROBE_DEFER) {
4091c9be310SJorge Ramirez-Ortiz uap->dma_probed = false;
4101c9be310SJorge Ramirez-Ortiz return;
4111c9be310SJorge Ramirez-Ortiz }
412787b0c1fSArnd Bergmann
413ab4382d2SGreg Kroah-Hartman /* We need platform data */
414ab4382d2SGreg Kroah-Hartman if (!plat || !plat->dma_filter) {
4156905ab83SFabio Estevam dev_dbg(uap->port.dev, "no DMA platform data\n");
416ab4382d2SGreg Kroah-Hartman return;
417ab4382d2SGreg Kroah-Hartman }
418ab4382d2SGreg Kroah-Hartman
419ead76f32SLinus Walleij /* Try to acquire a generic DMA engine slave TX channel */
420ab4382d2SGreg Kroah-Hartman dma_cap_zero(mask);
421ab4382d2SGreg Kroah-Hartman dma_cap_set(DMA_SLAVE, mask);
422ab4382d2SGreg Kroah-Hartman
423787b0c1fSArnd Bergmann chan = dma_request_channel(mask, plat->dma_filter,
424787b0c1fSArnd Bergmann plat->dma_tx_param);
425ab4382d2SGreg Kroah-Hartman if (!chan) {
426ab4382d2SGreg Kroah-Hartman dev_err(uap->port.dev, "no TX DMA channel!\n");
427ab4382d2SGreg Kroah-Hartman return;
428ab4382d2SGreg Kroah-Hartman }
429787b0c1fSArnd Bergmann }
430ab4382d2SGreg Kroah-Hartman
431ab4382d2SGreg Kroah-Hartman dmaengine_slave_config(chan, &tx_conf);
432ab4382d2SGreg Kroah-Hartman uap->dmatx.chan = chan;
433ab4382d2SGreg Kroah-Hartman
434ab4382d2SGreg Kroah-Hartman dev_info(uap->port.dev, "DMA channel TX %s\n",
435ab4382d2SGreg Kroah-Hartman dma_chan_name(uap->dmatx.chan));
436ead76f32SLinus Walleij
437ead76f32SLinus Walleij /* Optionally make use of an RX channel as well */
438e6cc3948SChristophe JAILLET chan = dma_request_chan(dev, "rx");
439787b0c1fSArnd Bergmann
440e6cc3948SChristophe JAILLET if (IS_ERR(chan) && plat && plat->dma_rx_param) {
441787b0c1fSArnd Bergmann chan = dma_request_channel(mask, plat->dma_filter, plat->dma_rx_param);
442787b0c1fSArnd Bergmann
443787b0c1fSArnd Bergmann if (!chan) {
444787b0c1fSArnd Bergmann dev_err(uap->port.dev, "no RX DMA channel!\n");
445787b0c1fSArnd Bergmann return;
446787b0c1fSArnd Bergmann }
447787b0c1fSArnd Bergmann }
448787b0c1fSArnd Bergmann
449e6cc3948SChristophe JAILLET if (!IS_ERR(chan)) {
450ead76f32SLinus Walleij struct dma_slave_config rx_conf = {
4519f25bc51SRussell King .src_addr = uap->port.mapbase +
4529f25bc51SRussell King pl011_reg_to_offset(uap, REG_DR),
453ead76f32SLinus Walleij .src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
454a485df4bSVinod Koul .direction = DMA_DEV_TO_MEM,
455b2aeb775SGuennadi Liakhovetski .src_maxburst = uap->fifosize >> 2,
456258aea76SViresh Kumar .device_fc = false,
457ead76f32SLinus Walleij };
4582d3b7d6eSAndrew Jackson struct dma_slave_caps caps;
459ead76f32SLinus Walleij
4602d3b7d6eSAndrew Jackson /*
4612d3b7d6eSAndrew Jackson * Some DMA controllers provide information on their capabilities.
4622d3b7d6eSAndrew Jackson * If the controller does, check for suitable residue processing
4632d3b7d6eSAndrew Jackson * otherwise assime all is well.
4642d3b7d6eSAndrew Jackson */
46528a7ec8cSThéo Lebrun if (dma_get_slave_caps(chan, &caps) == 0) {
4662d3b7d6eSAndrew Jackson if (caps.residue_granularity ==
4672d3b7d6eSAndrew Jackson DMA_RESIDUE_GRANULARITY_DESCRIPTOR) {
4682d3b7d6eSAndrew Jackson dma_release_channel(chan);
4692d3b7d6eSAndrew Jackson dev_info(uap->port.dev,
4702d3b7d6eSAndrew Jackson "RX DMA disabled - no residue processing\n");
4712d3b7d6eSAndrew Jackson return;
4722d3b7d6eSAndrew Jackson }
4732d3b7d6eSAndrew Jackson }
474ead76f32SLinus Walleij dmaengine_slave_config(chan, &rx_conf);
475ead76f32SLinus Walleij uap->dmarx.chan = chan;
476ead76f32SLinus Walleij
47798267d33SAndrew Jackson uap->dmarx.auto_poll_rate = false;
4788f898bfdSGreg Kroah-Hartman if (plat && plat->dma_rx_poll_enable) {
479cb06ff10SChanho Min /* Set poll rate if specified. */
480cb06ff10SChanho Min if (plat->dma_rx_poll_rate) {
481cb06ff10SChanho Min uap->dmarx.auto_poll_rate = false;
482cb06ff10SChanho Min uap->dmarx.poll_rate = plat->dma_rx_poll_rate;
483cb06ff10SChanho Min } else {
484cb06ff10SChanho Min /*
485cb06ff10SChanho Min * 100 ms defaults to poll rate if not
486cb06ff10SChanho Min * specified. This will be adjusted with
487cb06ff10SChanho Min * the baud rate at set_termios.
488cb06ff10SChanho Min */
489cb06ff10SChanho Min uap->dmarx.auto_poll_rate = true;
490cb06ff10SChanho Min uap->dmarx.poll_rate = 100;
491cb06ff10SChanho Min }
492cb06ff10SChanho Min /* 3 secs defaults poll_timeout if not specified. */
493cb06ff10SChanho Min if (plat->dma_rx_poll_timeout)
494cb06ff10SChanho Min uap->dmarx.poll_timeout =
495cb06ff10SChanho Min plat->dma_rx_poll_timeout;
496cb06ff10SChanho Min else
497cb06ff10SChanho Min uap->dmarx.poll_timeout = 3000;
49898267d33SAndrew Jackson } else if (!plat && dev->of_node) {
499d93ebe0fSThéo Lebrun uap->dmarx.auto_poll_rate =
500d93ebe0fSThéo Lebrun of_property_read_bool(dev->of_node, "auto-poll");
50198267d33SAndrew Jackson if (uap->dmarx.auto_poll_rate) {
50298267d33SAndrew Jackson u32 x;
503cb06ff10SChanho Min
50428a7ec8cSThéo Lebrun if (of_property_read_u32(dev->of_node, "poll-rate-ms", &x) == 0)
50598267d33SAndrew Jackson uap->dmarx.poll_rate = x;
50698267d33SAndrew Jackson else
50798267d33SAndrew Jackson uap->dmarx.poll_rate = 100;
50828a7ec8cSThéo Lebrun if (of_property_read_u32(dev->of_node, "poll-timeout-ms", &x) == 0)
50998267d33SAndrew Jackson uap->dmarx.poll_timeout = x;
51098267d33SAndrew Jackson else
51198267d33SAndrew Jackson uap->dmarx.poll_timeout = 3000;
51298267d33SAndrew Jackson }
51398267d33SAndrew Jackson }
514ead76f32SLinus Walleij dev_info(uap->port.dev, "DMA channel RX %s\n",
515ead76f32SLinus Walleij dma_chan_name(uap->dmarx.chan));
516ead76f32SLinus Walleij }
517ab4382d2SGreg Kroah-Hartman }
518ab4382d2SGreg Kroah-Hartman
pl011_dma_remove(struct uart_amba_port * uap)519ab4382d2SGreg Kroah-Hartman static void pl011_dma_remove(struct uart_amba_port *uap)
520ab4382d2SGreg Kroah-Hartman {
521ab4382d2SGreg Kroah-Hartman if (uap->dmatx.chan)
522ab4382d2SGreg Kroah-Hartman dma_release_channel(uap->dmatx.chan);
523ead76f32SLinus Walleij if (uap->dmarx.chan)
524ead76f32SLinus Walleij dma_release_channel(uap->dmarx.chan);
525ab4382d2SGreg Kroah-Hartman }
526ab4382d2SGreg Kroah-Hartman
527734745caSDave Martin /* Forward declare these for the refill routine */
528ab4382d2SGreg Kroah-Hartman static int pl011_dma_tx_refill(struct uart_amba_port *uap);
529734745caSDave Martin static void pl011_start_tx_pio(struct uart_amba_port *uap);
530ab4382d2SGreg Kroah-Hartman
531ab4382d2SGreg Kroah-Hartman /*
532ab4382d2SGreg Kroah-Hartman * The current DMA TX buffer has been sent.
533ab4382d2SGreg Kroah-Hartman * Try to queue up another DMA buffer.
534ab4382d2SGreg Kroah-Hartman */
pl011_dma_tx_callback(void * data)535ab4382d2SGreg Kroah-Hartman static void pl011_dma_tx_callback(void *data)
536ab4382d2SGreg Kroah-Hartman {
537ab4382d2SGreg Kroah-Hartman struct uart_amba_port *uap = data;
5381788cf6aSJiri Slaby (SUSE) struct tty_port *tport = &uap->port.state->port;
539ab4382d2SGreg Kroah-Hartman struct pl011_dmatx_data *dmatx = &uap->dmatx;
540ab4382d2SGreg Kroah-Hartman unsigned long flags;
541ab4382d2SGreg Kroah-Hartman u16 dmacr;
542ab4382d2SGreg Kroah-Hartman
54368ca3e72SThomas Gleixner uart_port_lock_irqsave(&uap->port, &flags);
544ab4382d2SGreg Kroah-Hartman if (uap->dmatx.queued)
54558ac1b37SArnd Bergmann dma_unmap_single(dmatx->chan->device->dev, dmatx->dma,
54658ac1b37SArnd Bergmann dmatx->len, DMA_TO_DEVICE);
547ab4382d2SGreg Kroah-Hartman
548ab4382d2SGreg Kroah-Hartman dmacr = uap->dmacr;
549ab4382d2SGreg Kroah-Hartman uap->dmacr = dmacr & ~UART011_TXDMAE;
5509f25bc51SRussell King pl011_write(uap->dmacr, uap, REG_DMACR);
551ab4382d2SGreg Kroah-Hartman
552ab4382d2SGreg Kroah-Hartman /*
553ab4382d2SGreg Kroah-Hartman * If TX DMA was disabled, it means that we've stopped the DMA for
554ab4382d2SGreg Kroah-Hartman * some reason (eg, XOFF received, or we want to send an X-char.)
555ab4382d2SGreg Kroah-Hartman *
556ab4382d2SGreg Kroah-Hartman * Note: we need to be careful here of a potential race between DMA
557ab4382d2SGreg Kroah-Hartman * and the rest of the driver - if the driver disables TX DMA while
558ab4382d2SGreg Kroah-Hartman * a TX buffer completing, we must update the tx queued status to
559ab4382d2SGreg Kroah-Hartman * get further refills (hence we check dmacr).
560ab4382d2SGreg Kroah-Hartman */
561ab4382d2SGreg Kroah-Hartman if (!(dmacr & UART011_TXDMAE) || uart_tx_stopped(&uap->port) ||
5621788cf6aSJiri Slaby (SUSE) kfifo_is_empty(&tport->xmit_fifo)) {
563ab4382d2SGreg Kroah-Hartman uap->dmatx.queued = false;
56468ca3e72SThomas Gleixner uart_port_unlock_irqrestore(&uap->port, flags);
565ab4382d2SGreg Kroah-Hartman return;
566ab4382d2SGreg Kroah-Hartman }
567ab4382d2SGreg Kroah-Hartman
568734745caSDave Martin if (pl011_dma_tx_refill(uap) <= 0)
569ab4382d2SGreg Kroah-Hartman /*
570ab4382d2SGreg Kroah-Hartman * We didn't queue a DMA buffer for some reason, but we
571ab4382d2SGreg Kroah-Hartman * have data pending to be sent. Re-enable the TX IRQ.
572ab4382d2SGreg Kroah-Hartman */
573734745caSDave Martin pl011_start_tx_pio(uap);
574734745caSDave Martin
57568ca3e72SThomas Gleixner uart_port_unlock_irqrestore(&uap->port, flags);
576ab4382d2SGreg Kroah-Hartman }
577ab4382d2SGreg Kroah-Hartman
578ab4382d2SGreg Kroah-Hartman /*
579ab4382d2SGreg Kroah-Hartman * Try to refill the TX DMA buffer.
580ab4382d2SGreg Kroah-Hartman * Locking: called with port lock held and IRQs disabled.
581ab4382d2SGreg Kroah-Hartman * Returns:
582ab4382d2SGreg Kroah-Hartman * 1 if we queued up a TX DMA buffer.
583ab4382d2SGreg Kroah-Hartman * 0 if we didn't want to handle this by DMA
584ab4382d2SGreg Kroah-Hartman * <0 on error
585ab4382d2SGreg Kroah-Hartman */
pl011_dma_tx_refill(struct uart_amba_port * uap)586ab4382d2SGreg Kroah-Hartman static int pl011_dma_tx_refill(struct uart_amba_port *uap)
587ab4382d2SGreg Kroah-Hartman {
588ab4382d2SGreg Kroah-Hartman struct pl011_dmatx_data *dmatx = &uap->dmatx;
589ab4382d2SGreg Kroah-Hartman struct dma_chan *chan = dmatx->chan;
590ab4382d2SGreg Kroah-Hartman struct dma_device *dma_dev = chan->device;
591ab4382d2SGreg Kroah-Hartman struct dma_async_tx_descriptor *desc;
5921788cf6aSJiri Slaby (SUSE) struct tty_port *tport = &uap->port.state->port;
593ab4382d2SGreg Kroah-Hartman unsigned int count;
594ab4382d2SGreg Kroah-Hartman
595ab4382d2SGreg Kroah-Hartman /*
596ab4382d2SGreg Kroah-Hartman * Try to avoid the overhead involved in using DMA if the
597ab4382d2SGreg Kroah-Hartman * transaction fits in the first half of the FIFO, by using
598ab4382d2SGreg Kroah-Hartman * the standard interrupt handling. This ensures that we
599ab4382d2SGreg Kroah-Hartman * issue a uart_write_wakeup() at the appropriate time.
600ab4382d2SGreg Kroah-Hartman */
6011788cf6aSJiri Slaby (SUSE) count = kfifo_len(&tport->xmit_fifo);
602ab4382d2SGreg Kroah-Hartman if (count < (uap->fifosize >> 1)) {
603ab4382d2SGreg Kroah-Hartman uap->dmatx.queued = false;
604ab4382d2SGreg Kroah-Hartman return 0;
605ab4382d2SGreg Kroah-Hartman }
606ab4382d2SGreg Kroah-Hartman
607ab4382d2SGreg Kroah-Hartman /*
608ab4382d2SGreg Kroah-Hartman * Bodge: don't send the last character by DMA, as this
609ab4382d2SGreg Kroah-Hartman * will prevent XON from notifying us to restart DMA.
610ab4382d2SGreg Kroah-Hartman */
611ab4382d2SGreg Kroah-Hartman count -= 1;
612ab4382d2SGreg Kroah-Hartman
613ab4382d2SGreg Kroah-Hartman /* Else proceed to copy the TX chars to the DMA buffer and fire DMA */
614ab4382d2SGreg Kroah-Hartman if (count > PL011_DMA_BUFFER_SIZE)
615ab4382d2SGreg Kroah-Hartman count = PL011_DMA_BUFFER_SIZE;
616ab4382d2SGreg Kroah-Hartman
6171788cf6aSJiri Slaby (SUSE) count = kfifo_out_peek(&tport->xmit_fifo, dmatx->buf, count);
61858ac1b37SArnd Bergmann dmatx->len = count;
61958ac1b37SArnd Bergmann dmatx->dma = dma_map_single(dma_dev->dev, dmatx->buf, count,
62058ac1b37SArnd Bergmann DMA_TO_DEVICE);
62158ac1b37SArnd Bergmann if (dmatx->dma == DMA_MAPPING_ERROR) {
622ab4382d2SGreg Kroah-Hartman uap->dmatx.queued = false;
623ab4382d2SGreg Kroah-Hartman dev_dbg(uap->port.dev, "unable to map TX DMA\n");
624ab4382d2SGreg Kroah-Hartman return -EBUSY;
625ab4382d2SGreg Kroah-Hartman }
626ab4382d2SGreg Kroah-Hartman
62758ac1b37SArnd Bergmann desc = dmaengine_prep_slave_single(chan, dmatx->dma, dmatx->len, DMA_MEM_TO_DEV,
628ab4382d2SGreg Kroah-Hartman DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
629ab4382d2SGreg Kroah-Hartman if (!desc) {
63058ac1b37SArnd Bergmann dma_unmap_single(dma_dev->dev, dmatx->dma, dmatx->len, DMA_TO_DEVICE);
631ab4382d2SGreg Kroah-Hartman uap->dmatx.queued = false;
632ab4382d2SGreg Kroah-Hartman /*
633ab4382d2SGreg Kroah-Hartman * If DMA cannot be used right now, we complete this
634ab4382d2SGreg Kroah-Hartman * transaction via IRQ and let the TTY layer retry.
635ab4382d2SGreg Kroah-Hartman */
636ab4382d2SGreg Kroah-Hartman dev_dbg(uap->port.dev, "TX DMA busy\n");
637ab4382d2SGreg Kroah-Hartman return -EBUSY;
638ab4382d2SGreg Kroah-Hartman }
639ab4382d2SGreg Kroah-Hartman
640ab4382d2SGreg Kroah-Hartman /* Some data to go along to the callback */
641ab4382d2SGreg Kroah-Hartman desc->callback = pl011_dma_tx_callback;
642ab4382d2SGreg Kroah-Hartman desc->callback_param = uap;
643ab4382d2SGreg Kroah-Hartman
644ab4382d2SGreg Kroah-Hartman /* All errors should happen at prepare time */
645ab4382d2SGreg Kroah-Hartman dmaengine_submit(desc);
646ab4382d2SGreg Kroah-Hartman
647ab4382d2SGreg Kroah-Hartman /* Fire the DMA transaction */
648ab4382d2SGreg Kroah-Hartman dma_dev->device_issue_pending(chan);
649ab4382d2SGreg Kroah-Hartman
650ab4382d2SGreg Kroah-Hartman uap->dmacr |= UART011_TXDMAE;
6519f25bc51SRussell King pl011_write(uap->dmacr, uap, REG_DMACR);
652ab4382d2SGreg Kroah-Hartman uap->dmatx.queued = true;
653ab4382d2SGreg Kroah-Hartman
654ab4382d2SGreg Kroah-Hartman /*
655ab4382d2SGreg Kroah-Hartman * Now we know that DMA will fire, so advance the ring buffer
656ab4382d2SGreg Kroah-Hartman * with the stuff we just dispatched.
657ab4382d2SGreg Kroah-Hartman */
65871a67573SIlpo Järvinen uart_xmit_advance(&uap->port, count);
659ab4382d2SGreg Kroah-Hartman
6601788cf6aSJiri Slaby (SUSE) if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
661ab4382d2SGreg Kroah-Hartman uart_write_wakeup(&uap->port);
662ab4382d2SGreg Kroah-Hartman
663ab4382d2SGreg Kroah-Hartman return 1;
664ab4382d2SGreg Kroah-Hartman }
665ab4382d2SGreg Kroah-Hartman
666ab4382d2SGreg Kroah-Hartman /*
667ab4382d2SGreg Kroah-Hartman * We received a transmit interrupt without a pending X-char but with
668ab4382d2SGreg Kroah-Hartman * pending characters.
669ab4382d2SGreg Kroah-Hartman * Locking: called with port lock held and IRQs disabled.
670ab4382d2SGreg Kroah-Hartman * Returns:
671ab4382d2SGreg Kroah-Hartman * false if we want to use PIO to transmit
672ab4382d2SGreg Kroah-Hartman * true if we queued a DMA buffer
673ab4382d2SGreg Kroah-Hartman */
pl011_dma_tx_irq(struct uart_amba_port * uap)674ab4382d2SGreg Kroah-Hartman static bool pl011_dma_tx_irq(struct uart_amba_port *uap)
675ab4382d2SGreg Kroah-Hartman {
676ead76f32SLinus Walleij if (!uap->using_tx_dma)
677ab4382d2SGreg Kroah-Hartman return false;
678ab4382d2SGreg Kroah-Hartman
679ab4382d2SGreg Kroah-Hartman /*
680ab4382d2SGreg Kroah-Hartman * If we already have a TX buffer queued, but received a
681ab4382d2SGreg Kroah-Hartman * TX interrupt, it will be because we've just sent an X-char.
682ab4382d2SGreg Kroah-Hartman * Ensure the TX DMA is enabled and the TX IRQ is disabled.
683ab4382d2SGreg Kroah-Hartman */
684ab4382d2SGreg Kroah-Hartman if (uap->dmatx.queued) {
685ab4382d2SGreg Kroah-Hartman uap->dmacr |= UART011_TXDMAE;
6869f25bc51SRussell King pl011_write(uap->dmacr, uap, REG_DMACR);
687ab4382d2SGreg Kroah-Hartman uap->im &= ~UART011_TXIM;
6889f25bc51SRussell King pl011_write(uap->im, uap, REG_IMSC);
689ab4382d2SGreg Kroah-Hartman return true;
690ab4382d2SGreg Kroah-Hartman }
691ab4382d2SGreg Kroah-Hartman
692ab4382d2SGreg Kroah-Hartman /*
693ab4382d2SGreg Kroah-Hartman * We don't have a TX buffer queued, so try to queue one.
69425985edcSLucas De Marchi * If we successfully queued a buffer, mask the TX IRQ.
695ab4382d2SGreg Kroah-Hartman */
696ab4382d2SGreg Kroah-Hartman if (pl011_dma_tx_refill(uap) > 0) {
697ab4382d2SGreg Kroah-Hartman uap->im &= ~UART011_TXIM;
6989f25bc51SRussell King pl011_write(uap->im, uap, REG_IMSC);
699ab4382d2SGreg Kroah-Hartman return true;
700ab4382d2SGreg Kroah-Hartman }
701ab4382d2SGreg Kroah-Hartman return false;
702ab4382d2SGreg Kroah-Hartman }
703ab4382d2SGreg Kroah-Hartman
704ab4382d2SGreg Kroah-Hartman /*
705ab4382d2SGreg Kroah-Hartman * Stop the DMA transmit (eg, due to received XOFF).
706ab4382d2SGreg Kroah-Hartman * Locking: called with port lock held and IRQs disabled.
707ab4382d2SGreg Kroah-Hartman */
pl011_dma_tx_stop(struct uart_amba_port * uap)708ab4382d2SGreg Kroah-Hartman static inline void pl011_dma_tx_stop(struct uart_amba_port *uap)
709ab4382d2SGreg Kroah-Hartman {
710ab4382d2SGreg Kroah-Hartman if (uap->dmatx.queued) {
711ab4382d2SGreg Kroah-Hartman uap->dmacr &= ~UART011_TXDMAE;
7129f25bc51SRussell King pl011_write(uap->dmacr, uap, REG_DMACR);
713ab4382d2SGreg Kroah-Hartman }
714ab4382d2SGreg Kroah-Hartman }
715ab4382d2SGreg Kroah-Hartman
716ab4382d2SGreg Kroah-Hartman /*
717ab4382d2SGreg Kroah-Hartman * Try to start a DMA transmit, or in the case of an XON/OFF
718ab4382d2SGreg Kroah-Hartman * character queued for send, try to get that character out ASAP.
719ab4382d2SGreg Kroah-Hartman * Locking: called with port lock held and IRQs disabled.
720ab4382d2SGreg Kroah-Hartman * Returns:
721ab4382d2SGreg Kroah-Hartman * false if we want the TX IRQ to be enabled
722ab4382d2SGreg Kroah-Hartman * true if we have a buffer queued
723ab4382d2SGreg Kroah-Hartman */
pl011_dma_tx_start(struct uart_amba_port * uap)724ab4382d2SGreg Kroah-Hartman static inline bool pl011_dma_tx_start(struct uart_amba_port *uap)
725ab4382d2SGreg Kroah-Hartman {
726ab4382d2SGreg Kroah-Hartman u16 dmacr;
727ab4382d2SGreg Kroah-Hartman
728ead76f32SLinus Walleij if (!uap->using_tx_dma)
729ab4382d2SGreg Kroah-Hartman return false;
730ab4382d2SGreg Kroah-Hartman
731ab4382d2SGreg Kroah-Hartman if (!uap->port.x_char) {
732ab4382d2SGreg Kroah-Hartman /* no X-char, try to push chars out in DMA mode */
733ab4382d2SGreg Kroah-Hartman bool ret = true;
734ab4382d2SGreg Kroah-Hartman
735ab4382d2SGreg Kroah-Hartman if (!uap->dmatx.queued) {
736ab4382d2SGreg Kroah-Hartman if (pl011_dma_tx_refill(uap) > 0) {
737ab4382d2SGreg Kroah-Hartman uap->im &= ~UART011_TXIM;
7389f25bc51SRussell King pl011_write(uap->im, uap, REG_IMSC);
73928a7ec8cSThéo Lebrun } else {
740ab4382d2SGreg Kroah-Hartman ret = false;
74128a7ec8cSThéo Lebrun }
742ab4382d2SGreg Kroah-Hartman } else if (!(uap->dmacr & UART011_TXDMAE)) {
743ab4382d2SGreg Kroah-Hartman uap->dmacr |= UART011_TXDMAE;
7449f25bc51SRussell King pl011_write(uap->dmacr, uap, REG_DMACR);
745ab4382d2SGreg Kroah-Hartman }
746ab4382d2SGreg Kroah-Hartman return ret;
747ab4382d2SGreg Kroah-Hartman }
748ab4382d2SGreg Kroah-Hartman
749ab4382d2SGreg Kroah-Hartman /*
750ab4382d2SGreg Kroah-Hartman * We have an X-char to send. Disable DMA to prevent it loading
751ab4382d2SGreg Kroah-Hartman * the TX fifo, and then see if we can stuff it into the FIFO.
752ab4382d2SGreg Kroah-Hartman */
753ab4382d2SGreg Kroah-Hartman dmacr = uap->dmacr;
754ab4382d2SGreg Kroah-Hartman uap->dmacr &= ~UART011_TXDMAE;
7559f25bc51SRussell King pl011_write(uap->dmacr, uap, REG_DMACR);
756ab4382d2SGreg Kroah-Hartman
7579f25bc51SRussell King if (pl011_read(uap, REG_FR) & UART01x_FR_TXFF) {
758ab4382d2SGreg Kroah-Hartman /*
759ab4382d2SGreg Kroah-Hartman * No space in the FIFO, so enable the transmit interrupt
760ab4382d2SGreg Kroah-Hartman * so we know when there is space. Note that once we've
761ab4382d2SGreg Kroah-Hartman * loaded the character, we should just re-enable DMA.
762ab4382d2SGreg Kroah-Hartman */
763ab4382d2SGreg Kroah-Hartman return false;
764ab4382d2SGreg Kroah-Hartman }
765ab4382d2SGreg Kroah-Hartman
7669f25bc51SRussell King pl011_write(uap->port.x_char, uap, REG_DR);
767ab4382d2SGreg Kroah-Hartman uap->port.icount.tx++;
768ab4382d2SGreg Kroah-Hartman uap->port.x_char = 0;
769ab4382d2SGreg Kroah-Hartman
770ab4382d2SGreg Kroah-Hartman /* Success - restore the DMA state */
771ab4382d2SGreg Kroah-Hartman uap->dmacr = dmacr;
7729f25bc51SRussell King pl011_write(dmacr, uap, REG_DMACR);
773ab4382d2SGreg Kroah-Hartman
774ab4382d2SGreg Kroah-Hartman return true;
775ab4382d2SGreg Kroah-Hartman }
776ab4382d2SGreg Kroah-Hartman
777ab4382d2SGreg Kroah-Hartman /*
778ab4382d2SGreg Kroah-Hartman * Flush the transmit buffer.
779ab4382d2SGreg Kroah-Hartman * Locking: called with port lock held and IRQs disabled.
780ab4382d2SGreg Kroah-Hartman */
pl011_dma_flush_buffer(struct uart_port * port)781ab4382d2SGreg Kroah-Hartman static void pl011_dma_flush_buffer(struct uart_port *port)
782b83286bfSFabio Estevam __releases(&uap->port.lock)
783b83286bfSFabio Estevam __acquires(&uap->port.lock)
784ab4382d2SGreg Kroah-Hartman {
785a5820c24SDaniel Thompson struct uart_amba_port *uap =
786a5820c24SDaniel Thompson container_of(port, struct uart_amba_port, port);
787ab4382d2SGreg Kroah-Hartman
788ead76f32SLinus Walleij if (!uap->using_tx_dma)
789ab4382d2SGreg Kroah-Hartman return;
790ab4382d2SGreg Kroah-Hartman
791f6a19647SVincent Whitchurch dmaengine_terminate_async(uap->dmatx.chan);
792f6a19647SVincent Whitchurch
793ab4382d2SGreg Kroah-Hartman if (uap->dmatx.queued) {
79458ac1b37SArnd Bergmann dma_unmap_single(uap->dmatx.chan->device->dev, uap->dmatx.dma,
79558ac1b37SArnd Bergmann uap->dmatx.len, DMA_TO_DEVICE);
796ab4382d2SGreg Kroah-Hartman uap->dmatx.queued = false;
797ab4382d2SGreg Kroah-Hartman uap->dmacr &= ~UART011_TXDMAE;
7989f25bc51SRussell King pl011_write(uap->dmacr, uap, REG_DMACR);
799ab4382d2SGreg Kroah-Hartman }
800ab4382d2SGreg Kroah-Hartman }
801ab4382d2SGreg Kroah-Hartman
802ead76f32SLinus Walleij static void pl011_dma_rx_callback(void *data);
803ead76f32SLinus Walleij
pl011_dma_rx_trigger_dma(struct uart_amba_port * uap)804ead76f32SLinus Walleij static int pl011_dma_rx_trigger_dma(struct uart_amba_port *uap)
805ead76f32SLinus Walleij {
806ead76f32SLinus Walleij struct dma_chan *rxchan = uap->dmarx.chan;
807ead76f32SLinus Walleij struct pl011_dmarx_data *dmarx = &uap->dmarx;
808ead76f32SLinus Walleij struct dma_async_tx_descriptor *desc;
80958ac1b37SArnd Bergmann struct pl011_dmabuf *dbuf;
810ead76f32SLinus Walleij
811ead76f32SLinus Walleij if (!rxchan)
812ead76f32SLinus Walleij return -EIO;
813ead76f32SLinus Walleij
814ead76f32SLinus Walleij /* Start the RX DMA job */
81558ac1b37SArnd Bergmann dbuf = uap->dmarx.use_buf_b ?
81658ac1b37SArnd Bergmann &uap->dmarx.dbuf_b : &uap->dmarx.dbuf_a;
81758ac1b37SArnd Bergmann desc = dmaengine_prep_slave_single(rxchan, dbuf->dma, dbuf->len,
818a485df4bSVinod Koul DMA_DEV_TO_MEM,
819ead76f32SLinus Walleij DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
820ead76f32SLinus Walleij /*
821ead76f32SLinus Walleij * If the DMA engine is busy and cannot prepare a
822ead76f32SLinus Walleij * channel, no big deal, the driver will fall back
823ead76f32SLinus Walleij * to interrupt mode as a result of this error code.
824ead76f32SLinus Walleij */
825ead76f32SLinus Walleij if (!desc) {
826ead76f32SLinus Walleij uap->dmarx.running = false;
827ead76f32SLinus Walleij dmaengine_terminate_all(rxchan);
828ead76f32SLinus Walleij return -EBUSY;
829ead76f32SLinus Walleij }
830ead76f32SLinus Walleij
831ead76f32SLinus Walleij /* Some data to go along to the callback */
832ead76f32SLinus Walleij desc->callback = pl011_dma_rx_callback;
833ead76f32SLinus Walleij desc->callback_param = uap;
834ead76f32SLinus Walleij dmarx->cookie = dmaengine_submit(desc);
835ead76f32SLinus Walleij dma_async_issue_pending(rxchan);
836ead76f32SLinus Walleij
837ead76f32SLinus Walleij uap->dmacr |= UART011_RXDMAE;
8389f25bc51SRussell King pl011_write(uap->dmacr, uap, REG_DMACR);
839ead76f32SLinus Walleij uap->dmarx.running = true;
840ead76f32SLinus Walleij
841ead76f32SLinus Walleij uap->im &= ~UART011_RXIM;
8429f25bc51SRussell King pl011_write(uap->im, uap, REG_IMSC);
843ead76f32SLinus Walleij
844ead76f32SLinus Walleij return 0;
845ead76f32SLinus Walleij }
846ead76f32SLinus Walleij
847ead76f32SLinus Walleij /*
848ead76f32SLinus Walleij * This is called when either the DMA job is complete, or
849ead76f32SLinus Walleij * the FIFO timeout interrupt occurred. This must be called
850ead76f32SLinus Walleij * with the port spinlock uap->port.lock held.
851ead76f32SLinus Walleij */
pl011_dma_rx_chars(struct uart_amba_port * uap,u32 pending,bool use_buf_b,bool readfifo)852ead76f32SLinus Walleij static void pl011_dma_rx_chars(struct uart_amba_port *uap,
853ead76f32SLinus Walleij u32 pending, bool use_buf_b,
854ead76f32SLinus Walleij bool readfifo)
855ead76f32SLinus Walleij {
85605c7cd39SJiri Slaby struct tty_port *port = &uap->port.state->port;
85758ac1b37SArnd Bergmann struct pl011_dmabuf *dbuf = use_buf_b ?
85858ac1b37SArnd Bergmann &uap->dmarx.dbuf_b : &uap->dmarx.dbuf_a;
859ead76f32SLinus Walleij int dma_count = 0;
860ead76f32SLinus Walleij u32 fifotaken = 0; /* only used for vdbg() */
861ead76f32SLinus Walleij
862cb06ff10SChanho Min struct pl011_dmarx_data *dmarx = &uap->dmarx;
863cb06ff10SChanho Min int dmataken = 0;
864cb06ff10SChanho Min
865cb06ff10SChanho Min if (uap->dmarx.poll_rate) {
866cb06ff10SChanho Min /* The data can be taken by polling */
86758ac1b37SArnd Bergmann dmataken = dbuf->len - dmarx->last_residue;
868cb06ff10SChanho Min /* Recalculate the pending size */
869cb06ff10SChanho Min if (pending >= dmataken)
870cb06ff10SChanho Min pending -= dmataken;
871cb06ff10SChanho Min }
872cb06ff10SChanho Min
873cb06ff10SChanho Min /* Pick the remain data from the DMA */
874ead76f32SLinus Walleij if (pending) {
875ead76f32SLinus Walleij /*
876ead76f32SLinus Walleij * First take all chars in the DMA pipe, then look in the FIFO.
877ead76f32SLinus Walleij * Note that tty_insert_flip_buf() tries to take as many chars
878ead76f32SLinus Walleij * as it can.
879ead76f32SLinus Walleij */
880d93ebe0fSThéo Lebrun dma_count = tty_insert_flip_string(port, dbuf->buf + dmataken, pending);
881ead76f32SLinus Walleij
882ead76f32SLinus Walleij uap->port.icount.rx += dma_count;
883ead76f32SLinus Walleij if (dma_count < pending)
884ead76f32SLinus Walleij dev_warn(uap->port.dev,
885ead76f32SLinus Walleij "couldn't insert all characters (TTY is full?)\n");
886ead76f32SLinus Walleij }
887ead76f32SLinus Walleij
888cb06ff10SChanho Min /* Reset the last_residue for Rx DMA poll */
889cb06ff10SChanho Min if (uap->dmarx.poll_rate)
89058ac1b37SArnd Bergmann dmarx->last_residue = dbuf->len;
891cb06ff10SChanho Min
892ead76f32SLinus Walleij /*
893ead76f32SLinus Walleij * Only continue with trying to read the FIFO if all DMA chars have
894ead76f32SLinus Walleij * been taken first.
895ead76f32SLinus Walleij */
896ead76f32SLinus Walleij if (dma_count == pending && readfifo) {
897ead76f32SLinus Walleij /* Clear any error flags */
89875836339SRussell King pl011_write(UART011_OEIS | UART011_BEIS | UART011_PEIS |
8999f25bc51SRussell King UART011_FEIS, uap, REG_ICR);
900ead76f32SLinus Walleij
901ead76f32SLinus Walleij /*
902ead76f32SLinus Walleij * If we read all the DMA'd characters, and we had an
90329772c4eSLinus Walleij * incomplete buffer, that could be due to an rx error, or
90429772c4eSLinus Walleij * maybe we just timed out. Read any pending chars and check
90529772c4eSLinus Walleij * the error status.
90629772c4eSLinus Walleij *
90729772c4eSLinus Walleij * Error conditions will only occur in the FIFO, these will
90829772c4eSLinus Walleij * trigger an immediate interrupt and stop the DMA job, so we
90929772c4eSLinus Walleij * will always find the error in the FIFO, never in the DMA
91029772c4eSLinus Walleij * buffer.
911ead76f32SLinus Walleij */
91229772c4eSLinus Walleij fifotaken = pl011_fifo_to_tty(uap);
913ead76f32SLinus Walleij }
914ead76f32SLinus Walleij
915ead76f32SLinus Walleij dev_vdbg(uap->port.dev,
916ead76f32SLinus Walleij "Took %d chars from DMA buffer and %d chars from the FIFO\n",
917ead76f32SLinus Walleij dma_count, fifotaken);
9182e124b4aSJiri Slaby tty_flip_buffer_push(port);
919ead76f32SLinus Walleij }
920ead76f32SLinus Walleij
pl011_dma_rx_irq(struct uart_amba_port * uap)921ead76f32SLinus Walleij static void pl011_dma_rx_irq(struct uart_amba_port *uap)
922ead76f32SLinus Walleij {
923ead76f32SLinus Walleij struct pl011_dmarx_data *dmarx = &uap->dmarx;
924ead76f32SLinus Walleij struct dma_chan *rxchan = dmarx->chan;
92558ac1b37SArnd Bergmann struct pl011_dmabuf *dbuf = dmarx->use_buf_b ?
92658ac1b37SArnd Bergmann &dmarx->dbuf_b : &dmarx->dbuf_a;
927ead76f32SLinus Walleij size_t pending;
928ead76f32SLinus Walleij struct dma_tx_state state;
929ead76f32SLinus Walleij enum dma_status dmastat;
930ead76f32SLinus Walleij
931ead76f32SLinus Walleij /*
932ead76f32SLinus Walleij * Pause the transfer so we can trust the current counter,
933ead76f32SLinus Walleij * do this before we pause the PL011 block, else we may
934ead76f32SLinus Walleij * overflow the FIFO.
935ead76f32SLinus Walleij */
936ead76f32SLinus Walleij if (dmaengine_pause(rxchan))
937ead76f32SLinus Walleij dev_err(uap->port.dev, "unable to pause DMA transfer\n");
938ead76f32SLinus Walleij dmastat = rxchan->device->device_tx_status(rxchan,
939ead76f32SLinus Walleij dmarx->cookie, &state);
940ead76f32SLinus Walleij if (dmastat != DMA_PAUSED)
941ead76f32SLinus Walleij dev_err(uap->port.dev, "unable to pause DMA transfer\n");
942ead76f32SLinus Walleij
943ead76f32SLinus Walleij /* Disable RX DMA - incoming data will wait in the FIFO */
944ead76f32SLinus Walleij uap->dmacr &= ~UART011_RXDMAE;
9459f25bc51SRussell King pl011_write(uap->dmacr, uap, REG_DMACR);
946ead76f32SLinus Walleij uap->dmarx.running = false;
947ead76f32SLinus Walleij
94858ac1b37SArnd Bergmann pending = dbuf->len - state.residue;
949ead76f32SLinus Walleij BUG_ON(pending > PL011_DMA_BUFFER_SIZE);
950ead76f32SLinus Walleij /* Then we terminate the transfer - we now know our residue */
951ead76f32SLinus Walleij dmaengine_terminate_all(rxchan);
952ead76f32SLinus Walleij
953ead76f32SLinus Walleij /*
954ead76f32SLinus Walleij * This will take the chars we have so far and insert
955ead76f32SLinus Walleij * into the framework.
956ead76f32SLinus Walleij */
957ead76f32SLinus Walleij pl011_dma_rx_chars(uap, pending, dmarx->use_buf_b, true);
958ead76f32SLinus Walleij
959ead76f32SLinus Walleij /* Switch buffer & re-trigger DMA job */
960ead76f32SLinus Walleij dmarx->use_buf_b = !dmarx->use_buf_b;
961ead76f32SLinus Walleij if (pl011_dma_rx_trigger_dma(uap)) {
962fd64ff09SThéo Lebrun dev_dbg(uap->port.dev,
963fd64ff09SThéo Lebrun "could not retrigger RX DMA job fall back to interrupt mode\n");
964ead76f32SLinus Walleij uap->im |= UART011_RXIM;
9659f25bc51SRussell King pl011_write(uap->im, uap, REG_IMSC);
966ead76f32SLinus Walleij }
967ead76f32SLinus Walleij }
968ead76f32SLinus Walleij
pl011_dma_rx_callback(void * data)969ead76f32SLinus Walleij static void pl011_dma_rx_callback(void *data)
970ead76f32SLinus Walleij {
971ead76f32SLinus Walleij struct uart_amba_port *uap = data;
972ead76f32SLinus Walleij struct pl011_dmarx_data *dmarx = &uap->dmarx;
9736dc01aa6SChanho Min struct dma_chan *rxchan = dmarx->chan;
974ead76f32SLinus Walleij bool lastbuf = dmarx->use_buf_b;
97558ac1b37SArnd Bergmann struct pl011_dmabuf *dbuf = dmarx->use_buf_b ?
97658ac1b37SArnd Bergmann &dmarx->dbuf_b : &dmarx->dbuf_a;
9776dc01aa6SChanho Min size_t pending;
9786dc01aa6SChanho Min struct dma_tx_state state;
979ead76f32SLinus Walleij int ret;
980ead76f32SLinus Walleij
981ead76f32SLinus Walleij /*
982ead76f32SLinus Walleij * This completion interrupt occurs typically when the
983ead76f32SLinus Walleij * RX buffer is totally stuffed but no timeout has yet
984ead76f32SLinus Walleij * occurred. When that happens, we just want the RX
985ead76f32SLinus Walleij * routine to flush out the secondary DMA buffer while
986ead76f32SLinus Walleij * we immediately trigger the next DMA job.
987ead76f32SLinus Walleij */
98868ca3e72SThomas Gleixner uart_port_lock_irq(&uap->port);
9896dc01aa6SChanho Min /*
9906dc01aa6SChanho Min * Rx data can be taken by the UART interrupts during
9916dc01aa6SChanho Min * the DMA irq handler. So we check the residue here.
9926dc01aa6SChanho Min */
9936dc01aa6SChanho Min rxchan->device->device_tx_status(rxchan, dmarx->cookie, &state);
99458ac1b37SArnd Bergmann pending = dbuf->len - state.residue;
9956dc01aa6SChanho Min BUG_ON(pending > PL011_DMA_BUFFER_SIZE);
9966dc01aa6SChanho Min /* Then we terminate the transfer - we now know our residue */
9976dc01aa6SChanho Min dmaengine_terminate_all(rxchan);
9986dc01aa6SChanho Min
999ead76f32SLinus Walleij uap->dmarx.running = false;
1000ead76f32SLinus Walleij dmarx->use_buf_b = !lastbuf;
1001ead76f32SLinus Walleij ret = pl011_dma_rx_trigger_dma(uap);
1002ead76f32SLinus Walleij
10036dc01aa6SChanho Min pl011_dma_rx_chars(uap, pending, lastbuf, false);
10042432f71cSSebastian Andrzej Siewior uart_unlock_and_check_sysrq(&uap->port);
1005ead76f32SLinus Walleij /*
1006ead76f32SLinus Walleij * Do this check after we picked the DMA chars so we don't
1007ead76f32SLinus Walleij * get some IRQ immediately from RX.
1008ead76f32SLinus Walleij */
1009ead76f32SLinus Walleij if (ret) {
1010fd64ff09SThéo Lebrun dev_dbg(uap->port.dev,
1011fd64ff09SThéo Lebrun "could not retrigger RX DMA job fall back to interrupt mode\n");
1012ead76f32SLinus Walleij uap->im |= UART011_RXIM;
10139f25bc51SRussell King pl011_write(uap->im, uap, REG_IMSC);
1014ead76f32SLinus Walleij }
1015ead76f32SLinus Walleij }
1016ead76f32SLinus Walleij
1017ead76f32SLinus Walleij /*
1018ead76f32SLinus Walleij * Stop accepting received characters, when we're shutting down or
1019ead76f32SLinus Walleij * suspending this port.
1020ead76f32SLinus Walleij * Locking: called with port lock held and IRQs disabled.
1021ead76f32SLinus Walleij */
pl011_dma_rx_stop(struct uart_amba_port * uap)1022ead76f32SLinus Walleij static inline void pl011_dma_rx_stop(struct uart_amba_port *uap)
1023ead76f32SLinus Walleij {
102494cdb9f3SJiamei Xie if (!uap->using_rx_dma)
102594cdb9f3SJiamei Xie return;
102694cdb9f3SJiamei Xie
1027ead76f32SLinus Walleij /* FIXME. Just disable the DMA enable */
1028ead76f32SLinus Walleij uap->dmacr &= ~UART011_RXDMAE;
10299f25bc51SRussell King pl011_write(uap->dmacr, uap, REG_DMACR);
1030ead76f32SLinus Walleij }
1031ab4382d2SGreg Kroah-Hartman
1032cb06ff10SChanho Min /*
1033cb06ff10SChanho Min * Timer handler for Rx DMA polling.
1034cb06ff10SChanho Min * Every polling, It checks the residue in the dma buffer and transfer
1035cb06ff10SChanho Min * data to the tty. Also, last_residue is updated for the next polling.
1036cb06ff10SChanho Min */
pl011_dma_rx_poll(struct timer_list * t)1037f7f73096SKees Cook static void pl011_dma_rx_poll(struct timer_list *t)
1038cb06ff10SChanho Min {
1039f7f73096SKees Cook struct uart_amba_port *uap = from_timer(uap, t, dmarx.timer);
1040cb06ff10SChanho Min struct tty_port *port = &uap->port.state->port;
1041cb06ff10SChanho Min struct pl011_dmarx_data *dmarx = &uap->dmarx;
1042cb06ff10SChanho Min struct dma_chan *rxchan = uap->dmarx.chan;
104318ee37e1SJohan Hovold unsigned long flags;
1044cb06ff10SChanho Min unsigned int dmataken = 0;
1045cb06ff10SChanho Min unsigned int size = 0;
104658ac1b37SArnd Bergmann struct pl011_dmabuf *dbuf;
1047cb06ff10SChanho Min int dma_count;
1048cb06ff10SChanho Min struct dma_tx_state state;
1049cb06ff10SChanho Min
105058ac1b37SArnd Bergmann dbuf = dmarx->use_buf_b ? &uap->dmarx.dbuf_b : &uap->dmarx.dbuf_a;
1051cb06ff10SChanho Min rxchan->device->device_tx_status(rxchan, dmarx->cookie, &state);
1052cb06ff10SChanho Min if (likely(state.residue < dmarx->last_residue)) {
105358ac1b37SArnd Bergmann dmataken = dbuf->len - dmarx->last_residue;
1054cb06ff10SChanho Min size = dmarx->last_residue - state.residue;
105558ac1b37SArnd Bergmann dma_count = tty_insert_flip_string(port, dbuf->buf + dmataken,
1056cb06ff10SChanho Min size);
1057cb06ff10SChanho Min if (dma_count == size)
1058cb06ff10SChanho Min dmarx->last_residue = state.residue;
1059cb06ff10SChanho Min dmarx->last_jiffies = jiffies;
1060cb06ff10SChanho Min }
1061cb06ff10SChanho Min tty_flip_buffer_push(port);
1062cb06ff10SChanho Min
1063cb06ff10SChanho Min /*
1064cb06ff10SChanho Min * If no data is received in poll_timeout, the driver will fall back
1065cb06ff10SChanho Min * to interrupt mode. We will retrigger DMA at the first interrupt.
1066cb06ff10SChanho Min */
1067cb06ff10SChanho Min if (jiffies_to_msecs(jiffies - dmarx->last_jiffies)
1068cb06ff10SChanho Min > uap->dmarx.poll_timeout) {
106968ca3e72SThomas Gleixner uart_port_lock_irqsave(&uap->port, &flags);
1070cb06ff10SChanho Min pl011_dma_rx_stop(uap);
1071c25a1ad7SGuennadi Liakhovetski uap->im |= UART011_RXIM;
10729f25bc51SRussell King pl011_write(uap->im, uap, REG_IMSC);
107368ca3e72SThomas Gleixner uart_port_unlock_irqrestore(&uap->port, flags);
1074cb06ff10SChanho Min
1075cb06ff10SChanho Min uap->dmarx.running = false;
1076cb06ff10SChanho Min dmaengine_terminate_all(rxchan);
1077cb06ff10SChanho Min del_timer(&uap->dmarx.timer);
1078cb06ff10SChanho Min } else {
1079cb06ff10SChanho Min mod_timer(&uap->dmarx.timer,
1080cb06ff10SChanho Min jiffies + msecs_to_jiffies(uap->dmarx.poll_rate));
1081cb06ff10SChanho Min }
1082cb06ff10SChanho Min }
1083cb06ff10SChanho Min
pl011_dma_startup(struct uart_amba_port * uap)1084ab4382d2SGreg Kroah-Hartman static void pl011_dma_startup(struct uart_amba_port *uap)
1085ab4382d2SGreg Kroah-Hartman {
1086ead76f32SLinus Walleij int ret;
1087ead76f32SLinus Walleij
10881c9be310SJorge Ramirez-Ortiz if (!uap->dma_probed)
10891c9be310SJorge Ramirez-Ortiz pl011_dma_probe(uap);
10901c9be310SJorge Ramirez-Ortiz
1091ab4382d2SGreg Kroah-Hartman if (!uap->dmatx.chan)
1092ab4382d2SGreg Kroah-Hartman return;
1093ab4382d2SGreg Kroah-Hartman
10944c0be45bSAndrew Jackson uap->dmatx.buf = kmalloc(PL011_DMA_BUFFER_SIZE, GFP_KERNEL | __GFP_DMA);
1095ab4382d2SGreg Kroah-Hartman if (!uap->dmatx.buf) {
1096ab4382d2SGreg Kroah-Hartman uap->port.fifosize = uap->fifosize;
1097ab4382d2SGreg Kroah-Hartman return;
1098ab4382d2SGreg Kroah-Hartman }
1099ab4382d2SGreg Kroah-Hartman
110058ac1b37SArnd Bergmann uap->dmatx.len = PL011_DMA_BUFFER_SIZE;
1101ab4382d2SGreg Kroah-Hartman
1102ab4382d2SGreg Kroah-Hartman /* The DMA buffer is now the FIFO the TTY subsystem can use */
1103ab4382d2SGreg Kroah-Hartman uap->port.fifosize = PL011_DMA_BUFFER_SIZE;
1104ead76f32SLinus Walleij uap->using_tx_dma = true;
1105ab4382d2SGreg Kroah-Hartman
1106ead76f32SLinus Walleij if (!uap->dmarx.chan)
1107ead76f32SLinus Walleij goto skip_rx;
1108ead76f32SLinus Walleij
1109ead76f32SLinus Walleij /* Allocate and map DMA RX buffers */
111058ac1b37SArnd Bergmann ret = pl011_dmabuf_init(uap->dmarx.chan, &uap->dmarx.dbuf_a,
1111ead76f32SLinus Walleij DMA_FROM_DEVICE);
1112ead76f32SLinus Walleij if (ret) {
1113ead76f32SLinus Walleij dev_err(uap->port.dev, "failed to init DMA %s: %d\n",
1114ead76f32SLinus Walleij "RX buffer A", ret);
1115ead76f32SLinus Walleij goto skip_rx;
1116ead76f32SLinus Walleij }
1117ead76f32SLinus Walleij
111858ac1b37SArnd Bergmann ret = pl011_dmabuf_init(uap->dmarx.chan, &uap->dmarx.dbuf_b,
1119ead76f32SLinus Walleij DMA_FROM_DEVICE);
1120ead76f32SLinus Walleij if (ret) {
1121ead76f32SLinus Walleij dev_err(uap->port.dev, "failed to init DMA %s: %d\n",
1122ead76f32SLinus Walleij "RX buffer B", ret);
112358ac1b37SArnd Bergmann pl011_dmabuf_free(uap->dmarx.chan, &uap->dmarx.dbuf_a,
1124ead76f32SLinus Walleij DMA_FROM_DEVICE);
1125ead76f32SLinus Walleij goto skip_rx;
1126ead76f32SLinus Walleij }
1127ead76f32SLinus Walleij
1128ead76f32SLinus Walleij uap->using_rx_dma = true;
1129ead76f32SLinus Walleij
1130ead76f32SLinus Walleij skip_rx:
1131ab4382d2SGreg Kroah-Hartman /* Turn on DMA error (RX/TX will be enabled on demand) */
1132ab4382d2SGreg Kroah-Hartman uap->dmacr |= UART011_DMAONERR;
11339f25bc51SRussell King pl011_write(uap->dmacr, uap, REG_DMACR);
1134ab4382d2SGreg Kroah-Hartman
1135ab4382d2SGreg Kroah-Hartman /*
1136ab4382d2SGreg Kroah-Hartman * ST Micro variants has some specific dma burst threshold
1137ab4382d2SGreg Kroah-Hartman * compensation. Set this to 16 bytes, so burst will only
1138ab4382d2SGreg Kroah-Hartman * be issued above/below 16 bytes.
1139ab4382d2SGreg Kroah-Hartman */
1140ab4382d2SGreg Kroah-Hartman if (uap->vendor->dma_threshold)
114175836339SRussell King pl011_write(ST_UART011_DMAWM_RX_16 | ST_UART011_DMAWM_TX_16,
11429f25bc51SRussell King uap, REG_ST_DMAWM);
1143ead76f32SLinus Walleij
1144ead76f32SLinus Walleij if (uap->using_rx_dma) {
1145ead76f32SLinus Walleij if (pl011_dma_rx_trigger_dma(uap))
1146fd64ff09SThéo Lebrun dev_dbg(uap->port.dev,
1147fd64ff09SThéo Lebrun "could not trigger initial RX DMA job, fall back to interrupt mode\n");
1148cb06ff10SChanho Min if (uap->dmarx.poll_rate) {
1149f7f73096SKees Cook timer_setup(&uap->dmarx.timer, pl011_dma_rx_poll, 0);
1150cb06ff10SChanho Min mod_timer(&uap->dmarx.timer,
1151d93ebe0fSThéo Lebrun jiffies + msecs_to_jiffies(uap->dmarx.poll_rate));
1152cb06ff10SChanho Min uap->dmarx.last_residue = PL011_DMA_BUFFER_SIZE;
1153cb06ff10SChanho Min uap->dmarx.last_jiffies = jiffies;
1154cb06ff10SChanho Min }
1155ead76f32SLinus Walleij }
1156ab4382d2SGreg Kroah-Hartman }
1157ab4382d2SGreg Kroah-Hartman
pl011_dma_shutdown(struct uart_amba_port * uap)1158ab4382d2SGreg Kroah-Hartman static void pl011_dma_shutdown(struct uart_amba_port *uap)
1159ab4382d2SGreg Kroah-Hartman {
1160ead76f32SLinus Walleij if (!(uap->using_tx_dma || uap->using_rx_dma))
1161ab4382d2SGreg Kroah-Hartman return;
1162ab4382d2SGreg Kroah-Hartman
1163ab4382d2SGreg Kroah-Hartman /* Disable RX and TX DMA */
11640e125a5fSShawn Guo while (pl011_read(uap, REG_FR) & uap->vendor->fr_busy)
11652f2fd089STimur Tabi cpu_relax();
1166ab4382d2SGreg Kroah-Hartman
116768ca3e72SThomas Gleixner uart_port_lock_irq(&uap->port);
1168ab4382d2SGreg Kroah-Hartman uap->dmacr &= ~(UART011_DMAONERR | UART011_RXDMAE | UART011_TXDMAE);
11699f25bc51SRussell King pl011_write(uap->dmacr, uap, REG_DMACR);
117068ca3e72SThomas Gleixner uart_port_unlock_irq(&uap->port);
1171ab4382d2SGreg Kroah-Hartman
1172ead76f32SLinus Walleij if (uap->using_tx_dma) {
1173ab4382d2SGreg Kroah-Hartman /* In theory, this should already be done by pl011_dma_flush_buffer */
1174ab4382d2SGreg Kroah-Hartman dmaengine_terminate_all(uap->dmatx.chan);
1175ab4382d2SGreg Kroah-Hartman if (uap->dmatx.queued) {
117658ac1b37SArnd Bergmann dma_unmap_single(uap->dmatx.chan->device->dev,
117758ac1b37SArnd Bergmann uap->dmatx.dma, uap->dmatx.len,
1178ab4382d2SGreg Kroah-Hartman DMA_TO_DEVICE);
1179ab4382d2SGreg Kroah-Hartman uap->dmatx.queued = false;
1180ab4382d2SGreg Kroah-Hartman }
1181ab4382d2SGreg Kroah-Hartman
1182ab4382d2SGreg Kroah-Hartman kfree(uap->dmatx.buf);
1183ead76f32SLinus Walleij uap->using_tx_dma = false;
1184ab4382d2SGreg Kroah-Hartman }
1185ab4382d2SGreg Kroah-Hartman
1186ead76f32SLinus Walleij if (uap->using_rx_dma) {
1187ead76f32SLinus Walleij dmaengine_terminate_all(uap->dmarx.chan);
1188ead76f32SLinus Walleij /* Clean up the RX DMA */
118958ac1b37SArnd Bergmann pl011_dmabuf_free(uap->dmarx.chan, &uap->dmarx.dbuf_a, DMA_FROM_DEVICE);
119058ac1b37SArnd Bergmann pl011_dmabuf_free(uap->dmarx.chan, &uap->dmarx.dbuf_b, DMA_FROM_DEVICE);
1191cb06ff10SChanho Min if (uap->dmarx.poll_rate)
1192cb06ff10SChanho Min del_timer_sync(&uap->dmarx.timer);
1193ead76f32SLinus Walleij uap->using_rx_dma = false;
1194ead76f32SLinus Walleij }
1195ead76f32SLinus Walleij }
1196ead76f32SLinus Walleij
pl011_dma_rx_available(struct uart_amba_port * uap)1197ead76f32SLinus Walleij static inline bool pl011_dma_rx_available(struct uart_amba_port *uap)
1198ead76f32SLinus Walleij {
1199ead76f32SLinus Walleij return uap->using_rx_dma;
1200ead76f32SLinus Walleij }
1201ead76f32SLinus Walleij
pl011_dma_rx_running(struct uart_amba_port * uap)1202ead76f32SLinus Walleij static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
1203ead76f32SLinus Walleij {
1204ead76f32SLinus Walleij return uap->using_rx_dma && uap->dmarx.running;
1205ead76f32SLinus Walleij }
1206ead76f32SLinus Walleij
1207ab4382d2SGreg Kroah-Hartman #else
1208ab4382d2SGreg Kroah-Hartman /* Blank functions if the DMA engine is not available */
pl011_dma_remove(struct uart_amba_port * uap)1209ab4382d2SGreg Kroah-Hartman static inline void pl011_dma_remove(struct uart_amba_port *uap)
1210ab4382d2SGreg Kroah-Hartman {
1211ab4382d2SGreg Kroah-Hartman }
1212ab4382d2SGreg Kroah-Hartman
pl011_dma_startup(struct uart_amba_port * uap)1213ab4382d2SGreg Kroah-Hartman static inline void pl011_dma_startup(struct uart_amba_port *uap)
1214ab4382d2SGreg Kroah-Hartman {
1215ab4382d2SGreg Kroah-Hartman }
1216ab4382d2SGreg Kroah-Hartman
pl011_dma_shutdown(struct uart_amba_port * uap)1217ab4382d2SGreg Kroah-Hartman static inline void pl011_dma_shutdown(struct uart_amba_port *uap)
1218ab4382d2SGreg Kroah-Hartman {
1219ab4382d2SGreg Kroah-Hartman }
1220ab4382d2SGreg Kroah-Hartman
pl011_dma_tx_irq(struct uart_amba_port * uap)1221ab4382d2SGreg Kroah-Hartman static inline bool pl011_dma_tx_irq(struct uart_amba_port *uap)
1222ab4382d2SGreg Kroah-Hartman {
1223ab4382d2SGreg Kroah-Hartman return false;
1224ab4382d2SGreg Kroah-Hartman }
1225ab4382d2SGreg Kroah-Hartman
pl011_dma_tx_stop(struct uart_amba_port * uap)1226ab4382d2SGreg Kroah-Hartman static inline void pl011_dma_tx_stop(struct uart_amba_port *uap)
1227ab4382d2SGreg Kroah-Hartman {
1228ab4382d2SGreg Kroah-Hartman }
1229ab4382d2SGreg Kroah-Hartman
pl011_dma_tx_start(struct uart_amba_port * uap)1230ab4382d2SGreg Kroah-Hartman static inline bool pl011_dma_tx_start(struct uart_amba_port *uap)
1231ab4382d2SGreg Kroah-Hartman {
1232ab4382d2SGreg Kroah-Hartman return false;
1233ab4382d2SGreg Kroah-Hartman }
1234ab4382d2SGreg Kroah-Hartman
pl011_dma_rx_irq(struct uart_amba_port * uap)1235ead76f32SLinus Walleij static inline void pl011_dma_rx_irq(struct uart_amba_port *uap)
1236ead76f32SLinus Walleij {
1237ead76f32SLinus Walleij }
1238ead76f32SLinus Walleij
pl011_dma_rx_stop(struct uart_amba_port * uap)1239ead76f32SLinus Walleij static inline void pl011_dma_rx_stop(struct uart_amba_port *uap)
1240ead76f32SLinus Walleij {
1241ead76f32SLinus Walleij }
1242ead76f32SLinus Walleij
pl011_dma_rx_trigger_dma(struct uart_amba_port * uap)1243ead76f32SLinus Walleij static inline int pl011_dma_rx_trigger_dma(struct uart_amba_port *uap)
1244ead76f32SLinus Walleij {
1245ead76f32SLinus Walleij return -EIO;
1246ead76f32SLinus Walleij }
1247ead76f32SLinus Walleij
pl011_dma_rx_available(struct uart_amba_port * uap)1248ead76f32SLinus Walleij static inline bool pl011_dma_rx_available(struct uart_amba_port *uap)
1249ead76f32SLinus Walleij {
1250ead76f32SLinus Walleij return false;
1251ead76f32SLinus Walleij }
1252ead76f32SLinus Walleij
pl011_dma_rx_running(struct uart_amba_port * uap)1253ead76f32SLinus Walleij static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
1254ead76f32SLinus Walleij {
1255ead76f32SLinus Walleij return false;
1256ead76f32SLinus Walleij }
1257ead76f32SLinus Walleij
1258ab4382d2SGreg Kroah-Hartman #define pl011_dma_flush_buffer NULL
1259ab4382d2SGreg Kroah-Hartman #endif
1260ab4382d2SGreg Kroah-Hartman
pl011_rs485_tx_stop(struct uart_amba_port * uap)12618d479237SLino Sanfilippo static void pl011_rs485_tx_stop(struct uart_amba_port *uap)
12628d479237SLino Sanfilippo {
12630e4deb56SLino Sanfilippo /*
12640e4deb56SLino Sanfilippo * To be on the safe side only time out after twice as many iterations
12650e4deb56SLino Sanfilippo * as fifo size.
12660e4deb56SLino Sanfilippo */
12670e4deb56SLino Sanfilippo const int MAX_TX_DRAIN_ITERS = uap->port.fifosize * 2;
12688d479237SLino Sanfilippo struct uart_port *port = &uap->port;
12698d479237SLino Sanfilippo int i = 0;
12708d479237SLino Sanfilippo u32 cr;
12718d479237SLino Sanfilippo
12728d479237SLino Sanfilippo /* Wait until hardware tx queue is empty */
12738d479237SLino Sanfilippo while (!pl011_tx_empty(port)) {
12740e4deb56SLino Sanfilippo if (i > MAX_TX_DRAIN_ITERS) {
12758d479237SLino Sanfilippo dev_warn(port->dev,
12768d479237SLino Sanfilippo "timeout while draining hardware tx queue\n");
12778d479237SLino Sanfilippo break;
12788d479237SLino Sanfilippo }
12798d479237SLino Sanfilippo
12808d479237SLino Sanfilippo udelay(uap->rs485_tx_drain_interval);
12818d479237SLino Sanfilippo i++;
12828d479237SLino Sanfilippo }
12838d479237SLino Sanfilippo
12848d479237SLino Sanfilippo if (port->rs485.delay_rts_after_send)
12858d479237SLino Sanfilippo mdelay(port->rs485.delay_rts_after_send);
12868d479237SLino Sanfilippo
12878d479237SLino Sanfilippo cr = pl011_read(uap, REG_CR);
12888d479237SLino Sanfilippo
12898d479237SLino Sanfilippo if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
12908d479237SLino Sanfilippo cr &= ~UART011_CR_RTS;
12918d479237SLino Sanfilippo else
12928d479237SLino Sanfilippo cr |= UART011_CR_RTS;
12938d479237SLino Sanfilippo
12948d479237SLino Sanfilippo /* Disable the transmitter and reenable the transceiver */
12958d479237SLino Sanfilippo cr &= ~UART011_CR_TXE;
12968d479237SLino Sanfilippo cr |= UART011_CR_RXE;
12978d479237SLino Sanfilippo pl011_write(cr, uap, REG_CR);
12988d479237SLino Sanfilippo
12998d479237SLino Sanfilippo uap->rs485_tx_started = false;
13008d479237SLino Sanfilippo }
13018d479237SLino Sanfilippo
pl011_stop_tx(struct uart_port * port)1302ab4382d2SGreg Kroah-Hartman static void pl011_stop_tx(struct uart_port *port)
1303ab4382d2SGreg Kroah-Hartman {
1304a5820c24SDaniel Thompson struct uart_amba_port *uap =
1305a5820c24SDaniel Thompson container_of(port, struct uart_amba_port, port);
1306ab4382d2SGreg Kroah-Hartman
1307ab4382d2SGreg Kroah-Hartman uap->im &= ~UART011_TXIM;
13089f25bc51SRussell King pl011_write(uap->im, uap, REG_IMSC);
1309ab4382d2SGreg Kroah-Hartman pl011_dma_tx_stop(uap);
13108d479237SLino Sanfilippo
13118d479237SLino Sanfilippo if ((port->rs485.flags & SER_RS485_ENABLED) && uap->rs485_tx_started)
13128d479237SLino Sanfilippo pl011_rs485_tx_stop(uap);
1313ab4382d2SGreg Kroah-Hartman }
1314ab4382d2SGreg Kroah-Hartman
13157d05587cSJayachandran C static bool pl011_tx_chars(struct uart_amba_port *uap, bool from_irq);
1316734745caSDave Martin
1317734745caSDave Martin /* Start TX with programmed I/O only (no DMA) */
pl011_start_tx_pio(struct uart_amba_port * uap)1318734745caSDave Martin static void pl011_start_tx_pio(struct uart_amba_port *uap)
1319734745caSDave Martin {
13207d05587cSJayachandran C if (pl011_tx_chars(uap, false)) {
1321734745caSDave Martin uap->im |= UART011_TXIM;
13229f25bc51SRussell King pl011_write(uap->im, uap, REG_IMSC);
13237d05587cSJayachandran C }
1324734745caSDave Martin }
1325734745caSDave Martin
pl011_rs485_tx_start(struct uart_amba_port * uap)13263b69e32eSLino Sanfilippo static void pl011_rs485_tx_start(struct uart_amba_port *uap)
13273b69e32eSLino Sanfilippo {
13283b69e32eSLino Sanfilippo struct uart_port *port = &uap->port;
13293b69e32eSLino Sanfilippo u32 cr;
13303b69e32eSLino Sanfilippo
13313b69e32eSLino Sanfilippo /* Enable transmitter */
13323b69e32eSLino Sanfilippo cr = pl011_read(uap, REG_CR);
13333b69e32eSLino Sanfilippo cr |= UART011_CR_TXE;
13343b69e32eSLino Sanfilippo
13353b69e32eSLino Sanfilippo /* Disable receiver if half-duplex */
13363b69e32eSLino Sanfilippo if (!(port->rs485.flags & SER_RS485_RX_DURING_TX))
13373b69e32eSLino Sanfilippo cr &= ~UART011_CR_RXE;
13383b69e32eSLino Sanfilippo
13393b69e32eSLino Sanfilippo if (port->rs485.flags & SER_RS485_RTS_ON_SEND)
13403b69e32eSLino Sanfilippo cr &= ~UART011_CR_RTS;
13413b69e32eSLino Sanfilippo else
13423b69e32eSLino Sanfilippo cr |= UART011_CR_RTS;
13433b69e32eSLino Sanfilippo
13443b69e32eSLino Sanfilippo pl011_write(cr, uap, REG_CR);
13453b69e32eSLino Sanfilippo
13463b69e32eSLino Sanfilippo if (port->rs485.delay_rts_before_send)
13473b69e32eSLino Sanfilippo mdelay(port->rs485.delay_rts_before_send);
13483b69e32eSLino Sanfilippo
13493b69e32eSLino Sanfilippo uap->rs485_tx_started = true;
13503b69e32eSLino Sanfilippo }
13513b69e32eSLino Sanfilippo
pl011_start_tx(struct uart_port * port)1352ab4382d2SGreg Kroah-Hartman static void pl011_start_tx(struct uart_port *port)
1353ab4382d2SGreg Kroah-Hartman {
1354a5820c24SDaniel Thompson struct uart_amba_port *uap =
1355a5820c24SDaniel Thompson container_of(port, struct uart_amba_port, port);
1356ab4382d2SGreg Kroah-Hartman
13573b69e32eSLino Sanfilippo if ((uap->port.rs485.flags & SER_RS485_ENABLED) &&
13583b69e32eSLino Sanfilippo !uap->rs485_tx_started)
13593b69e32eSLino Sanfilippo pl011_rs485_tx_start(uap);
13603b69e32eSLino Sanfilippo
1361734745caSDave Martin if (!pl011_dma_tx_start(uap))
1362734745caSDave Martin pl011_start_tx_pio(uap);
1363ab4382d2SGreg Kroah-Hartman }
1364ab4382d2SGreg Kroah-Hartman
pl011_stop_rx(struct uart_port * port)1365ab4382d2SGreg Kroah-Hartman static void pl011_stop_rx(struct uart_port *port)
1366ab4382d2SGreg Kroah-Hartman {
1367a5820c24SDaniel Thompson struct uart_amba_port *uap =
1368a5820c24SDaniel Thompson container_of(port, struct uart_amba_port, port);
1369ab4382d2SGreg Kroah-Hartman
1370ab4382d2SGreg Kroah-Hartman uap->im &= ~(UART011_RXIM | UART011_RTIM | UART011_FEIM |
1371ab4382d2SGreg Kroah-Hartman UART011_PEIM | UART011_BEIM | UART011_OEIM);
13729f25bc51SRussell King pl011_write(uap->im, uap, REG_IMSC);
1373ead76f32SLinus Walleij
1374ead76f32SLinus Walleij pl011_dma_rx_stop(uap);
1375ab4382d2SGreg Kroah-Hartman }
1376ab4382d2SGreg Kroah-Hartman
pl011_throttle_rx(struct uart_port * port)1377211565b1SIlpo Järvinen static void pl011_throttle_rx(struct uart_port *port)
1378211565b1SIlpo Järvinen {
1379211565b1SIlpo Järvinen unsigned long flags;
1380211565b1SIlpo Järvinen
138168ca3e72SThomas Gleixner uart_port_lock_irqsave(port, &flags);
1382211565b1SIlpo Järvinen pl011_stop_rx(port);
138368ca3e72SThomas Gleixner uart_port_unlock_irqrestore(port, flags);
1384211565b1SIlpo Järvinen }
1385211565b1SIlpo Järvinen
pl011_enable_ms(struct uart_port * port)1386ab4382d2SGreg Kroah-Hartman static void pl011_enable_ms(struct uart_port *port)
1387ab4382d2SGreg Kroah-Hartman {
1388a5820c24SDaniel Thompson struct uart_amba_port *uap =
1389a5820c24SDaniel Thompson container_of(port, struct uart_amba_port, port);
1390ab4382d2SGreg Kroah-Hartman
1391ab4382d2SGreg Kroah-Hartman uap->im |= UART011_RIMIM | UART011_CTSMIM | UART011_DCDMIM | UART011_DSRMIM;
13929f25bc51SRussell King pl011_write(uap->im, uap, REG_IMSC);
1393ab4382d2SGreg Kroah-Hartman }
1394ab4382d2SGreg Kroah-Hartman
pl011_rx_chars(struct uart_amba_port * uap)1395ab4382d2SGreg Kroah-Hartman static void pl011_rx_chars(struct uart_amba_port *uap)
1396b83286bfSFabio Estevam __releases(&uap->port.lock)
1397b83286bfSFabio Estevam __acquires(&uap->port.lock)
1398ab4382d2SGreg Kroah-Hartman {
139929772c4eSLinus Walleij pl011_fifo_to_tty(uap);
1400ab4382d2SGreg Kroah-Hartman
140168ca3e72SThomas Gleixner uart_port_unlock(&uap->port);
14022e124b4aSJiri Slaby tty_flip_buffer_push(&uap->port.state->port);
1403ead76f32SLinus Walleij /*
1404ead76f32SLinus Walleij * If we were temporarily out of DMA mode for a while,
1405ead76f32SLinus Walleij * attempt to switch back to DMA mode again.
1406ead76f32SLinus Walleij */
1407ead76f32SLinus Walleij if (pl011_dma_rx_available(uap)) {
1408ead76f32SLinus Walleij if (pl011_dma_rx_trigger_dma(uap)) {
1409fd64ff09SThéo Lebrun dev_dbg(uap->port.dev,
1410fd64ff09SThéo Lebrun "could not trigger RX DMA job fall back to interrupt mode again\n");
1411ead76f32SLinus Walleij uap->im |= UART011_RXIM;
14129f25bc51SRussell King pl011_write(uap->im, uap, REG_IMSC);
1413cb06ff10SChanho Min } else {
141489fa28dbSChanho Min #ifdef CONFIG_DMA_ENGINE
1415cb06ff10SChanho Min /* Start Rx DMA poll */
1416cb06ff10SChanho Min if (uap->dmarx.poll_rate) {
1417cb06ff10SChanho Min uap->dmarx.last_jiffies = jiffies;
1418cb06ff10SChanho Min uap->dmarx.last_residue = PL011_DMA_BUFFER_SIZE;
1419cb06ff10SChanho Min mod_timer(&uap->dmarx.timer,
1420d93ebe0fSThéo Lebrun jiffies + msecs_to_jiffies(uap->dmarx.poll_rate));
1421cb06ff10SChanho Min }
142289fa28dbSChanho Min #endif
1423cb06ff10SChanho Min }
1424ead76f32SLinus Walleij }
142568ca3e72SThomas Gleixner uart_port_lock(&uap->port);
1426ab4382d2SGreg Kroah-Hartman }
1427ab4382d2SGreg Kroah-Hartman
pl011_tx_char(struct uart_amba_port * uap,unsigned char c,bool from_irq)14281e84d223SDave Martin static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c,
14291e84d223SDave Martin bool from_irq)
1430734745caSDave Martin {
14311e84d223SDave Martin if (unlikely(!from_irq) &&
14329f25bc51SRussell King pl011_read(uap, REG_FR) & UART01x_FR_TXFF)
14331e84d223SDave Martin return false; /* unable to transmit character */
14341e84d223SDave Martin
14359f25bc51SRussell King pl011_write(c, uap, REG_DR);
1436734745caSDave Martin uap->port.icount.tx++;
1437734745caSDave Martin
1438734745caSDave Martin return true;
1439734745caSDave Martin }
1440734745caSDave Martin
14417d05587cSJayachandran C /* Returns true if tx interrupts have to be (kept) enabled */
pl011_tx_chars(struct uart_amba_port * uap,bool from_irq)14427d05587cSJayachandran C static bool pl011_tx_chars(struct uart_amba_port *uap, bool from_irq)
1443ab4382d2SGreg Kroah-Hartman {
14441788cf6aSJiri Slaby (SUSE) struct tty_port *tport = &uap->port.state->port;
14451e84d223SDave Martin int count = uap->fifosize >> 1;
1446734745caSDave Martin
1447ab4382d2SGreg Kroah-Hartman if (uap->port.x_char) {
14481e84d223SDave Martin if (!pl011_tx_char(uap, uap->port.x_char, from_irq))
14497d05587cSJayachandran C return true;
1450ab4382d2SGreg Kroah-Hartman uap->port.x_char = 0;
1451734745caSDave Martin --count;
1452ab4382d2SGreg Kroah-Hartman }
14531788cf6aSJiri Slaby (SUSE) if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(&uap->port)) {
1454ab4382d2SGreg Kroah-Hartman pl011_stop_tx(&uap->port);
14557d05587cSJayachandran C return false;
1456ab4382d2SGreg Kroah-Hartman }
1457ab4382d2SGreg Kroah-Hartman
1458ab4382d2SGreg Kroah-Hartman /* If we are using DMA mode, try to send some characters. */
1459ab4382d2SGreg Kroah-Hartman if (pl011_dma_tx_irq(uap))
14607d05587cSJayachandran C return true;
1461ab4382d2SGreg Kroah-Hartman
14621788cf6aSJiri Slaby (SUSE) while (1) {
14631788cf6aSJiri Slaby (SUSE) unsigned char c;
14641788cf6aSJiri Slaby (SUSE)
14651e84d223SDave Martin if (likely(from_irq) && count-- == 0)
1466ab4382d2SGreg Kroah-Hartman break;
14671e84d223SDave Martin
14681788cf6aSJiri Slaby (SUSE) if (!kfifo_peek(&tport->xmit_fifo, &c))
14691e84d223SDave Martin break;
14701e84d223SDave Martin
14711788cf6aSJiri Slaby (SUSE) if (!pl011_tx_char(uap, c, from_irq))
14721788cf6aSJiri Slaby (SUSE) break;
1473ab4382d2SGreg Kroah-Hartman
14741788cf6aSJiri Slaby (SUSE) kfifo_skip(&tport->xmit_fifo);
14751788cf6aSJiri Slaby (SUSE) }
14761788cf6aSJiri Slaby (SUSE)
14771788cf6aSJiri Slaby (SUSE) if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
1478ab4382d2SGreg Kroah-Hartman uart_write_wakeup(&uap->port);
1479ab4382d2SGreg Kroah-Hartman
14801788cf6aSJiri Slaby (SUSE) if (kfifo_is_empty(&tport->xmit_fifo)) {
1481ab4382d2SGreg Kroah-Hartman pl011_stop_tx(&uap->port);
14827d05587cSJayachandran C return false;
14837d05587cSJayachandran C }
14847d05587cSJayachandran C return true;
1485ab4382d2SGreg Kroah-Hartman }
1486ab4382d2SGreg Kroah-Hartman
pl011_modem_status(struct uart_amba_port * uap)1487ab4382d2SGreg Kroah-Hartman static void pl011_modem_status(struct uart_amba_port *uap)
1488ab4382d2SGreg Kroah-Hartman {
1489ab4382d2SGreg Kroah-Hartman unsigned int status, delta;
1490ab4382d2SGreg Kroah-Hartman
14919f25bc51SRussell King status = pl011_read(uap, REG_FR) & UART01x_FR_MODEM_ANY;
1492ab4382d2SGreg Kroah-Hartman
1493ab4382d2SGreg Kroah-Hartman delta = status ^ uap->old_status;
1494ab4382d2SGreg Kroah-Hartman uap->old_status = status;
1495ab4382d2SGreg Kroah-Hartman
1496ab4382d2SGreg Kroah-Hartman if (!delta)
1497ab4382d2SGreg Kroah-Hartman return;
1498ab4382d2SGreg Kroah-Hartman
1499ab4382d2SGreg Kroah-Hartman if (delta & UART01x_FR_DCD)
1500ab4382d2SGreg Kroah-Hartman uart_handle_dcd_change(&uap->port, status & UART01x_FR_DCD);
1501ab4382d2SGreg Kroah-Hartman
15020e125a5fSShawn Guo if (delta & uap->vendor->fr_dsr)
1503ab4382d2SGreg Kroah-Hartman uap->port.icount.dsr++;
1504ab4382d2SGreg Kroah-Hartman
15050e125a5fSShawn Guo if (delta & uap->vendor->fr_cts)
15060e125a5fSShawn Guo uart_handle_cts_change(&uap->port,
15070e125a5fSShawn Guo status & uap->vendor->fr_cts);
1508ab4382d2SGreg Kroah-Hartman
1509ab4382d2SGreg Kroah-Hartman wake_up_interruptible(&uap->port.state->port.delta_msr_wait);
1510ab4382d2SGreg Kroah-Hartman }
1511ab4382d2SGreg Kroah-Hartman
check_apply_cts_event_workaround(struct uart_amba_port * uap)15129c4ef4b0SAndre Przywara static void check_apply_cts_event_workaround(struct uart_amba_port *uap)
1513ab4382d2SGreg Kroah-Hartman {
15149c4ef4b0SAndre Przywara if (!uap->vendor->cts_event_workaround)
15159c4ef4b0SAndre Przywara return;
15169c4ef4b0SAndre Przywara
15174fd0690bSRajanikanth H.V /* workaround to make sure that all bits are unlocked.. */
15189f25bc51SRussell King pl011_write(0x00, uap, REG_ICR);
15194fd0690bSRajanikanth H.V
15204fd0690bSRajanikanth H.V /*
15214fd0690bSRajanikanth H.V * WA: introduce 26ns(1 uart clk) delay before W1C;
15224fd0690bSRajanikanth H.V * single apb access will incur 2 pclk(133.12Mhz) delay,
15234fd0690bSRajanikanth H.V * so add 2 dummy reads
15244fd0690bSRajanikanth H.V */
152594345aeeSXiongfeng Wang pl011_read(uap, REG_ICR);
152694345aeeSXiongfeng Wang pl011_read(uap, REG_ICR);
15274fd0690bSRajanikanth H.V }
15284fd0690bSRajanikanth H.V
pl011_int(int irq,void * dev_id)15299c4ef4b0SAndre Przywara static irqreturn_t pl011_int(int irq, void *dev_id)
15309c4ef4b0SAndre Przywara {
15319c4ef4b0SAndre Przywara struct uart_amba_port *uap = dev_id;
15329c4ef4b0SAndre Przywara unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
15339c4ef4b0SAndre Przywara int handled = 0;
15349c4ef4b0SAndre Przywara
15352432f71cSSebastian Andrzej Siewior uart_port_lock(&uap->port);
1536d3a96c94SLukas Wunner status = pl011_read(uap, REG_RIS) & uap->im;
15379c4ef4b0SAndre Przywara if (status) {
15389c4ef4b0SAndre Przywara do {
15399c4ef4b0SAndre Przywara check_apply_cts_event_workaround(uap);
1540f11c9841SGreg Kroah-Hartman
1541d93ebe0fSThéo Lebrun pl011_write(status & ~(UART011_TXIS | UART011_RTIS | UART011_RXIS),
15429f25bc51SRussell King uap, REG_ICR);
1543ab4382d2SGreg Kroah-Hartman
1544ead76f32SLinus Walleij if (status & (UART011_RTIS | UART011_RXIS)) {
1545ead76f32SLinus Walleij if (pl011_dma_rx_running(uap))
1546ead76f32SLinus Walleij pl011_dma_rx_irq(uap);
1547ead76f32SLinus Walleij else
1548ab4382d2SGreg Kroah-Hartman pl011_rx_chars(uap);
1549ead76f32SLinus Walleij }
1550ab4382d2SGreg Kroah-Hartman if (status & (UART011_DSRMIS | UART011_DCDMIS |
1551ab4382d2SGreg Kroah-Hartman UART011_CTSMIS | UART011_RIMIS))
1552ab4382d2SGreg Kroah-Hartman pl011_modem_status(uap);
15531e84d223SDave Martin if (status & UART011_TXIS)
15541e84d223SDave Martin pl011_tx_chars(uap, true);
1555ab4382d2SGreg Kroah-Hartman
15564fd0690bSRajanikanth H.V if (pass_counter-- == 0)
1557ab4382d2SGreg Kroah-Hartman break;
1558ab4382d2SGreg Kroah-Hartman
1559d3a96c94SLukas Wunner status = pl011_read(uap, REG_RIS) & uap->im;
1560ab4382d2SGreg Kroah-Hartman } while (status != 0);
1561ab4382d2SGreg Kroah-Hartman handled = 1;
1562ab4382d2SGreg Kroah-Hartman }
1563ab4382d2SGreg Kroah-Hartman
15642432f71cSSebastian Andrzej Siewior uart_unlock_and_check_sysrq(&uap->port);
1565ab4382d2SGreg Kroah-Hartman
1566ab4382d2SGreg Kroah-Hartman return IRQ_RETVAL(handled);
1567ab4382d2SGreg Kroah-Hartman }
1568ab4382d2SGreg Kroah-Hartman
pl011_tx_empty(struct uart_port * port)1569e643f87fSLinus Walleij static unsigned int pl011_tx_empty(struct uart_port *port)
1570ab4382d2SGreg Kroah-Hartman {
1571a5820c24SDaniel Thompson struct uart_amba_port *uap =
1572a5820c24SDaniel Thompson container_of(port, struct uart_amba_port, port);
1573d8a4995bSChristopher Covington
1574d8a4995bSChristopher Covington /* Allow feature register bits to be inverted to work around errata */
1575d8a4995bSChristopher Covington unsigned int status = pl011_read(uap, REG_FR) ^ uap->vendor->inv_fr;
1576d8a4995bSChristopher Covington
15770e125a5fSShawn Guo return status & (uap->vendor->fr_busy | UART01x_FR_TXFF) ?
15780e125a5fSShawn Guo 0 : TIOCSER_TEMT;
1579ab4382d2SGreg Kroah-Hartman }
1580ab4382d2SGreg Kroah-Hartman
pl011_maybe_set_bit(bool cond,unsigned int * ptr,unsigned int mask)1581dc00f0ccSThéo Lebrun static void pl011_maybe_set_bit(bool cond, unsigned int *ptr, unsigned int mask)
1582dc00f0ccSThéo Lebrun {
1583dc00f0ccSThéo Lebrun if (cond)
1584dc00f0ccSThéo Lebrun *ptr |= mask;
1585dc00f0ccSThéo Lebrun }
1586dc00f0ccSThéo Lebrun
pl011_get_mctrl(struct uart_port * port)1587e643f87fSLinus Walleij static unsigned int pl011_get_mctrl(struct uart_port *port)
1588ab4382d2SGreg Kroah-Hartman {
1589a5820c24SDaniel Thompson struct uart_amba_port *uap =
1590a5820c24SDaniel Thompson container_of(port, struct uart_amba_port, port);
1591ab4382d2SGreg Kroah-Hartman unsigned int result = 0;
15929f25bc51SRussell King unsigned int status = pl011_read(uap, REG_FR);
1593ab4382d2SGreg Kroah-Hartman
1594dc00f0ccSThéo Lebrun pl011_maybe_set_bit(status & UART01x_FR_DCD, &result, TIOCM_CAR);
1595dc00f0ccSThéo Lebrun pl011_maybe_set_bit(status & uap->vendor->fr_dsr, &result, TIOCM_DSR);
1596dc00f0ccSThéo Lebrun pl011_maybe_set_bit(status & uap->vendor->fr_cts, &result, TIOCM_CTS);
1597dc00f0ccSThéo Lebrun pl011_maybe_set_bit(status & uap->vendor->fr_ri, &result, TIOCM_RNG);
1598ab4382d2SGreg Kroah-Hartman
1599ab4382d2SGreg Kroah-Hartman return result;
1600ab4382d2SGreg Kroah-Hartman }
1601ab4382d2SGreg Kroah-Hartman
pl011_assign_bit(bool cond,unsigned int * ptr,unsigned int mask)1602dc00f0ccSThéo Lebrun static void pl011_assign_bit(bool cond, unsigned int *ptr, unsigned int mask)
1603dc00f0ccSThéo Lebrun {
1604dc00f0ccSThéo Lebrun if (cond)
1605dc00f0ccSThéo Lebrun *ptr |= mask;
1606dc00f0ccSThéo Lebrun else
1607dc00f0ccSThéo Lebrun *ptr &= ~mask;
1608dc00f0ccSThéo Lebrun }
1609dc00f0ccSThéo Lebrun
pl011_set_mctrl(struct uart_port * port,unsigned int mctrl)1610ab4382d2SGreg Kroah-Hartman static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl)
1611ab4382d2SGreg Kroah-Hartman {
1612a5820c24SDaniel Thompson struct uart_amba_port *uap =
1613a5820c24SDaniel Thompson container_of(port, struct uart_amba_port, port);
1614ab4382d2SGreg Kroah-Hartman unsigned int cr;
1615ab4382d2SGreg Kroah-Hartman
16169f25bc51SRussell King cr = pl011_read(uap, REG_CR);
1617ab4382d2SGreg Kroah-Hartman
1618dc00f0ccSThéo Lebrun pl011_assign_bit(mctrl & TIOCM_RTS, &cr, UART011_CR_RTS);
1619dc00f0ccSThéo Lebrun pl011_assign_bit(mctrl & TIOCM_DTR, &cr, UART011_CR_DTR);
1620dc00f0ccSThéo Lebrun pl011_assign_bit(mctrl & TIOCM_OUT1, &cr, UART011_CR_OUT1);
1621dc00f0ccSThéo Lebrun pl011_assign_bit(mctrl & TIOCM_OUT2, &cr, UART011_CR_OUT2);
1622dc00f0ccSThéo Lebrun pl011_assign_bit(mctrl & TIOCM_LOOP, &cr, UART011_CR_LBE);
1623ab4382d2SGreg Kroah-Hartman
16242a76fa28SLukas Wunner if (port->status & UPSTAT_AUTORTS) {
1625ab4382d2SGreg Kroah-Hartman /* We need to disable auto-RTS if we want to turn RTS off */
1626dc00f0ccSThéo Lebrun pl011_assign_bit(mctrl & TIOCM_RTS, &cr, UART011_CR_RTSEN);
1627ab4382d2SGreg Kroah-Hartman }
1628ab4382d2SGreg Kroah-Hartman
16299f25bc51SRussell King pl011_write(cr, uap, REG_CR);
1630ab4382d2SGreg Kroah-Hartman }
1631ab4382d2SGreg Kroah-Hartman
pl011_break_ctl(struct uart_port * port,int break_state)1632ab4382d2SGreg Kroah-Hartman static void pl011_break_ctl(struct uart_port *port, int break_state)
1633ab4382d2SGreg Kroah-Hartman {
1634a5820c24SDaniel Thompson struct uart_amba_port *uap =
1635a5820c24SDaniel Thompson container_of(port, struct uart_amba_port, port);
1636ab4382d2SGreg Kroah-Hartman unsigned long flags;
1637ab4382d2SGreg Kroah-Hartman unsigned int lcr_h;
1638ab4382d2SGreg Kroah-Hartman
163968ca3e72SThomas Gleixner uart_port_lock_irqsave(&uap->port, &flags);
1640e4df9a80SRussell King lcr_h = pl011_read(uap, REG_LCRH_TX);
1641ab4382d2SGreg Kroah-Hartman if (break_state == -1)
1642ab4382d2SGreg Kroah-Hartman lcr_h |= UART01x_LCRH_BRK;
1643ab4382d2SGreg Kroah-Hartman else
1644ab4382d2SGreg Kroah-Hartman lcr_h &= ~UART01x_LCRH_BRK;
1645e4df9a80SRussell King pl011_write(lcr_h, uap, REG_LCRH_TX);
164668ca3e72SThomas Gleixner uart_port_unlock_irqrestore(&uap->port, flags);
1647ab4382d2SGreg Kroah-Hartman }
1648ab4382d2SGreg Kroah-Hartman
1649ab4382d2SGreg Kroah-Hartman #ifdef CONFIG_CONSOLE_POLL
16505c8124a0SAnton Vorontsov
pl011_quiesce_irqs(struct uart_port * port)16515c8124a0SAnton Vorontsov static void pl011_quiesce_irqs(struct uart_port *port)
16525c8124a0SAnton Vorontsov {
1653a5820c24SDaniel Thompson struct uart_amba_port *uap =
1654a5820c24SDaniel Thompson container_of(port, struct uart_amba_port, port);
16555c8124a0SAnton Vorontsov
16569f25bc51SRussell King pl011_write(pl011_read(uap, REG_MIS), uap, REG_ICR);
16575c8124a0SAnton Vorontsov /*
16585c8124a0SAnton Vorontsov * There is no way to clear TXIM as this is "ready to transmit IRQ", so
16595c8124a0SAnton Vorontsov * we simply mask it. start_tx() will unmask it.
16605c8124a0SAnton Vorontsov *
16615c8124a0SAnton Vorontsov * Note we can race with start_tx(), and if the race happens, the
16625c8124a0SAnton Vorontsov * polling user might get another interrupt just after we clear it.
16635c8124a0SAnton Vorontsov * But it should be OK and can happen even w/o the race, e.g.
16645c8124a0SAnton Vorontsov * controller immediately got some new data and raised the IRQ.
16655c8124a0SAnton Vorontsov *
16665c8124a0SAnton Vorontsov * And whoever uses polling routines assumes that it manages the device
16675c8124a0SAnton Vorontsov * (including tx queue), so we're also fine with start_tx()'s caller
16685c8124a0SAnton Vorontsov * side.
16695c8124a0SAnton Vorontsov */
16709f25bc51SRussell King pl011_write(pl011_read(uap, REG_IMSC) & ~UART011_TXIM, uap,
16719f25bc51SRussell King REG_IMSC);
16725c8124a0SAnton Vorontsov }
16735c8124a0SAnton Vorontsov
pl011_get_poll_char(struct uart_port * port)1674e643f87fSLinus Walleij static int pl011_get_poll_char(struct uart_port *port)
1675ab4382d2SGreg Kroah-Hartman {
1676a5820c24SDaniel Thompson struct uart_amba_port *uap =
1677a5820c24SDaniel Thompson container_of(port, struct uart_amba_port, port);
1678ab4382d2SGreg Kroah-Hartman unsigned int status;
1679ab4382d2SGreg Kroah-Hartman
16805c8124a0SAnton Vorontsov /*
16815c8124a0SAnton Vorontsov * The caller might need IRQs lowered, e.g. if used with KDB NMI
16825c8124a0SAnton Vorontsov * debugger.
16835c8124a0SAnton Vorontsov */
16845c8124a0SAnton Vorontsov pl011_quiesce_irqs(port);
16855c8124a0SAnton Vorontsov
16869f25bc51SRussell King status = pl011_read(uap, REG_FR);
1687ab4382d2SGreg Kroah-Hartman if (status & UART01x_FR_RXFE)
1688ab4382d2SGreg Kroah-Hartman return NO_POLL_CHAR;
1689ab4382d2SGreg Kroah-Hartman
16909f25bc51SRussell King return pl011_read(uap, REG_DR);
1691ab4382d2SGreg Kroah-Hartman }
1692ab4382d2SGreg Kroah-Hartman
pl011_put_poll_char(struct uart_port * port,unsigned char ch)1693d93ebe0fSThéo Lebrun static void pl011_put_poll_char(struct uart_port *port, unsigned char ch)
1694ab4382d2SGreg Kroah-Hartman {
1695a5820c24SDaniel Thompson struct uart_amba_port *uap =
1696a5820c24SDaniel Thompson container_of(port, struct uart_amba_port, port);
1697ab4382d2SGreg Kroah-Hartman
16989f25bc51SRussell King while (pl011_read(uap, REG_FR) & UART01x_FR_TXFF)
16992f2fd089STimur Tabi cpu_relax();
1700ab4382d2SGreg Kroah-Hartman
17019f25bc51SRussell King pl011_write(ch, uap, REG_DR);
1702ab4382d2SGreg Kroah-Hartman }
1703ab4382d2SGreg Kroah-Hartman
1704ab4382d2SGreg Kroah-Hartman #endif /* CONFIG_CONSOLE_POLL */
1705ab4382d2SGreg Kroah-Hartman
pl011_hwinit(struct uart_port * port)1706b3564c2cSAnton Vorontsov static int pl011_hwinit(struct uart_port *port)
1707ab4382d2SGreg Kroah-Hartman {
1708a5820c24SDaniel Thompson struct uart_amba_port *uap =
1709a5820c24SDaniel Thompson container_of(port, struct uart_amba_port, port);
1710ab4382d2SGreg Kroah-Hartman int retval;
1711ab4382d2SGreg Kroah-Hartman
171278d80c5aSLinus Walleij /* Optionaly enable pins to be muxed in and configured */
17132b996fc5SLinus Walleij pinctrl_pm_select_default_state(port->dev);
171478d80c5aSLinus Walleij
1715ab4382d2SGreg Kroah-Hartman /*
1716ab4382d2SGreg Kroah-Hartman * Try to enable the clock producer.
1717ab4382d2SGreg Kroah-Hartman */
17181c4c4394SJulia Lawall retval = clk_prepare_enable(uap->clk);
1719ab4382d2SGreg Kroah-Hartman if (retval)
17207f6d942aSTushar Behera return retval;
1721ab4382d2SGreg Kroah-Hartman
1722ab4382d2SGreg Kroah-Hartman uap->port.uartclk = clk_get_rate(uap->clk);
1723ab4382d2SGreg Kroah-Hartman
17249b96fbacSLinus Walleij /* Clear pending error and receive interrupts */
172575836339SRussell King pl011_write(UART011_OEIS | UART011_BEIS | UART011_PEIS |
172675836339SRussell King UART011_FEIS | UART011_RTIS | UART011_RXIS,
17279f25bc51SRussell King uap, REG_ICR);
17289b96fbacSLinus Walleij
1729ab4382d2SGreg Kroah-Hartman /*
1730b3564c2cSAnton Vorontsov * Save interrupts enable mask, and enable RX interrupts in case if
1731b3564c2cSAnton Vorontsov * the interrupt is used for NMI entry.
1732b3564c2cSAnton Vorontsov */
17339f25bc51SRussell King uap->im = pl011_read(uap, REG_IMSC);
17349f25bc51SRussell King pl011_write(UART011_RTIM | UART011_RXIM, uap, REG_IMSC);
1735b3564c2cSAnton Vorontsov
1736574de559SJingoo Han if (dev_get_platdata(uap->port.dev)) {
1737b3564c2cSAnton Vorontsov struct amba_pl011_data *plat;
1738b3564c2cSAnton Vorontsov
1739574de559SJingoo Han plat = dev_get_platdata(uap->port.dev);
1740b3564c2cSAnton Vorontsov if (plat->init)
1741b3564c2cSAnton Vorontsov plat->init();
1742b3564c2cSAnton Vorontsov }
1743b3564c2cSAnton Vorontsov return 0;
1744b3564c2cSAnton Vorontsov }
1745b3564c2cSAnton Vorontsov
pl011_split_lcrh(const struct uart_amba_port * uap)17467fe9a5a9SRussell King static bool pl011_split_lcrh(const struct uart_amba_port *uap)
17477fe9a5a9SRussell King {
1748e4df9a80SRussell King return pl011_reg_to_offset(uap, REG_LCRH_RX) !=
1749e4df9a80SRussell King pl011_reg_to_offset(uap, REG_LCRH_TX);
17507fe9a5a9SRussell King }
17517fe9a5a9SRussell King
pl011_write_lcr_h(struct uart_amba_port * uap,unsigned int lcr_h)1752b60f2f66SJon Medhurst static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h)
1753b60f2f66SJon Medhurst {
1754e4df9a80SRussell King pl011_write(lcr_h, uap, REG_LCRH_RX);
17557fe9a5a9SRussell King if (pl011_split_lcrh(uap)) {
1756b60f2f66SJon Medhurst int i;
1757b60f2f66SJon Medhurst /*
1758b60f2f66SJon Medhurst * Wait 10 PCLKs before writing LCRH_TX register,
1759b60f2f66SJon Medhurst * to get this delay write read only register 10 times
1760b60f2f66SJon Medhurst */
1761b60f2f66SJon Medhurst for (i = 0; i < 10; ++i)
17629f25bc51SRussell King pl011_write(0xff, uap, REG_MIS);
1763e4df9a80SRussell King pl011_write(lcr_h, uap, REG_LCRH_TX);
1764b60f2f66SJon Medhurst }
1765b60f2f66SJon Medhurst }
1766b60f2f66SJon Medhurst
pl011_allocate_irq(struct uart_amba_port * uap)1767867b8e8eSAndre Przywara static int pl011_allocate_irq(struct uart_amba_port *uap)
1768867b8e8eSAndre Przywara {
17699f25bc51SRussell King pl011_write(uap->im, uap, REG_IMSC);
1770867b8e8eSAndre Przywara
177194560f61SQian Cai return request_irq(uap->port.irq, pl011_int, IRQF_SHARED, "uart-pl011", uap);
1772867b8e8eSAndre Przywara }
1773867b8e8eSAndre Przywara
1774867b8e8eSAndre Przywara /*
1775867b8e8eSAndre Przywara * Enable interrupts, only timeouts when using DMA
1776867b8e8eSAndre Przywara * if initial RX DMA job failed, start in interrupt mode
1777867b8e8eSAndre Przywara * as well.
1778867b8e8eSAndre Przywara */
pl011_enable_interrupts(struct uart_amba_port * uap)1779867b8e8eSAndre Przywara static void pl011_enable_interrupts(struct uart_amba_port *uap)
1780867b8e8eSAndre Przywara {
1781211565b1SIlpo Järvinen unsigned long flags;
17824a7e625cSDave Martin unsigned int i;
17834a7e625cSDave Martin
178468ca3e72SThomas Gleixner uart_port_lock_irqsave(&uap->port, &flags);
1785867b8e8eSAndre Przywara
1786867b8e8eSAndre Przywara /* Clear out any spuriously appearing RX interrupts */
17879f25bc51SRussell King pl011_write(UART011_RTIS | UART011_RXIS, uap, REG_ICR);
17884a7e625cSDave Martin
17894a7e625cSDave Martin /*
17904a7e625cSDave Martin * RXIS is asserted only when the RX FIFO transitions from below
17914a7e625cSDave Martin * to above the trigger threshold. If the RX FIFO is already
17924a7e625cSDave Martin * full to the threshold this can't happen and RXIS will now be
17934a7e625cSDave Martin * stuck off. Drain the RX FIFO explicitly to fix this:
17944a7e625cSDave Martin */
17954a7e625cSDave Martin for (i = 0; i < uap->fifosize * 2; ++i) {
17964a7e625cSDave Martin if (pl011_read(uap, REG_FR) & UART01x_FR_RXFE)
17974a7e625cSDave Martin break;
17984a7e625cSDave Martin
17994a7e625cSDave Martin pl011_read(uap, REG_DR);
18004a7e625cSDave Martin }
18014a7e625cSDave Martin
1802867b8e8eSAndre Przywara uap->im = UART011_RTIM;
1803867b8e8eSAndre Przywara if (!pl011_dma_rx_running(uap))
1804867b8e8eSAndre Przywara uap->im |= UART011_RXIM;
18059f25bc51SRussell King pl011_write(uap->im, uap, REG_IMSC);
180668ca3e72SThomas Gleixner uart_port_unlock_irqrestore(&uap->port, flags);
1807211565b1SIlpo Järvinen }
1808211565b1SIlpo Järvinen
pl011_unthrottle_rx(struct uart_port * port)1809211565b1SIlpo Järvinen static void pl011_unthrottle_rx(struct uart_port *port)
1810211565b1SIlpo Järvinen {
1811211565b1SIlpo Järvinen struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port);
1812032d5a71Sdelisun unsigned long flags;
1813211565b1SIlpo Järvinen
181468ca3e72SThomas Gleixner uart_port_lock_irqsave(&uap->port, &flags);
1815032d5a71Sdelisun
1816032d5a71Sdelisun uap->im = UART011_RTIM;
1817032d5a71Sdelisun if (!pl011_dma_rx_running(uap))
1818032d5a71Sdelisun uap->im |= UART011_RXIM;
1819032d5a71Sdelisun
1820032d5a71Sdelisun pl011_write(uap->im, uap, REG_IMSC);
1821032d5a71Sdelisun
182268ca3e72SThomas Gleixner uart_port_unlock_irqrestore(&uap->port, flags);
1823867b8e8eSAndre Przywara }
1824867b8e8eSAndre Przywara
pl011_startup(struct uart_port * port)1825b3564c2cSAnton Vorontsov static int pl011_startup(struct uart_port *port)
1826b3564c2cSAnton Vorontsov {
1827a5820c24SDaniel Thompson struct uart_amba_port *uap =
1828a5820c24SDaniel Thompson container_of(port, struct uart_amba_port, port);
1829734745caSDave Martin unsigned int cr;
1830b3564c2cSAnton Vorontsov int retval;
1831b3564c2cSAnton Vorontsov
1832b3564c2cSAnton Vorontsov retval = pl011_hwinit(port);
1833b3564c2cSAnton Vorontsov if (retval)
1834b3564c2cSAnton Vorontsov goto clk_dis;
1835b3564c2cSAnton Vorontsov
1836867b8e8eSAndre Przywara retval = pl011_allocate_irq(uap);
1837ab4382d2SGreg Kroah-Hartman if (retval)
1838ab4382d2SGreg Kroah-Hartman goto clk_dis;
1839ab4382d2SGreg Kroah-Hartman
18409f25bc51SRussell King pl011_write(uap->vendor->ifls, uap, REG_IFLS);
1841ab4382d2SGreg Kroah-Hartman
184268ca3e72SThomas Gleixner uart_port_lock_irq(&uap->port);
1843fe433907SJon Medhurst
184449a80424SLukas Wunner cr = pl011_read(uap, REG_CR);
184549a80424SLukas Wunner cr &= UART011_CR_RTS | UART011_CR_DTR;
18468d479237SLino Sanfilippo cr |= UART01x_CR_UARTEN | UART011_CR_RXE;
18478d479237SLino Sanfilippo
18482dd8a74fSLukas Wunner if (!(port->rs485.flags & SER_RS485_ENABLED))
18498d479237SLino Sanfilippo cr |= UART011_CR_TXE;
18508d479237SLino Sanfilippo
18519f25bc51SRussell King pl011_write(cr, uap, REG_CR);
1852ab4382d2SGreg Kroah-Hartman
185368ca3e72SThomas Gleixner uart_port_unlock_irq(&uap->port);
1854fe433907SJon Medhurst
1855ab4382d2SGreg Kroah-Hartman /*
1856ab4382d2SGreg Kroah-Hartman * initialise the old status of the modem signals
1857ab4382d2SGreg Kroah-Hartman */
18589f25bc51SRussell King uap->old_status = pl011_read(uap, REG_FR) & UART01x_FR_MODEM_ANY;
1859ab4382d2SGreg Kroah-Hartman
1860ab4382d2SGreg Kroah-Hartman /* Startup DMA */
1861ab4382d2SGreg Kroah-Hartman pl011_dma_startup(uap);
1862ab4382d2SGreg Kroah-Hartman
1863867b8e8eSAndre Przywara pl011_enable_interrupts(uap);
1864ab4382d2SGreg Kroah-Hartman
1865ab4382d2SGreg Kroah-Hartman return 0;
1866ab4382d2SGreg Kroah-Hartman
1867ab4382d2SGreg Kroah-Hartman clk_dis:
18681c4c4394SJulia Lawall clk_disable_unprepare(uap->clk);
1869ab4382d2SGreg Kroah-Hartman return retval;
1870ab4382d2SGreg Kroah-Hartman }
1871ab4382d2SGreg Kroah-Hartman
sbsa_uart_startup(struct uart_port * port)18720dd1e247SAndre Przywara static int sbsa_uart_startup(struct uart_port *port)
18730dd1e247SAndre Przywara {
18740dd1e247SAndre Przywara struct uart_amba_port *uap =
18750dd1e247SAndre Przywara container_of(port, struct uart_amba_port, port);
18760dd1e247SAndre Przywara int retval;
18770dd1e247SAndre Przywara
18780dd1e247SAndre Przywara retval = pl011_hwinit(port);
18790dd1e247SAndre Przywara if (retval)
18800dd1e247SAndre Przywara return retval;
18810dd1e247SAndre Przywara
18820dd1e247SAndre Przywara retval = pl011_allocate_irq(uap);
18830dd1e247SAndre Przywara if (retval)
18840dd1e247SAndre Przywara return retval;
18850dd1e247SAndre Przywara
18860dd1e247SAndre Przywara /* The SBSA UART does not support any modem status lines. */
18870dd1e247SAndre Przywara uap->old_status = 0;
18880dd1e247SAndre Przywara
18890dd1e247SAndre Przywara pl011_enable_interrupts(uap);
18900dd1e247SAndre Przywara
18910dd1e247SAndre Przywara return 0;
18920dd1e247SAndre Przywara }
18930dd1e247SAndre Przywara
pl011_shutdown_channel(struct uart_amba_port * uap,unsigned int lcrh)1894d93ebe0fSThéo Lebrun static void pl011_shutdown_channel(struct uart_amba_port *uap, unsigned int lcrh)
1895ab4382d2SGreg Kroah-Hartman {
1896ab4382d2SGreg Kroah-Hartman unsigned long val;
1897ab4382d2SGreg Kroah-Hartman
1898b2a4e24cSRussell King val = pl011_read(uap, lcrh);
1899ab4382d2SGreg Kroah-Hartman val &= ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN);
1900b2a4e24cSRussell King pl011_write(val, uap, lcrh);
1901ab4382d2SGreg Kroah-Hartman }
1902ab4382d2SGreg Kroah-Hartman
1903ab4382d2SGreg Kroah-Hartman /*
1904d8d8ffa4SShreshtha Kumar Sahu * disable the port. It should not disable RTS and DTR.
1905d8d8ffa4SShreshtha Kumar Sahu * Also RTS and DTR state should be preserved to restore
1906d8d8ffa4SShreshtha Kumar Sahu * it during startup().
1907ab4382d2SGreg Kroah-Hartman */
pl011_disable_uart(struct uart_amba_port * uap)190895166a3fSAndre Przywara static void pl011_disable_uart(struct uart_amba_port *uap)
190995166a3fSAndre Przywara {
191095166a3fSAndre Przywara unsigned int cr;
191195166a3fSAndre Przywara
19122a76fa28SLukas Wunner uap->port.status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS);
191368ca3e72SThomas Gleixner uart_port_lock_irq(&uap->port);
19149f25bc51SRussell King cr = pl011_read(uap, REG_CR);
1915d8d8ffa4SShreshtha Kumar Sahu cr &= UART011_CR_RTS | UART011_CR_DTR;
1916d8d8ffa4SShreshtha Kumar Sahu cr |= UART01x_CR_UARTEN | UART011_CR_TXE;
19179f25bc51SRussell King pl011_write(cr, uap, REG_CR);
191868ca3e72SThomas Gleixner uart_port_unlock_irq(&uap->port);
1919ab4382d2SGreg Kroah-Hartman
1920ab4382d2SGreg Kroah-Hartman /*
1921ab4382d2SGreg Kroah-Hartman * disable break condition and fifos
1922ab4382d2SGreg Kroah-Hartman */
1923e4df9a80SRussell King pl011_shutdown_channel(uap, REG_LCRH_RX);
19247fe9a5a9SRussell King if (pl011_split_lcrh(uap))
1925e4df9a80SRussell King pl011_shutdown_channel(uap, REG_LCRH_TX);
192695166a3fSAndre Przywara }
192795166a3fSAndre Przywara
pl011_disable_interrupts(struct uart_amba_port * uap)192895166a3fSAndre Przywara static void pl011_disable_interrupts(struct uart_amba_port *uap)
192995166a3fSAndre Przywara {
193068ca3e72SThomas Gleixner uart_port_lock_irq(&uap->port);
193195166a3fSAndre Przywara
193295166a3fSAndre Przywara /* mask all interrupts and clear all pending ones */
193395166a3fSAndre Przywara uap->im = 0;
19349f25bc51SRussell King pl011_write(uap->im, uap, REG_IMSC);
19359f25bc51SRussell King pl011_write(0xffff, uap, REG_ICR);
193695166a3fSAndre Przywara
193768ca3e72SThomas Gleixner uart_port_unlock_irq(&uap->port);
193895166a3fSAndre Przywara }
193995166a3fSAndre Przywara
pl011_shutdown(struct uart_port * port)194095166a3fSAndre Przywara static void pl011_shutdown(struct uart_port *port)
194195166a3fSAndre Przywara {
194295166a3fSAndre Przywara struct uart_amba_port *uap =
194395166a3fSAndre Przywara container_of(port, struct uart_amba_port, port);
194495166a3fSAndre Przywara
194595166a3fSAndre Przywara pl011_disable_interrupts(uap);
194695166a3fSAndre Przywara
194795166a3fSAndre Przywara pl011_dma_shutdown(uap);
194895166a3fSAndre Przywara
19498d479237SLino Sanfilippo if ((port->rs485.flags & SER_RS485_ENABLED) && uap->rs485_tx_started)
19508d479237SLino Sanfilippo pl011_rs485_tx_stop(uap);
19518d479237SLino Sanfilippo
195294560f61SQian Cai free_irq(uap->port.irq, uap);
195395166a3fSAndre Przywara
195495166a3fSAndre Przywara pl011_disable_uart(uap);
1955ab4382d2SGreg Kroah-Hartman
1956ab4382d2SGreg Kroah-Hartman /*
1957ab4382d2SGreg Kroah-Hartman * Shut down the clock producer
1958ab4382d2SGreg Kroah-Hartman */
19591c4c4394SJulia Lawall clk_disable_unprepare(uap->clk);
196078d80c5aSLinus Walleij /* Optionally let pins go into sleep states */
19612b996fc5SLinus Walleij pinctrl_pm_select_sleep_state(port->dev);
1962c16d51a3SShreshtha Kumar Sahu
1963574de559SJingoo Han if (dev_get_platdata(uap->port.dev)) {
1964c16d51a3SShreshtha Kumar Sahu struct amba_pl011_data *plat;
1965c16d51a3SShreshtha Kumar Sahu
1966574de559SJingoo Han plat = dev_get_platdata(uap->port.dev);
1967c16d51a3SShreshtha Kumar Sahu if (plat->exit)
1968c16d51a3SShreshtha Kumar Sahu plat->exit();
1969c16d51a3SShreshtha Kumar Sahu }
1970c16d51a3SShreshtha Kumar Sahu
197136f339d1SPeter Hurley if (uap->port.ops->flush_buffer)
197236f339d1SPeter Hurley uap->port.ops->flush_buffer(port);
1973ab4382d2SGreg Kroah-Hartman }
1974ab4382d2SGreg Kroah-Hartman
sbsa_uart_shutdown(struct uart_port * port)19750dd1e247SAndre Przywara static void sbsa_uart_shutdown(struct uart_port *port)
19760dd1e247SAndre Przywara {
19770dd1e247SAndre Przywara struct uart_amba_port *uap =
19780dd1e247SAndre Przywara container_of(port, struct uart_amba_port, port);
19790dd1e247SAndre Przywara
19800dd1e247SAndre Przywara pl011_disable_interrupts(uap);
19810dd1e247SAndre Przywara
198294560f61SQian Cai free_irq(uap->port.irq, uap);
19830dd1e247SAndre Przywara
19840dd1e247SAndre Przywara if (uap->port.ops->flush_buffer)
19850dd1e247SAndre Przywara uap->port.ops->flush_buffer(port);
19860dd1e247SAndre Przywara }
19870dd1e247SAndre Przywara
1988ab4382d2SGreg Kroah-Hartman static void
pl011_setup_status_masks(struct uart_port * port,struct ktermios * termios)1989ef5a9358SAndre Przywara pl011_setup_status_masks(struct uart_port *port, struct ktermios *termios)
1990ef5a9358SAndre Przywara {
1991ef5a9358SAndre Przywara port->read_status_mask = UART011_DR_OE | 255;
1992ef5a9358SAndre Przywara if (termios->c_iflag & INPCK)
1993ef5a9358SAndre Przywara port->read_status_mask |= UART011_DR_FE | UART011_DR_PE;
1994ef5a9358SAndre Przywara if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
1995ef5a9358SAndre Przywara port->read_status_mask |= UART011_DR_BE;
1996ef5a9358SAndre Przywara
1997ef5a9358SAndre Przywara /*
1998ef5a9358SAndre Przywara * Characters to ignore
1999ef5a9358SAndre Przywara */
2000ef5a9358SAndre Przywara port->ignore_status_mask = 0;
2001ef5a9358SAndre Przywara if (termios->c_iflag & IGNPAR)
2002ef5a9358SAndre Przywara port->ignore_status_mask |= UART011_DR_FE | UART011_DR_PE;
2003ef5a9358SAndre Przywara if (termios->c_iflag & IGNBRK) {
2004ef5a9358SAndre Przywara port->ignore_status_mask |= UART011_DR_BE;
2005ef5a9358SAndre Przywara /*
2006ef5a9358SAndre Przywara * If we're ignoring parity and break indicators,
2007ef5a9358SAndre Przywara * ignore overruns too (for real raw support).
2008ef5a9358SAndre Przywara */
2009ef5a9358SAndre Przywara if (termios->c_iflag & IGNPAR)
2010ef5a9358SAndre Przywara port->ignore_status_mask |= UART011_DR_OE;
2011ef5a9358SAndre Przywara }
2012ef5a9358SAndre Przywara
2013ef5a9358SAndre Przywara /*
2014ef5a9358SAndre Przywara * Ignore all characters if CREAD is not set.
2015ef5a9358SAndre Przywara */
2016ef5a9358SAndre Przywara if ((termios->c_cflag & CREAD) == 0)
2017ef5a9358SAndre Przywara port->ignore_status_mask |= UART_DUMMY_DR_RX;
2018ef5a9358SAndre Przywara }
2019ef5a9358SAndre Przywara
2020ef5a9358SAndre Przywara static void
pl011_set_termios(struct uart_port * port,struct ktermios * termios,const struct ktermios * old)2021ab4382d2SGreg Kroah-Hartman pl011_set_termios(struct uart_port *port, struct ktermios *termios,
2022bec5b814SIlpo Järvinen const struct ktermios *old)
2023ab4382d2SGreg Kroah-Hartman {
2024a5820c24SDaniel Thompson struct uart_amba_port *uap =
2025a5820c24SDaniel Thompson container_of(port, struct uart_amba_port, port);
2026ab4382d2SGreg Kroah-Hartman unsigned int lcr_h, old_cr;
2027ab4382d2SGreg Kroah-Hartman unsigned long flags;
2028ab4382d2SGreg Kroah-Hartman unsigned int baud, quot, clkdiv;
20298d479237SLino Sanfilippo unsigned int bits;
2030ab4382d2SGreg Kroah-Hartman
2031ab4382d2SGreg Kroah-Hartman if (uap->vendor->oversampling)
2032ab4382d2SGreg Kroah-Hartman clkdiv = 8;
2033ab4382d2SGreg Kroah-Hartman else
2034ab4382d2SGreg Kroah-Hartman clkdiv = 16;
2035ab4382d2SGreg Kroah-Hartman
2036ab4382d2SGreg Kroah-Hartman /*
2037ab4382d2SGreg Kroah-Hartman * Ask the core to calculate the divisor for us.
2038ab4382d2SGreg Kroah-Hartman */
2039ab4382d2SGreg Kroah-Hartman baud = uart_get_baud_rate(port, termios, old, 0,
2040ab4382d2SGreg Kroah-Hartman port->uartclk / clkdiv);
204189fa28dbSChanho Min #ifdef CONFIG_DMA_ENGINE
2042cb06ff10SChanho Min /*
2043cb06ff10SChanho Min * Adjust RX DMA polling rate with baud rate if not specified.
2044cb06ff10SChanho Min */
2045cb06ff10SChanho Min if (uap->dmarx.auto_poll_rate)
2046cb06ff10SChanho Min uap->dmarx.poll_rate = DIV_ROUND_UP(10000000, baud);
204789fa28dbSChanho Min #endif
2048ab4382d2SGreg Kroah-Hartman
2049ab4382d2SGreg Kroah-Hartman if (baud > port->uartclk / 16)
2050ab4382d2SGreg Kroah-Hartman quot = DIV_ROUND_CLOSEST(port->uartclk * 8, baud);
2051ab4382d2SGreg Kroah-Hartman else
2052ab4382d2SGreg Kroah-Hartman quot = DIV_ROUND_CLOSEST(port->uartclk * 4, baud);
2053ab4382d2SGreg Kroah-Hartman
2054ab4382d2SGreg Kroah-Hartman switch (termios->c_cflag & CSIZE) {
2055ab4382d2SGreg Kroah-Hartman case CS5:
2056ab4382d2SGreg Kroah-Hartman lcr_h = UART01x_LCRH_WLEN_5;
2057ab4382d2SGreg Kroah-Hartman break;
2058ab4382d2SGreg Kroah-Hartman case CS6:
2059ab4382d2SGreg Kroah-Hartman lcr_h = UART01x_LCRH_WLEN_6;
2060ab4382d2SGreg Kroah-Hartman break;
2061ab4382d2SGreg Kroah-Hartman case CS7:
2062ab4382d2SGreg Kroah-Hartman lcr_h = UART01x_LCRH_WLEN_7;
2063ab4382d2SGreg Kroah-Hartman break;
2064ab4382d2SGreg Kroah-Hartman default: // CS8
2065ab4382d2SGreg Kroah-Hartman lcr_h = UART01x_LCRH_WLEN_8;
2066ab4382d2SGreg Kroah-Hartman break;
2067ab4382d2SGreg Kroah-Hartman }
2068ab4382d2SGreg Kroah-Hartman if (termios->c_cflag & CSTOPB)
2069ab4382d2SGreg Kroah-Hartman lcr_h |= UART01x_LCRH_STP2;
2070ab4382d2SGreg Kroah-Hartman if (termios->c_cflag & PARENB) {
2071ab4382d2SGreg Kroah-Hartman lcr_h |= UART01x_LCRH_PEN;
2072ab4382d2SGreg Kroah-Hartman if (!(termios->c_cflag & PARODD))
2073ab4382d2SGreg Kroah-Hartman lcr_h |= UART01x_LCRH_EPS;
2074bb70002cSEd Spiridonov if (termios->c_cflag & CMSPAR)
2075bb70002cSEd Spiridonov lcr_h |= UART011_LCRH_SPS;
2076ab4382d2SGreg Kroah-Hartman }
2077ab4382d2SGreg Kroah-Hartman if (uap->fifosize > 1)
2078ab4382d2SGreg Kroah-Hartman lcr_h |= UART01x_LCRH_FEN;
2079ab4382d2SGreg Kroah-Hartman
20808d479237SLino Sanfilippo bits = tty_get_frame_size(termios->c_cflag);
20818d479237SLino Sanfilippo
208268ca3e72SThomas Gleixner uart_port_lock_irqsave(port, &flags);
2083ab4382d2SGreg Kroah-Hartman
2084ab4382d2SGreg Kroah-Hartman /*
2085ab4382d2SGreg Kroah-Hartman * Update the per-port timeout.
2086ab4382d2SGreg Kroah-Hartman */
2087ab4382d2SGreg Kroah-Hartman uart_update_timeout(port, termios->c_cflag, baud);
2088ab4382d2SGreg Kroah-Hartman
20898d479237SLino Sanfilippo /*
20908d479237SLino Sanfilippo * Calculate the approximated time it takes to transmit one character
20918d479237SLino Sanfilippo * with the given baud rate. We use this as the poll interval when we
20928d479237SLino Sanfilippo * wait for the tx queue to empty.
20938d479237SLino Sanfilippo */
20940e4deb56SLino Sanfilippo uap->rs485_tx_drain_interval = DIV_ROUND_UP(bits * 1000 * 1000, baud);
20958d479237SLino Sanfilippo
2096ef5a9358SAndre Przywara pl011_setup_status_masks(port, termios);
2097ab4382d2SGreg Kroah-Hartman
2098ab4382d2SGreg Kroah-Hartman if (UART_ENABLE_MS(port, termios->c_cflag))
2099ab4382d2SGreg Kroah-Hartman pl011_enable_ms(port);
2100ab4382d2SGreg Kroah-Hartman
21018d479237SLino Sanfilippo if (port->rs485.flags & SER_RS485_ENABLED)
21028d479237SLino Sanfilippo termios->c_cflag &= ~CRTSCTS;
21038d479237SLino Sanfilippo
21049f25bc51SRussell King old_cr = pl011_read(uap, REG_CR);
2105ab4382d2SGreg Kroah-Hartman
2106ab4382d2SGreg Kroah-Hartman if (termios->c_cflag & CRTSCTS) {
2107ab4382d2SGreg Kroah-Hartman if (old_cr & UART011_CR_RTS)
2108ab4382d2SGreg Kroah-Hartman old_cr |= UART011_CR_RTSEN;
2109ab4382d2SGreg Kroah-Hartman
2110ab4382d2SGreg Kroah-Hartman old_cr |= UART011_CR_CTSEN;
21112a76fa28SLukas Wunner port->status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS;
2112ab4382d2SGreg Kroah-Hartman } else {
2113ab4382d2SGreg Kroah-Hartman old_cr &= ~(UART011_CR_CTSEN | UART011_CR_RTSEN);
21142a76fa28SLukas Wunner port->status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS);
2115ab4382d2SGreg Kroah-Hartman }
2116ab4382d2SGreg Kroah-Hartman
2117ab4382d2SGreg Kroah-Hartman if (uap->vendor->oversampling) {
2118ab4382d2SGreg Kroah-Hartman if (baud > port->uartclk / 16)
2119ab4382d2SGreg Kroah-Hartman old_cr |= ST_UART011_CR_OVSFACT;
2120ab4382d2SGreg Kroah-Hartman else
2121ab4382d2SGreg Kroah-Hartman old_cr &= ~ST_UART011_CR_OVSFACT;
2122ab4382d2SGreg Kroah-Hartman }
2123ab4382d2SGreg Kroah-Hartman
2124c5dd553bSLinus Walleij /*
2125c5dd553bSLinus Walleij * Workaround for the ST Micro oversampling variants to
2126c5dd553bSLinus Walleij * increase the bitrate slightly, by lowering the divisor,
2127c5dd553bSLinus Walleij * to avoid delayed sampling of start bit at high speeds,
2128c5dd553bSLinus Walleij * else we see data corruption.
2129c5dd553bSLinus Walleij */
2130c5dd553bSLinus Walleij if (uap->vendor->oversampling) {
213128a7ec8cSThéo Lebrun if (baud >= 3000000 && baud < 3250000 && quot > 1)
2132c5dd553bSLinus Walleij quot -= 1;
213328a7ec8cSThéo Lebrun else if (baud > 3250000 && quot > 2)
2134c5dd553bSLinus Walleij quot -= 2;
2135c5dd553bSLinus Walleij }
2136ab4382d2SGreg Kroah-Hartman /* Set baud rate */
21379f25bc51SRussell King pl011_write(quot & 0x3f, uap, REG_FBRD);
21389f25bc51SRussell King pl011_write(quot >> 6, uap, REG_IBRD);
2139ab4382d2SGreg Kroah-Hartman
2140ab4382d2SGreg Kroah-Hartman /*
2141ab4382d2SGreg Kroah-Hartman * ----------v----------v----------v----------v-----
2142e4df9a80SRussell King * NOTE: REG_LCRH_TX and REG_LCRH_RX MUST BE WRITTEN AFTER
21439f25bc51SRussell King * REG_FBRD & REG_IBRD.
2144ab4382d2SGreg Kroah-Hartman * ----------^----------^----------^----------^-----
2145ab4382d2SGreg Kroah-Hartman */
2146b60f2f66SJon Medhurst pl011_write_lcr_h(uap, lcr_h);
21476d8c1fcaSHongyu Xie
21486d8c1fcaSHongyu Xie /*
21496d8c1fcaSHongyu Xie * Receive was disabled by pl011_disable_uart during shutdown.
21506d8c1fcaSHongyu Xie * Need to reenable receive if you need to use a tty_driver
21516d8c1fcaSHongyu Xie * returns from tty_find_polling_driver() after a port shutdown.
21526d8c1fcaSHongyu Xie */
21536d8c1fcaSHongyu Xie old_cr |= UART011_CR_RXE;
21549f25bc51SRussell King pl011_write(old_cr, uap, REG_CR);
2155ab4382d2SGreg Kroah-Hartman
215668ca3e72SThomas Gleixner uart_port_unlock_irqrestore(port, flags);
2157ab4382d2SGreg Kroah-Hartman }
2158ab4382d2SGreg Kroah-Hartman
21590dd1e247SAndre Przywara static void
sbsa_uart_set_termios(struct uart_port * port,struct ktermios * termios,const struct ktermios * old)21600dd1e247SAndre Przywara sbsa_uart_set_termios(struct uart_port *port, struct ktermios *termios,
2161bec5b814SIlpo Järvinen const struct ktermios *old)
21620dd1e247SAndre Przywara {
21630dd1e247SAndre Przywara struct uart_amba_port *uap =
21640dd1e247SAndre Przywara container_of(port, struct uart_amba_port, port);
21650dd1e247SAndre Przywara unsigned long flags;
21660dd1e247SAndre Przywara
21670dd1e247SAndre Przywara tty_termios_encode_baud_rate(termios, uap->fixed_baud, uap->fixed_baud);
21680dd1e247SAndre Przywara
21690dd1e247SAndre Przywara /* The SBSA UART only supports 8n1 without hardware flow control. */
21700dd1e247SAndre Przywara termios->c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD);
21710dd1e247SAndre Przywara termios->c_cflag &= ~(CMSPAR | CRTSCTS);
21720dd1e247SAndre Przywara termios->c_cflag |= CS8 | CLOCAL;
21730dd1e247SAndre Przywara
217468ca3e72SThomas Gleixner uart_port_lock_irqsave(port, &flags);
21750dd1e247SAndre Przywara uart_update_timeout(port, CS8, uap->fixed_baud);
21760dd1e247SAndre Przywara pl011_setup_status_masks(port, termios);
217768ca3e72SThomas Gleixner uart_port_unlock_irqrestore(port, flags);
21780dd1e247SAndre Przywara }
21790dd1e247SAndre Przywara
pl011_type(struct uart_port * port)2180ab4382d2SGreg Kroah-Hartman static const char *pl011_type(struct uart_port *port)
2181ab4382d2SGreg Kroah-Hartman {
2182a5820c24SDaniel Thompson struct uart_amba_port *uap =
2183a5820c24SDaniel Thompson container_of(port, struct uart_amba_port, port);
2184ab4382d2SGreg Kroah-Hartman return uap->port.type == PORT_AMBA ? uap->type : NULL;
2185ab4382d2SGreg Kroah-Hartman }
2186ab4382d2SGreg Kroah-Hartman
2187ab4382d2SGreg Kroah-Hartman /*
2188ab4382d2SGreg Kroah-Hartman * Configure/autoconfigure the port.
2189ab4382d2SGreg Kroah-Hartman */
pl011_config_port(struct uart_port * port,int flags)2190e643f87fSLinus Walleij static void pl011_config_port(struct uart_port *port, int flags)
2191ab4382d2SGreg Kroah-Hartman {
2192d1180405SLino Sanfilippo if (flags & UART_CONFIG_TYPE)
2193ab4382d2SGreg Kroah-Hartman port->type = PORT_AMBA;
2194ab4382d2SGreg Kroah-Hartman }
2195ab4382d2SGreg Kroah-Hartman
2196ab4382d2SGreg Kroah-Hartman /*
2197ab4382d2SGreg Kroah-Hartman * verify the new serial_struct (for TIOCSSERIAL).
2198ab4382d2SGreg Kroah-Hartman */
pl011_verify_port(struct uart_port * port,struct serial_struct * ser)2199e643f87fSLinus Walleij static int pl011_verify_port(struct uart_port *port, struct serial_struct *ser)
2200ab4382d2SGreg Kroah-Hartman {
2201ab4382d2SGreg Kroah-Hartman int ret = 0;
2202d93ebe0fSThéo Lebrun
2203ab4382d2SGreg Kroah-Hartman if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA)
2204ab4382d2SGreg Kroah-Hartman ret = -EINVAL;
2205ab4382d2SGreg Kroah-Hartman if (ser->irq < 0 || ser->irq >= nr_irqs)
2206ab4382d2SGreg Kroah-Hartman ret = -EINVAL;
2207ab4382d2SGreg Kroah-Hartman if (ser->baud_base < 9600)
2208ab4382d2SGreg Kroah-Hartman ret = -EINVAL;
2209d1180405SLino Sanfilippo if (port->mapbase != (unsigned long)ser->iomem_base)
2210d1180405SLino Sanfilippo ret = -EINVAL;
2211ab4382d2SGreg Kroah-Hartman return ret;
2212ab4382d2SGreg Kroah-Hartman }
2213ab4382d2SGreg Kroah-Hartman
pl011_rs485_config(struct uart_port * port,struct ktermios * termios,struct serial_rs485 * rs485)2214ae50bb27SIlpo Järvinen static int pl011_rs485_config(struct uart_port *port, struct ktermios *termios,
22158d479237SLino Sanfilippo struct serial_rs485 *rs485)
22168d479237SLino Sanfilippo {
22178d479237SLino Sanfilippo struct uart_amba_port *uap =
22188d479237SLino Sanfilippo container_of(port, struct uart_amba_port, port);
22198d479237SLino Sanfilippo
22208d479237SLino Sanfilippo if (port->rs485.flags & SER_RS485_ENABLED)
22218d479237SLino Sanfilippo pl011_rs485_tx_stop(uap);
22228d479237SLino Sanfilippo
22238d479237SLino Sanfilippo /* Make sure auto RTS is disabled */
2224a9efa452SLino Sanfilippo if (rs485->flags & SER_RS485_ENABLED) {
22258d479237SLino Sanfilippo u32 cr = pl011_read(uap, REG_CR);
22268d479237SLino Sanfilippo
22278d479237SLino Sanfilippo cr &= ~UART011_CR_RTSEN;
22288d479237SLino Sanfilippo pl011_write(cr, uap, REG_CR);
22298d479237SLino Sanfilippo port->status &= ~UPSTAT_AUTORTS;
22308d479237SLino Sanfilippo }
22318d479237SLino Sanfilippo
22328d479237SLino Sanfilippo return 0;
22338d479237SLino Sanfilippo }
22348d479237SLino Sanfilippo
22352331e068SBhumika Goyal static const struct uart_ops amba_pl011_pops = {
2236e643f87fSLinus Walleij .tx_empty = pl011_tx_empty,
2237ab4382d2SGreg Kroah-Hartman .set_mctrl = pl011_set_mctrl,
2238e643f87fSLinus Walleij .get_mctrl = pl011_get_mctrl,
2239ab4382d2SGreg Kroah-Hartman .stop_tx = pl011_stop_tx,
2240ab4382d2SGreg Kroah-Hartman .start_tx = pl011_start_tx,
2241ab4382d2SGreg Kroah-Hartman .stop_rx = pl011_stop_rx,
2242211565b1SIlpo Järvinen .throttle = pl011_throttle_rx,
2243211565b1SIlpo Järvinen .unthrottle = pl011_unthrottle_rx,
2244ab4382d2SGreg Kroah-Hartman .enable_ms = pl011_enable_ms,
2245ab4382d2SGreg Kroah-Hartman .break_ctl = pl011_break_ctl,
2246ab4382d2SGreg Kroah-Hartman .startup = pl011_startup,
2247ab4382d2SGreg Kroah-Hartman .shutdown = pl011_shutdown,
2248ab4382d2SGreg Kroah-Hartman .flush_buffer = pl011_dma_flush_buffer,
2249ab4382d2SGreg Kroah-Hartman .set_termios = pl011_set_termios,
2250ab4382d2SGreg Kroah-Hartman .type = pl011_type,
2251e643f87fSLinus Walleij .config_port = pl011_config_port,
2252e643f87fSLinus Walleij .verify_port = pl011_verify_port,
2253ab4382d2SGreg Kroah-Hartman #ifdef CONFIG_CONSOLE_POLL
2254b3564c2cSAnton Vorontsov .poll_init = pl011_hwinit,
2255e643f87fSLinus Walleij .poll_get_char = pl011_get_poll_char,
2256e643f87fSLinus Walleij .poll_put_char = pl011_put_poll_char,
2257ab4382d2SGreg Kroah-Hartman #endif
2258ab4382d2SGreg Kroah-Hartman };
2259ab4382d2SGreg Kroah-Hartman
sbsa_uart_set_mctrl(struct uart_port * port,unsigned int mctrl)22600dd1e247SAndre Przywara static void sbsa_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
22610dd1e247SAndre Przywara {
22620dd1e247SAndre Przywara }
22630dd1e247SAndre Przywara
sbsa_uart_get_mctrl(struct uart_port * port)22640dd1e247SAndre Przywara static unsigned int sbsa_uart_get_mctrl(struct uart_port *port)
22650dd1e247SAndre Przywara {
22660dd1e247SAndre Przywara return 0;
22670dd1e247SAndre Przywara }
22680dd1e247SAndre Przywara
22690dd1e247SAndre Przywara static const struct uart_ops sbsa_uart_pops = {
22700dd1e247SAndre Przywara .tx_empty = pl011_tx_empty,
22710dd1e247SAndre Przywara .set_mctrl = sbsa_uart_set_mctrl,
22720dd1e247SAndre Przywara .get_mctrl = sbsa_uart_get_mctrl,
22730dd1e247SAndre Przywara .stop_tx = pl011_stop_tx,
22740dd1e247SAndre Przywara .start_tx = pl011_start_tx,
22750dd1e247SAndre Przywara .stop_rx = pl011_stop_rx,
22760dd1e247SAndre Przywara .startup = sbsa_uart_startup,
22770dd1e247SAndre Przywara .shutdown = sbsa_uart_shutdown,
22780dd1e247SAndre Przywara .set_termios = sbsa_uart_set_termios,
22790dd1e247SAndre Przywara .type = pl011_type,
22800dd1e247SAndre Przywara .config_port = pl011_config_port,
22810dd1e247SAndre Przywara .verify_port = pl011_verify_port,
22820dd1e247SAndre Przywara #ifdef CONFIG_CONSOLE_POLL
22830dd1e247SAndre Przywara .poll_init = pl011_hwinit,
22840dd1e247SAndre Przywara .poll_get_char = pl011_get_poll_char,
22850dd1e247SAndre Przywara .poll_put_char = pl011_put_poll_char,
22860dd1e247SAndre Przywara #endif
22870dd1e247SAndre Przywara };
22880dd1e247SAndre Przywara
2289ab4382d2SGreg Kroah-Hartman static struct uart_amba_port *amba_ports[UART_NR];
2290ab4382d2SGreg Kroah-Hartman
2291ab4382d2SGreg Kroah-Hartman #ifdef CONFIG_SERIAL_AMBA_PL011_CONSOLE
2292ab4382d2SGreg Kroah-Hartman
pl011_console_putchar(struct uart_port * port,unsigned char ch)22933f8bab17SJiri Slaby static void pl011_console_putchar(struct uart_port *port, unsigned char ch)
2294ab4382d2SGreg Kroah-Hartman {
2295a5820c24SDaniel Thompson struct uart_amba_port *uap =
2296a5820c24SDaniel Thompson container_of(port, struct uart_amba_port, port);
2297ab4382d2SGreg Kroah-Hartman
22989f25bc51SRussell King while (pl011_read(uap, REG_FR) & UART01x_FR_TXFF)
22992f2fd089STimur Tabi cpu_relax();
23009f25bc51SRussell King pl011_write(ch, uap, REG_DR);
2301ab4382d2SGreg Kroah-Hartman }
2302ab4382d2SGreg Kroah-Hartman
2303ab4382d2SGreg Kroah-Hartman static void
pl011_console_write(struct console * co,const char * s,unsigned int count)2304ab4382d2SGreg Kroah-Hartman pl011_console_write(struct console *co, const char *s, unsigned int count)
2305ab4382d2SGreg Kroah-Hartman {
2306ab4382d2SGreg Kroah-Hartman struct uart_amba_port *uap = amba_ports[co->index];
23072f2fd089STimur Tabi unsigned int old_cr = 0, new_cr;
2308ef605fdbSRabin Vincent unsigned long flags;
2309ef605fdbSRabin Vincent int locked = 1;
2310ab4382d2SGreg Kroah-Hartman
2311ab4382d2SGreg Kroah-Hartman clk_enable(uap->clk);
2312ab4382d2SGreg Kroah-Hartman
23132432f71cSSebastian Andrzej Siewior if (oops_in_progress)
23142432f71cSSebastian Andrzej Siewior locked = uart_port_trylock_irqsave(&uap->port, &flags);
2315ef605fdbSRabin Vincent else
23162432f71cSSebastian Andrzej Siewior uart_port_lock_irqsave(&uap->port, &flags);
2317ef605fdbSRabin Vincent
2318ab4382d2SGreg Kroah-Hartman /*
2319ab4382d2SGreg Kroah-Hartman * First save the CR then disable the interrupts
2320ab4382d2SGreg Kroah-Hartman */
232171eec483SAndre Przywara if (!uap->vendor->always_enabled) {
23229f25bc51SRussell King old_cr = pl011_read(uap, REG_CR);
2323ab4382d2SGreg Kroah-Hartman new_cr = old_cr & ~UART011_CR_CTSEN;
2324ab4382d2SGreg Kroah-Hartman new_cr |= UART01x_CR_UARTEN | UART011_CR_TXE;
23259f25bc51SRussell King pl011_write(new_cr, uap, REG_CR);
232671eec483SAndre Przywara }
2327ab4382d2SGreg Kroah-Hartman
2328ab4382d2SGreg Kroah-Hartman uart_console_write(&uap->port, s, count, pl011_console_putchar);
2329ab4382d2SGreg Kroah-Hartman
2330ab4382d2SGreg Kroah-Hartman /*
2331d8a4995bSChristopher Covington * Finally, wait for transmitter to become empty and restore the
2332d8a4995bSChristopher Covington * TCR. Allow feature register bits to be inverted to work around
2333d8a4995bSChristopher Covington * errata.
2334ab4382d2SGreg Kroah-Hartman */
2335d8a4995bSChristopher Covington while ((pl011_read(uap, REG_FR) ^ uap->vendor->inv_fr)
2336d8a4995bSChristopher Covington & uap->vendor->fr_busy)
23372f2fd089STimur Tabi cpu_relax();
233871eec483SAndre Przywara if (!uap->vendor->always_enabled)
23399f25bc51SRussell King pl011_write(old_cr, uap, REG_CR);
2340ab4382d2SGreg Kroah-Hartman
2341ef605fdbSRabin Vincent if (locked)
23422432f71cSSebastian Andrzej Siewior uart_port_unlock_irqrestore(&uap->port, flags);
2343ef605fdbSRabin Vincent
2344ab4382d2SGreg Kroah-Hartman clk_disable(uap->clk);
2345ab4382d2SGreg Kroah-Hartman }
2346ab4382d2SGreg Kroah-Hartman
pl011_console_get_options(struct uart_amba_port * uap,int * baud,int * parity,int * bits)234727afac93SLukas Wunner static void pl011_console_get_options(struct uart_amba_port *uap, int *baud,
2348ab4382d2SGreg Kroah-Hartman int *parity, int *bits)
2349ab4382d2SGreg Kroah-Hartman {
2350ab4382d2SGreg Kroah-Hartman unsigned int lcr_h, ibrd, fbrd;
2351ab4382d2SGreg Kroah-Hartman
23528ff87406SThéo Lebrun if (!(pl011_read(uap, REG_CR) & UART01x_CR_UARTEN))
23538ff87406SThéo Lebrun return;
23548ff87406SThéo Lebrun
2355e4df9a80SRussell King lcr_h = pl011_read(uap, REG_LCRH_TX);
2356ab4382d2SGreg Kroah-Hartman
2357ab4382d2SGreg Kroah-Hartman *parity = 'n';
2358ab4382d2SGreg Kroah-Hartman if (lcr_h & UART01x_LCRH_PEN) {
2359ab4382d2SGreg Kroah-Hartman if (lcr_h & UART01x_LCRH_EPS)
2360ab4382d2SGreg Kroah-Hartman *parity = 'e';
2361ab4382d2SGreg Kroah-Hartman else
2362ab4382d2SGreg Kroah-Hartman *parity = 'o';
2363ab4382d2SGreg Kroah-Hartman }
2364ab4382d2SGreg Kroah-Hartman
2365ab4382d2SGreg Kroah-Hartman if ((lcr_h & 0x60) == UART01x_LCRH_WLEN_7)
2366ab4382d2SGreg Kroah-Hartman *bits = 7;
2367ab4382d2SGreg Kroah-Hartman else
2368ab4382d2SGreg Kroah-Hartman *bits = 8;
2369ab4382d2SGreg Kroah-Hartman
23709f25bc51SRussell King ibrd = pl011_read(uap, REG_IBRD);
23719f25bc51SRussell King fbrd = pl011_read(uap, REG_FBRD);
2372ab4382d2SGreg Kroah-Hartman
2373ab4382d2SGreg Kroah-Hartman *baud = uap->port.uartclk * 4 / (64 * ibrd + fbrd);
2374ab4382d2SGreg Kroah-Hartman
23758ff87406SThéo Lebrun if (uap->vendor->oversampling &&
23768ff87406SThéo Lebrun (pl011_read(uap, REG_CR) & ST_UART011_CR_OVSFACT))
2377ab4382d2SGreg Kroah-Hartman *baud *= 2;
2378ab4382d2SGreg Kroah-Hartman }
2379ab4382d2SGreg Kroah-Hartman
pl011_console_setup(struct console * co,char * options)238027afac93SLukas Wunner static int pl011_console_setup(struct console *co, char *options)
2381ab4382d2SGreg Kroah-Hartman {
2382ab4382d2SGreg Kroah-Hartman struct uart_amba_port *uap;
2383ab4382d2SGreg Kroah-Hartman int baud = 38400;
2384ab4382d2SGreg Kroah-Hartman int bits = 8;
2385ab4382d2SGreg Kroah-Hartman int parity = 'n';
2386ab4382d2SGreg Kroah-Hartman int flow = 'n';
23874b4851c6SRussell King int ret;
2388ab4382d2SGreg Kroah-Hartman
2389ab4382d2SGreg Kroah-Hartman /*
2390ab4382d2SGreg Kroah-Hartman * Check whether an invalid uart number has been specified, and
2391ab4382d2SGreg Kroah-Hartman * if so, search for the first available port that does have
2392ab4382d2SGreg Kroah-Hartman * console support.
2393ab4382d2SGreg Kroah-Hartman */
2394ab4382d2SGreg Kroah-Hartman if (co->index >= UART_NR)
2395ab4382d2SGreg Kroah-Hartman co->index = 0;
2396ab4382d2SGreg Kroah-Hartman uap = amba_ports[co->index];
2397ab4382d2SGreg Kroah-Hartman if (!uap)
2398ab4382d2SGreg Kroah-Hartman return -ENODEV;
2399ab4382d2SGreg Kroah-Hartman
240078d80c5aSLinus Walleij /* Allow pins to be muxed in and configured */
24012b996fc5SLinus Walleij pinctrl_pm_select_default_state(uap->port.dev);
240278d80c5aSLinus Walleij
24034b4851c6SRussell King ret = clk_prepare(uap->clk);
24044b4851c6SRussell King if (ret)
24054b4851c6SRussell King return ret;
24064b4851c6SRussell King
2407574de559SJingoo Han if (dev_get_platdata(uap->port.dev)) {
2408c16d51a3SShreshtha Kumar Sahu struct amba_pl011_data *plat;
2409c16d51a3SShreshtha Kumar Sahu
2410574de559SJingoo Han plat = dev_get_platdata(uap->port.dev);
2411c16d51a3SShreshtha Kumar Sahu if (plat->init)
2412c16d51a3SShreshtha Kumar Sahu plat->init();
2413c16d51a3SShreshtha Kumar Sahu }
2414c16d51a3SShreshtha Kumar Sahu
2415ab4382d2SGreg Kroah-Hartman uap->port.uartclk = clk_get_rate(uap->clk);
2416ab4382d2SGreg Kroah-Hartman
2417cefc2d1dSAndre Przywara if (uap->vendor->fixed_options) {
2418cefc2d1dSAndre Przywara baud = uap->fixed_baud;
2419cefc2d1dSAndre Przywara } else {
2420ab4382d2SGreg Kroah-Hartman if (options)
2421cefc2d1dSAndre Przywara uart_parse_options(options,
2422cefc2d1dSAndre Przywara &baud, &parity, &bits, &flow);
2423ab4382d2SGreg Kroah-Hartman else
2424ab4382d2SGreg Kroah-Hartman pl011_console_get_options(uap, &baud, &parity, &bits);
2425cefc2d1dSAndre Przywara }
2426ab4382d2SGreg Kroah-Hartman
2427ab4382d2SGreg Kroah-Hartman return uart_set_options(&uap->port, co, baud, parity, bits, flow);
2428ab4382d2SGreg Kroah-Hartman }
2429ab4382d2SGreg Kroah-Hartman
243010879ae5SAleksey Makarov /**
243110879ae5SAleksey Makarov * pl011_console_match - non-standard console matching
243210879ae5SAleksey Makarov * @co: registering console
243310879ae5SAleksey Makarov * @name: name from console command line
243410879ae5SAleksey Makarov * @idx: index from console command line
243510879ae5SAleksey Makarov * @options: ptr to option string from console command line
243610879ae5SAleksey Makarov *
243710879ae5SAleksey Makarov * Only attempts to match console command lines of the form:
243810879ae5SAleksey Makarov * console=pl011,mmio|mmio32,<addr>[,<options>]
243910879ae5SAleksey Makarov * console=pl011,0x<addr>[,<options>]
244010879ae5SAleksey Makarov * This form is used to register an initial earlycon boot console and
244110879ae5SAleksey Makarov * replace it with the amba_console at pl011 driver init.
244210879ae5SAleksey Makarov *
244310879ae5SAleksey Makarov * Performs console setup for a match (as required by interface)
244410879ae5SAleksey Makarov * If no <options> are specified, then assume the h/w is already setup.
244510879ae5SAleksey Makarov *
244610879ae5SAleksey Makarov * Returns 0 if console matches; otherwise non-zero to use default matching
244710879ae5SAleksey Makarov */
pl011_console_match(struct console * co,char * name,int idx,char * options)244827afac93SLukas Wunner static int pl011_console_match(struct console *co, char *name, int idx,
244910879ae5SAleksey Makarov char *options)
245010879ae5SAleksey Makarov {
245110879ae5SAleksey Makarov unsigned char iotype;
245210879ae5SAleksey Makarov resource_size_t addr;
245310879ae5SAleksey Makarov int i;
245410879ae5SAleksey Makarov
245537ef38f3STimur Tabi /*
245637ef38f3STimur Tabi * Systems affected by the Qualcomm Technologies QDF2400 E44 erratum
245737ef38f3STimur Tabi * have a distinct console name, so make sure we check for that.
245837ef38f3STimur Tabi * The actual implementation of the erratum occurs in the probe
245937ef38f3STimur Tabi * function.
246037ef38f3STimur Tabi */
246137ef38f3STimur Tabi if ((strcmp(name, "qdf2400_e44") != 0) && (strcmp(name, "pl011") != 0))
246210879ae5SAleksey Makarov return -ENODEV;
246310879ae5SAleksey Makarov
246410879ae5SAleksey Makarov if (uart_parse_earlycon(options, &iotype, &addr, &options))
246510879ae5SAleksey Makarov return -ENODEV;
246610879ae5SAleksey Makarov
246710879ae5SAleksey Makarov if (iotype != UPIO_MEM && iotype != UPIO_MEM32)
246810879ae5SAleksey Makarov return -ENODEV;
246910879ae5SAleksey Makarov
247010879ae5SAleksey Makarov /* try to match the port specified on the command line */
247110879ae5SAleksey Makarov for (i = 0; i < ARRAY_SIZE(amba_ports); i++) {
247210879ae5SAleksey Makarov struct uart_port *port;
247310879ae5SAleksey Makarov
247410879ae5SAleksey Makarov if (!amba_ports[i])
247510879ae5SAleksey Makarov continue;
247610879ae5SAleksey Makarov
247710879ae5SAleksey Makarov port = &amba_ports[i]->port;
247810879ae5SAleksey Makarov
247910879ae5SAleksey Makarov if (port->mapbase != addr)
248010879ae5SAleksey Makarov continue;
248110879ae5SAleksey Makarov
248210879ae5SAleksey Makarov co->index = i;
248310879ae5SAleksey Makarov port->cons = co;
248410879ae5SAleksey Makarov return pl011_console_setup(co, options);
248510879ae5SAleksey Makarov }
248610879ae5SAleksey Makarov
248710879ae5SAleksey Makarov return -ENODEV;
248810879ae5SAleksey Makarov }
248910879ae5SAleksey Makarov
2490ab4382d2SGreg Kroah-Hartman static struct uart_driver amba_reg;
2491ab4382d2SGreg Kroah-Hartman static struct console amba_console = {
2492ab4382d2SGreg Kroah-Hartman .name = "ttyAMA",
2493ab4382d2SGreg Kroah-Hartman .write = pl011_console_write,
2494ab4382d2SGreg Kroah-Hartman .device = uart_console_device,
2495ab4382d2SGreg Kroah-Hartman .setup = pl011_console_setup,
249610879ae5SAleksey Makarov .match = pl011_console_match,
24977951ffc9SAlexander Sverdlin .flags = CON_PRINTBUFFER | CON_ANYTIME,
2498ab4382d2SGreg Kroah-Hartman .index = -1,
2499ab4382d2SGreg Kroah-Hartman .data = &amba_reg,
2500ab4382d2SGreg Kroah-Hartman };
2501ab4382d2SGreg Kroah-Hartman
2502ab4382d2SGreg Kroah-Hartman #define AMBA_CONSOLE (&amba_console)
25030d3c673eSRob Herring
qdf2400_e44_putc(struct uart_port * port,unsigned char c)25043f8bab17SJiri Slaby static void qdf2400_e44_putc(struct uart_port *port, unsigned char c)
2505d8a4995bSChristopher Covington {
2506d8a4995bSChristopher Covington while (readl(port->membase + UART01x_FR) & UART01x_FR_TXFF)
2507d8a4995bSChristopher Covington cpu_relax();
2508d8a4995bSChristopher Covington writel(c, port->membase + UART01x_DR);
2509d8a4995bSChristopher Covington while (!(readl(port->membase + UART01x_FR) & UART011_FR_TXFE))
2510d8a4995bSChristopher Covington cpu_relax();
2511d8a4995bSChristopher Covington }
2512d8a4995bSChristopher Covington
qdf2400_e44_early_write(struct console * con,const char * s,unsigned int n)2513826bd77aSThéo Lebrun static void qdf2400_e44_early_write(struct console *con, const char *s, unsigned int n)
2514d8a4995bSChristopher Covington {
2515d8a4995bSChristopher Covington struct earlycon_device *dev = con->data;
2516d8a4995bSChristopher Covington
2517d8a4995bSChristopher Covington uart_console_write(&dev->port, s, n, qdf2400_e44_putc);
2518d8a4995bSChristopher Covington }
2519d8a4995bSChristopher Covington
pl011_putc(struct uart_port * port,unsigned char c)25203f8bab17SJiri Slaby static void pl011_putc(struct uart_port *port, unsigned char c)
25210d3c673eSRob Herring {
2522cdf091caSRussell King while (readl(port->membase + UART01x_FR) & UART01x_FR_TXFF)
25232f2fd089STimur Tabi cpu_relax();
25243b78fae7STimur Tabi if (port->iotype == UPIO_MEM32)
25253b78fae7STimur Tabi writel(c, port->membase + UART01x_DR);
25263b78fae7STimur Tabi else
2527cdf091caSRussell King writeb(c, port->membase + UART01x_DR);
2528e06690bfSShawn Guo while (readl(port->membase + UART01x_FR) & UART01x_FR_BUSY)
25292f2fd089STimur Tabi cpu_relax();
25300d3c673eSRob Herring }
25310d3c673eSRob Herring
pl011_early_write(struct console * con,const char * s,unsigned int n)2532826bd77aSThéo Lebrun static void pl011_early_write(struct console *con, const char *s, unsigned int n)
25330d3c673eSRob Herring {
25340d3c673eSRob Herring struct earlycon_device *dev = con->data;
25350d3c673eSRob Herring
25360d3c673eSRob Herring uart_console_write(&dev->port, s, n, pl011_putc);
25370d3c673eSRob Herring }
25380d3c673eSRob Herring
2539195867ffSSumit Garg #ifdef CONFIG_CONSOLE_POLL
pl011_getc(struct uart_port * port)2540195867ffSSumit Garg static int pl011_getc(struct uart_port *port)
2541195867ffSSumit Garg {
2542195867ffSSumit Garg if (readl(port->membase + UART01x_FR) & UART01x_FR_RXFE)
2543195867ffSSumit Garg return NO_POLL_CHAR;
2544195867ffSSumit Garg
2545195867ffSSumit Garg if (port->iotype == UPIO_MEM32)
2546195867ffSSumit Garg return readl(port->membase + UART01x_DR);
2547195867ffSSumit Garg else
2548195867ffSSumit Garg return readb(port->membase + UART01x_DR);
2549195867ffSSumit Garg }
2550195867ffSSumit Garg
pl011_early_read(struct console * con,char * s,unsigned int n)2551195867ffSSumit Garg static int pl011_early_read(struct console *con, char *s, unsigned int n)
2552195867ffSSumit Garg {
2553195867ffSSumit Garg struct earlycon_device *dev = con->data;
2554195867ffSSumit Garg int ch, num_read = 0;
2555195867ffSSumit Garg
2556195867ffSSumit Garg while (num_read < n) {
2557195867ffSSumit Garg ch = pl011_getc(&dev->port);
2558195867ffSSumit Garg if (ch == NO_POLL_CHAR)
2559195867ffSSumit Garg break;
2560195867ffSSumit Garg
2561195867ffSSumit Garg s[num_read++] = ch;
2562195867ffSSumit Garg }
2563195867ffSSumit Garg
2564195867ffSSumit Garg return num_read;
2565195867ffSSumit Garg }
2566195867ffSSumit Garg #else
2567195867ffSSumit Garg #define pl011_early_read NULL
2568195867ffSSumit Garg #endif
2569195867ffSSumit Garg
2570e53e597fSTimur Tabi /*
2571e53e597fSTimur Tabi * On non-ACPI systems, earlycon is enabled by specifying
2572e53e597fSTimur Tabi * "earlycon=pl011,<address>" on the kernel command line.
2573e53e597fSTimur Tabi *
2574e53e597fSTimur Tabi * On ACPI ARM64 systems, an "early" console is enabled via the SPCR table,
2575e53e597fSTimur Tabi * by specifying only "earlycon" on the command line. Because it requires
2576e53e597fSTimur Tabi * SPCR, the console starts after ACPI is parsed, which is later than a
2577e53e597fSTimur Tabi * traditional early console.
2578e53e597fSTimur Tabi *
2579e53e597fSTimur Tabi * To get the traditional early console that starts before ACPI is parsed,
2580e53e597fSTimur Tabi * specify the full "earlycon=pl011,<address>" option.
2581e53e597fSTimur Tabi */
pl011_early_console_setup(struct earlycon_device * device,const char * opt)25820d3c673eSRob Herring static int __init pl011_early_console_setup(struct earlycon_device *device,
25830d3c673eSRob Herring const char *opt)
25840d3c673eSRob Herring {
25850d3c673eSRob Herring if (!device->port.membase)
25860d3c673eSRob Herring return -ENODEV;
25870d3c673eSRob Herring
2588e53e597fSTimur Tabi device->con->write = pl011_early_write;
2589195867ffSSumit Garg device->con->read = pl011_early_read;
2590e53e597fSTimur Tabi
25910d3c673eSRob Herring return 0;
25920d3c673eSRob Herring }
2593d93ebe0fSThéo Lebrun
259445e0f0f5SRob Herring OF_EARLYCON_DECLARE(pl011, "arm,pl011", pl011_early_console_setup);
2595d93ebe0fSThéo Lebrun
2596fcb32159SKefeng Wang OF_EARLYCON_DECLARE(pl011, "arm,sbsa-uart", pl011_early_console_setup);
25975a0722b8STimur Tabi
25985a0722b8STimur Tabi /*
25995a0722b8STimur Tabi * On Qualcomm Datacenter Technologies QDF2400 SOCs affected by
26005a0722b8STimur Tabi * Erratum 44, traditional earlycon can be enabled by specifying
26015a0722b8STimur Tabi * "earlycon=qdf2400_e44,<address>". Any options are ignored.
26025a0722b8STimur Tabi *
26035a0722b8STimur Tabi * Alternatively, you can just specify "earlycon", and the early console
26045a0722b8STimur Tabi * will be enabled with the information from the SPCR table. In this
26055a0722b8STimur Tabi * case, the SPCR code will detect the need for the E44 work-around,
26065a0722b8STimur Tabi * and set the console name to "qdf2400_e44".
26075a0722b8STimur Tabi */
26085a0722b8STimur Tabi static int __init
qdf2400_e44_early_console_setup(struct earlycon_device * device,const char * opt)26095a0722b8STimur Tabi qdf2400_e44_early_console_setup(struct earlycon_device *device,
26105a0722b8STimur Tabi const char *opt)
26115a0722b8STimur Tabi {
26125a0722b8STimur Tabi if (!device->port.membase)
26135a0722b8STimur Tabi return -ENODEV;
26145a0722b8STimur Tabi
26155a0722b8STimur Tabi device->con->write = qdf2400_e44_early_write;
26165a0722b8STimur Tabi return 0;
26175a0722b8STimur Tabi }
2618d93ebe0fSThéo Lebrun
26195a0722b8STimur Tabi EARLYCON_DECLARE(qdf2400_e44, qdf2400_e44_early_console_setup);
26200d3c673eSRob Herring
2621ab4382d2SGreg Kroah-Hartman #else
2622ab4382d2SGreg Kroah-Hartman #define AMBA_CONSOLE NULL
2623ab4382d2SGreg Kroah-Hartman #endif
2624ab4382d2SGreg Kroah-Hartman
2625ab4382d2SGreg Kroah-Hartman static struct uart_driver amba_reg = {
2626ab4382d2SGreg Kroah-Hartman .owner = THIS_MODULE,
2627ab4382d2SGreg Kroah-Hartman .driver_name = "ttyAMA",
2628ab4382d2SGreg Kroah-Hartman .dev_name = "ttyAMA",
2629ab4382d2SGreg Kroah-Hartman .major = SERIAL_AMBA_MAJOR,
2630ab4382d2SGreg Kroah-Hartman .minor = SERIAL_AMBA_MINOR,
2631ab4382d2SGreg Kroah-Hartman .nr = UART_NR,
2632ab4382d2SGreg Kroah-Hartman .cons = AMBA_CONSOLE,
2633ab4382d2SGreg Kroah-Hartman };
2634ab4382d2SGreg Kroah-Hartman
pl011_probe_dt_alias(int index,struct device * dev)263532614aadSMatthew Leach static int pl011_probe_dt_alias(int index, struct device *dev)
263632614aadSMatthew Leach {
263732614aadSMatthew Leach struct device_node *np;
2638826bd77aSThéo Lebrun static bool seen_dev_with_alias;
2639826bd77aSThéo Lebrun static bool seen_dev_without_alias;
264032614aadSMatthew Leach int ret = index;
264132614aadSMatthew Leach
264232614aadSMatthew Leach if (!IS_ENABLED(CONFIG_OF))
264332614aadSMatthew Leach return ret;
264432614aadSMatthew Leach
264532614aadSMatthew Leach np = dev->of_node;
264632614aadSMatthew Leach if (!np)
264732614aadSMatthew Leach return ret;
264832614aadSMatthew Leach
264932614aadSMatthew Leach ret = of_alias_get_id(np, "serial");
2650287980e4SArnd Bergmann if (ret < 0) {
265132614aadSMatthew Leach seen_dev_without_alias = true;
265232614aadSMatthew Leach ret = index;
265332614aadSMatthew Leach } else {
265432614aadSMatthew Leach seen_dev_with_alias = true;
265528a7ec8cSThéo Lebrun if (ret >= ARRAY_SIZE(amba_ports) || amba_ports[ret]) {
265632614aadSMatthew Leach dev_warn(dev, "requested serial port %d not available.\n", ret);
265732614aadSMatthew Leach ret = index;
265832614aadSMatthew Leach }
265932614aadSMatthew Leach }
266032614aadSMatthew Leach
266132614aadSMatthew Leach if (seen_dev_with_alias && seen_dev_without_alias)
266232614aadSMatthew Leach dev_warn(dev, "aliased and non-aliased serial devices found in device tree. Serial port enumeration may be unpredictable.\n");
266332614aadSMatthew Leach
266432614aadSMatthew Leach return ret;
266532614aadSMatthew Leach }
266632614aadSMatthew Leach
266749bb3c86SAndre Przywara /* unregisters the driver also if no more ports are left */
pl011_unregister_port(struct uart_amba_port * uap)266849bb3c86SAndre Przywara static void pl011_unregister_port(struct uart_amba_port *uap)
266949bb3c86SAndre Przywara {
267049bb3c86SAndre Przywara int i;
267149bb3c86SAndre Przywara bool busy = false;
267249bb3c86SAndre Przywara
267349bb3c86SAndre Przywara for (i = 0; i < ARRAY_SIZE(amba_ports); i++) {
267449bb3c86SAndre Przywara if (amba_ports[i] == uap)
267549bb3c86SAndre Przywara amba_ports[i] = NULL;
267649bb3c86SAndre Przywara else if (amba_ports[i])
267749bb3c86SAndre Przywara busy = true;
267849bb3c86SAndre Przywara }
267949bb3c86SAndre Przywara pl011_dma_remove(uap);
268049bb3c86SAndre Przywara if (!busy)
268149bb3c86SAndre Przywara uart_unregister_driver(&amba_reg);
268249bb3c86SAndre Przywara }
268349bb3c86SAndre Przywara
pl011_find_free_port(void)26843873e2d7SAndre Przywara static int pl011_find_free_port(void)
2685ab4382d2SGreg Kroah-Hartman {
26863873e2d7SAndre Przywara int i;
2687ab4382d2SGreg Kroah-Hartman
2688ab4382d2SGreg Kroah-Hartman for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
268928a7ec8cSThéo Lebrun if (!amba_ports[i])
26903873e2d7SAndre Przywara return i;
2691ab4382d2SGreg Kroah-Hartman
26927f6d942aSTushar Behera return -EBUSY;
26933873e2d7SAndre Przywara }
2694ab4382d2SGreg Kroah-Hartman
pl011_setup_port(struct device * dev,struct uart_amba_port * uap,struct resource * mmiobase,int index)26953873e2d7SAndre Przywara static int pl011_setup_port(struct device *dev, struct uart_amba_port *uap,
26963873e2d7SAndre Przywara struct resource *mmiobase, int index)
26973873e2d7SAndre Przywara {
26983873e2d7SAndre Przywara void __iomem *base;
26998d479237SLino Sanfilippo int ret;
2700ab4382d2SGreg Kroah-Hartman
27013873e2d7SAndre Przywara base = devm_ioremap_resource(dev, mmiobase);
270297a60eacSKrzysztof Kozlowski if (IS_ERR(base))
270397a60eacSKrzysztof Kozlowski return PTR_ERR(base);
2704ab4382d2SGreg Kroah-Hartman
27053873e2d7SAndre Przywara index = pl011_probe_dt_alias(index, dev);
2706ab4382d2SGreg Kroah-Hartman
27073873e2d7SAndre Przywara uap->port.dev = dev;
27083873e2d7SAndre Przywara uap->port.mapbase = mmiobase->start;
2709ab4382d2SGreg Kroah-Hartman uap->port.membase = base;
2710ab4382d2SGreg Kroah-Hartman uap->port.fifosize = uap->fifosize;
27115f99fca9SDmitry Safonov uap->port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_AMBA_PL011_CONSOLE);
2712ab4382d2SGreg Kroah-Hartman uap->port.flags = UPF_BOOT_AUTOCONF;
27133873e2d7SAndre Przywara uap->port.line = index;
27143873e2d7SAndre Przywara
2715838022deSLino Sanfilippo ret = uart_get_rs485_mode(&uap->port);
27168d479237SLino Sanfilippo if (ret)
27178d479237SLino Sanfilippo return ret;
27188d479237SLino Sanfilippo
27193873e2d7SAndre Przywara amba_ports[index] = uap;
27203873e2d7SAndre Przywara
27213873e2d7SAndre Przywara return 0;
27223873e2d7SAndre Przywara }
27233873e2d7SAndre Przywara
pl011_register_port(struct uart_amba_port * uap)27243873e2d7SAndre Przywara static int pl011_register_port(struct uart_amba_port *uap)
27253873e2d7SAndre Przywara {
272689efbe70SLukas Wunner int ret, i;
2727ab4382d2SGreg Kroah-Hartman
2728c3d8b76fSLinus Walleij /* Ensure interrupts from this UART are masked and cleared */
27299f25bc51SRussell King pl011_write(0, uap, REG_IMSC);
27309f25bc51SRussell King pl011_write(0xffff, uap, REG_ICR);
2731c3d8b76fSLinus Walleij
2732ef2889f7STushar Behera if (!amba_reg.state) {
2733ef2889f7STushar Behera ret = uart_register_driver(&amba_reg);
2734ef2889f7STushar Behera if (ret < 0) {
27353873e2d7SAndre Przywara dev_err(uap->port.dev,
27361c9be310SJorge Ramirez-Ortiz "Failed to register AMBA-PL011 driver\n");
273789efbe70SLukas Wunner for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
273889efbe70SLukas Wunner if (amba_ports[i] == uap)
273989efbe70SLukas Wunner amba_ports[i] = NULL;
2740ef2889f7STushar Behera return ret;
2741ef2889f7STushar Behera }
2742ef2889f7STushar Behera }
2743ef2889f7STushar Behera
2744ab4382d2SGreg Kroah-Hartman ret = uart_add_one_port(&amba_reg, &uap->port);
274549bb3c86SAndre Przywara if (ret)
274649bb3c86SAndre Przywara pl011_unregister_port(uap);
27477f6d942aSTushar Behera
2748ab4382d2SGreg Kroah-Hartman return ret;
2749ab4382d2SGreg Kroah-Hartman }
2750ab4382d2SGreg Kroah-Hartman
2751ebe2cf73SIlpo Järvinen static const struct serial_rs485 pl011_rs485_supported = {
2752ebe2cf73SIlpo Järvinen .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND |
2753ebe2cf73SIlpo Järvinen SER_RS485_RX_DURING_TX,
2754ebe2cf73SIlpo Järvinen .delay_rts_before_send = 1,
2755ebe2cf73SIlpo Järvinen .delay_rts_after_send = 1,
2756ebe2cf73SIlpo Järvinen };
2757ebe2cf73SIlpo Järvinen
pl011_probe(struct amba_device * dev,const struct amba_id * id)27583873e2d7SAndre Przywara static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
27593873e2d7SAndre Przywara {
27603873e2d7SAndre Przywara struct uart_amba_port *uap;
27613873e2d7SAndre Przywara struct vendor_data *vendor = id->data;
27623873e2d7SAndre Przywara int portnr, ret;
276381db9e8eSShubhrajyoti Datta u32 val;
27643873e2d7SAndre Przywara
27653873e2d7SAndre Przywara portnr = pl011_find_free_port();
27663873e2d7SAndre Przywara if (portnr < 0)
27673873e2d7SAndre Przywara return portnr;
27683873e2d7SAndre Przywara
27693873e2d7SAndre Przywara uap = devm_kzalloc(&dev->dev, sizeof(struct uart_amba_port),
27703873e2d7SAndre Przywara GFP_KERNEL);
27713873e2d7SAndre Przywara if (!uap)
27723873e2d7SAndre Przywara return -ENOMEM;
27733873e2d7SAndre Przywara
27743873e2d7SAndre Przywara uap->clk = devm_clk_get(&dev->dev, NULL);
27753873e2d7SAndre Przywara if (IS_ERR(uap->clk))
27763873e2d7SAndre Przywara return PTR_ERR(uap->clk);
27773873e2d7SAndre Przywara
2778439403bdSRussell King uap->reg_offset = vendor->reg_offset;
27793873e2d7SAndre Przywara uap->vendor = vendor;
27803873e2d7SAndre Przywara uap->fifosize = vendor->get_fifosize(dev);
27813b78fae7STimur Tabi uap->port.iotype = vendor->access_32b ? UPIO_MEM32 : UPIO_MEM;
27823873e2d7SAndre Przywara uap->port.irq = dev->irq[0];
27833873e2d7SAndre Przywara uap->port.ops = &amba_pl011_pops;
27848d479237SLino Sanfilippo uap->port.rs485_config = pl011_rs485_config;
27850139da50SIlpo Järvinen uap->port.rs485_supported = pl011_rs485_supported;
27863873e2d7SAndre Przywara snprintf(uap->type, sizeof(uap->type), "PL011 rev%u", amba_rev(dev));
27873873e2d7SAndre Przywara
278881db9e8eSShubhrajyoti Datta if (device_property_read_u32(&dev->dev, "reg-io-width", &val) == 0) {
278981db9e8eSShubhrajyoti Datta switch (val) {
279081db9e8eSShubhrajyoti Datta case 1:
279181db9e8eSShubhrajyoti Datta uap->port.iotype = UPIO_MEM;
279281db9e8eSShubhrajyoti Datta break;
279381db9e8eSShubhrajyoti Datta case 4:
279481db9e8eSShubhrajyoti Datta uap->port.iotype = UPIO_MEM32;
279581db9e8eSShubhrajyoti Datta break;
279681db9e8eSShubhrajyoti Datta default:
279781db9e8eSShubhrajyoti Datta dev_warn(&dev->dev, "unsupported reg-io-width (%d)\n",
279881db9e8eSShubhrajyoti Datta val);
279981db9e8eSShubhrajyoti Datta return -EINVAL;
280081db9e8eSShubhrajyoti Datta }
280181db9e8eSShubhrajyoti Datta }
280281db9e8eSShubhrajyoti Datta
28033873e2d7SAndre Przywara ret = pl011_setup_port(&dev->dev, uap, &dev->res, portnr);
28043873e2d7SAndre Przywara if (ret)
28053873e2d7SAndre Przywara return ret;
28063873e2d7SAndre Przywara
28073873e2d7SAndre Przywara amba_set_drvdata(dev, uap);
28083873e2d7SAndre Przywara
28093873e2d7SAndre Przywara return pl011_register_port(uap);
28103873e2d7SAndre Przywara }
28113873e2d7SAndre Przywara
pl011_remove(struct amba_device * dev)28123fd269e7SUwe Kleine-König static void pl011_remove(struct amba_device *dev)
2813ab4382d2SGreg Kroah-Hartman {
2814ab4382d2SGreg Kroah-Hartman struct uart_amba_port *uap = amba_get_drvdata(dev);
2815ab4382d2SGreg Kroah-Hartman
2816ab4382d2SGreg Kroah-Hartman uart_remove_one_port(&amba_reg, &uap->port);
281749bb3c86SAndre Przywara pl011_unregister_port(uap);
2818ab4382d2SGreg Kroah-Hartman }
2819ab4382d2SGreg Kroah-Hartman
2820d0ce850dSUlf Hansson #ifdef CONFIG_PM_SLEEP
pl011_suspend(struct device * dev)2821d0ce850dSUlf Hansson static int pl011_suspend(struct device *dev)
2822ab4382d2SGreg Kroah-Hartman {
2823d0ce850dSUlf Hansson struct uart_amba_port *uap = dev_get_drvdata(dev);
2824ab4382d2SGreg Kroah-Hartman
2825ab4382d2SGreg Kroah-Hartman if (!uap)
2826ab4382d2SGreg Kroah-Hartman return -EINVAL;
2827ab4382d2SGreg Kroah-Hartman
2828ab4382d2SGreg Kroah-Hartman return uart_suspend_port(&amba_reg, &uap->port);
2829ab4382d2SGreg Kroah-Hartman }
2830ab4382d2SGreg Kroah-Hartman
pl011_resume(struct device * dev)2831d0ce850dSUlf Hansson static int pl011_resume(struct device *dev)
2832ab4382d2SGreg Kroah-Hartman {
2833d0ce850dSUlf Hansson struct uart_amba_port *uap = dev_get_drvdata(dev);
2834ab4382d2SGreg Kroah-Hartman
2835ab4382d2SGreg Kroah-Hartman if (!uap)
2836ab4382d2SGreg Kroah-Hartman return -EINVAL;
2837ab4382d2SGreg Kroah-Hartman
2838ab4382d2SGreg Kroah-Hartman return uart_resume_port(&amba_reg, &uap->port);
2839ab4382d2SGreg Kroah-Hartman }
2840ab4382d2SGreg Kroah-Hartman #endif
2841ab4382d2SGreg Kroah-Hartman
2842d0ce850dSUlf Hansson static SIMPLE_DEV_PM_OPS(pl011_dev_pm_ops, pl011_suspend, pl011_resume);
2843d0ce850dSUlf Hansson
2844a49a8b9dSThéo Lebrun #ifdef CONFIG_ACPI_SPCR_TABLE
qpdf2400_erratum44_workaround(struct device * dev,struct uart_amba_port * uap)2845a49a8b9dSThéo Lebrun static void qpdf2400_erratum44_workaround(struct device *dev,
2846a49a8b9dSThéo Lebrun struct uart_amba_port *uap)
2847a49a8b9dSThéo Lebrun {
2848a49a8b9dSThéo Lebrun if (!qdf2400_e44_present)
2849a49a8b9dSThéo Lebrun return;
2850a49a8b9dSThéo Lebrun
2851a49a8b9dSThéo Lebrun dev_info(dev, "working around QDF2400 SoC erratum 44\n");
2852a49a8b9dSThéo Lebrun uap->vendor = &vendor_qdt_qdf2400_e44;
2853a49a8b9dSThéo Lebrun }
2854a49a8b9dSThéo Lebrun #else
qpdf2400_erratum44_workaround(struct device * dev,struct uart_amba_port * uap)2855a49a8b9dSThéo Lebrun static void qpdf2400_erratum44_workaround(struct device *dev,
2856a49a8b9dSThéo Lebrun struct uart_amba_port *uap)
2857a49a8b9dSThéo Lebrun { /* empty */ }
2858a49a8b9dSThéo Lebrun #endif
2859a49a8b9dSThéo Lebrun
sbsa_uart_probe(struct platform_device * pdev)28600dd1e247SAndre Przywara static int sbsa_uart_probe(struct platform_device *pdev)
28610dd1e247SAndre Przywara {
28620dd1e247SAndre Przywara struct uart_amba_port *uap;
28630dd1e247SAndre Przywara struct resource *r;
28640dd1e247SAndre Przywara int portnr, ret;
28650dd1e247SAndre Przywara int baudrate;
28660dd1e247SAndre Przywara
28670dd1e247SAndre Przywara /*
28680dd1e247SAndre Przywara * Check the mandatory baud rate parameter in the DT node early
28690dd1e247SAndre Przywara * so that we can easily exit with the error.
28700dd1e247SAndre Przywara */
28710dd1e247SAndre Przywara if (pdev->dev.of_node) {
28720dd1e247SAndre Przywara struct device_node *np = pdev->dev.of_node;
28730dd1e247SAndre Przywara
28740dd1e247SAndre Przywara ret = of_property_read_u32(np, "current-speed", &baudrate);
28750dd1e247SAndre Przywara if (ret)
28760dd1e247SAndre Przywara return ret;
28770dd1e247SAndre Przywara } else {
28780dd1e247SAndre Przywara baudrate = 115200;
28790dd1e247SAndre Przywara }
28800dd1e247SAndre Przywara
28810dd1e247SAndre Przywara portnr = pl011_find_free_port();
28820dd1e247SAndre Przywara if (portnr < 0)
28830dd1e247SAndre Przywara return portnr;
28840dd1e247SAndre Przywara
28850dd1e247SAndre Przywara uap = devm_kzalloc(&pdev->dev, sizeof(struct uart_amba_port),
28860dd1e247SAndre Przywara GFP_KERNEL);
28870dd1e247SAndre Przywara if (!uap)
28880dd1e247SAndre Przywara return -ENOMEM;
28890dd1e247SAndre Przywara
2890394a9e2cSJiri Slaby ret = platform_get_irq(pdev, 0);
28911df21786SStephen Boyd if (ret < 0)
2892394a9e2cSJiri Slaby return ret;
2893394a9e2cSJiri Slaby uap->port.irq = ret;
2894394a9e2cSJiri Slaby
289537ef38f3STimur Tabi uap->vendor = &vendor_sbsa;
2896a49a8b9dSThéo Lebrun qpdf2400_erratum44_workaround(&pdev->dev, uap);
289737ef38f3STimur Tabi
289837ef38f3STimur Tabi uap->reg_offset = uap->vendor->reg_offset;
28990dd1e247SAndre Przywara uap->fifosize = 32;
290037ef38f3STimur Tabi uap->port.iotype = uap->vendor->access_32b ? UPIO_MEM32 : UPIO_MEM;
29010dd1e247SAndre Przywara uap->port.ops = &sbsa_uart_pops;
29020dd1e247SAndre Przywara uap->fixed_baud = baudrate;
29030dd1e247SAndre Przywara
29040dd1e247SAndre Przywara snprintf(uap->type, sizeof(uap->type), "SBSA");
29050dd1e247SAndre Przywara
29060dd1e247SAndre Przywara r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
29070dd1e247SAndre Przywara
29080dd1e247SAndre Przywara ret = pl011_setup_port(&pdev->dev, uap, r, portnr);
29090dd1e247SAndre Przywara if (ret)
29100dd1e247SAndre Przywara return ret;
29110dd1e247SAndre Przywara
29120dd1e247SAndre Przywara platform_set_drvdata(pdev, uap);
29130dd1e247SAndre Przywara
29140dd1e247SAndre Przywara return pl011_register_port(uap);
29150dd1e247SAndre Przywara }
29160dd1e247SAndre Przywara
sbsa_uart_remove(struct platform_device * pdev)2917788f501aSUwe Kleine-König static void sbsa_uart_remove(struct platform_device *pdev)
29180dd1e247SAndre Przywara {
29190dd1e247SAndre Przywara struct uart_amba_port *uap = platform_get_drvdata(pdev);
29200dd1e247SAndre Przywara
29210dd1e247SAndre Przywara uart_remove_one_port(&amba_reg, &uap->port);
29220dd1e247SAndre Przywara pl011_unregister_port(uap);
29230dd1e247SAndre Przywara }
29240dd1e247SAndre Przywara
29250dd1e247SAndre Przywara static const struct of_device_id sbsa_uart_of_match[] = {
29260dd1e247SAndre Przywara { .compatible = "arm,sbsa-uart", },
29270dd1e247SAndre Przywara {},
29280dd1e247SAndre Przywara };
29290dd1e247SAndre Przywara MODULE_DEVICE_TABLE(of, sbsa_uart_of_match);
29300dd1e247SAndre Przywara
29317789c1f1SLee Jones static const struct acpi_device_id __maybe_unused sbsa_uart_acpi_match[] = {
29323db9ab0bSGraeme Gregory { "ARMH0011", 0 },
2933ac442a07SPierre Gondois { "ARMHB000", 0 },
29343db9ab0bSGraeme Gregory {},
29353db9ab0bSGraeme Gregory };
29363db9ab0bSGraeme Gregory MODULE_DEVICE_TABLE(acpi, sbsa_uart_acpi_match);
29373db9ab0bSGraeme Gregory
29380dd1e247SAndre Przywara static struct platform_driver arm_sbsa_uart_platform_driver = {
29390dd1e247SAndre Przywara .probe = sbsa_uart_probe,
2940788f501aSUwe Kleine-König .remove_new = sbsa_uart_remove,
29410dd1e247SAndre Przywara .driver = {
29420dd1e247SAndre Przywara .name = "sbsa-uart",
29432301ec36SShubhrajyoti Datta .pm = &pl011_dev_pm_ops,
29440dd1e247SAndre Przywara .of_match_table = of_match_ptr(sbsa_uart_of_match),
29453db9ab0bSGraeme Gregory .acpi_match_table = ACPI_PTR(sbsa_uart_acpi_match),
294664609794SAnders Roxell .suppress_bind_attrs = IS_BUILTIN(CONFIG_SERIAL_AMBA_PL011),
29470dd1e247SAndre Przywara },
29480dd1e247SAndre Przywara };
29490dd1e247SAndre Przywara
2950a704ddc2SArvind Yadav static const struct amba_id pl011_ids[] = {
2951ab4382d2SGreg Kroah-Hartman {
2952ab4382d2SGreg Kroah-Hartman .id = 0x00041011,
2953ab4382d2SGreg Kroah-Hartman .mask = 0x000fffff,
2954ab4382d2SGreg Kroah-Hartman .data = &vendor_arm,
2955ab4382d2SGreg Kroah-Hartman },
2956ab4382d2SGreg Kroah-Hartman {
2957ab4382d2SGreg Kroah-Hartman .id = 0x00380802,
2958ab4382d2SGreg Kroah-Hartman .mask = 0x00ffffff,
2959ab4382d2SGreg Kroah-Hartman .data = &vendor_st,
2960ab4382d2SGreg Kroah-Hartman },
2961ab4382d2SGreg Kroah-Hartman { 0, 0 },
2962ab4382d2SGreg Kroah-Hartman };
2963ab4382d2SGreg Kroah-Hartman
296460f7a33bSDave Martin MODULE_DEVICE_TABLE(amba, pl011_ids);
296560f7a33bSDave Martin
2966ab4382d2SGreg Kroah-Hartman static struct amba_driver pl011_driver = {
2967ab4382d2SGreg Kroah-Hartman .drv = {
2968ab4382d2SGreg Kroah-Hartman .name = "uart-pl011",
2969d0ce850dSUlf Hansson .pm = &pl011_dev_pm_ops,
297064609794SAnders Roxell .suppress_bind_attrs = IS_BUILTIN(CONFIG_SERIAL_AMBA_PL011),
2971ab4382d2SGreg Kroah-Hartman },
2972ab4382d2SGreg Kroah-Hartman .id_table = pl011_ids,
2973ab4382d2SGreg Kroah-Hartman .probe = pl011_probe,
2974ab4382d2SGreg Kroah-Hartman .remove = pl011_remove,
2975ab4382d2SGreg Kroah-Hartman };
2976ab4382d2SGreg Kroah-Hartman
pl011_init(void)2977ab4382d2SGreg Kroah-Hartman static int __init pl011_init(void)
2978ab4382d2SGreg Kroah-Hartman {
2979826bd77aSThéo Lebrun pr_info("Serial: AMBA PL011 UART driver\n");
2980ab4382d2SGreg Kroah-Hartman
29810dd1e247SAndre Przywara if (platform_driver_register(&arm_sbsa_uart_platform_driver))
29820dd1e247SAndre Przywara pr_warn("could not register SBSA UART platform driver\n");
2983062a68a5SGreg Kroah-Hartman return amba_driver_register(&pl011_driver);
2984ab4382d2SGreg Kroah-Hartman }
2985ab4382d2SGreg Kroah-Hartman
pl011_exit(void)2986ab4382d2SGreg Kroah-Hartman static void __exit pl011_exit(void)
2987ab4382d2SGreg Kroah-Hartman {
29880dd1e247SAndre Przywara platform_driver_unregister(&arm_sbsa_uart_platform_driver);
2989ab4382d2SGreg Kroah-Hartman amba_driver_unregister(&pl011_driver);
2990ab4382d2SGreg Kroah-Hartman }
2991ab4382d2SGreg Kroah-Hartman
2992ab4382d2SGreg Kroah-Hartman /*
2993ab4382d2SGreg Kroah-Hartman * While this can be a module, if builtin it's most likely the console
2994ab4382d2SGreg Kroah-Hartman * So let's leave module_exit but move module_init to an earlier place
2995ab4382d2SGreg Kroah-Hartman */
2996ab4382d2SGreg Kroah-Hartman arch_initcall(pl011_init);
2997ab4382d2SGreg Kroah-Hartman module_exit(pl011_exit);
2998ab4382d2SGreg Kroah-Hartman
2999ab4382d2SGreg Kroah-Hartman MODULE_AUTHOR("ARM Ltd/Deep Blue Solutions Ltd");
3000ab4382d2SGreg Kroah-Hartman MODULE_DESCRIPTION("ARM AMBA serial port driver");
3001ab4382d2SGreg Kroah-Hartman MODULE_LICENSE("GPL");
3002