1e3b3d0f5SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2ab4382d2SGreg Kroah-Hartman /*
3ab4382d2SGreg Kroah-Hartman * SuperH on-chip serial module support. (SCI with no FIFO / with FIFO)
4ab4382d2SGreg Kroah-Hartman *
5fc887b15SLinus Torvalds * Copyright (C) 2002 - 2011 Paul Mundt
6f4998e55SGeert Uytterhoeven * Copyright (C) 2015 Glider bvba
7ab4382d2SGreg Kroah-Hartman * Modified to support SH7720 SCIF. Markus Brunner, Mark Jonas (Jul 2007).
8ab4382d2SGreg Kroah-Hartman *
9ab4382d2SGreg Kroah-Hartman * based off of the old drivers/char/sh-sci.c by:
10ab4382d2SGreg Kroah-Hartman *
11ab4382d2SGreg Kroah-Hartman * Copyright (C) 1999, 2000 Niibe Yutaka
12ab4382d2SGreg Kroah-Hartman * Copyright (C) 2000 Sugioka Toshinobu
13ab4382d2SGreg Kroah-Hartman * Modified to support multiple serial ports. Stuart Menefy (May 2000).
14ab4382d2SGreg Kroah-Hartman * Modified to support SecureEdge. David McCullough (2002)
15ab4382d2SGreg Kroah-Hartman * Modified to support SH7300 SCIF. Takashi Kusuda (Jun 2003).
16ab4382d2SGreg Kroah-Hartman * Removed SH7300 support (Jul 2007).
17ab4382d2SGreg Kroah-Hartman */
18ab4382d2SGreg Kroah-Hartman #undef DEBUG
19ab4382d2SGreg Kroah-Hartman
20ab4382d2SGreg Kroah-Hartman #include <linux/clk.h>
218fb9631cSLaurent Pinchart #include <linux/console.h>
22ab4382d2SGreg Kroah-Hartman #include <linux/ctype.h>
238fb9631cSLaurent Pinchart #include <linux/cpufreq.h>
248fb9631cSLaurent Pinchart #include <linux/delay.h>
25ab4382d2SGreg Kroah-Hartman #include <linux/dmaengine.h>
265beabc7fSMagnus Damm #include <linux/dma-mapping.h>
278fb9631cSLaurent Pinchart #include <linux/err.h>
288fb9631cSLaurent Pinchart #include <linux/errno.h>
298fb9631cSLaurent Pinchart #include <linux/init.h>
308fb9631cSLaurent Pinchart #include <linux/interrupt.h>
318fb9631cSLaurent Pinchart #include <linux/ioport.h>
32b96408b4SUlrich Hecht #include <linux/ktime.h>
338fb9631cSLaurent Pinchart #include <linux/major.h>
34b43a1864SBiju Das #include <linux/minmax.h>
358fb9631cSLaurent Pinchart #include <linux/module.h>
368fb9631cSLaurent Pinchart #include <linux/mm.h>
3720bdcab8SBastian Hecht #include <linux/of.h>
388fb9631cSLaurent Pinchart #include <linux/platform_device.h>
398fb9631cSLaurent Pinchart #include <linux/pm_runtime.h>
40862f7218SLad Prabhakar #include <linux/reset.h>
418fb9631cSLaurent Pinchart #include <linux/scatterlist.h>
428fb9631cSLaurent Pinchart #include <linux/serial.h>
438fb9631cSLaurent Pinchart #include <linux/serial_sci.h>
448fb9631cSLaurent Pinchart #include <linux/sh_dma.h>
458fb9631cSLaurent Pinchart #include <linux/slab.h>
468fb9631cSLaurent Pinchart #include <linux/string.h>
478fb9631cSLaurent Pinchart #include <linux/sysrq.h>
488fb9631cSLaurent Pinchart #include <linux/timer.h>
498fb9631cSLaurent Pinchart #include <linux/tty.h>
508fb9631cSLaurent Pinchart #include <linux/tty_flip.h>
51ab4382d2SGreg Kroah-Hartman
52ab4382d2SGreg Kroah-Hartman #ifdef CONFIG_SUPERH
53ab4382d2SGreg Kroah-Hartman #include <asm/sh_bios.h>
54507fd01dSBartosz Golaszewski #include <asm/platform_early.h>
55ab4382d2SGreg Kroah-Hartman #endif
56ab4382d2SGreg Kroah-Hartman
57f907c9eaSGeert Uytterhoeven #include "serial_mctrl_gpio.h"
58ab4382d2SGreg Kroah-Hartman #include "sh-sci.h"
59ab4382d2SGreg Kroah-Hartman
6089b5c1abSLaurent Pinchart /* Offsets into the sci_port->irqs array */
6189b5c1abSLaurent Pinchart enum {
6289b5c1abSLaurent Pinchart SCIx_ERI_IRQ,
6389b5c1abSLaurent Pinchart SCIx_RXI_IRQ,
6489b5c1abSLaurent Pinchart SCIx_TXI_IRQ,
6589b5c1abSLaurent Pinchart SCIx_BRI_IRQ,
66628c534aSChris Brandt SCIx_DRI_IRQ,
67628c534aSChris Brandt SCIx_TEI_IRQ,
6889b5c1abSLaurent Pinchart SCIx_NR_IRQS,
6989b5c1abSLaurent Pinchart
7089b5c1abSLaurent Pinchart SCIx_MUX_IRQ = SCIx_NR_IRQS, /* special case */
7189b5c1abSLaurent Pinchart };
7289b5c1abSLaurent Pinchart
7389b5c1abSLaurent Pinchart #define SCIx_IRQ_IS_MUXED(port) \
7489b5c1abSLaurent Pinchart ((port)->irqs[SCIx_ERI_IRQ] == \
7589b5c1abSLaurent Pinchart (port)->irqs[SCIx_RXI_IRQ]) || \
7689b5c1abSLaurent Pinchart ((port)->irqs[SCIx_ERI_IRQ] && \
7789b5c1abSLaurent Pinchart ((port)->irqs[SCIx_RXI_IRQ] < 0))
7889b5c1abSLaurent Pinchart
79f4998e55SGeert Uytterhoeven enum SCI_CLKS {
80f4998e55SGeert Uytterhoeven SCI_FCK, /* Functional Clock */
816af27bf2SGeert Uytterhoeven SCI_SCK, /* Optional External Clock */
821270f865SGeert Uytterhoeven SCI_BRG_INT, /* Optional BRG Internal Clock Source */
831270f865SGeert Uytterhoeven SCI_SCIF_CLK, /* Optional BRG External Clock Source */
84f4998e55SGeert Uytterhoeven SCI_NUM_CLKS
85f4998e55SGeert Uytterhoeven };
86f4998e55SGeert Uytterhoeven
8769eee8e9SGeert Uytterhoeven /* Bit x set means sampling rate x + 1 is supported */
8869eee8e9SGeert Uytterhoeven #define SCI_SR(x) BIT((x) - 1)
8969eee8e9SGeert Uytterhoeven #define SCI_SR_RANGE(x, y) GENMASK((y) - 1, (x) - 1)
9069eee8e9SGeert Uytterhoeven
9192a05748SGeert Uytterhoeven #define SCI_SR_SCIFAB SCI_SR(5) | SCI_SR(7) | SCI_SR(11) | \
9292a05748SGeert Uytterhoeven SCI_SR(13) | SCI_SR(16) | SCI_SR(17) | \
9392a05748SGeert Uytterhoeven SCI_SR(19) | SCI_SR(27)
9492a05748SGeert Uytterhoeven
9569eee8e9SGeert Uytterhoeven #define min_sr(_port) ffs((_port)->sampling_rate_mask)
9669eee8e9SGeert Uytterhoeven #define max_sr(_port) fls((_port)->sampling_rate_mask)
9769eee8e9SGeert Uytterhoeven
9869eee8e9SGeert Uytterhoeven /* Iterate over all supported sampling rates, from high to low */
9969eee8e9SGeert Uytterhoeven #define for_each_sr(_sr, _port) \
10069eee8e9SGeert Uytterhoeven for ((_sr) = max_sr(_port); (_sr) >= min_sr(_port); (_sr)--) \
10169eee8e9SGeert Uytterhoeven if ((_port)->sampling_rate_mask & SCI_SR((_sr)))
10269eee8e9SGeert Uytterhoeven
103e095ee6bSLaurent Pinchart struct plat_sci_reg {
104e095ee6bSLaurent Pinchart u8 offset, size;
105e095ee6bSLaurent Pinchart };
106e095ee6bSLaurent Pinchart
10722a6984cSClaudiu Beznea struct sci_suspend_regs {
10881100b9aSGeert Uytterhoeven u16 scdl;
10981100b9aSGeert Uytterhoeven u16 sccks;
11022a6984cSClaudiu Beznea u16 scsmr;
11122a6984cSClaudiu Beznea u16 scscr;
11222a6984cSClaudiu Beznea u16 scfcr;
11322a6984cSClaudiu Beznea u16 scsptr;
11481100b9aSGeert Uytterhoeven u16 hssrr;
11581100b9aSGeert Uytterhoeven u16 scpcr;
11681100b9aSGeert Uytterhoeven u16 scpdr;
11722a6984cSClaudiu Beznea u8 scbrr;
11822a6984cSClaudiu Beznea u8 semr;
11922a6984cSClaudiu Beznea };
12022a6984cSClaudiu Beznea
121e095ee6bSLaurent Pinchart struct sci_port_params {
122e095ee6bSLaurent Pinchart const struct plat_sci_reg regs[SCIx_NR_REGS];
123b2f20ed9SLaurent Pinchart unsigned int fifosize;
124b2f20ed9SLaurent Pinchart unsigned int overrun_reg;
125b2f20ed9SLaurent Pinchart unsigned int overrun_mask;
126b2f20ed9SLaurent Pinchart unsigned int sampling_rate_mask;
127b2f20ed9SLaurent Pinchart unsigned int error_mask;
128b2f20ed9SLaurent Pinchart unsigned int error_clear;
129e095ee6bSLaurent Pinchart };
130e095ee6bSLaurent Pinchart
131ab4382d2SGreg Kroah-Hartman struct sci_port {
132ab4382d2SGreg Kroah-Hartman struct uart_port port;
133ab4382d2SGreg Kroah-Hartman
1346b620478SPaul Mundt /* Platform configuration */
135e095ee6bSLaurent Pinchart const struct sci_port_params *params;
136daf5a895SLaurent Pinchart const struct plat_sci_port *cfg;
13769eee8e9SGeert Uytterhoeven unsigned int sampling_rate_mask;
138e4d6f911SYoshinori Sato resource_size_t reg_size;
139f907c9eaSGeert Uytterhoeven struct mctrl_gpios *gpios;
140ab4382d2SGreg Kroah-Hartman
141f4998e55SGeert Uytterhoeven /* Clocks */
142f4998e55SGeert Uytterhoeven struct clk *clks[SCI_NUM_CLKS];
143f4998e55SGeert Uytterhoeven unsigned long clk_rates[SCI_NUM_CLKS];
144ab4382d2SGreg Kroah-Hartman
1451fcc91a6SLaurent Pinchart int irqs[SCIx_NR_IRQS];
1469174fc8fSPaul Mundt char *irqstr[SCIx_NR_IRQS];
1479174fc8fSPaul Mundt
148ab4382d2SGreg Kroah-Hartman struct dma_chan *chan_tx;
149ab4382d2SGreg Kroah-Hartman struct dma_chan *chan_rx;
150fc887b15SLinus Torvalds
15122a6984cSClaudiu Beznea struct reset_control *rstc;
15222a6984cSClaudiu Beznea
153ab4382d2SGreg Kroah-Hartman #ifdef CONFIG_SERIAL_SH_SCI_DMA
1542c4ee235SGeert Uytterhoeven struct dma_chan *chan_tx_saved;
1552c4ee235SGeert Uytterhoeven struct dma_chan *chan_rx_saved;
156ab4382d2SGreg Kroah-Hartman dma_cookie_t cookie_tx;
157ab4382d2SGreg Kroah-Hartman dma_cookie_t cookie_rx[2];
158ab4382d2SGreg Kroah-Hartman dma_cookie_t active_rx;
15979904420SGeert Uytterhoeven dma_addr_t tx_dma_addr;
16079904420SGeert Uytterhoeven unsigned int tx_dma_len;
161ab4382d2SGreg Kroah-Hartman struct scatterlist sg_rx[2];
1627b39d901SYoshihiro Shimoda void *rx_buf[2];
163ab4382d2SGreg Kroah-Hartman size_t buf_len_rx;
164ab4382d2SGreg Kroah-Hartman struct work_struct work_tx;
165b96408b4SUlrich Hecht struct hrtimer rx_timer;
166b96408b4SUlrich Hecht unsigned int rx_timeout; /* microseconds */
167ab4382d2SGreg Kroah-Hartman #endif
16803940376SUlrich Hecht unsigned int rx_frame;
16918e8cf15SUlrich Hecht int rx_trigger;
17003940376SUlrich Hecht struct timer_list rx_fifo_timer;
17103940376SUlrich Hecht int rx_fifo_timeout;
17222a6984cSClaudiu Beznea struct sci_suspend_regs suspend_regs;
173fa2abb03SUlrich Hecht u16 hscif_tot;
17433f50ffcSGeert Uytterhoeven
17597ed9790SLaurent Pinchart bool has_rtscts;
17633f50ffcSGeert Uytterhoeven bool autorts;
1777cc0e0a4SClaudiu Beznea bool tx_occurred;
178ab4382d2SGreg Kroah-Hartman };
179ab4382d2SGreg Kroah-Hartman
180ab4382d2SGreg Kroah-Hartman #define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS
181ab4382d2SGreg Kroah-Hartman
182ab4382d2SGreg Kroah-Hartman static struct sci_port sci_ports[SCI_NPORTS];
1837678f4c2SGeert Uytterhoeven static unsigned long sci_ports_in_use;
184ab4382d2SGreg Kroah-Hartman static struct uart_driver sci_uart_driver;
1859f7dea87SClaudiu Beznea static bool sci_uart_earlycon;
1865f101706SClaudiu Beznea static bool sci_uart_earlycon_dev_probing;
187ab4382d2SGreg Kroah-Hartman
188ab4382d2SGreg Kroah-Hartman static inline struct sci_port *
to_sci_port(struct uart_port * uart)189ab4382d2SGreg Kroah-Hartman to_sci_port(struct uart_port *uart)
190ab4382d2SGreg Kroah-Hartman {
191ab4382d2SGreg Kroah-Hartman return container_of(uart, struct sci_port, port);
192ab4382d2SGreg Kroah-Hartman }
193ab4382d2SGreg Kroah-Hartman
194e095ee6bSLaurent Pinchart static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
19561a6976bSPaul Mundt /*
19661a6976bSPaul Mundt * Common SCI definitions, dependent on the port's regshift
19761a6976bSPaul Mundt * value.
19861a6976bSPaul Mundt */
19961a6976bSPaul Mundt [SCIx_SCI_REGTYPE] = {
200e095ee6bSLaurent Pinchart .regs = {
20161a6976bSPaul Mundt [SCSMR] = { 0x00, 8 },
20261a6976bSPaul Mundt [SCBRR] = { 0x01, 8 },
20361a6976bSPaul Mundt [SCSCR] = { 0x02, 8 },
20461a6976bSPaul Mundt [SCxTDR] = { 0x03, 8 },
20561a6976bSPaul Mundt [SCxSR] = { 0x04, 8 },
20661a6976bSPaul Mundt [SCxRDR] = { 0x05, 8 },
20761a6976bSPaul Mundt },
208b2f20ed9SLaurent Pinchart .fifosize = 1,
209b2f20ed9SLaurent Pinchart .overrun_reg = SCxSR,
210b2f20ed9SLaurent Pinchart .overrun_mask = SCI_ORER,
211b2f20ed9SLaurent Pinchart .sampling_rate_mask = SCI_SR(32),
212b2f20ed9SLaurent Pinchart .error_mask = SCI_DEFAULT_ERROR_MASK | SCI_ORER,
213b2f20ed9SLaurent Pinchart .error_clear = SCI_ERROR_CLEAR & ~SCI_ORER,
214e095ee6bSLaurent Pinchart },
21561a6976bSPaul Mundt
21661a6976bSPaul Mundt /*
217a752ba18SLaurent Pinchart * Common definitions for legacy IrDA ports.
21861a6976bSPaul Mundt */
21961a6976bSPaul Mundt [SCIx_IRDA_REGTYPE] = {
220e095ee6bSLaurent Pinchart .regs = {
22161a6976bSPaul Mundt [SCSMR] = { 0x00, 8 },
222a752ba18SLaurent Pinchart [SCBRR] = { 0x02, 8 },
223a752ba18SLaurent Pinchart [SCSCR] = { 0x04, 8 },
224a752ba18SLaurent Pinchart [SCxTDR] = { 0x06, 8 },
225a752ba18SLaurent Pinchart [SCxSR] = { 0x08, 16 },
226a752ba18SLaurent Pinchart [SCxRDR] = { 0x0a, 8 },
227a752ba18SLaurent Pinchart [SCFCR] = { 0x0c, 8 },
228a752ba18SLaurent Pinchart [SCFDR] = { 0x0e, 16 },
22961a6976bSPaul Mundt },
230b2f20ed9SLaurent Pinchart .fifosize = 1,
231b2f20ed9SLaurent Pinchart .overrun_reg = SCxSR,
232b2f20ed9SLaurent Pinchart .overrun_mask = SCI_ORER,
233b2f20ed9SLaurent Pinchart .sampling_rate_mask = SCI_SR(32),
234b2f20ed9SLaurent Pinchart .error_mask = SCI_DEFAULT_ERROR_MASK | SCI_ORER,
235b2f20ed9SLaurent Pinchart .error_clear = SCI_ERROR_CLEAR & ~SCI_ORER,
236e095ee6bSLaurent Pinchart },
23761a6976bSPaul Mundt
23861a6976bSPaul Mundt /*
23961a6976bSPaul Mundt * Common SCIFA definitions.
24061a6976bSPaul Mundt */
24161a6976bSPaul Mundt [SCIx_SCIFA_REGTYPE] = {
242e095ee6bSLaurent Pinchart .regs = {
24361a6976bSPaul Mundt [SCSMR] = { 0x00, 16 },
24461a6976bSPaul Mundt [SCBRR] = { 0x04, 8 },
24561a6976bSPaul Mundt [SCSCR] = { 0x08, 16 },
24661a6976bSPaul Mundt [SCxTDR] = { 0x20, 8 },
24761a6976bSPaul Mundt [SCxSR] = { 0x14, 16 },
24861a6976bSPaul Mundt [SCxRDR] = { 0x24, 8 },
24961a6976bSPaul Mundt [SCFCR] = { 0x18, 16 },
25061a6976bSPaul Mundt [SCFDR] = { 0x1c, 16 },
251c097abc3SGeert Uytterhoeven [SCPCR] = { 0x30, 16 },
252c097abc3SGeert Uytterhoeven [SCPDR] = { 0x34, 16 },
25361a6976bSPaul Mundt },
254b2f20ed9SLaurent Pinchart .fifosize = 64,
255b2f20ed9SLaurent Pinchart .overrun_reg = SCxSR,
256b2f20ed9SLaurent Pinchart .overrun_mask = SCIFA_ORER,
257b2f20ed9SLaurent Pinchart .sampling_rate_mask = SCI_SR_SCIFAB,
258b2f20ed9SLaurent Pinchart .error_mask = SCIF_DEFAULT_ERROR_MASK | SCIFA_ORER,
259b2f20ed9SLaurent Pinchart .error_clear = SCIF_ERROR_CLEAR & ~SCIFA_ORER,
260e095ee6bSLaurent Pinchart },
26161a6976bSPaul Mundt
26261a6976bSPaul Mundt /*
26361a6976bSPaul Mundt * Common SCIFB definitions.
26461a6976bSPaul Mundt */
26561a6976bSPaul Mundt [SCIx_SCIFB_REGTYPE] = {
266e095ee6bSLaurent Pinchart .regs = {
26761a6976bSPaul Mundt [SCSMR] = { 0x00, 16 },
26861a6976bSPaul Mundt [SCBRR] = { 0x04, 8 },
26961a6976bSPaul Mundt [SCSCR] = { 0x08, 16 },
27061a6976bSPaul Mundt [SCxTDR] = { 0x40, 8 },
27161a6976bSPaul Mundt [SCxSR] = { 0x14, 16 },
27261a6976bSPaul Mundt [SCxRDR] = { 0x60, 8 },
27361a6976bSPaul Mundt [SCFCR] = { 0x18, 16 },
2748c66d6d2STakashi Yoshii [SCTFDR] = { 0x38, 16 },
2758c66d6d2STakashi Yoshii [SCRFDR] = { 0x3c, 16 },
276c097abc3SGeert Uytterhoeven [SCPCR] = { 0x30, 16 },
277c097abc3SGeert Uytterhoeven [SCPDR] = { 0x34, 16 },
27861a6976bSPaul Mundt },
279b2f20ed9SLaurent Pinchart .fifosize = 256,
280b2f20ed9SLaurent Pinchart .overrun_reg = SCxSR,
281b2f20ed9SLaurent Pinchart .overrun_mask = SCIFA_ORER,
282b2f20ed9SLaurent Pinchart .sampling_rate_mask = SCI_SR_SCIFAB,
283b2f20ed9SLaurent Pinchart .error_mask = SCIF_DEFAULT_ERROR_MASK | SCIFA_ORER,
284b2f20ed9SLaurent Pinchart .error_clear = SCIF_ERROR_CLEAR & ~SCIFA_ORER,
285e095ee6bSLaurent Pinchart },
28661a6976bSPaul Mundt
28761a6976bSPaul Mundt /*
2883af1f8a4SPhil Edworthy * Common SH-2(A) SCIF definitions for ports with FIFO data
2893af1f8a4SPhil Edworthy * count registers.
2903af1f8a4SPhil Edworthy */
2913af1f8a4SPhil Edworthy [SCIx_SH2_SCIF_FIFODATA_REGTYPE] = {
292e095ee6bSLaurent Pinchart .regs = {
2933af1f8a4SPhil Edworthy [SCSMR] = { 0x00, 16 },
2943af1f8a4SPhil Edworthy [SCBRR] = { 0x04, 8 },
2953af1f8a4SPhil Edworthy [SCSCR] = { 0x08, 16 },
2963af1f8a4SPhil Edworthy [SCxTDR] = { 0x0c, 8 },
2973af1f8a4SPhil Edworthy [SCxSR] = { 0x10, 16 },
2983af1f8a4SPhil Edworthy [SCxRDR] = { 0x14, 8 },
2993af1f8a4SPhil Edworthy [SCFCR] = { 0x18, 16 },
3003af1f8a4SPhil Edworthy [SCFDR] = { 0x1c, 16 },
3013af1f8a4SPhil Edworthy [SCSPTR] = { 0x20, 16 },
3023af1f8a4SPhil Edworthy [SCLSR] = { 0x24, 16 },
3033af1f8a4SPhil Edworthy },
304b2f20ed9SLaurent Pinchart .fifosize = 16,
305b2f20ed9SLaurent Pinchart .overrun_reg = SCLSR,
306b2f20ed9SLaurent Pinchart .overrun_mask = SCLSR_ORER,
307b2f20ed9SLaurent Pinchart .sampling_rate_mask = SCI_SR(32),
308b2f20ed9SLaurent Pinchart .error_mask = SCIF_DEFAULT_ERROR_MASK,
309b2f20ed9SLaurent Pinchart .error_clear = SCIF_ERROR_CLEAR,
310e095ee6bSLaurent Pinchart },
3113af1f8a4SPhil Edworthy
3123af1f8a4SPhil Edworthy /*
3133b2cd606SBiju Das * The "SCIFA" that is in RZ/A2, RZ/G2L and RZ/T.
31410c63443SGeert Uytterhoeven * It looks like a normal SCIF with FIFO data, but with a
31510c63443SGeert Uytterhoeven * compressed address space. Also, the break out of interrupts
31610c63443SGeert Uytterhoeven * are different: ERI/BRI, RXI, TXI, TEI, DRI.
31710c63443SGeert Uytterhoeven */
31810c63443SGeert Uytterhoeven [SCIx_RZ_SCIFA_REGTYPE] = {
31910c63443SGeert Uytterhoeven .regs = {
32010c63443SGeert Uytterhoeven [SCSMR] = { 0x00, 16 },
32110c63443SGeert Uytterhoeven [SCBRR] = { 0x02, 8 },
32210c63443SGeert Uytterhoeven [SCSCR] = { 0x04, 16 },
32310c63443SGeert Uytterhoeven [SCxTDR] = { 0x06, 8 },
32410c63443SGeert Uytterhoeven [SCxSR] = { 0x08, 16 },
32510c63443SGeert Uytterhoeven [SCxRDR] = { 0x0A, 8 },
32610c63443SGeert Uytterhoeven [SCFCR] = { 0x0C, 16 },
32710c63443SGeert Uytterhoeven [SCFDR] = { 0x0E, 16 },
32810c63443SGeert Uytterhoeven [SCSPTR] = { 0x10, 16 },
32910c63443SGeert Uytterhoeven [SCLSR] = { 0x12, 16 },
3303b2cd606SBiju Das [SEMR] = { 0x14, 8 },
33110c63443SGeert Uytterhoeven },
33210c63443SGeert Uytterhoeven .fifosize = 16,
33310c63443SGeert Uytterhoeven .overrun_reg = SCLSR,
33410c63443SGeert Uytterhoeven .overrun_mask = SCLSR_ORER,
33510c63443SGeert Uytterhoeven .sampling_rate_mask = SCI_SR(32),
33610c63443SGeert Uytterhoeven .error_mask = SCIF_DEFAULT_ERROR_MASK,
33710c63443SGeert Uytterhoeven .error_clear = SCIF_ERROR_CLEAR,
33810c63443SGeert Uytterhoeven },
33910c63443SGeert Uytterhoeven
34010c63443SGeert Uytterhoeven /*
3412f50304eSLad Prabhakar * The "SCIF" that is in RZ/V2H(P) SoC is similar to one found on RZ/G2L SoC
3422f50304eSLad Prabhakar * with below differences,
3432f50304eSLad Prabhakar * - Break out of interrupts are different: ERI, BRI, RXI, TXI, TEI, DRI,
3442f50304eSLad Prabhakar * TEI-DRI, RXI-EDGE and TXI-EDGE.
3452f50304eSLad Prabhakar * - SCSMR register does not have CM bit (BIT(7)) ie it does not support synchronous mode.
3462f50304eSLad Prabhakar * - SCFCR register does not have SCFCR_MCE bit.
3472f50304eSLad Prabhakar * - SCSPTR register has only bits SCSPTR_SPB2DT and SCSPTR_SPB2IO.
3482f50304eSLad Prabhakar */
3492f50304eSLad Prabhakar [SCIx_RZV2H_SCIF_REGTYPE] = {
3502f50304eSLad Prabhakar .regs = {
3512f50304eSLad Prabhakar [SCSMR] = { 0x00, 16 },
3522f50304eSLad Prabhakar [SCBRR] = { 0x02, 8 },
3532f50304eSLad Prabhakar [SCSCR] = { 0x04, 16 },
3542f50304eSLad Prabhakar [SCxTDR] = { 0x06, 8 },
3552f50304eSLad Prabhakar [SCxSR] = { 0x08, 16 },
3562f50304eSLad Prabhakar [SCxRDR] = { 0x0a, 8 },
3572f50304eSLad Prabhakar [SCFCR] = { 0x0c, 16 },
3582f50304eSLad Prabhakar [SCFDR] = { 0x0e, 16 },
3592f50304eSLad Prabhakar [SCSPTR] = { 0x10, 16 },
3602f50304eSLad Prabhakar [SCLSR] = { 0x12, 16 },
3612f50304eSLad Prabhakar [SEMR] = { 0x14, 8 },
3622f50304eSLad Prabhakar },
3632f50304eSLad Prabhakar .fifosize = 16,
3642f50304eSLad Prabhakar .overrun_reg = SCLSR,
3652f50304eSLad Prabhakar .overrun_mask = SCLSR_ORER,
3662f50304eSLad Prabhakar .sampling_rate_mask = SCI_SR(32),
3672f50304eSLad Prabhakar .error_mask = SCIF_DEFAULT_ERROR_MASK,
3682f50304eSLad Prabhakar .error_clear = SCIF_ERROR_CLEAR,
3692f50304eSLad Prabhakar },
3702f50304eSLad Prabhakar
3712f50304eSLad Prabhakar /*
37261a6976bSPaul Mundt * Common SH-3 SCIF definitions.
37361a6976bSPaul Mundt */
37461a6976bSPaul Mundt [SCIx_SH3_SCIF_REGTYPE] = {
375e095ee6bSLaurent Pinchart .regs = {
37661a6976bSPaul Mundt [SCSMR] = { 0x00, 8 },
37761a6976bSPaul Mundt [SCBRR] = { 0x02, 8 },
37861a6976bSPaul Mundt [SCSCR] = { 0x04, 8 },
37961a6976bSPaul Mundt [SCxTDR] = { 0x06, 8 },
38061a6976bSPaul Mundt [SCxSR] = { 0x08, 16 },
38161a6976bSPaul Mundt [SCxRDR] = { 0x0a, 8 },
38261a6976bSPaul Mundt [SCFCR] = { 0x0c, 8 },
38361a6976bSPaul Mundt [SCFDR] = { 0x0e, 16 },
38461a6976bSPaul Mundt },
385b2f20ed9SLaurent Pinchart .fifosize = 16,
386b2f20ed9SLaurent Pinchart .overrun_reg = SCLSR,
387b2f20ed9SLaurent Pinchart .overrun_mask = SCLSR_ORER,
388b2f20ed9SLaurent Pinchart .sampling_rate_mask = SCI_SR(32),
389b2f20ed9SLaurent Pinchart .error_mask = SCIF_DEFAULT_ERROR_MASK,
390b2f20ed9SLaurent Pinchart .error_clear = SCIF_ERROR_CLEAR,
391e095ee6bSLaurent Pinchart },
39261a6976bSPaul Mundt
39361a6976bSPaul Mundt /*
39461a6976bSPaul Mundt * Common SH-4(A) SCIF(B) definitions.
39561a6976bSPaul Mundt */
39661a6976bSPaul Mundt [SCIx_SH4_SCIF_REGTYPE] = {
397e095ee6bSLaurent Pinchart .regs = {
39861a6976bSPaul Mundt [SCSMR] = { 0x00, 16 },
399a1c2fd7eSGeert Uytterhoeven [SCBRR] = { 0x04, 8 },
400a1c2fd7eSGeert Uytterhoeven [SCSCR] = { 0x08, 16 },
401a1c2fd7eSGeert Uytterhoeven [SCxTDR] = { 0x0c, 8 },
402a1c2fd7eSGeert Uytterhoeven [SCxSR] = { 0x10, 16 },
403a1c2fd7eSGeert Uytterhoeven [SCxRDR] = { 0x14, 8 },
404a1c2fd7eSGeert Uytterhoeven [SCFCR] = { 0x18, 16 },
405a1c2fd7eSGeert Uytterhoeven [SCFDR] = { 0x1c, 16 },
406a1c2fd7eSGeert Uytterhoeven [SCSPTR] = { 0x20, 16 },
407a1c2fd7eSGeert Uytterhoeven [SCLSR] = { 0x24, 16 },
408b8bbd6b2SGeert Uytterhoeven },
409b2f20ed9SLaurent Pinchart .fifosize = 16,
410b2f20ed9SLaurent Pinchart .overrun_reg = SCLSR,
411b2f20ed9SLaurent Pinchart .overrun_mask = SCLSR_ORER,
412b2f20ed9SLaurent Pinchart .sampling_rate_mask = SCI_SR(32),
413b2f20ed9SLaurent Pinchart .error_mask = SCIF_DEFAULT_ERROR_MASK,
414b2f20ed9SLaurent Pinchart .error_clear = SCIF_ERROR_CLEAR,
415e095ee6bSLaurent Pinchart },
416b8bbd6b2SGeert Uytterhoeven
417b8bbd6b2SGeert Uytterhoeven /*
418b8bbd6b2SGeert Uytterhoeven * Common SCIF definitions for ports with a Baud Rate Generator for
419b8bbd6b2SGeert Uytterhoeven * External Clock (BRG).
420b8bbd6b2SGeert Uytterhoeven */
421b8bbd6b2SGeert Uytterhoeven [SCIx_SH4_SCIF_BRG_REGTYPE] = {
422e095ee6bSLaurent Pinchart .regs = {
423b8bbd6b2SGeert Uytterhoeven [SCSMR] = { 0x00, 16 },
424b8bbd6b2SGeert Uytterhoeven [SCBRR] = { 0x04, 8 },
425b8bbd6b2SGeert Uytterhoeven [SCSCR] = { 0x08, 16 },
426b8bbd6b2SGeert Uytterhoeven [SCxTDR] = { 0x0c, 8 },
427b8bbd6b2SGeert Uytterhoeven [SCxSR] = { 0x10, 16 },
428b8bbd6b2SGeert Uytterhoeven [SCxRDR] = { 0x14, 8 },
429b8bbd6b2SGeert Uytterhoeven [SCFCR] = { 0x18, 16 },
430b8bbd6b2SGeert Uytterhoeven [SCFDR] = { 0x1c, 16 },
431b8bbd6b2SGeert Uytterhoeven [SCSPTR] = { 0x20, 16 },
432b8bbd6b2SGeert Uytterhoeven [SCLSR] = { 0x24, 16 },
433b8bbd6b2SGeert Uytterhoeven [SCDL] = { 0x30, 16 },
434b8bbd6b2SGeert Uytterhoeven [SCCKS] = { 0x34, 16 },
435f303b364SUlrich Hecht },
436b2f20ed9SLaurent Pinchart .fifosize = 16,
437b2f20ed9SLaurent Pinchart .overrun_reg = SCLSR,
438b2f20ed9SLaurent Pinchart .overrun_mask = SCLSR_ORER,
439b2f20ed9SLaurent Pinchart .sampling_rate_mask = SCI_SR(32),
440b2f20ed9SLaurent Pinchart .error_mask = SCIF_DEFAULT_ERROR_MASK,
441b2f20ed9SLaurent Pinchart .error_clear = SCIF_ERROR_CLEAR,
442e095ee6bSLaurent Pinchart },
443f303b364SUlrich Hecht
444f303b364SUlrich Hecht /*
445f303b364SUlrich Hecht * Common HSCIF definitions.
446f303b364SUlrich Hecht */
447f303b364SUlrich Hecht [SCIx_HSCIF_REGTYPE] = {
448e095ee6bSLaurent Pinchart .regs = {
449f303b364SUlrich Hecht [SCSMR] = { 0x00, 16 },
450f303b364SUlrich Hecht [SCBRR] = { 0x04, 8 },
451f303b364SUlrich Hecht [SCSCR] = { 0x08, 16 },
452f303b364SUlrich Hecht [SCxTDR] = { 0x0c, 8 },
453f303b364SUlrich Hecht [SCxSR] = { 0x10, 16 },
454f303b364SUlrich Hecht [SCxRDR] = { 0x14, 8 },
455f303b364SUlrich Hecht [SCFCR] = { 0x18, 16 },
456f303b364SUlrich Hecht [SCFDR] = { 0x1c, 16 },
457f303b364SUlrich Hecht [SCSPTR] = { 0x20, 16 },
458f303b364SUlrich Hecht [SCLSR] = { 0x24, 16 },
459f303b364SUlrich Hecht [HSSRR] = { 0x40, 16 },
460b8bbd6b2SGeert Uytterhoeven [SCDL] = { 0x30, 16 },
461b8bbd6b2SGeert Uytterhoeven [SCCKS] = { 0x34, 16 },
46254e14ae2SUlrich Hecht [HSRTRGR] = { 0x54, 16 },
46354e14ae2SUlrich Hecht [HSTTRGR] = { 0x58, 16 },
46461a6976bSPaul Mundt },
465b2f20ed9SLaurent Pinchart .fifosize = 128,
466b2f20ed9SLaurent Pinchart .overrun_reg = SCLSR,
467b2f20ed9SLaurent Pinchart .overrun_mask = SCLSR_ORER,
468b2f20ed9SLaurent Pinchart .sampling_rate_mask = SCI_SR_RANGE(8, 32),
469b2f20ed9SLaurent Pinchart .error_mask = SCIF_DEFAULT_ERROR_MASK,
470b2f20ed9SLaurent Pinchart .error_clear = SCIF_ERROR_CLEAR,
471e095ee6bSLaurent Pinchart },
47261a6976bSPaul Mundt
47361a6976bSPaul Mundt /*
47461a6976bSPaul Mundt * Common SH-4(A) SCIF(B) definitions for ports without an SCSPTR
47561a6976bSPaul Mundt * register.
47661a6976bSPaul Mundt */
47761a6976bSPaul Mundt [SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE] = {
478e095ee6bSLaurent Pinchart .regs = {
47961a6976bSPaul Mundt [SCSMR] = { 0x00, 16 },
48061a6976bSPaul Mundt [SCBRR] = { 0x04, 8 },
48161a6976bSPaul Mundt [SCSCR] = { 0x08, 16 },
48261a6976bSPaul Mundt [SCxTDR] = { 0x0c, 8 },
48361a6976bSPaul Mundt [SCxSR] = { 0x10, 16 },
48461a6976bSPaul Mundt [SCxRDR] = { 0x14, 8 },
48561a6976bSPaul Mundt [SCFCR] = { 0x18, 16 },
48661a6976bSPaul Mundt [SCFDR] = { 0x1c, 16 },
48761a6976bSPaul Mundt [SCLSR] = { 0x24, 16 },
48861a6976bSPaul Mundt },
489b2f20ed9SLaurent Pinchart .fifosize = 16,
490b2f20ed9SLaurent Pinchart .overrun_reg = SCLSR,
491b2f20ed9SLaurent Pinchart .overrun_mask = SCLSR_ORER,
492b2f20ed9SLaurent Pinchart .sampling_rate_mask = SCI_SR(32),
493b2f20ed9SLaurent Pinchart .error_mask = SCIF_DEFAULT_ERROR_MASK,
494b2f20ed9SLaurent Pinchart .error_clear = SCIF_ERROR_CLEAR,
495e095ee6bSLaurent Pinchart },
49661a6976bSPaul Mundt
49761a6976bSPaul Mundt /*
49861a6976bSPaul Mundt * Common SH-4(A) SCIF(B) definitions for ports with FIFO data
49961a6976bSPaul Mundt * count registers.
50061a6976bSPaul Mundt */
50161a6976bSPaul Mundt [SCIx_SH4_SCIF_FIFODATA_REGTYPE] = {
502e095ee6bSLaurent Pinchart .regs = {
50361a6976bSPaul Mundt [SCSMR] = { 0x00, 16 },
50461a6976bSPaul Mundt [SCBRR] = { 0x04, 8 },
50561a6976bSPaul Mundt [SCSCR] = { 0x08, 16 },
50661a6976bSPaul Mundt [SCxTDR] = { 0x0c, 8 },
50761a6976bSPaul Mundt [SCxSR] = { 0x10, 16 },
50861a6976bSPaul Mundt [SCxRDR] = { 0x14, 8 },
50961a6976bSPaul Mundt [SCFCR] = { 0x18, 16 },
51061a6976bSPaul Mundt [SCFDR] = { 0x1c, 16 },
51161a6976bSPaul Mundt [SCTFDR] = { 0x1c, 16 }, /* aliased to SCFDR */
51261a6976bSPaul Mundt [SCRFDR] = { 0x20, 16 },
51361a6976bSPaul Mundt [SCSPTR] = { 0x24, 16 },
51461a6976bSPaul Mundt [SCLSR] = { 0x28, 16 },
51561a6976bSPaul Mundt },
516b2f20ed9SLaurent Pinchart .fifosize = 16,
517b2f20ed9SLaurent Pinchart .overrun_reg = SCLSR,
518b2f20ed9SLaurent Pinchart .overrun_mask = SCLSR_ORER,
519b2f20ed9SLaurent Pinchart .sampling_rate_mask = SCI_SR(32),
520b2f20ed9SLaurent Pinchart .error_mask = SCIF_DEFAULT_ERROR_MASK,
521b2f20ed9SLaurent Pinchart .error_clear = SCIF_ERROR_CLEAR,
522e095ee6bSLaurent Pinchart },
52361a6976bSPaul Mundt
52461a6976bSPaul Mundt /*
52561a6976bSPaul Mundt * SH7705-style SCIF(B) ports, lacking both SCSPTR and SCLSR
52661a6976bSPaul Mundt * registers.
52761a6976bSPaul Mundt */
52861a6976bSPaul Mundt [SCIx_SH7705_SCIF_REGTYPE] = {
529e095ee6bSLaurent Pinchart .regs = {
53061a6976bSPaul Mundt [SCSMR] = { 0x00, 16 },
53161a6976bSPaul Mundt [SCBRR] = { 0x04, 8 },
53261a6976bSPaul Mundt [SCSCR] = { 0x08, 16 },
53361a6976bSPaul Mundt [SCxTDR] = { 0x20, 8 },
53461a6976bSPaul Mundt [SCxSR] = { 0x14, 16 },
53561a6976bSPaul Mundt [SCxRDR] = { 0x24, 8 },
53661a6976bSPaul Mundt [SCFCR] = { 0x18, 16 },
53761a6976bSPaul Mundt [SCFDR] = { 0x1c, 16 },
53861a6976bSPaul Mundt },
53918e8cf15SUlrich Hecht .fifosize = 64,
540b2f20ed9SLaurent Pinchart .overrun_reg = SCxSR,
541b2f20ed9SLaurent Pinchart .overrun_mask = SCIFA_ORER,
542b2f20ed9SLaurent Pinchart .sampling_rate_mask = SCI_SR(16),
543b2f20ed9SLaurent Pinchart .error_mask = SCIF_DEFAULT_ERROR_MASK | SCIFA_ORER,
544b2f20ed9SLaurent Pinchart .error_clear = SCIF_ERROR_CLEAR & ~SCIFA_ORER,
545e095ee6bSLaurent Pinchart },
54661a6976bSPaul Mundt };
54761a6976bSPaul Mundt
548e095ee6bSLaurent Pinchart #define sci_getreg(up, offset) (&to_sci_port(up)->params->regs[offset])
54972b294cfSPaul Mundt
55061a6976bSPaul Mundt /*
55161a6976bSPaul Mundt * The "offset" here is rather misleading, in that it refers to an enum
55261a6976bSPaul Mundt * value relative to the port mapping rather than the fixed offset
55361a6976bSPaul Mundt * itself, which needs to be manually retrieved from the platform's
55461a6976bSPaul Mundt * register map for the given port.
55561a6976bSPaul Mundt */
sci_serial_in(struct uart_port * p,int offset)55661a6976bSPaul Mundt static unsigned int sci_serial_in(struct uart_port *p, int offset)
55761a6976bSPaul Mundt {
558d3184e68SGeert Uytterhoeven const struct plat_sci_reg *reg = sci_getreg(p, offset);
55961a6976bSPaul Mundt
56061a6976bSPaul Mundt if (reg->size == 8)
56161a6976bSPaul Mundt return ioread8(p->membase + (reg->offset << p->regshift));
56261a6976bSPaul Mundt else if (reg->size == 16)
56361a6976bSPaul Mundt return ioread16(p->membase + (reg->offset << p->regshift));
56461a6976bSPaul Mundt else
56561a6976bSPaul Mundt WARN(1, "Invalid register access\n");
56661a6976bSPaul Mundt
56761a6976bSPaul Mundt return 0;
56861a6976bSPaul Mundt }
56961a6976bSPaul Mundt
sci_serial_out(struct uart_port * p,int offset,int value)57061a6976bSPaul Mundt static void sci_serial_out(struct uart_port *p, int offset, int value)
57161a6976bSPaul Mundt {
572d3184e68SGeert Uytterhoeven const struct plat_sci_reg *reg = sci_getreg(p, offset);
57361a6976bSPaul Mundt
57461a6976bSPaul Mundt if (reg->size == 8)
57561a6976bSPaul Mundt iowrite8(value, p->membase + (reg->offset << p->regshift));
57661a6976bSPaul Mundt else if (reg->size == 16)
57761a6976bSPaul Mundt iowrite16(value, p->membase + (reg->offset << p->regshift));
57861a6976bSPaul Mundt else
57961a6976bSPaul Mundt WARN(1, "Invalid register access\n");
58061a6976bSPaul Mundt }
58161a6976bSPaul Mundt
sci_port_enable(struct sci_port * sci_port)58223241d43SPaul Mundt static void sci_port_enable(struct sci_port *sci_port)
58323241d43SPaul Mundt {
584f4998e55SGeert Uytterhoeven unsigned int i;
585f4998e55SGeert Uytterhoeven
58623241d43SPaul Mundt if (!sci_port->port.dev)
58723241d43SPaul Mundt return;
58823241d43SPaul Mundt
58923241d43SPaul Mundt pm_runtime_get_sync(sci_port->port.dev);
59023241d43SPaul Mundt
591f4998e55SGeert Uytterhoeven for (i = 0; i < SCI_NUM_CLKS; i++) {
592f4998e55SGeert Uytterhoeven clk_prepare_enable(sci_port->clks[i]);
593f4998e55SGeert Uytterhoeven sci_port->clk_rates[i] = clk_get_rate(sci_port->clks[i]);
594f4998e55SGeert Uytterhoeven }
595f4998e55SGeert Uytterhoeven sci_port->port.uartclk = sci_port->clk_rates[SCI_FCK];
59623241d43SPaul Mundt }
59723241d43SPaul Mundt
sci_port_disable(struct sci_port * sci_port)59823241d43SPaul Mundt static void sci_port_disable(struct sci_port *sci_port)
59923241d43SPaul Mundt {
600f4998e55SGeert Uytterhoeven unsigned int i;
601f4998e55SGeert Uytterhoeven
60223241d43SPaul Mundt if (!sci_port->port.dev)
60323241d43SPaul Mundt return;
60423241d43SPaul Mundt
605f4998e55SGeert Uytterhoeven for (i = SCI_NUM_CLKS; i-- > 0; )
606f4998e55SGeert Uytterhoeven clk_disable_unprepare(sci_port->clks[i]);
60723241d43SPaul Mundt
60823241d43SPaul Mundt pm_runtime_put_sync(sci_port->port.dev);
60923241d43SPaul Mundt }
61023241d43SPaul Mundt
port_rx_irq_mask(struct uart_port * port)611e1910fcdSGeert Uytterhoeven static inline unsigned long port_rx_irq_mask(struct uart_port *port)
612e1910fcdSGeert Uytterhoeven {
613e1910fcdSGeert Uytterhoeven /*
614e1910fcdSGeert Uytterhoeven * Not all ports (such as SCIFA) will support REIE. Rather than
615e1910fcdSGeert Uytterhoeven * special-casing the port type, we check the port initialization
616e1910fcdSGeert Uytterhoeven * IRQ enable mask to see whether the IRQ is desired at all. If
617e1910fcdSGeert Uytterhoeven * it's unset, it's logically inferred that there's no point in
618e1910fcdSGeert Uytterhoeven * testing for it.
619e1910fcdSGeert Uytterhoeven */
620e1910fcdSGeert Uytterhoeven return SCSCR_RIE | (to_sci_port(port)->cfg->scscr & SCSCR_REIE);
621e1910fcdSGeert Uytterhoeven }
622e1910fcdSGeert Uytterhoeven
sci_start_tx(struct uart_port * port)623e1910fcdSGeert Uytterhoeven static void sci_start_tx(struct uart_port *port)
624e1910fcdSGeert Uytterhoeven {
625e1910fcdSGeert Uytterhoeven struct sci_port *s = to_sci_port(port);
626e1910fcdSGeert Uytterhoeven unsigned short ctrl;
627e1910fcdSGeert Uytterhoeven
628e1910fcdSGeert Uytterhoeven #ifdef CONFIG_SERIAL_SH_SCI_DMA
629e1910fcdSGeert Uytterhoeven if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
6306deab514SGeert Uytterhoeven u16 new, scr = sci_serial_in(port, SCSCR);
631e1910fcdSGeert Uytterhoeven if (s->chan_tx)
632e1910fcdSGeert Uytterhoeven new = scr | SCSCR_TDRQE;
633e1910fcdSGeert Uytterhoeven else
634e1910fcdSGeert Uytterhoeven new = scr & ~SCSCR_TDRQE;
635e1910fcdSGeert Uytterhoeven if (new != scr)
6366deab514SGeert Uytterhoeven sci_serial_out(port, SCSCR, new);
637e1910fcdSGeert Uytterhoeven }
638e1910fcdSGeert Uytterhoeven
6391788cf6aSJiri Slaby (SUSE) if (s->chan_tx && !kfifo_is_empty(&port->state->port.xmit_fifo) &&
640e1910fcdSGeert Uytterhoeven dma_submit_error(s->cookie_tx)) {
6418749061bSBiju Das if (s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE)
6428749061bSBiju Das /* Switch irq from SCIF to DMA */
64357c984f6SBiju Das disable_irq_nosync(s->irqs[SCIx_TXI_IRQ]);
6448749061bSBiju Das
645e1910fcdSGeert Uytterhoeven s->cookie_tx = 0;
646e1910fcdSGeert Uytterhoeven schedule_work(&s->work_tx);
647e1910fcdSGeert Uytterhoeven }
648e1910fcdSGeert Uytterhoeven #endif
649e1910fcdSGeert Uytterhoeven
6508749061bSBiju Das if (!s->chan_tx || s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE ||
6518749061bSBiju Das port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
652e1910fcdSGeert Uytterhoeven /* Set TIE (Transmit Interrupt Enable) bit in SCSCR */
6536deab514SGeert Uytterhoeven ctrl = sci_serial_in(port, SCSCR);
6541707ce2dSBiju Das
6551707ce2dSBiju Das /*
6561707ce2dSBiju Das * For SCI, TE (transmit enable) must be set after setting TIE
6571707ce2dSBiju Das * (transmit interrupt enable) or in the same instruction to start
6581707ce2dSBiju Das * the transmit process.
6591707ce2dSBiju Das */
6601707ce2dSBiju Das if (port->type == PORT_SCI)
6611707ce2dSBiju Das ctrl |= SCSCR_TE;
6621707ce2dSBiju Das
6636deab514SGeert Uytterhoeven sci_serial_out(port, SCSCR, ctrl | SCSCR_TIE);
664e1910fcdSGeert Uytterhoeven }
665e1910fcdSGeert Uytterhoeven }
666e1910fcdSGeert Uytterhoeven
sci_stop_tx(struct uart_port * port)667e1910fcdSGeert Uytterhoeven static void sci_stop_tx(struct uart_port *port)
668e1910fcdSGeert Uytterhoeven {
669e1910fcdSGeert Uytterhoeven unsigned short ctrl;
670e1910fcdSGeert Uytterhoeven
671e1910fcdSGeert Uytterhoeven /* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */
6726deab514SGeert Uytterhoeven ctrl = sci_serial_in(port, SCSCR);
673e1910fcdSGeert Uytterhoeven
674e1910fcdSGeert Uytterhoeven if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
675e1910fcdSGeert Uytterhoeven ctrl &= ~SCSCR_TDRQE;
676e1910fcdSGeert Uytterhoeven
677e1910fcdSGeert Uytterhoeven ctrl &= ~SCSCR_TIE;
678e1910fcdSGeert Uytterhoeven
6796deab514SGeert Uytterhoeven sci_serial_out(port, SCSCR, ctrl);
68008a84410SYoshihiro Shimoda
68108a84410SYoshihiro Shimoda #ifdef CONFIG_SERIAL_SH_SCI_DMA
68208a84410SYoshihiro Shimoda if (to_sci_port(port)->chan_tx &&
68308a84410SYoshihiro Shimoda !dma_submit_error(to_sci_port(port)->cookie_tx)) {
68408a84410SYoshihiro Shimoda dmaengine_terminate_async(to_sci_port(port)->chan_tx);
68508a84410SYoshihiro Shimoda to_sci_port(port)->cookie_tx = -EINVAL;
68608a84410SYoshihiro Shimoda }
68708a84410SYoshihiro Shimoda #endif
688e1910fcdSGeert Uytterhoeven }
689e1910fcdSGeert Uytterhoeven
sci_start_rx(struct uart_port * port)690e1910fcdSGeert Uytterhoeven static void sci_start_rx(struct uart_port *port)
691e1910fcdSGeert Uytterhoeven {
692e1910fcdSGeert Uytterhoeven unsigned short ctrl;
693e1910fcdSGeert Uytterhoeven
6946deab514SGeert Uytterhoeven ctrl = sci_serial_in(port, SCSCR) | port_rx_irq_mask(port);
695e1910fcdSGeert Uytterhoeven
696e1910fcdSGeert Uytterhoeven if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
697e1910fcdSGeert Uytterhoeven ctrl &= ~SCSCR_RDRQE;
698e1910fcdSGeert Uytterhoeven
6996deab514SGeert Uytterhoeven sci_serial_out(port, SCSCR, ctrl);
700e1910fcdSGeert Uytterhoeven }
701e1910fcdSGeert Uytterhoeven
sci_stop_rx(struct uart_port * port)702e1910fcdSGeert Uytterhoeven static void sci_stop_rx(struct uart_port *port)
703e1910fcdSGeert Uytterhoeven {
704e1910fcdSGeert Uytterhoeven unsigned short ctrl;
705e1910fcdSGeert Uytterhoeven
7066deab514SGeert Uytterhoeven ctrl = sci_serial_in(port, SCSCR);
707e1910fcdSGeert Uytterhoeven
708e1910fcdSGeert Uytterhoeven if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
709e1910fcdSGeert Uytterhoeven ctrl &= ~SCSCR_RDRQE;
710e1910fcdSGeert Uytterhoeven
711e1910fcdSGeert Uytterhoeven ctrl &= ~port_rx_irq_mask(port);
712e1910fcdSGeert Uytterhoeven
7136deab514SGeert Uytterhoeven sci_serial_out(port, SCSCR, ctrl);
714e1910fcdSGeert Uytterhoeven }
715e1910fcdSGeert Uytterhoeven
sci_clear_SCxSR(struct uart_port * port,unsigned int mask)716a1b5b43fSGeert Uytterhoeven static void sci_clear_SCxSR(struct uart_port *port, unsigned int mask)
717a1b5b43fSGeert Uytterhoeven {
718a1b5b43fSGeert Uytterhoeven if (port->type == PORT_SCI) {
719a1b5b43fSGeert Uytterhoeven /* Just store the mask */
7206deab514SGeert Uytterhoeven sci_serial_out(port, SCxSR, mask);
721b2f20ed9SLaurent Pinchart } else if (to_sci_port(port)->params->overrun_mask == SCIFA_ORER) {
722a1b5b43fSGeert Uytterhoeven /* SCIFA/SCIFB and SCIF on SH7705/SH7720/SH7721 */
723a1b5b43fSGeert Uytterhoeven /* Only clear the status bits we want to clear */
7246deab514SGeert Uytterhoeven sci_serial_out(port, SCxSR, sci_serial_in(port, SCxSR) & mask);
725a1b5b43fSGeert Uytterhoeven } else {
726a1b5b43fSGeert Uytterhoeven /* Store the mask, clear parity/framing errors */
7276deab514SGeert Uytterhoeven sci_serial_out(port, SCxSR, mask & ~(SCIF_FERC | SCIF_PERC));
728a1b5b43fSGeert Uytterhoeven }
729a1b5b43fSGeert Uytterhoeven }
730a1b5b43fSGeert Uytterhoeven
7310b0cced1SYoshinori Sato #if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_SH_SCI_CONSOLE) || \
7320b0cced1SYoshinori Sato defined(CONFIG_SERIAL_SH_SCI_EARLYCON)
733ab4382d2SGreg Kroah-Hartman
734ab4382d2SGreg Kroah-Hartman #ifdef CONFIG_CONSOLE_POLL
sci_poll_get_char(struct uart_port * port)735ab4382d2SGreg Kroah-Hartman static int sci_poll_get_char(struct uart_port *port)
736ab4382d2SGreg Kroah-Hartman {
737ab4382d2SGreg Kroah-Hartman unsigned short status;
738ab4382d2SGreg Kroah-Hartman int c;
739ab4382d2SGreg Kroah-Hartman
740ab4382d2SGreg Kroah-Hartman do {
7416deab514SGeert Uytterhoeven status = sci_serial_in(port, SCxSR);
742ab4382d2SGreg Kroah-Hartman if (status & SCxSR_ERRORS(port)) {
743a1b5b43fSGeert Uytterhoeven sci_clear_SCxSR(port, SCxSR_ERROR_CLEAR(port));
744ab4382d2SGreg Kroah-Hartman continue;
745ab4382d2SGreg Kroah-Hartman }
746ab4382d2SGreg Kroah-Hartman break;
747ab4382d2SGreg Kroah-Hartman } while (1);
748ab4382d2SGreg Kroah-Hartman
749ab4382d2SGreg Kroah-Hartman if (!(status & SCxSR_RDxF(port)))
750ab4382d2SGreg Kroah-Hartman return NO_POLL_CHAR;
751ab4382d2SGreg Kroah-Hartman
7526deab514SGeert Uytterhoeven c = sci_serial_in(port, SCxRDR);
753ab4382d2SGreg Kroah-Hartman
754ab4382d2SGreg Kroah-Hartman /* Dummy read */
7556deab514SGeert Uytterhoeven sci_serial_in(port, SCxSR);
756a1b5b43fSGeert Uytterhoeven sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
757ab4382d2SGreg Kroah-Hartman
758ab4382d2SGreg Kroah-Hartman return c;
759ab4382d2SGreg Kroah-Hartman }
760ab4382d2SGreg Kroah-Hartman #endif
761ab4382d2SGreg Kroah-Hartman
sci_poll_put_char(struct uart_port * port,unsigned char c)762ab4382d2SGreg Kroah-Hartman static void sci_poll_put_char(struct uart_port *port, unsigned char c)
763ab4382d2SGreg Kroah-Hartman {
764ab4382d2SGreg Kroah-Hartman unsigned short status;
765ab4382d2SGreg Kroah-Hartman
766ab4382d2SGreg Kroah-Hartman do {
7676deab514SGeert Uytterhoeven status = sci_serial_in(port, SCxSR);
768ab4382d2SGreg Kroah-Hartman } while (!(status & SCxSR_TDxE(port)));
769ab4382d2SGreg Kroah-Hartman
7706deab514SGeert Uytterhoeven sci_serial_out(port, SCxTDR, c);
771a1b5b43fSGeert Uytterhoeven sci_clear_SCxSR(port, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port));
772ab4382d2SGreg Kroah-Hartman }
7730b0cced1SYoshinori Sato #endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE ||
7740b0cced1SYoshinori Sato CONFIG_SERIAL_SH_SCI_EARLYCON */
775ab4382d2SGreg Kroah-Hartman
sci_init_pins(struct uart_port * port,unsigned int cflag)77661a6976bSPaul Mundt static void sci_init_pins(struct uart_port *port, unsigned int cflag)
777ab4382d2SGreg Kroah-Hartman {
77861a6976bSPaul Mundt struct sci_port *s = to_sci_port(port);
779ab4382d2SGreg Kroah-Hartman
78061a6976bSPaul Mundt /*
78161a6976bSPaul Mundt * Use port-specific handler if provided.
78261a6976bSPaul Mundt */
78361a6976bSPaul Mundt if (s->cfg->ops && s->cfg->ops->init_pins) {
78461a6976bSPaul Mundt s->cfg->ops->init_pins(port, cflag);
78561a6976bSPaul Mundt return;
786ab4382d2SGreg Kroah-Hartman }
787ab4382d2SGreg Kroah-Hartman
788e9d7a45aSGeert Uytterhoeven if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
7896deab514SGeert Uytterhoeven u16 data = sci_serial_in(port, SCPDR);
7906deab514SGeert Uytterhoeven u16 ctrl = sci_serial_in(port, SCPCR);
791e9d7a45aSGeert Uytterhoeven
792e9d7a45aSGeert Uytterhoeven /* Enable RXD and TXD pin functions */
793e9d7a45aSGeert Uytterhoeven ctrl &= ~(SCPCR_RXDC | SCPCR_TXDC);
79497ed9790SLaurent Pinchart if (to_sci_port(port)->has_rtscts) {
795cfa6eb23SGeert Uytterhoeven /* RTS# is output, active low, unless autorts */
796cfa6eb23SGeert Uytterhoeven if (!(port->mctrl & TIOCM_RTS)) {
797e9d7a45aSGeert Uytterhoeven ctrl |= SCPCR_RTSC;
798cfa6eb23SGeert Uytterhoeven data |= SCPDR_RTSD;
799cfa6eb23SGeert Uytterhoeven } else if (!s->autorts) {
800cfa6eb23SGeert Uytterhoeven ctrl |= SCPCR_RTSC;
801cfa6eb23SGeert Uytterhoeven data &= ~SCPDR_RTSD;
802cfa6eb23SGeert Uytterhoeven } else {
803cfa6eb23SGeert Uytterhoeven /* Enable RTS# pin function */
804cfa6eb23SGeert Uytterhoeven ctrl &= ~SCPCR_RTSC;
805cfa6eb23SGeert Uytterhoeven }
806e9d7a45aSGeert Uytterhoeven /* Enable CTS# pin function */
807e9d7a45aSGeert Uytterhoeven ctrl &= ~SCPCR_CTSC;
808e9d7a45aSGeert Uytterhoeven }
8096deab514SGeert Uytterhoeven sci_serial_out(port, SCPDR, data);
8106deab514SGeert Uytterhoeven sci_serial_out(port, SCPCR, ctrl);
8112f50304eSLad Prabhakar } else if (sci_getreg(port, SCSPTR)->size && s->cfg->regtype != SCIx_RZV2H_SCIF_REGTYPE) {
8126deab514SGeert Uytterhoeven u16 status = sci_serial_in(port, SCSPTR);
813ab4382d2SGreg Kroah-Hartman
814cfa6eb23SGeert Uytterhoeven /* RTS# is always output; and active low, unless autorts */
815cfa6eb23SGeert Uytterhoeven status |= SCSPTR_RTSIO;
816cfa6eb23SGeert Uytterhoeven if (!(port->mctrl & TIOCM_RTS))
817cfa6eb23SGeert Uytterhoeven status |= SCSPTR_RTSDT;
818cfa6eb23SGeert Uytterhoeven else if (!s->autorts)
819cfa6eb23SGeert Uytterhoeven status &= ~SCSPTR_RTSDT;
820d2b9775dSGeert Uytterhoeven /* CTS# and SCK are inputs */
821d2b9775dSGeert Uytterhoeven status &= ~(SCSPTR_CTSIO | SCSPTR_SCKIO);
8226deab514SGeert Uytterhoeven sci_serial_out(port, SCSPTR, status);
823faf02f8fSPaul Mundt }
824ab4382d2SGreg Kroah-Hartman }
825ab4382d2SGreg Kroah-Hartman
sci_txfill(struct uart_port * port)826ab4382d2SGreg Kroah-Hartman static int sci_txfill(struct uart_port *port)
827ab4382d2SGreg Kroah-Hartman {
828b2f20ed9SLaurent Pinchart struct sci_port *s = to_sci_port(port);
829b2f20ed9SLaurent Pinchart unsigned int fifo_mask = (s->params->fifosize << 1) - 1;
830d3184e68SGeert Uytterhoeven const struct plat_sci_reg *reg;
83172b294cfSPaul Mundt
83272b294cfSPaul Mundt reg = sci_getreg(port, SCTFDR);
83372b294cfSPaul Mundt if (reg->size)
8346deab514SGeert Uytterhoeven return sci_serial_in(port, SCTFDR) & fifo_mask;
83572b294cfSPaul Mundt
83672b294cfSPaul Mundt reg = sci_getreg(port, SCFDR);
83772b294cfSPaul Mundt if (reg->size)
8386deab514SGeert Uytterhoeven return sci_serial_in(port, SCFDR) >> 8;
83972b294cfSPaul Mundt
8406deab514SGeert Uytterhoeven return !(sci_serial_in(port, SCxSR) & SCI_TDRE);
841ab4382d2SGreg Kroah-Hartman }
842ab4382d2SGreg Kroah-Hartman
sci_txroom(struct uart_port * port)843ab4382d2SGreg Kroah-Hartman static int sci_txroom(struct uart_port *port)
844ab4382d2SGreg Kroah-Hartman {
84572b294cfSPaul Mundt return port->fifosize - sci_txfill(port);
846ab4382d2SGreg Kroah-Hartman }
847ab4382d2SGreg Kroah-Hartman
sci_rxfill(struct uart_port * port)848ab4382d2SGreg Kroah-Hartman static int sci_rxfill(struct uart_port *port)
849ab4382d2SGreg Kroah-Hartman {
850b2f20ed9SLaurent Pinchart struct sci_port *s = to_sci_port(port);
851b2f20ed9SLaurent Pinchart unsigned int fifo_mask = (s->params->fifosize << 1) - 1;
852d3184e68SGeert Uytterhoeven const struct plat_sci_reg *reg;
85372b294cfSPaul Mundt
85472b294cfSPaul Mundt reg = sci_getreg(port, SCRFDR);
85572b294cfSPaul Mundt if (reg->size)
8566deab514SGeert Uytterhoeven return sci_serial_in(port, SCRFDR) & fifo_mask;
85772b294cfSPaul Mundt
85872b294cfSPaul Mundt reg = sci_getreg(port, SCFDR);
85972b294cfSPaul Mundt if (reg->size)
8606deab514SGeert Uytterhoeven return sci_serial_in(port, SCFDR) & fifo_mask;
86172b294cfSPaul Mundt
8626deab514SGeert Uytterhoeven return (sci_serial_in(port, SCxSR) & SCxSR_RDxF(port)) != 0;
863ab4382d2SGreg Kroah-Hartman }
864ab4382d2SGreg Kroah-Hartman
865ab4382d2SGreg Kroah-Hartman /* ********************************************************************** *
866ab4382d2SGreg Kroah-Hartman * the interrupt related routines *
867ab4382d2SGreg Kroah-Hartman * ********************************************************************** */
868ab4382d2SGreg Kroah-Hartman
sci_transmit_chars(struct uart_port * port)869ab4382d2SGreg Kroah-Hartman static void sci_transmit_chars(struct uart_port *port)
870ab4382d2SGreg Kroah-Hartman {
8711788cf6aSJiri Slaby (SUSE) struct tty_port *tport = &port->state->port;
872ab4382d2SGreg Kroah-Hartman unsigned int stopped = uart_tx_stopped(port);
8737cc0e0a4SClaudiu Beznea struct sci_port *s = to_sci_port(port);
874ab4382d2SGreg Kroah-Hartman unsigned short status;
875ab4382d2SGreg Kroah-Hartman unsigned short ctrl;
876ab4382d2SGreg Kroah-Hartman int count;
877ab4382d2SGreg Kroah-Hartman
8786deab514SGeert Uytterhoeven status = sci_serial_in(port, SCxSR);
879ab4382d2SGreg Kroah-Hartman if (!(status & SCxSR_TDxE(port))) {
8806deab514SGeert Uytterhoeven ctrl = sci_serial_in(port, SCSCR);
8811788cf6aSJiri Slaby (SUSE) if (kfifo_is_empty(&tport->xmit_fifo))
882fc887b15SLinus Torvalds ctrl &= ~SCSCR_TIE;
883ab4382d2SGreg Kroah-Hartman else
884fc887b15SLinus Torvalds ctrl |= SCSCR_TIE;
8856deab514SGeert Uytterhoeven sci_serial_out(port, SCSCR, ctrl);
886ab4382d2SGreg Kroah-Hartman return;
887ab4382d2SGreg Kroah-Hartman }
888ab4382d2SGreg Kroah-Hartman
889ab4382d2SGreg Kroah-Hartman count = sci_txroom(port);
890ab4382d2SGreg Kroah-Hartman
891ab4382d2SGreg Kroah-Hartman do {
892ab4382d2SGreg Kroah-Hartman unsigned char c;
893ab4382d2SGreg Kroah-Hartman
894ab4382d2SGreg Kroah-Hartman if (port->x_char) {
895ab4382d2SGreg Kroah-Hartman c = port->x_char;
896ab4382d2SGreg Kroah-Hartman port->x_char = 0;
8971788cf6aSJiri Slaby (SUSE) } else if (stopped || !kfifo_get(&tport->xmit_fifo, &c)) {
8981788cf6aSJiri Slaby (SUSE) if (port->type == PORT_SCI &&
8991788cf6aSJiri Slaby (SUSE) kfifo_is_empty(&tport->xmit_fifo)) {
9006deab514SGeert Uytterhoeven ctrl = sci_serial_in(port, SCSCR);
901f06c2a90SBiju Das ctrl &= ~SCSCR_TE;
9026deab514SGeert Uytterhoeven sci_serial_out(port, SCSCR, ctrl);
903f06c2a90SBiju Das return;
9041788cf6aSJiri Slaby (SUSE) }
905ab4382d2SGreg Kroah-Hartman break;
906ab4382d2SGreg Kroah-Hartman }
907ab4382d2SGreg Kroah-Hartman
9086deab514SGeert Uytterhoeven sci_serial_out(port, SCxTDR, c);
9097cc0e0a4SClaudiu Beznea s->tx_occurred = true;
910ab4382d2SGreg Kroah-Hartman
911ab4382d2SGreg Kroah-Hartman port->icount.tx++;
912ab4382d2SGreg Kroah-Hartman } while (--count > 0);
913ab4382d2SGreg Kroah-Hartman
914a1b5b43fSGeert Uytterhoeven sci_clear_SCxSR(port, SCxSR_TDxE_CLEAR(port));
915ab4382d2SGreg Kroah-Hartman
9161788cf6aSJiri Slaby (SUSE) if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
917ab4382d2SGreg Kroah-Hartman uart_write_wakeup(port);
9181788cf6aSJiri Slaby (SUSE) if (kfifo_is_empty(&tport->xmit_fifo)) {
919d61ae331SBiju Das if (port->type == PORT_SCI) {
9206deab514SGeert Uytterhoeven ctrl = sci_serial_in(port, SCSCR);
921d61ae331SBiju Das ctrl &= ~SCSCR_TIE;
922d61ae331SBiju Das ctrl |= SCSCR_TEIE;
9236deab514SGeert Uytterhoeven sci_serial_out(port, SCSCR, ctrl);
924d61ae331SBiju Das }
925ab4382d2SGreg Kroah-Hartman
926d61ae331SBiju Das sci_stop_tx(port);
927d61ae331SBiju Das }
928ab4382d2SGreg Kroah-Hartman }
929ab4382d2SGreg Kroah-Hartman
sci_receive_chars(struct uart_port * port)9306b620478SPaul Mundt static void sci_receive_chars(struct uart_port *port)
931ab4382d2SGreg Kroah-Hartman {
932227434f8SJiri Slaby struct tty_port *tport = &port->state->port;
933ab4382d2SGreg Kroah-Hartman int i, count, copied = 0;
934ab4382d2SGreg Kroah-Hartman unsigned short status;
935ab4382d2SGreg Kroah-Hartman unsigned char flag;
936ab4382d2SGreg Kroah-Hartman
9376deab514SGeert Uytterhoeven status = sci_serial_in(port, SCxSR);
938ab4382d2SGreg Kroah-Hartman if (!(status & SCxSR_RDxF(port)))
939ab4382d2SGreg Kroah-Hartman return;
940ab4382d2SGreg Kroah-Hartman
941ab4382d2SGreg Kroah-Hartman while (1) {
942ab4382d2SGreg Kroah-Hartman /* Don't copy more bytes than there is room for in the buffer */
943227434f8SJiri Slaby count = tty_buffer_request_room(tport, sci_rxfill(port));
944ab4382d2SGreg Kroah-Hartman
945ab4382d2SGreg Kroah-Hartman /* If for any reason we can't copy more data, we're done! */
946ab4382d2SGreg Kroah-Hartman if (count == 0)
947ab4382d2SGreg Kroah-Hartman break;
948ab4382d2SGreg Kroah-Hartman
949ab4382d2SGreg Kroah-Hartman if (port->type == PORT_SCI) {
9506deab514SGeert Uytterhoeven char c = sci_serial_in(port, SCxRDR);
951d5cb1319SLaurent Pinchart if (uart_handle_sysrq_char(port, c))
952ab4382d2SGreg Kroah-Hartman count = 0;
953ab4382d2SGreg Kroah-Hartman else
95492a19f9cSJiri Slaby tty_insert_flip_char(tport, c, TTY_NORMAL);
955ab4382d2SGreg Kroah-Hartman } else {
956ab4382d2SGreg Kroah-Hartman for (i = 0; i < count; i++) {
9573dc4db36SKazuhiro Fujita char c;
958d97fbbedSPaul Mundt
9593dc4db36SKazuhiro Fujita if (port->type == PORT_SCIF ||
9603dc4db36SKazuhiro Fujita port->type == PORT_HSCIF) {
9616deab514SGeert Uytterhoeven status = sci_serial_in(port, SCxSR);
9626deab514SGeert Uytterhoeven c = sci_serial_in(port, SCxRDR);
9633dc4db36SKazuhiro Fujita } else {
9646deab514SGeert Uytterhoeven c = sci_serial_in(port, SCxRDR);
9656deab514SGeert Uytterhoeven status = sci_serial_in(port, SCxSR);
9663dc4db36SKazuhiro Fujita }
967ab4382d2SGreg Kroah-Hartman if (uart_handle_sysrq_char(port, c)) {
968ab4382d2SGreg Kroah-Hartman count--; i--;
969ab4382d2SGreg Kroah-Hartman continue;
970ab4382d2SGreg Kroah-Hartman }
971ab4382d2SGreg Kroah-Hartman
972ab4382d2SGreg Kroah-Hartman /* Store data and status */
973ab4382d2SGreg Kroah-Hartman if (status & SCxSR_FER(port)) {
974ab4382d2SGreg Kroah-Hartman flag = TTY_FRAME;
975d97fbbedSPaul Mundt port->icount.frame++;
976ab4382d2SGreg Kroah-Hartman } else if (status & SCxSR_PER(port)) {
977ab4382d2SGreg Kroah-Hartman flag = TTY_PARITY;
978d97fbbedSPaul Mundt port->icount.parity++;
979ab4382d2SGreg Kroah-Hartman } else
980ab4382d2SGreg Kroah-Hartman flag = TTY_NORMAL;
981ab4382d2SGreg Kroah-Hartman
98292a19f9cSJiri Slaby tty_insert_flip_char(tport, c, flag);
983ab4382d2SGreg Kroah-Hartman }
984ab4382d2SGreg Kroah-Hartman }
985ab4382d2SGreg Kroah-Hartman
9866deab514SGeert Uytterhoeven sci_serial_in(port, SCxSR); /* dummy read */
987a1b5b43fSGeert Uytterhoeven sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
988ab4382d2SGreg Kroah-Hartman
989ab4382d2SGreg Kroah-Hartman copied += count;
990ab4382d2SGreg Kroah-Hartman port->icount.rx += count;
991ab4382d2SGreg Kroah-Hartman }
992ab4382d2SGreg Kroah-Hartman
993ab4382d2SGreg Kroah-Hartman if (copied) {
994ab4382d2SGreg Kroah-Hartman /* Tell the rest of the system the news. New characters! */
9952e124b4aSJiri Slaby tty_flip_buffer_push(tport);
996ab4382d2SGreg Kroah-Hartman } else {
9977842055bSUlrich Hecht /* TTY buffers full; read from RX reg to prevent lockup */
9986deab514SGeert Uytterhoeven sci_serial_in(port, SCxRDR);
9996deab514SGeert Uytterhoeven sci_serial_in(port, SCxSR); /* dummy read */
1000a1b5b43fSGeert Uytterhoeven sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
1001ab4382d2SGreg Kroah-Hartman }
1002ab4382d2SGreg Kroah-Hartman }
1003ab4382d2SGreg Kroah-Hartman
sci_handle_errors(struct uart_port * port)10046b620478SPaul Mundt static int sci_handle_errors(struct uart_port *port)
1005ab4382d2SGreg Kroah-Hartman {
1006ab4382d2SGreg Kroah-Hartman int copied = 0;
10076deab514SGeert Uytterhoeven unsigned short status = sci_serial_in(port, SCxSR);
100892a19f9cSJiri Slaby struct tty_port *tport = &port->state->port;
1009debf9507SPaul Mundt struct sci_port *s = to_sci_port(port);
1010ab4382d2SGreg Kroah-Hartman
10113ae988d9SLaurent Pinchart /* Handle overruns */
1012b2f20ed9SLaurent Pinchart if (status & s->params->overrun_mask) {
1013d97fbbedSPaul Mundt port->icount.overrun++;
1014d97fbbedSPaul Mundt
1015ab4382d2SGreg Kroah-Hartman /* overrun error */
101692a19f9cSJiri Slaby if (tty_insert_flip_char(tport, 0, TTY_OVERRUN))
1017ab4382d2SGreg Kroah-Hartman copied++;
1018ab4382d2SGreg Kroah-Hartman }
1019ab4382d2SGreg Kroah-Hartman
1020ab4382d2SGreg Kroah-Hartman if (status & SCxSR_FER(port)) {
1021ab4382d2SGreg Kroah-Hartman /* frame error */
1022d97fbbedSPaul Mundt port->icount.frame++;
1023d97fbbedSPaul Mundt
102492a19f9cSJiri Slaby if (tty_insert_flip_char(tport, 0, TTY_FRAME))
1025ab4382d2SGreg Kroah-Hartman copied++;
1026ab4382d2SGreg Kroah-Hartman }
1027ab4382d2SGreg Kroah-Hartman
1028ab4382d2SGreg Kroah-Hartman if (status & SCxSR_PER(port)) {
1029ab4382d2SGreg Kroah-Hartman /* parity error */
1030d97fbbedSPaul Mundt port->icount.parity++;
1031d97fbbedSPaul Mundt
103292a19f9cSJiri Slaby if (tty_insert_flip_char(tport, 0, TTY_PARITY))
1033ab4382d2SGreg Kroah-Hartman copied++;
1034ab4382d2SGreg Kroah-Hartman }
1035ab4382d2SGreg Kroah-Hartman
1036ab4382d2SGreg Kroah-Hartman if (copied)
10372e124b4aSJiri Slaby tty_flip_buffer_push(tport);
1038ab4382d2SGreg Kroah-Hartman
1039ab4382d2SGreg Kroah-Hartman return copied;
1040ab4382d2SGreg Kroah-Hartman }
1041ab4382d2SGreg Kroah-Hartman
sci_handle_fifo_overrun(struct uart_port * port)10426b620478SPaul Mundt static int sci_handle_fifo_overrun(struct uart_port *port)
1043ab4382d2SGreg Kroah-Hartman {
104492a19f9cSJiri Slaby struct tty_port *tport = &port->state->port;
1045debf9507SPaul Mundt struct sci_port *s = to_sci_port(port);
1046d3184e68SGeert Uytterhoeven const struct plat_sci_reg *reg;
10472e0842a1SGeert Uytterhoeven int copied = 0;
104875c249fdSGeert Uytterhoeven u16 status;
1049ab4382d2SGreg Kroah-Hartman
1050b2f20ed9SLaurent Pinchart reg = sci_getreg(port, s->params->overrun_reg);
10514b8c59a3SPaul Mundt if (!reg->size)
1052ab4382d2SGreg Kroah-Hartman return 0;
1053ab4382d2SGreg Kroah-Hartman
10546deab514SGeert Uytterhoeven status = sci_serial_in(port, s->params->overrun_reg);
1055b2f20ed9SLaurent Pinchart if (status & s->params->overrun_mask) {
1056b2f20ed9SLaurent Pinchart status &= ~s->params->overrun_mask;
10576deab514SGeert Uytterhoeven sci_serial_out(port, s->params->overrun_reg, status);
1058ab4382d2SGreg Kroah-Hartman
1059d97fbbedSPaul Mundt port->icount.overrun++;
1060d97fbbedSPaul Mundt
106192a19f9cSJiri Slaby tty_insert_flip_char(tport, 0, TTY_OVERRUN);
10622e124b4aSJiri Slaby tty_flip_buffer_push(tport);
1063ab4382d2SGreg Kroah-Hartman copied++;
1064ab4382d2SGreg Kroah-Hartman }
1065ab4382d2SGreg Kroah-Hartman
1066ab4382d2SGreg Kroah-Hartman return copied;
1067ab4382d2SGreg Kroah-Hartman }
1068ab4382d2SGreg Kroah-Hartman
sci_handle_breaks(struct uart_port * port)10696b620478SPaul Mundt static int sci_handle_breaks(struct uart_port *port)
1070ab4382d2SGreg Kroah-Hartman {
1071ab4382d2SGreg Kroah-Hartman int copied = 0;
10726deab514SGeert Uytterhoeven unsigned short status = sci_serial_in(port, SCxSR);
107392a19f9cSJiri Slaby struct tty_port *tport = &port->state->port;
1074ab4382d2SGreg Kroah-Hartman
1075ab4382d2SGreg Kroah-Hartman if (uart_handle_break(port))
1076ab4382d2SGreg Kroah-Hartman return 0;
1077ab4382d2SGreg Kroah-Hartman
1078d5cb1319SLaurent Pinchart if (status & SCxSR_BRK(port)) {
1079d97fbbedSPaul Mundt port->icount.brk++;
1080d97fbbedSPaul Mundt
1081ab4382d2SGreg Kroah-Hartman /* Notify of BREAK */
108292a19f9cSJiri Slaby if (tty_insert_flip_char(tport, 0, TTY_BREAK))
1083ab4382d2SGreg Kroah-Hartman copied++;
1084ab4382d2SGreg Kroah-Hartman }
1085ab4382d2SGreg Kroah-Hartman
1086ab4382d2SGreg Kroah-Hartman if (copied)
10872e124b4aSJiri Slaby tty_flip_buffer_push(tport);
1088ab4382d2SGreg Kroah-Hartman
1089ab4382d2SGreg Kroah-Hartman copied += sci_handle_fifo_overrun(port);
1090ab4382d2SGreg Kroah-Hartman
1091ab4382d2SGreg Kroah-Hartman return copied;
1092ab4382d2SGreg Kroah-Hartman }
1093ab4382d2SGreg Kroah-Hartman
scif_set_rtrg(struct uart_port * port,int rx_trig)1094a380ed46SUlrich Hecht static int scif_set_rtrg(struct uart_port *port, int rx_trig)
1095a380ed46SUlrich Hecht {
1096a380ed46SUlrich Hecht unsigned int bits;
1097a380ed46SUlrich Hecht
10982ea2e019SGeert Uytterhoeven if (rx_trig >= port->fifosize)
10992ea2e019SGeert Uytterhoeven rx_trig = port->fifosize - 1;
1100a380ed46SUlrich Hecht if (rx_trig < 1)
1101a380ed46SUlrich Hecht rx_trig = 1;
1102a380ed46SUlrich Hecht
1103a380ed46SUlrich Hecht /* HSCIF can be set to an arbitrary level. */
1104a380ed46SUlrich Hecht if (sci_getreg(port, HSRTRGR)->size) {
11056deab514SGeert Uytterhoeven sci_serial_out(port, HSRTRGR, rx_trig);
1106a380ed46SUlrich Hecht return rx_trig;
1107a380ed46SUlrich Hecht }
1108a380ed46SUlrich Hecht
1109a380ed46SUlrich Hecht switch (port->type) {
1110a380ed46SUlrich Hecht case PORT_SCIF:
1111a380ed46SUlrich Hecht if (rx_trig < 4) {
1112a380ed46SUlrich Hecht bits = 0;
1113a380ed46SUlrich Hecht rx_trig = 1;
1114a380ed46SUlrich Hecht } else if (rx_trig < 8) {
1115a380ed46SUlrich Hecht bits = SCFCR_RTRG0;
1116a380ed46SUlrich Hecht rx_trig = 4;
1117a380ed46SUlrich Hecht } else if (rx_trig < 14) {
1118a380ed46SUlrich Hecht bits = SCFCR_RTRG1;
1119a380ed46SUlrich Hecht rx_trig = 8;
1120a380ed46SUlrich Hecht } else {
1121a380ed46SUlrich Hecht bits = SCFCR_RTRG0 | SCFCR_RTRG1;
1122a380ed46SUlrich Hecht rx_trig = 14;
1123a380ed46SUlrich Hecht }
1124a380ed46SUlrich Hecht break;
1125a380ed46SUlrich Hecht case PORT_SCIFA:
1126a380ed46SUlrich Hecht case PORT_SCIFB:
1127a380ed46SUlrich Hecht if (rx_trig < 16) {
1128a380ed46SUlrich Hecht bits = 0;
1129a380ed46SUlrich Hecht rx_trig = 1;
1130a380ed46SUlrich Hecht } else if (rx_trig < 32) {
1131a380ed46SUlrich Hecht bits = SCFCR_RTRG0;
1132a380ed46SUlrich Hecht rx_trig = 16;
1133a380ed46SUlrich Hecht } else if (rx_trig < 48) {
1134a380ed46SUlrich Hecht bits = SCFCR_RTRG1;
1135a380ed46SUlrich Hecht rx_trig = 32;
1136a380ed46SUlrich Hecht } else {
1137a380ed46SUlrich Hecht bits = SCFCR_RTRG0 | SCFCR_RTRG1;
1138a380ed46SUlrich Hecht rx_trig = 48;
1139a380ed46SUlrich Hecht }
1140a380ed46SUlrich Hecht break;
1141a380ed46SUlrich Hecht default:
1142a380ed46SUlrich Hecht WARN(1, "unknown FIFO configuration");
1143a380ed46SUlrich Hecht return 1;
1144a380ed46SUlrich Hecht }
1145a380ed46SUlrich Hecht
11466deab514SGeert Uytterhoeven sci_serial_out(port, SCFCR,
11476deab514SGeert Uytterhoeven (sci_serial_in(port, SCFCR) &
1148a380ed46SUlrich Hecht ~(SCFCR_RTRG1 | SCFCR_RTRG0)) | bits);
1149a380ed46SUlrich Hecht
1150a380ed46SUlrich Hecht return rx_trig;
1151a380ed46SUlrich Hecht }
1152a380ed46SUlrich Hecht
scif_rtrg_enabled(struct uart_port * port)115303940376SUlrich Hecht static int scif_rtrg_enabled(struct uart_port *port)
115403940376SUlrich Hecht {
115503940376SUlrich Hecht if (sci_getreg(port, HSRTRGR)->size)
11566deab514SGeert Uytterhoeven return sci_serial_in(port, HSRTRGR) != 0;
115703940376SUlrich Hecht else
11586deab514SGeert Uytterhoeven return (sci_serial_in(port, SCFCR) &
115903940376SUlrich Hecht (SCFCR_RTRG0 | SCFCR_RTRG1)) != 0;
116003940376SUlrich Hecht }
116103940376SUlrich Hecht
rx_fifo_timer_fn(struct timer_list * t)1162e99e88a9SKees Cook static void rx_fifo_timer_fn(struct timer_list *t)
116303940376SUlrich Hecht {
1164e99e88a9SKees Cook struct sci_port *s = from_timer(s, t, rx_fifo_timer);
116503940376SUlrich Hecht struct uart_port *port = &s->port;
116603940376SUlrich Hecht
116703940376SUlrich Hecht dev_dbg(port->dev, "Rx timed out\n");
116803940376SUlrich Hecht scif_set_rtrg(port, 1);
116903940376SUlrich Hecht }
117003940376SUlrich Hecht
rx_fifo_trigger_show(struct device * dev,struct device_attribute * attr,char * buf)11717027e62aSGeert Uytterhoeven static ssize_t rx_fifo_trigger_show(struct device *dev,
11727027e62aSGeert Uytterhoeven struct device_attribute *attr, char *buf)
11735d23188aSUlrich Hecht {
11745d23188aSUlrich Hecht struct uart_port *port = dev_get_drvdata(dev);
11755d23188aSUlrich Hecht struct sci_port *sci = to_sci_port(port);
11765d23188aSUlrich Hecht
11775d23188aSUlrich Hecht return sprintf(buf, "%d\n", sci->rx_trigger);
11785d23188aSUlrich Hecht }
11795d23188aSUlrich Hecht
rx_fifo_trigger_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)11807027e62aSGeert Uytterhoeven static ssize_t rx_fifo_trigger_store(struct device *dev,
11815d23188aSUlrich Hecht struct device_attribute *attr,
11827027e62aSGeert Uytterhoeven const char *buf, size_t count)
11835d23188aSUlrich Hecht {
11845d23188aSUlrich Hecht struct uart_port *port = dev_get_drvdata(dev);
11855d23188aSUlrich Hecht struct sci_port *sci = to_sci_port(port);
11864ab3c51eSDan Carpenter int ret;
11875d23188aSUlrich Hecht long r;
11885d23188aSUlrich Hecht
11894ab3c51eSDan Carpenter ret = kstrtol(buf, 0, &r);
11904ab3c51eSDan Carpenter if (ret)
11914ab3c51eSDan Carpenter return ret;
119290afa525SUlrich Hecht
11935d23188aSUlrich Hecht sci->rx_trigger = scif_set_rtrg(port, r);
119490afa525SUlrich Hecht if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
11955d23188aSUlrich Hecht scif_set_rtrg(port, 1);
119690afa525SUlrich Hecht
11975d23188aSUlrich Hecht return count;
11985d23188aSUlrich Hecht }
11995d23188aSUlrich Hecht
12007027e62aSGeert Uytterhoeven static DEVICE_ATTR_RW(rx_fifo_trigger);
12015d23188aSUlrich Hecht
rx_fifo_timeout_show(struct device * dev,struct device_attribute * attr,char * buf)12025d23188aSUlrich Hecht static ssize_t rx_fifo_timeout_show(struct device *dev,
12035d23188aSUlrich Hecht struct device_attribute *attr,
12045d23188aSUlrich Hecht char *buf)
12055d23188aSUlrich Hecht {
12065d23188aSUlrich Hecht struct uart_port *port = dev_get_drvdata(dev);
12075d23188aSUlrich Hecht struct sci_port *sci = to_sci_port(port);
1208fa2abb03SUlrich Hecht int v;
12095d23188aSUlrich Hecht
1210fa2abb03SUlrich Hecht if (port->type == PORT_HSCIF)
1211fa2abb03SUlrich Hecht v = sci->hscif_tot >> HSSCR_TOT_SHIFT;
1212fa2abb03SUlrich Hecht else
1213fa2abb03SUlrich Hecht v = sci->rx_fifo_timeout;
1214fa2abb03SUlrich Hecht
1215fa2abb03SUlrich Hecht return sprintf(buf, "%d\n", v);
12165d23188aSUlrich Hecht }
12175d23188aSUlrich Hecht
rx_fifo_timeout_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)12185d23188aSUlrich Hecht static ssize_t rx_fifo_timeout_store(struct device *dev,
12195d23188aSUlrich Hecht struct device_attribute *attr,
12205d23188aSUlrich Hecht const char *buf,
12215d23188aSUlrich Hecht size_t count)
12225d23188aSUlrich Hecht {
12235d23188aSUlrich Hecht struct uart_port *port = dev_get_drvdata(dev);
12245d23188aSUlrich Hecht struct sci_port *sci = to_sci_port(port);
12254ab3c51eSDan Carpenter int ret;
12265d23188aSUlrich Hecht long r;
12275d23188aSUlrich Hecht
12284ab3c51eSDan Carpenter ret = kstrtol(buf, 0, &r);
12294ab3c51eSDan Carpenter if (ret)
12304ab3c51eSDan Carpenter return ret;
1231fa2abb03SUlrich Hecht
1232fa2abb03SUlrich Hecht if (port->type == PORT_HSCIF) {
1233fa2abb03SUlrich Hecht if (r < 0 || r > 3)
1234fa2abb03SUlrich Hecht return -EINVAL;
1235fa2abb03SUlrich Hecht sci->hscif_tot = r << HSSCR_TOT_SHIFT;
1236fa2abb03SUlrich Hecht } else {
12375d23188aSUlrich Hecht sci->rx_fifo_timeout = r;
12385d23188aSUlrich Hecht scif_set_rtrg(port, 1);
12395d23188aSUlrich Hecht if (r > 0)
1240e99e88a9SKees Cook timer_setup(&sci->rx_fifo_timer, rx_fifo_timer_fn, 0);
1241fa2abb03SUlrich Hecht }
1242fa2abb03SUlrich Hecht
12435d23188aSUlrich Hecht return count;
12445d23188aSUlrich Hecht }
12455d23188aSUlrich Hecht
1246b6b996b6SJoe Perches static DEVICE_ATTR_RW(rx_fifo_timeout);
12475d23188aSUlrich Hecht
12485d23188aSUlrich Hecht
1249e1910fcdSGeert Uytterhoeven #ifdef CONFIG_SERIAL_SH_SCI_DMA
sci_dma_tx_complete(void * arg)1250e1910fcdSGeert Uytterhoeven static void sci_dma_tx_complete(void *arg)
1251e1910fcdSGeert Uytterhoeven {
1252e1910fcdSGeert Uytterhoeven struct sci_port *s = arg;
1253e1910fcdSGeert Uytterhoeven struct uart_port *port = &s->port;
12541788cf6aSJiri Slaby (SUSE) struct tty_port *tport = &port->state->port;
1255e1910fcdSGeert Uytterhoeven unsigned long flags;
1256e1910fcdSGeert Uytterhoeven
1257e1910fcdSGeert Uytterhoeven dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
1258e1910fcdSGeert Uytterhoeven
125994c53770SThomas Gleixner uart_port_lock_irqsave(port, &flags);
1260e1910fcdSGeert Uytterhoeven
1261e234ef0eSIlpo Järvinen uart_xmit_advance(port, s->tx_dma_len);
1262e1910fcdSGeert Uytterhoeven
12631788cf6aSJiri Slaby (SUSE) if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
1264e1910fcdSGeert Uytterhoeven uart_write_wakeup(port);
1265e1910fcdSGeert Uytterhoeven
12667cc0e0a4SClaudiu Beznea s->tx_occurred = true;
12677cc0e0a4SClaudiu Beznea
12681788cf6aSJiri Slaby (SUSE) if (!kfifo_is_empty(&tport->xmit_fifo)) {
1269e1910fcdSGeert Uytterhoeven s->cookie_tx = 0;
1270e1910fcdSGeert Uytterhoeven schedule_work(&s->work_tx);
1271e1910fcdSGeert Uytterhoeven } else {
1272e1910fcdSGeert Uytterhoeven s->cookie_tx = -EINVAL;
12738749061bSBiju Das if (port->type == PORT_SCIFA || port->type == PORT_SCIFB ||
12748749061bSBiju Das s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) {
12756deab514SGeert Uytterhoeven u16 ctrl = sci_serial_in(port, SCSCR);
12766deab514SGeert Uytterhoeven sci_serial_out(port, SCSCR, ctrl & ~SCSCR_TIE);
12778749061bSBiju Das if (s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) {
12788749061bSBiju Das /* Switch irq from DMA to SCIF */
12798749061bSBiju Das dmaengine_pause(s->chan_tx_saved);
12808749061bSBiju Das enable_irq(s->irqs[SCIx_TXI_IRQ]);
12818749061bSBiju Das }
1282e1910fcdSGeert Uytterhoeven }
1283e1910fcdSGeert Uytterhoeven }
1284e1910fcdSGeert Uytterhoeven
128594c53770SThomas Gleixner uart_port_unlock_irqrestore(port, flags);
1286e1910fcdSGeert Uytterhoeven }
1287e1910fcdSGeert Uytterhoeven
1288e1910fcdSGeert Uytterhoeven /* Locking: called with port lock held */
sci_dma_rx_push(struct sci_port * s,void * buf,size_t count)1289e1910fcdSGeert Uytterhoeven static int sci_dma_rx_push(struct sci_port *s, void *buf, size_t count)
1290e1910fcdSGeert Uytterhoeven {
1291e1910fcdSGeert Uytterhoeven struct uart_port *port = &s->port;
1292e1910fcdSGeert Uytterhoeven struct tty_port *tport = &port->state->port;
1293e1910fcdSGeert Uytterhoeven int copied;
1294e1910fcdSGeert Uytterhoeven
1295e1910fcdSGeert Uytterhoeven copied = tty_insert_flip_string(tport, buf, count);
12966fc5a520STakatoshi Akiyama if (copied < count)
1297e1910fcdSGeert Uytterhoeven port->icount.buf_overrun++;
1298e1910fcdSGeert Uytterhoeven
1299e1910fcdSGeert Uytterhoeven port->icount.rx += copied;
1300e1910fcdSGeert Uytterhoeven
1301e1910fcdSGeert Uytterhoeven return copied;
1302e1910fcdSGeert Uytterhoeven }
1303e1910fcdSGeert Uytterhoeven
sci_dma_rx_find_active(struct sci_port * s)1304e1910fcdSGeert Uytterhoeven static int sci_dma_rx_find_active(struct sci_port *s)
1305e1910fcdSGeert Uytterhoeven {
1306e1910fcdSGeert Uytterhoeven unsigned int i;
1307e1910fcdSGeert Uytterhoeven
1308e1910fcdSGeert Uytterhoeven for (i = 0; i < ARRAY_SIZE(s->cookie_rx); i++)
1309e1910fcdSGeert Uytterhoeven if (s->active_rx == s->cookie_rx[i])
1310e1910fcdSGeert Uytterhoeven return i;
1311e1910fcdSGeert Uytterhoeven
1312e1910fcdSGeert Uytterhoeven return -1;
1313e1910fcdSGeert Uytterhoeven }
1314e1910fcdSGeert Uytterhoeven
13158efc4405SWolfram Sang /* Must only be called with uart_port_lock taken */
sci_dma_rx_chan_invalidate(struct sci_port * s)131611b3770dSGeert Uytterhoeven static void sci_dma_rx_chan_invalidate(struct sci_port *s)
131711b3770dSGeert Uytterhoeven {
131811b3770dSGeert Uytterhoeven unsigned int i;
131911b3770dSGeert Uytterhoeven
132011b3770dSGeert Uytterhoeven s->chan_rx = NULL;
132111b3770dSGeert Uytterhoeven for (i = 0; i < ARRAY_SIZE(s->cookie_rx); i++)
132211b3770dSGeert Uytterhoeven s->cookie_rx[i] = -EINVAL;
132311b3770dSGeert Uytterhoeven s->active_rx = 0;
132411b3770dSGeert Uytterhoeven }
132511b3770dSGeert Uytterhoeven
sci_dma_rx_release(struct sci_port * s)13268fcf7a65SGeert Uytterhoeven static void sci_dma_rx_release(struct sci_port *s)
1327e1910fcdSGeert Uytterhoeven {
13282c4ee235SGeert Uytterhoeven struct dma_chan *chan = s->chan_rx_saved;
1329aae20f6eSWolfram Sang struct uart_port *port = &s->port;
1330aae20f6eSWolfram Sang unsigned long flags;
1331e1910fcdSGeert Uytterhoeven
1332aae20f6eSWolfram Sang uart_port_lock_irqsave(port, &flags);
133311b3770dSGeert Uytterhoeven s->chan_rx_saved = NULL;
133411b3770dSGeert Uytterhoeven sci_dma_rx_chan_invalidate(s);
1335aae20f6eSWolfram Sang uart_port_unlock_irqrestore(port, flags);
1336aae20f6eSWolfram Sang
13376eefc68dSGeert Uytterhoeven dmaengine_terminate_sync(chan);
1338e1910fcdSGeert Uytterhoeven dma_free_coherent(chan->device->dev, s->buf_len_rx * 2, s->rx_buf[0],
1339e1910fcdSGeert Uytterhoeven sg_dma_address(&s->sg_rx[0]));
1340e1910fcdSGeert Uytterhoeven dma_release_channel(chan);
1341e1910fcdSGeert Uytterhoeven }
1342e1910fcdSGeert Uytterhoeven
start_hrtimer_us(struct hrtimer * hrt,unsigned long usec)1343b96408b4SUlrich Hecht static void start_hrtimer_us(struct hrtimer *hrt, unsigned long usec)
1344b96408b4SUlrich Hecht {
1345b96408b4SUlrich Hecht long sec = usec / 1000000;
1346b96408b4SUlrich Hecht long nsec = (usec % 1000000) * 1000;
1347b96408b4SUlrich Hecht ktime_t t = ktime_set(sec, nsec);
1348b96408b4SUlrich Hecht
1349b96408b4SUlrich Hecht hrtimer_start(hrt, t, HRTIMER_MODE_REL);
1350b96408b4SUlrich Hecht }
1351b96408b4SUlrich Hecht
sci_dma_rx_reenable_irq(struct sci_port * s)135238766e4bSGeert Uytterhoeven static void sci_dma_rx_reenable_irq(struct sci_port *s)
135338766e4bSGeert Uytterhoeven {
135438766e4bSGeert Uytterhoeven struct uart_port *port = &s->port;
135538766e4bSGeert Uytterhoeven u16 scr;
135638766e4bSGeert Uytterhoeven
135738766e4bSGeert Uytterhoeven /* Direct new serial port interrupts back to CPU */
13586deab514SGeert Uytterhoeven scr = sci_serial_in(port, SCSCR);
1359cf383d12SBiju Das if (port->type == PORT_SCIFA || port->type == PORT_SCIFB ||
1360cf383d12SBiju Das s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) {
136138766e4bSGeert Uytterhoeven enable_irq(s->irqs[SCIx_RXI_IRQ]);
1362cf383d12SBiju Das if (s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE)
1363cf383d12SBiju Das scif_set_rtrg(port, s->rx_trigger);
1364cf383d12SBiju Das else
1365cf383d12SBiju Das scr &= ~SCSCR_RDRQE;
136638766e4bSGeert Uytterhoeven }
13676deab514SGeert Uytterhoeven sci_serial_out(port, SCSCR, scr | SCSCR_RIE);
136838766e4bSGeert Uytterhoeven }
136938766e4bSGeert Uytterhoeven
sci_dma_rx_complete(void * arg)1370e1910fcdSGeert Uytterhoeven static void sci_dma_rx_complete(void *arg)
1371e1910fcdSGeert Uytterhoeven {
1372e1910fcdSGeert Uytterhoeven struct sci_port *s = arg;
13731d3db608SMuhammad Hamza Farooq struct dma_chan *chan = s->chan_rx;
1374e1910fcdSGeert Uytterhoeven struct uart_port *port = &s->port;
137567f462b0SGeert Uytterhoeven struct dma_async_tx_descriptor *desc;
1376e1910fcdSGeert Uytterhoeven unsigned long flags;
1377e1910fcdSGeert Uytterhoeven int active, count = 0;
1378e1910fcdSGeert Uytterhoeven
1379e1910fcdSGeert Uytterhoeven dev_dbg(port->dev, "%s(%d) active cookie %d\n", __func__, port->line,
1380e1910fcdSGeert Uytterhoeven s->active_rx);
1381e1910fcdSGeert Uytterhoeven
13820c9c1ea5SWolfram Sang hrtimer_cancel(&s->rx_timer);
13830c9c1ea5SWolfram Sang
138494c53770SThomas Gleixner uart_port_lock_irqsave(port, &flags);
1385e1910fcdSGeert Uytterhoeven
1386e1910fcdSGeert Uytterhoeven active = sci_dma_rx_find_active(s);
1387e1910fcdSGeert Uytterhoeven if (active >= 0)
1388e1910fcdSGeert Uytterhoeven count = sci_dma_rx_push(s, s->rx_buf[active], s->buf_len_rx);
1389e1910fcdSGeert Uytterhoeven
1390e1910fcdSGeert Uytterhoeven if (count)
1391e1910fcdSGeert Uytterhoeven tty_flip_buffer_push(&port->state->port);
1392e1910fcdSGeert Uytterhoeven
139367f462b0SGeert Uytterhoeven desc = dmaengine_prep_slave_sg(s->chan_rx, &s->sg_rx[active], 1,
139467f462b0SGeert Uytterhoeven DMA_DEV_TO_MEM,
139567f462b0SGeert Uytterhoeven DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
139667f462b0SGeert Uytterhoeven if (!desc)
139767f462b0SGeert Uytterhoeven goto fail;
139867f462b0SGeert Uytterhoeven
139967f462b0SGeert Uytterhoeven desc->callback = sci_dma_rx_complete;
140067f462b0SGeert Uytterhoeven desc->callback_param = s;
140167f462b0SGeert Uytterhoeven s->cookie_rx[active] = dmaengine_submit(desc);
140267f462b0SGeert Uytterhoeven if (dma_submit_error(s->cookie_rx[active]))
140367f462b0SGeert Uytterhoeven goto fail;
140467f462b0SGeert Uytterhoeven
140567f462b0SGeert Uytterhoeven s->active_rx = s->cookie_rx[!active];
140667f462b0SGeert Uytterhoeven
14071d3db608SMuhammad Hamza Farooq dma_async_issue_pending(chan);
14081d3db608SMuhammad Hamza Farooq
140994c53770SThomas Gleixner uart_port_unlock_irqrestore(port, flags);
141067f462b0SGeert Uytterhoeven dev_dbg(port->dev, "%s: cookie %d #%d, new active cookie %d\n",
141167f462b0SGeert Uytterhoeven __func__, s->cookie_rx[active], active, s->active_rx);
14120c9c1ea5SWolfram Sang
14130c9c1ea5SWolfram Sang start_hrtimer_us(&s->rx_timer, s->rx_timeout);
14140c9c1ea5SWolfram Sang
141567f462b0SGeert Uytterhoeven return;
141667f462b0SGeert Uytterhoeven
141767f462b0SGeert Uytterhoeven fail:
14182c4ee235SGeert Uytterhoeven /* Switch to PIO */
141926f07399SGeert Uytterhoeven dmaengine_terminate_async(chan);
142026f07399SGeert Uytterhoeven sci_dma_rx_chan_invalidate(s);
142126f07399SGeert Uytterhoeven sci_dma_rx_reenable_irq(s);
142294c53770SThomas Gleixner uart_port_unlock_irqrestore(port, flags);
1423ae1b6b4cSWolfram Sang dev_warn(port->dev, "Failed submitting Rx DMA descriptor\n");
1424e1910fcdSGeert Uytterhoeven }
1425e1910fcdSGeert Uytterhoeven
sci_dma_tx_release(struct sci_port * s)14268fcf7a65SGeert Uytterhoeven static void sci_dma_tx_release(struct sci_port *s)
1427e1910fcdSGeert Uytterhoeven {
14282c4ee235SGeert Uytterhoeven struct dma_chan *chan = s->chan_tx_saved;
1429e1910fcdSGeert Uytterhoeven
1430f6611317SGeert Uytterhoeven cancel_work_sync(&s->work_tx);
14312c4ee235SGeert Uytterhoeven s->chan_tx_saved = s->chan_tx = NULL;
1432e1910fcdSGeert Uytterhoeven s->cookie_tx = -EINVAL;
14336eefc68dSGeert Uytterhoeven dmaengine_terminate_sync(chan);
1434e1910fcdSGeert Uytterhoeven dma_unmap_single(chan->device->dev, s->tx_dma_addr, UART_XMIT_SIZE,
1435e1910fcdSGeert Uytterhoeven DMA_TO_DEVICE);
1436e1910fcdSGeert Uytterhoeven dma_release_channel(chan);
1437e1910fcdSGeert Uytterhoeven }
1438e1910fcdSGeert Uytterhoeven
sci_dma_rx_submit(struct sci_port * s,bool port_lock_held)14398fcf7a65SGeert Uytterhoeven static int sci_dma_rx_submit(struct sci_port *s, bool port_lock_held)
1440e1910fcdSGeert Uytterhoeven {
1441e1910fcdSGeert Uytterhoeven struct dma_chan *chan = s->chan_rx;
14422c4ee235SGeert Uytterhoeven struct uart_port *port = &s->port;
14432c4ee235SGeert Uytterhoeven unsigned long flags;
1444e1910fcdSGeert Uytterhoeven int i;
1445e1910fcdSGeert Uytterhoeven
1446e1910fcdSGeert Uytterhoeven for (i = 0; i < 2; i++) {
1447e1910fcdSGeert Uytterhoeven struct scatterlist *sg = &s->sg_rx[i];
1448e1910fcdSGeert Uytterhoeven struct dma_async_tx_descriptor *desc;
1449e1910fcdSGeert Uytterhoeven
1450e1910fcdSGeert Uytterhoeven desc = dmaengine_prep_slave_sg(chan,
1451e1910fcdSGeert Uytterhoeven sg, 1, DMA_DEV_TO_MEM,
1452e1910fcdSGeert Uytterhoeven DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
1453e1910fcdSGeert Uytterhoeven if (!desc)
1454e1910fcdSGeert Uytterhoeven goto fail;
1455e1910fcdSGeert Uytterhoeven
1456e1910fcdSGeert Uytterhoeven desc->callback = sci_dma_rx_complete;
1457e1910fcdSGeert Uytterhoeven desc->callback_param = s;
1458e1910fcdSGeert Uytterhoeven s->cookie_rx[i] = dmaengine_submit(desc);
1459e1910fcdSGeert Uytterhoeven if (dma_submit_error(s->cookie_rx[i]))
1460e1910fcdSGeert Uytterhoeven goto fail;
1461e1910fcdSGeert Uytterhoeven
1462e1910fcdSGeert Uytterhoeven }
1463e1910fcdSGeert Uytterhoeven
1464e1910fcdSGeert Uytterhoeven s->active_rx = s->cookie_rx[0];
1465e1910fcdSGeert Uytterhoeven
1466e1910fcdSGeert Uytterhoeven dma_async_issue_pending(chan);
146771ab1c03SGeert Uytterhoeven return 0;
1468e1910fcdSGeert Uytterhoeven
1469e1910fcdSGeert Uytterhoeven fail:
1470dd1f2250SGeert Uytterhoeven /* Switch to PIO */
1471dd1f2250SGeert Uytterhoeven if (!port_lock_held)
147294c53770SThomas Gleixner uart_port_lock_irqsave(port, &flags);
1473e1910fcdSGeert Uytterhoeven if (i)
14746eefc68dSGeert Uytterhoeven dmaengine_terminate_async(chan);
147511b3770dSGeert Uytterhoeven sci_dma_rx_chan_invalidate(s);
14762c4ee235SGeert Uytterhoeven sci_start_rx(port);
1477dd1f2250SGeert Uytterhoeven if (!port_lock_held)
147894c53770SThomas Gleixner uart_port_unlock_irqrestore(port, flags);
147971ab1c03SGeert Uytterhoeven return -EAGAIN;
1480e1910fcdSGeert Uytterhoeven }
1481e1910fcdSGeert Uytterhoeven
sci_dma_tx_work_fn(struct work_struct * work)14828fcf7a65SGeert Uytterhoeven static void sci_dma_tx_work_fn(struct work_struct *work)
1483e1910fcdSGeert Uytterhoeven {
1484e1910fcdSGeert Uytterhoeven struct sci_port *s = container_of(work, struct sci_port, work_tx);
1485e1910fcdSGeert Uytterhoeven struct dma_async_tx_descriptor *desc;
1486e1910fcdSGeert Uytterhoeven struct dma_chan *chan = s->chan_tx;
1487e1910fcdSGeert Uytterhoeven struct uart_port *port = &s->port;
14881788cf6aSJiri Slaby (SUSE) struct tty_port *tport = &port->state->port;
14892c4ee235SGeert Uytterhoeven unsigned long flags;
14901788cf6aSJiri Slaby (SUSE) unsigned int tail;
1491e1910fcdSGeert Uytterhoeven dma_addr_t buf;
1492e1910fcdSGeert Uytterhoeven
1493e1910fcdSGeert Uytterhoeven /*
1494e1910fcdSGeert Uytterhoeven * DMA is idle now.
1495e1910fcdSGeert Uytterhoeven * Port xmit buffer is already mapped, and it is one page... Just adjust
1496e1910fcdSGeert Uytterhoeven * offsets and lengths. Since it is a circular buffer, we have to
1497e1910fcdSGeert Uytterhoeven * transmit till the end, and then the rest. Take the port lock to get a
1498e1910fcdSGeert Uytterhoeven * consistent xmit buffer state.
1499e1910fcdSGeert Uytterhoeven */
150094c53770SThomas Gleixner uart_port_lock_irq(port);
15011788cf6aSJiri Slaby (SUSE) s->tx_dma_len = kfifo_out_linear(&tport->xmit_fifo, &tail,
15021788cf6aSJiri Slaby (SUSE) UART_XMIT_SIZE);
1503575ca2cbSIlpo Järvinen buf = s->tx_dma_addr + tail;
15048493eab0SGeert Uytterhoeven if (!s->tx_dma_len) {
15058493eab0SGeert Uytterhoeven /* Transmit buffer has been flushed */
150694c53770SThomas Gleixner uart_port_unlock_irq(port);
15078493eab0SGeert Uytterhoeven return;
15088493eab0SGeert Uytterhoeven }
1509e1910fcdSGeert Uytterhoeven
1510e1910fcdSGeert Uytterhoeven desc = dmaengine_prep_slave_single(chan, buf, s->tx_dma_len,
1511e1910fcdSGeert Uytterhoeven DMA_MEM_TO_DEV,
1512e1910fcdSGeert Uytterhoeven DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
1513e1910fcdSGeert Uytterhoeven if (!desc) {
151494c53770SThomas Gleixner uart_port_unlock_irq(port);
1515e1910fcdSGeert Uytterhoeven dev_warn(port->dev, "Failed preparing Tx DMA descriptor\n");
15162c4ee235SGeert Uytterhoeven goto switch_to_pio;
1517e1910fcdSGeert Uytterhoeven }
1518e1910fcdSGeert Uytterhoeven
1519e1910fcdSGeert Uytterhoeven dma_sync_single_for_device(chan->device->dev, buf, s->tx_dma_len,
1520e1910fcdSGeert Uytterhoeven DMA_TO_DEVICE);
1521e1910fcdSGeert Uytterhoeven
1522e1910fcdSGeert Uytterhoeven desc->callback = sci_dma_tx_complete;
1523e1910fcdSGeert Uytterhoeven desc->callback_param = s;
1524e1910fcdSGeert Uytterhoeven s->cookie_tx = dmaengine_submit(desc);
1525e1910fcdSGeert Uytterhoeven if (dma_submit_error(s->cookie_tx)) {
152694c53770SThomas Gleixner uart_port_unlock_irq(port);
1527e1910fcdSGeert Uytterhoeven dev_warn(port->dev, "Failed submitting Tx DMA descriptor\n");
15282c4ee235SGeert Uytterhoeven goto switch_to_pio;
1529e1910fcdSGeert Uytterhoeven }
1530e1910fcdSGeert Uytterhoeven
153194c53770SThomas Gleixner uart_port_unlock_irq(port);
15321788cf6aSJiri Slaby (SUSE) dev_dbg(port->dev, "%s: %p: %u, cookie %d\n",
15331788cf6aSJiri Slaby (SUSE) __func__, tport->xmit_buf, tail, s->cookie_tx);
1534e1910fcdSGeert Uytterhoeven
1535e1910fcdSGeert Uytterhoeven dma_async_issue_pending(chan);
15362c4ee235SGeert Uytterhoeven return;
15372c4ee235SGeert Uytterhoeven
15382c4ee235SGeert Uytterhoeven switch_to_pio:
153994c53770SThomas Gleixner uart_port_lock_irqsave(port, &flags);
15402c4ee235SGeert Uytterhoeven s->chan_tx = NULL;
15412c4ee235SGeert Uytterhoeven sci_start_tx(port);
154294c53770SThomas Gleixner uart_port_unlock_irqrestore(port, flags);
15432c4ee235SGeert Uytterhoeven return;
1544e1910fcdSGeert Uytterhoeven }
1545e1910fcdSGeert Uytterhoeven
sci_dma_rx_timer_fn(struct hrtimer * t)15468fcf7a65SGeert Uytterhoeven static enum hrtimer_restart sci_dma_rx_timer_fn(struct hrtimer *t)
1547e1910fcdSGeert Uytterhoeven {
1548b96408b4SUlrich Hecht struct sci_port *s = container_of(t, struct sci_port, rx_timer);
1549e7327c09SMuhammad Hamza Farooq struct dma_chan *chan = s->chan_rx;
1550e1910fcdSGeert Uytterhoeven struct uart_port *port = &s->port;
155167f462b0SGeert Uytterhoeven struct dma_tx_state state;
155267f462b0SGeert Uytterhoeven enum dma_status status;
155367f462b0SGeert Uytterhoeven unsigned long flags;
155467f462b0SGeert Uytterhoeven unsigned int read;
155567f462b0SGeert Uytterhoeven int active, count;
1556e1910fcdSGeert Uytterhoeven
155767f462b0SGeert Uytterhoeven dev_dbg(port->dev, "DMA Rx timed out\n");
155867f462b0SGeert Uytterhoeven
155994c53770SThomas Gleixner uart_port_lock_irqsave(port, &flags);
15606fc5a520STakatoshi Akiyama
156167f462b0SGeert Uytterhoeven active = sci_dma_rx_find_active(s);
156267f462b0SGeert Uytterhoeven if (active < 0) {
156394c53770SThomas Gleixner uart_port_unlock_irqrestore(port, flags);
1564b96408b4SUlrich Hecht return HRTIMER_NORESTART;
156567f462b0SGeert Uytterhoeven }
156667f462b0SGeert Uytterhoeven
156767f462b0SGeert Uytterhoeven status = dmaengine_tx_status(s->chan_rx, s->active_rx, &state);
15683b963042SMuhammad Hamza Farooq if (status == DMA_COMPLETE) {
156994c53770SThomas Gleixner uart_port_unlock_irqrestore(port, flags);
157067f462b0SGeert Uytterhoeven dev_dbg(port->dev, "Cookie %d #%d has already completed\n",
157167f462b0SGeert Uytterhoeven s->active_rx, active);
15723b963042SMuhammad Hamza Farooq
15733b963042SMuhammad Hamza Farooq /* Let packet complete handler take care of the packet */
1574b96408b4SUlrich Hecht return HRTIMER_NORESTART;
15753b963042SMuhammad Hamza Farooq }
157667f462b0SGeert Uytterhoeven
1577e7327c09SMuhammad Hamza Farooq dmaengine_pause(chan);
1578e7327c09SMuhammad Hamza Farooq
1579e7327c09SMuhammad Hamza Farooq /*
1580e7327c09SMuhammad Hamza Farooq * sometimes DMA transfer doesn't stop even if it is stopped and
1581e7327c09SMuhammad Hamza Farooq * data keeps on coming until transaction is complete so check
1582e7327c09SMuhammad Hamza Farooq * for DMA_COMPLETE again
1583e7327c09SMuhammad Hamza Farooq * Let packet complete handler take care of the packet
1584e7327c09SMuhammad Hamza Farooq */
1585e7327c09SMuhammad Hamza Farooq status = dmaengine_tx_status(s->chan_rx, s->active_rx, &state);
1586e7327c09SMuhammad Hamza Farooq if (status == DMA_COMPLETE) {
158794c53770SThomas Gleixner uart_port_unlock_irqrestore(port, flags);
1588e7327c09SMuhammad Hamza Farooq dev_dbg(port->dev, "Transaction complete after DMA engine was stopped");
1589b96408b4SUlrich Hecht return HRTIMER_NORESTART;
1590e7327c09SMuhammad Hamza Farooq }
1591e7327c09SMuhammad Hamza Farooq
159267f462b0SGeert Uytterhoeven /* Handle incomplete DMA receive */
15936eefc68dSGeert Uytterhoeven dmaengine_terminate_async(s->chan_rx);
159467f462b0SGeert Uytterhoeven read = sg_dma_len(&s->sg_rx[active]) - state.residue;
159567f462b0SGeert Uytterhoeven
159667f462b0SGeert Uytterhoeven if (read) {
159767f462b0SGeert Uytterhoeven count = sci_dma_rx_push(s, s->rx_buf[active], read);
159867f462b0SGeert Uytterhoeven if (count)
159967f462b0SGeert Uytterhoeven tty_flip_buffer_push(&port->state->port);
160067f462b0SGeert Uytterhoeven }
160167f462b0SGeert Uytterhoeven
1602cf383d12SBiju Das if (port->type == PORT_SCIFA || port->type == PORT_SCIFB ||
1603cf383d12SBiju Das s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE)
16048fcf7a65SGeert Uytterhoeven sci_dma_rx_submit(s, true);
1605371cfed3SMuhammad Hamza Farooq
160638766e4bSGeert Uytterhoeven sci_dma_rx_reenable_irq(s);
1607371cfed3SMuhammad Hamza Farooq
160894c53770SThomas Gleixner uart_port_unlock_irqrestore(port, flags);
1609b96408b4SUlrich Hecht
1610b96408b4SUlrich Hecht return HRTIMER_NORESTART;
1611e1910fcdSGeert Uytterhoeven }
1612e1910fcdSGeert Uytterhoeven
sci_request_dma_chan(struct uart_port * port,enum dma_transfer_direction dir)1613ff441129SGeert Uytterhoeven static struct dma_chan *sci_request_dma_chan(struct uart_port *port,
1614219fb0c1SLaurent Pinchart enum dma_transfer_direction dir)
1615e1910fcdSGeert Uytterhoeven {
1616ff441129SGeert Uytterhoeven struct dma_chan *chan;
1617ff441129SGeert Uytterhoeven struct dma_slave_config cfg;
1618ff441129SGeert Uytterhoeven int ret;
1619e1910fcdSGeert Uytterhoeven
1620f1c7f92eSChristophe JAILLET chan = dma_request_chan(port->dev, dir == DMA_MEM_TO_DEV ? "tx" : "rx");
1621f1c7f92eSChristophe JAILLET if (IS_ERR(chan)) {
1622f1c7f92eSChristophe JAILLET dev_dbg(port->dev, "dma_request_chan failed\n");
1623ff441129SGeert Uytterhoeven return NULL;
1624ff441129SGeert Uytterhoeven }
1625e1910fcdSGeert Uytterhoeven
1626ff441129SGeert Uytterhoeven memset(&cfg, 0, sizeof(cfg));
1627ff441129SGeert Uytterhoeven cfg.direction = dir;
1628ff441129SGeert Uytterhoeven cfg.dst_addr = port->mapbase +
1629ff441129SGeert Uytterhoeven (sci_getreg(port, SCxTDR)->offset << port->regshift);
1630ff441129SGeert Uytterhoeven cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
1631ff441129SGeert Uytterhoeven cfg.src_addr = port->mapbase +
1632ff441129SGeert Uytterhoeven (sci_getreg(port, SCxRDR)->offset << port->regshift);
1633ff441129SGeert Uytterhoeven cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
1634ff441129SGeert Uytterhoeven
1635ff441129SGeert Uytterhoeven ret = dmaengine_slave_config(chan, &cfg);
1636ff441129SGeert Uytterhoeven if (ret) {
1637ff441129SGeert Uytterhoeven dev_warn(port->dev, "dmaengine_slave_config failed %d\n", ret);
1638ff441129SGeert Uytterhoeven dma_release_channel(chan);
1639ff441129SGeert Uytterhoeven return NULL;
1640ff441129SGeert Uytterhoeven }
1641ff441129SGeert Uytterhoeven
1642ff441129SGeert Uytterhoeven return chan;
1643ff441129SGeert Uytterhoeven }
1644ff441129SGeert Uytterhoeven
sci_request_dma(struct uart_port * port)1645ff441129SGeert Uytterhoeven static void sci_request_dma(struct uart_port *port)
1646ff441129SGeert Uytterhoeven {
1647ff441129SGeert Uytterhoeven struct sci_port *s = to_sci_port(port);
16481788cf6aSJiri Slaby (SUSE) struct tty_port *tport = &port->state->port;
1649ff441129SGeert Uytterhoeven struct dma_chan *chan;
1650ff441129SGeert Uytterhoeven
1651ff441129SGeert Uytterhoeven dev_dbg(port->dev, "%s: port %d\n", __func__, port->line);
1652ff441129SGeert Uytterhoeven
1653099506cbSGeorge G. Davis /*
1654099506cbSGeorge G. Davis * DMA on console may interfere with Kernel log messages which use
1655099506cbSGeorge G. Davis * plain putchar(). So, simply don't use it with a console.
1656099506cbSGeorge G. Davis */
1657099506cbSGeorge G. Davis if (uart_console(port))
1658099506cbSGeorge G. Davis return;
1659099506cbSGeorge G. Davis
1660219fb0c1SLaurent Pinchart if (!port->dev->of_node)
1661ff441129SGeert Uytterhoeven return;
1662e1910fcdSGeert Uytterhoeven
1663e1910fcdSGeert Uytterhoeven s->cookie_tx = -EINVAL;
16647464779fSAndy Lowe
16657464779fSAndy Lowe /*
16667464779fSAndy Lowe * Don't request a dma channel if no channel was specified
16677464779fSAndy Lowe * in the device tree.
16687464779fSAndy Lowe */
1669ef194140SRob Herring if (!of_property_present(port->dev->of_node, "dmas"))
16707464779fSAndy Lowe return;
16717464779fSAndy Lowe
1672219fb0c1SLaurent Pinchart chan = sci_request_dma_chan(port, DMA_MEM_TO_DEV);
1673e1910fcdSGeert Uytterhoeven dev_dbg(port->dev, "%s: TX: got channel %p\n", __func__, chan);
1674e1910fcdSGeert Uytterhoeven if (chan) {
1675e1910fcdSGeert Uytterhoeven /* UART circular tx buffer is an aligned page. */
1676e1910fcdSGeert Uytterhoeven s->tx_dma_addr = dma_map_single(chan->device->dev,
16771788cf6aSJiri Slaby (SUSE) tport->xmit_buf,
1678e1910fcdSGeert Uytterhoeven UART_XMIT_SIZE,
1679e1910fcdSGeert Uytterhoeven DMA_TO_DEVICE);
1680e1910fcdSGeert Uytterhoeven if (dma_mapping_error(chan->device->dev, s->tx_dma_addr)) {
1681e1910fcdSGeert Uytterhoeven dev_warn(port->dev, "Failed mapping Tx DMA descriptor\n");
1682e1910fcdSGeert Uytterhoeven dma_release_channel(chan);
1683e1910fcdSGeert Uytterhoeven } else {
1684e1910fcdSGeert Uytterhoeven dev_dbg(port->dev, "%s: mapped %lu@%p to %pad\n",
1685e1910fcdSGeert Uytterhoeven __func__, UART_XMIT_SIZE,
16861788cf6aSJiri Slaby (SUSE) tport->xmit_buf, &s->tx_dma_addr);
16872c4ee235SGeert Uytterhoeven
16888fcf7a65SGeert Uytterhoeven INIT_WORK(&s->work_tx, sci_dma_tx_work_fn);
16892c4ee235SGeert Uytterhoeven s->chan_tx_saved = s->chan_tx = chan;
1690e1910fcdSGeert Uytterhoeven }
1691e1910fcdSGeert Uytterhoeven }
1692e1910fcdSGeert Uytterhoeven
1693219fb0c1SLaurent Pinchart chan = sci_request_dma_chan(port, DMA_DEV_TO_MEM);
1694e1910fcdSGeert Uytterhoeven dev_dbg(port->dev, "%s: RX: got channel %p\n", __func__, chan);
1695e1910fcdSGeert Uytterhoeven if (chan) {
1696e1910fcdSGeert Uytterhoeven unsigned int i;
1697e1910fcdSGeert Uytterhoeven dma_addr_t dma;
1698e1910fcdSGeert Uytterhoeven void *buf;
1699e1910fcdSGeert Uytterhoeven
1700e1910fcdSGeert Uytterhoeven s->buf_len_rx = 2 * max_t(size_t, 16, port->fifosize);
1701e1910fcdSGeert Uytterhoeven buf = dma_alloc_coherent(chan->device->dev, s->buf_len_rx * 2,
1702e1910fcdSGeert Uytterhoeven &dma, GFP_KERNEL);
1703e1910fcdSGeert Uytterhoeven if (!buf) {
1704e1910fcdSGeert Uytterhoeven dev_warn(port->dev,
1705e1910fcdSGeert Uytterhoeven "Failed to allocate Rx dma buffer, using PIO\n");
1706e1910fcdSGeert Uytterhoeven dma_release_channel(chan);
1707e1910fcdSGeert Uytterhoeven return;
1708e1910fcdSGeert Uytterhoeven }
1709e1910fcdSGeert Uytterhoeven
1710e1910fcdSGeert Uytterhoeven for (i = 0; i < 2; i++) {
1711e1910fcdSGeert Uytterhoeven struct scatterlist *sg = &s->sg_rx[i];
1712e1910fcdSGeert Uytterhoeven
1713e1910fcdSGeert Uytterhoeven sg_init_table(sg, 1);
1714e1910fcdSGeert Uytterhoeven s->rx_buf[i] = buf;
1715e1910fcdSGeert Uytterhoeven sg_dma_address(sg) = dma;
1716d09959e7SYoshihiro Shimoda sg_dma_len(sg) = s->buf_len_rx;
1717e1910fcdSGeert Uytterhoeven
1718e1910fcdSGeert Uytterhoeven buf += s->buf_len_rx;
1719e1910fcdSGeert Uytterhoeven dma += s->buf_len_rx;
1720e1910fcdSGeert Uytterhoeven }
1721e1910fcdSGeert Uytterhoeven
17227ba2faccSNam Cao hrtimer_setup(&s->rx_timer, sci_dma_rx_timer_fn, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
1723e1910fcdSGeert Uytterhoeven
1724202dc3ccSGeert Uytterhoeven s->chan_rx_saved = s->chan_rx = chan;
1725202dc3ccSGeert Uytterhoeven
1726cf383d12SBiju Das if (port->type == PORT_SCIFA || port->type == PORT_SCIFB ||
1727cf383d12SBiju Das s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE)
17288fcf7a65SGeert Uytterhoeven sci_dma_rx_submit(s, false);
1729e1910fcdSGeert Uytterhoeven }
1730e1910fcdSGeert Uytterhoeven }
1731e1910fcdSGeert Uytterhoeven
sci_free_dma(struct uart_port * port)1732e1910fcdSGeert Uytterhoeven static void sci_free_dma(struct uart_port *port)
1733e1910fcdSGeert Uytterhoeven {
1734e1910fcdSGeert Uytterhoeven struct sci_port *s = to_sci_port(port);
1735e1910fcdSGeert Uytterhoeven
17362c4ee235SGeert Uytterhoeven if (s->chan_tx_saved)
17378fcf7a65SGeert Uytterhoeven sci_dma_tx_release(s);
17382c4ee235SGeert Uytterhoeven if (s->chan_rx_saved)
17398fcf7a65SGeert Uytterhoeven sci_dma_rx_release(s);
1740e1910fcdSGeert Uytterhoeven }
17411cf4a7efSGeert Uytterhoeven
sci_flush_buffer(struct uart_port * port)17421cf4a7efSGeert Uytterhoeven static void sci_flush_buffer(struct uart_port *port)
17431cf4a7efSGeert Uytterhoeven {
1744775b7ffdSGeert Uytterhoeven struct sci_port *s = to_sci_port(port);
1745775b7ffdSGeert Uytterhoeven
17461cf4a7efSGeert Uytterhoeven /*
17471cf4a7efSGeert Uytterhoeven * In uart_flush_buffer(), the xmit circular buffer has just been
1748775b7ffdSGeert Uytterhoeven * cleared, so we have to reset tx_dma_len accordingly, and stop any
1749775b7ffdSGeert Uytterhoeven * pending transfers
17501cf4a7efSGeert Uytterhoeven */
1751775b7ffdSGeert Uytterhoeven s->tx_dma_len = 0;
1752775b7ffdSGeert Uytterhoeven if (s->chan_tx) {
1753775b7ffdSGeert Uytterhoeven dmaengine_terminate_async(s->chan_tx);
1754775b7ffdSGeert Uytterhoeven s->cookie_tx = -EINVAL;
1755775b7ffdSGeert Uytterhoeven }
17561cf4a7efSGeert Uytterhoeven }
17577cc0e0a4SClaudiu Beznea
sci_dma_check_tx_occurred(struct sci_port * s)17587cc0e0a4SClaudiu Beznea static void sci_dma_check_tx_occurred(struct sci_port *s)
17597cc0e0a4SClaudiu Beznea {
17607cc0e0a4SClaudiu Beznea struct dma_tx_state state;
17617cc0e0a4SClaudiu Beznea enum dma_status status;
17627cc0e0a4SClaudiu Beznea
17637cc0e0a4SClaudiu Beznea if (!s->chan_tx)
17647cc0e0a4SClaudiu Beznea return;
17657cc0e0a4SClaudiu Beznea
17667cc0e0a4SClaudiu Beznea status = dmaengine_tx_status(s->chan_tx, s->cookie_tx, &state);
17677cc0e0a4SClaudiu Beznea if (status == DMA_COMPLETE || status == DMA_IN_PROGRESS)
17687cc0e0a4SClaudiu Beznea s->tx_occurred = true;
17697cc0e0a4SClaudiu Beznea }
17701cf4a7efSGeert Uytterhoeven #else /* !CONFIG_SERIAL_SH_SCI_DMA */
sci_request_dma(struct uart_port * port)1771e1910fcdSGeert Uytterhoeven static inline void sci_request_dma(struct uart_port *port)
1772e1910fcdSGeert Uytterhoeven {
1773e1910fcdSGeert Uytterhoeven }
1774e1910fcdSGeert Uytterhoeven
sci_free_dma(struct uart_port * port)1775e1910fcdSGeert Uytterhoeven static inline void sci_free_dma(struct uart_port *port)
1776e1910fcdSGeert Uytterhoeven {
1777e1910fcdSGeert Uytterhoeven }
17781cf4a7efSGeert Uytterhoeven
sci_dma_check_tx_occurred(struct sci_port * s)17797cc0e0a4SClaudiu Beznea static void sci_dma_check_tx_occurred(struct sci_port *s)
17807cc0e0a4SClaudiu Beznea {
17817cc0e0a4SClaudiu Beznea }
17827cc0e0a4SClaudiu Beznea
17831cf4a7efSGeert Uytterhoeven #define sci_flush_buffer NULL
17841cf4a7efSGeert Uytterhoeven #endif /* !CONFIG_SERIAL_SH_SCI_DMA */
1785e1910fcdSGeert Uytterhoeven
sci_rx_interrupt(int irq,void * ptr)1786ab4382d2SGreg Kroah-Hartman static irqreturn_t sci_rx_interrupt(int irq, void *ptr)
1787ab4382d2SGreg Kroah-Hartman {
1788ab4382d2SGreg Kroah-Hartman struct uart_port *port = ptr;
1789ab4382d2SGreg Kroah-Hartman struct sci_port *s = to_sci_port(port);
1790ab4382d2SGreg Kroah-Hartman
179103940376SUlrich Hecht #ifdef CONFIG_SERIAL_SH_SCI_DMA
1792ab4382d2SGreg Kroah-Hartman if (s->chan_rx) {
17936deab514SGeert Uytterhoeven u16 scr = sci_serial_in(port, SCSCR);
17946deab514SGeert Uytterhoeven u16 ssr = sci_serial_in(port, SCxSR);
1795ab4382d2SGreg Kroah-Hartman
1796ab4382d2SGreg Kroah-Hartman /* Disable future Rx interrupts */
1797cf383d12SBiju Das if (port->type == PORT_SCIFA || port->type == PORT_SCIFB ||
1798cf383d12SBiju Das s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) {
1799cf383d12SBiju Das disable_irq_nosync(s->irqs[SCIx_RXI_IRQ]);
1800cf383d12SBiju Das if (s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) {
1801cf383d12SBiju Das scif_set_rtrg(port, 1);
1802cf383d12SBiju Das scr |= SCSCR_RIE;
1803cf383d12SBiju Das } else {
180426de4f1bSGeert Uytterhoeven scr |= SCSCR_RDRQE;
1805cf383d12SBiju Das }
1806ab4382d2SGreg Kroah-Hartman } else {
18078fcf7a65SGeert Uytterhoeven if (sci_dma_rx_submit(s, false) < 0)
180871ab1c03SGeert Uytterhoeven goto handle_pio;
180971ab1c03SGeert Uytterhoeven
1810fc887b15SLinus Torvalds scr &= ~SCSCR_RIE;
1811ab4382d2SGreg Kroah-Hartman }
18126deab514SGeert Uytterhoeven sci_serial_out(port, SCSCR, scr);
1813ab4382d2SGreg Kroah-Hartman /* Clear current interrupt */
18146deab514SGeert Uytterhoeven sci_serial_out(port, SCxSR,
181554af5001SGeert Uytterhoeven ssr & ~(SCIF_DR | SCxSR_RDxF(port)));
1816b96408b4SUlrich Hecht dev_dbg(port->dev, "Rx IRQ %lu: setup t-out in %u us\n",
1817ab4382d2SGreg Kroah-Hartman jiffies, s->rx_timeout);
1818b96408b4SUlrich Hecht start_hrtimer_us(&s->rx_timer, s->rx_timeout);
1819ab4382d2SGreg Kroah-Hartman
1820ab4382d2SGreg Kroah-Hartman return IRQ_HANDLED;
1821ab4382d2SGreg Kroah-Hartman }
182271ab1c03SGeert Uytterhoeven
182371ab1c03SGeert Uytterhoeven handle_pio:
1824ab4382d2SGreg Kroah-Hartman #endif
1825ab4382d2SGreg Kroah-Hartman
182603940376SUlrich Hecht if (s->rx_trigger > 1 && s->rx_fifo_timeout > 0) {
182703940376SUlrich Hecht if (!scif_rtrg_enabled(port))
182803940376SUlrich Hecht scif_set_rtrg(port, s->rx_trigger);
182903940376SUlrich Hecht
183003940376SUlrich Hecht mod_timer(&s->rx_fifo_timer, jiffies + DIV_ROUND_UP(
1831b96408b4SUlrich Hecht s->rx_frame * HZ * s->rx_fifo_timeout, 1000000));
183203940376SUlrich Hecht }
183303940376SUlrich Hecht
1834ab4382d2SGreg Kroah-Hartman /* I think sci_receive_chars has to be called irrespective
1835ab4382d2SGreg Kroah-Hartman * of whether the I_IXOFF is set, otherwise, how is the interrupt
1836ab4382d2SGreg Kroah-Hartman * to be disabled?
1837ab4382d2SGreg Kroah-Hartman */
1838ed8c8e1eSGeert Uytterhoeven sci_receive_chars(port);
1839ab4382d2SGreg Kroah-Hartman
1840ab4382d2SGreg Kroah-Hartman return IRQ_HANDLED;
1841ab4382d2SGreg Kroah-Hartman }
1842ab4382d2SGreg Kroah-Hartman
sci_tx_interrupt(int irq,void * ptr)1843ab4382d2SGreg Kroah-Hartman static irqreturn_t sci_tx_interrupt(int irq, void *ptr)
1844ab4382d2SGreg Kroah-Hartman {
1845ab4382d2SGreg Kroah-Hartman struct uart_port *port = ptr;
1846ab4382d2SGreg Kroah-Hartman unsigned long flags;
1847ab4382d2SGreg Kroah-Hartman
184894c53770SThomas Gleixner uart_port_lock_irqsave(port, &flags);
1849ab4382d2SGreg Kroah-Hartman sci_transmit_chars(port);
185094c53770SThomas Gleixner uart_port_unlock_irqrestore(port, flags);
1851ab4382d2SGreg Kroah-Hartman
1852ab4382d2SGreg Kroah-Hartman return IRQ_HANDLED;
1853ab4382d2SGreg Kroah-Hartman }
1854ab4382d2SGreg Kroah-Hartman
sci_tx_end_interrupt(int irq,void * ptr)1855d61ae331SBiju Das static irqreturn_t sci_tx_end_interrupt(int irq, void *ptr)
1856d61ae331SBiju Das {
1857d61ae331SBiju Das struct uart_port *port = ptr;
1858d61ae331SBiju Das unsigned long flags;
1859d61ae331SBiju Das unsigned short ctrl;
1860d61ae331SBiju Das
1861d61ae331SBiju Das if (port->type != PORT_SCI)
1862d61ae331SBiju Das return sci_tx_interrupt(irq, ptr);
1863d61ae331SBiju Das
186494c53770SThomas Gleixner uart_port_lock_irqsave(port, &flags);
18656deab514SGeert Uytterhoeven ctrl = sci_serial_in(port, SCSCR);
1866d61ae331SBiju Das ctrl &= ~(SCSCR_TE | SCSCR_TEIE);
18676deab514SGeert Uytterhoeven sci_serial_out(port, SCSCR, ctrl);
186894c53770SThomas Gleixner uart_port_unlock_irqrestore(port, flags);
1869d61ae331SBiju Das
1870d61ae331SBiju Das return IRQ_HANDLED;
1871d61ae331SBiju Das }
1872d61ae331SBiju Das
sci_br_interrupt(int irq,void * ptr)1873628c534aSChris Brandt static irqreturn_t sci_br_interrupt(int irq, void *ptr)
1874628c534aSChris Brandt {
1875628c534aSChris Brandt struct uart_port *port = ptr;
1876628c534aSChris Brandt
1877628c534aSChris Brandt /* Handle BREAKs */
1878628c534aSChris Brandt sci_handle_breaks(port);
187987b8061bSUlrich Hecht
188087b8061bSUlrich Hecht /* drop invalid character received before break was detected */
18816deab514SGeert Uytterhoeven sci_serial_in(port, SCxRDR);
188287b8061bSUlrich Hecht
1883628c534aSChris Brandt sci_clear_SCxSR(port, SCxSR_BREAK_CLEAR(port));
1884628c534aSChris Brandt
1885628c534aSChris Brandt return IRQ_HANDLED;
1886628c534aSChris Brandt }
18878b0bbd95SChris Brandt
sci_er_interrupt(int irq,void * ptr)1888ab4382d2SGreg Kroah-Hartman static irqreturn_t sci_er_interrupt(int irq, void *ptr)
1889ab4382d2SGreg Kroah-Hartman {
1890ab4382d2SGreg Kroah-Hartman struct uart_port *port = ptr;
1891e6403c11SGeert Uytterhoeven struct sci_port *s = to_sci_port(port);
1892ab4382d2SGreg Kroah-Hartman
1893628c534aSChris Brandt if (s->irqs[SCIx_ERI_IRQ] == s->irqs[SCIx_BRI_IRQ]) {
18948b0bbd95SChris Brandt /* Break and Error interrupts are muxed */
18956deab514SGeert Uytterhoeven unsigned short ssr_status = sci_serial_in(port, SCxSR);
18968b0bbd95SChris Brandt
18978b0bbd95SChris Brandt /* Break Interrupt */
18988b0bbd95SChris Brandt if (ssr_status & SCxSR_BRK(port))
18998b0bbd95SChris Brandt sci_br_interrupt(irq, ptr);
19008b0bbd95SChris Brandt
19018b0bbd95SChris Brandt /* Break only? */
19028b0bbd95SChris Brandt if (!(ssr_status & SCxSR_ERRORS(port)))
19038b0bbd95SChris Brandt return IRQ_HANDLED;
19048b0bbd95SChris Brandt }
19058b0bbd95SChris Brandt
1906ab4382d2SGreg Kroah-Hartman /* Handle errors */
1907ab4382d2SGreg Kroah-Hartman if (port->type == PORT_SCI) {
1908ab4382d2SGreg Kroah-Hartman if (sci_handle_errors(port)) {
1909ab4382d2SGreg Kroah-Hartman /* discard character in rx buffer */
19106deab514SGeert Uytterhoeven sci_serial_in(port, SCxSR);
1911a1b5b43fSGeert Uytterhoeven sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
1912ab4382d2SGreg Kroah-Hartman }
1913ab4382d2SGreg Kroah-Hartman } else {
1914ab4382d2SGreg Kroah-Hartman sci_handle_fifo_overrun(port);
1915e6403c11SGeert Uytterhoeven if (!s->chan_rx)
1916ed8c8e1eSGeert Uytterhoeven sci_receive_chars(port);
1917ab4382d2SGreg Kroah-Hartman }
1918ab4382d2SGreg Kroah-Hartman
1919a1b5b43fSGeert Uytterhoeven sci_clear_SCxSR(port, SCxSR_ERROR_CLEAR(port));
1920ab4382d2SGreg Kroah-Hartman
1921ab4382d2SGreg Kroah-Hartman /* Kick the transmission */
19228eadb56dSYoshihiro Shimoda if (!s->chan_tx)
1923ab4382d2SGreg Kroah-Hartman sci_tx_interrupt(irq, ptr);
1924ab4382d2SGreg Kroah-Hartman
1925ab4382d2SGreg Kroah-Hartman return IRQ_HANDLED;
1926ab4382d2SGreg Kroah-Hartman }
1927ab4382d2SGreg Kroah-Hartman
sci_mpxed_interrupt(int irq,void * ptr)1928ab4382d2SGreg Kroah-Hartman static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr)
1929ab4382d2SGreg Kroah-Hartman {
1930cb772fe7SNobuhiro Iwamatsu unsigned short ssr_status, scr_status, err_enabled, orer_status = 0;
1931ab4382d2SGreg Kroah-Hartman struct uart_port *port = ptr;
1932ab4382d2SGreg Kroah-Hartman struct sci_port *s = to_sci_port(port);
1933ab4382d2SGreg Kroah-Hartman irqreturn_t ret = IRQ_NONE;
1934ab4382d2SGreg Kroah-Hartman
19356deab514SGeert Uytterhoeven ssr_status = sci_serial_in(port, SCxSR);
19366deab514SGeert Uytterhoeven scr_status = sci_serial_in(port, SCSCR);
1937b2f20ed9SLaurent Pinchart if (s->params->overrun_reg == SCxSR)
1938cb772fe7SNobuhiro Iwamatsu orer_status = ssr_status;
1939b2f20ed9SLaurent Pinchart else if (sci_getreg(port, s->params->overrun_reg)->size)
19406deab514SGeert Uytterhoeven orer_status = sci_serial_in(port, s->params->overrun_reg);
1941cb772fe7SNobuhiro Iwamatsu
1942fc887b15SLinus Torvalds err_enabled = scr_status & port_rx_irq_mask(port);
1943ab4382d2SGreg Kroah-Hartman
1944ab4382d2SGreg Kroah-Hartman /* Tx Interrupt */
1945fc887b15SLinus Torvalds if ((ssr_status & SCxSR_TDxE(port)) && (scr_status & SCSCR_TIE) &&
1946ab4382d2SGreg Kroah-Hartman !s->chan_tx)
1947ab4382d2SGreg Kroah-Hartman ret = sci_tx_interrupt(irq, ptr);
1948fc887b15SLinus Torvalds
1949ab4382d2SGreg Kroah-Hartman /*
1950ab4382d2SGreg Kroah-Hartman * Rx Interrupt: if we're using DMA, the DMA controller clears RDF /
1951ab4382d2SGreg Kroah-Hartman * DR flags
1952ab4382d2SGreg Kroah-Hartman */
1953ab4382d2SGreg Kroah-Hartman if (((ssr_status & SCxSR_RDxF(port)) || s->chan_rx) &&
1954e0a12a27SGeert Uytterhoeven (scr_status & SCSCR_RIE))
1955ab4382d2SGreg Kroah-Hartman ret = sci_rx_interrupt(irq, ptr);
1956fc887b15SLinus Torvalds
1957ab4382d2SGreg Kroah-Hartman /* Error Interrupt */
1958ab4382d2SGreg Kroah-Hartman if ((ssr_status & SCxSR_ERRORS(port)) && err_enabled)
1959ab4382d2SGreg Kroah-Hartman ret = sci_er_interrupt(irq, ptr);
1960fc887b15SLinus Torvalds
1961ab4382d2SGreg Kroah-Hartman /* Break Interrupt */
196287b8061bSUlrich Hecht if (s->irqs[SCIx_ERI_IRQ] != s->irqs[SCIx_BRI_IRQ] &&
196387b8061bSUlrich Hecht (ssr_status & SCxSR_BRK(port)) && err_enabled)
1964ab4382d2SGreg Kroah-Hartman ret = sci_br_interrupt(irq, ptr);
1965ab4382d2SGreg Kroah-Hartman
19668b6ff84cSHisashi Nakamura /* Overrun Interrupt */
1967b2f20ed9SLaurent Pinchart if (orer_status & s->params->overrun_mask) {
19688b6ff84cSHisashi Nakamura sci_handle_fifo_overrun(port);
196990803072SYoshihiro Shimoda ret = IRQ_HANDLED;
197090803072SYoshihiro Shimoda }
19718b6ff84cSHisashi Nakamura
1972ab4382d2SGreg Kroah-Hartman return ret;
1973ab4382d2SGreg Kroah-Hartman }
1974ab4382d2SGreg Kroah-Hartman
1975d56a91e8SGeert Uytterhoeven static const struct sci_irq_desc {
19769174fc8fSPaul Mundt const char *desc;
19779174fc8fSPaul Mundt irq_handler_t handler;
19789174fc8fSPaul Mundt } sci_irq_desc[] = {
19799174fc8fSPaul Mundt /*
19809174fc8fSPaul Mundt * Split out handlers, the default case.
19819174fc8fSPaul Mundt */
19829174fc8fSPaul Mundt [SCIx_ERI_IRQ] = {
19839174fc8fSPaul Mundt .desc = "rx err",
19849174fc8fSPaul Mundt .handler = sci_er_interrupt,
19859174fc8fSPaul Mundt },
19869174fc8fSPaul Mundt
19879174fc8fSPaul Mundt [SCIx_RXI_IRQ] = {
19889174fc8fSPaul Mundt .desc = "rx full",
19899174fc8fSPaul Mundt .handler = sci_rx_interrupt,
19909174fc8fSPaul Mundt },
19919174fc8fSPaul Mundt
19929174fc8fSPaul Mundt [SCIx_TXI_IRQ] = {
19939174fc8fSPaul Mundt .desc = "tx empty",
19949174fc8fSPaul Mundt .handler = sci_tx_interrupt,
19959174fc8fSPaul Mundt },
19969174fc8fSPaul Mundt
19979174fc8fSPaul Mundt [SCIx_BRI_IRQ] = {
19989174fc8fSPaul Mundt .desc = "break",
19999174fc8fSPaul Mundt .handler = sci_br_interrupt,
20009174fc8fSPaul Mundt },
20019174fc8fSPaul Mundt
2002628c534aSChris Brandt [SCIx_DRI_IRQ] = {
2003628c534aSChris Brandt .desc = "rx ready",
2004628c534aSChris Brandt .handler = sci_rx_interrupt,
2005628c534aSChris Brandt },
2006628c534aSChris Brandt
2007628c534aSChris Brandt [SCIx_TEI_IRQ] = {
2008628c534aSChris Brandt .desc = "tx end",
2009d61ae331SBiju Das .handler = sci_tx_end_interrupt,
2010628c534aSChris Brandt },
2011628c534aSChris Brandt
20129174fc8fSPaul Mundt /*
20139174fc8fSPaul Mundt * Special muxed handler.
20149174fc8fSPaul Mundt */
20159174fc8fSPaul Mundt [SCIx_MUX_IRQ] = {
20169174fc8fSPaul Mundt .desc = "mux",
20179174fc8fSPaul Mundt .handler = sci_mpxed_interrupt,
20189174fc8fSPaul Mundt },
20199174fc8fSPaul Mundt };
20209174fc8fSPaul Mundt
sci_request_irq(struct sci_port * port)2021ab4382d2SGreg Kroah-Hartman static int sci_request_irq(struct sci_port *port)
2022ab4382d2SGreg Kroah-Hartman {
20239174fc8fSPaul Mundt struct uart_port *up = &port->port;
2024628c534aSChris Brandt int i, j, w, ret = 0;
2025ab4382d2SGreg Kroah-Hartman
20269174fc8fSPaul Mundt for (i = j = 0; i < SCIx_NR_IRQS; i++, j++) {
2027d56a91e8SGeert Uytterhoeven const struct sci_irq_desc *desc;
20281fcc91a6SLaurent Pinchart int irq;
2029ab4382d2SGreg Kroah-Hartman
2030628c534aSChris Brandt /* Check if already registered (muxed) */
2031628c534aSChris Brandt for (w = 0; w < i; w++)
2032628c534aSChris Brandt if (port->irqs[w] == port->irqs[i])
2033628c534aSChris Brandt w = i + 1;
2034628c534aSChris Brandt if (w > i)
2035628c534aSChris Brandt continue;
2036628c534aSChris Brandt
20379174fc8fSPaul Mundt if (SCIx_IRQ_IS_MUXED(port)) {
20389174fc8fSPaul Mundt i = SCIx_MUX_IRQ;
20399174fc8fSPaul Mundt irq = up->irq;
20400e8963deSPaul Mundt } else {
20411fcc91a6SLaurent Pinchart irq = port->irqs[i];
20429174fc8fSPaul Mundt
20430e8963deSPaul Mundt /*
20440e8963deSPaul Mundt * Certain port types won't support all of the
20450e8963deSPaul Mundt * available interrupt sources.
20460e8963deSPaul Mundt */
20471fcc91a6SLaurent Pinchart if (unlikely(irq < 0))
20480e8963deSPaul Mundt continue;
20490e8963deSPaul Mundt }
20500e8963deSPaul Mundt
20519174fc8fSPaul Mundt desc = sci_irq_desc + i;
20529174fc8fSPaul Mundt port->irqstr[j] = kasprintf(GFP_KERNEL, "%s:%s",
2053628c534aSChris Brandt dev_name(up->dev), desc->desc);
2054623ac1d4SPan Bian if (!port->irqstr[j]) {
2055623ac1d4SPan Bian ret = -ENOMEM;
20569174fc8fSPaul Mundt goto out_nomem;
2057623ac1d4SPan Bian }
2058ab4382d2SGreg Kroah-Hartman
20599174fc8fSPaul Mundt ret = request_irq(irq, desc->handler, up->irqflags,
20609174fc8fSPaul Mundt port->irqstr[j], port);
20619174fc8fSPaul Mundt if (unlikely(ret)) {
20629174fc8fSPaul Mundt dev_err(up->dev, "Can't allocate %s IRQ\n", desc->desc);
20639174fc8fSPaul Mundt goto out_noirq;
2064ab4382d2SGreg Kroah-Hartman }
2065ab4382d2SGreg Kroah-Hartman }
2066ab4382d2SGreg Kroah-Hartman
2067ab4382d2SGreg Kroah-Hartman return 0;
20689174fc8fSPaul Mundt
20699174fc8fSPaul Mundt out_noirq:
20709174fc8fSPaul Mundt while (--i >= 0)
20711fcc91a6SLaurent Pinchart free_irq(port->irqs[i], port);
20729174fc8fSPaul Mundt
20739174fc8fSPaul Mundt out_nomem:
20749174fc8fSPaul Mundt while (--j >= 0)
20759174fc8fSPaul Mundt kfree(port->irqstr[j]);
20769174fc8fSPaul Mundt
20779174fc8fSPaul Mundt return ret;
2078ab4382d2SGreg Kroah-Hartman }
2079ab4382d2SGreg Kroah-Hartman
sci_free_irq(struct sci_port * port)2080ab4382d2SGreg Kroah-Hartman static void sci_free_irq(struct sci_port *port)
2081ab4382d2SGreg Kroah-Hartman {
20824d95987aSChris Brandt int i, j;
2083ab4382d2SGreg Kroah-Hartman
20849174fc8fSPaul Mundt /*
20859174fc8fSPaul Mundt * Intentionally in reverse order so we iterate over the muxed
20869174fc8fSPaul Mundt * IRQ first.
20879174fc8fSPaul Mundt */
20889174fc8fSPaul Mundt for (i = 0; i < SCIx_NR_IRQS; i++) {
20891fcc91a6SLaurent Pinchart int irq = port->irqs[i];
20900e8963deSPaul Mundt
20910e8963deSPaul Mundt /*
20920e8963deSPaul Mundt * Certain port types won't support all of the available
20930e8963deSPaul Mundt * interrupt sources.
20940e8963deSPaul Mundt */
20951fcc91a6SLaurent Pinchart if (unlikely(irq < 0))
20960e8963deSPaul Mundt continue;
20970e8963deSPaul Mundt
20984d95987aSChris Brandt /* Check if already freed (irq was muxed) */
20994d95987aSChris Brandt for (j = 0; j < i; j++)
21004d95987aSChris Brandt if (port->irqs[j] == irq)
21014d95987aSChris Brandt j = i + 1;
21024d95987aSChris Brandt if (j > i)
21034d95987aSChris Brandt continue;
21044d95987aSChris Brandt
21051fcc91a6SLaurent Pinchart free_irq(port->irqs[i], port);
21069174fc8fSPaul Mundt kfree(port->irqstr[i]);
21079174fc8fSPaul Mundt
21089174fc8fSPaul Mundt if (SCIx_IRQ_IS_MUXED(port)) {
21099174fc8fSPaul Mundt /* If there's only one IRQ, we're done. */
21109174fc8fSPaul Mundt return;
2111ab4382d2SGreg Kroah-Hartman }
2112ab4382d2SGreg Kroah-Hartman }
2113ab4382d2SGreg Kroah-Hartman }
2114ab4382d2SGreg Kroah-Hartman
sci_tx_empty(struct uart_port * port)2115ab4382d2SGreg Kroah-Hartman static unsigned int sci_tx_empty(struct uart_port *port)
2116ab4382d2SGreg Kroah-Hartman {
21176deab514SGeert Uytterhoeven unsigned short status = sci_serial_in(port, SCxSR);
211872b294cfSPaul Mundt unsigned short in_tx_fifo = sci_txfill(port);
21197cc0e0a4SClaudiu Beznea struct sci_port *s = to_sci_port(port);
21207cc0e0a4SClaudiu Beznea
21217cc0e0a4SClaudiu Beznea sci_dma_check_tx_occurred(s);
21227cc0e0a4SClaudiu Beznea
21237cc0e0a4SClaudiu Beznea if (!s->tx_occurred)
21247cc0e0a4SClaudiu Beznea return TIOCSER_TEMT;
2125ab4382d2SGreg Kroah-Hartman
2126ab4382d2SGreg Kroah-Hartman return (status & SCxSR_TEND(port)) && !in_tx_fifo ? TIOCSER_TEMT : 0;
2127ab4382d2SGreg Kroah-Hartman }
2128ab4382d2SGreg Kroah-Hartman
sci_set_rts(struct uart_port * port,bool state)212933f50ffcSGeert Uytterhoeven static void sci_set_rts(struct uart_port *port, bool state)
213033f50ffcSGeert Uytterhoeven {
213133f50ffcSGeert Uytterhoeven if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
21326deab514SGeert Uytterhoeven u16 data = sci_serial_in(port, SCPDR);
213333f50ffcSGeert Uytterhoeven
213433f50ffcSGeert Uytterhoeven /* Active low */
213533f50ffcSGeert Uytterhoeven if (state)
213633f50ffcSGeert Uytterhoeven data &= ~SCPDR_RTSD;
213733f50ffcSGeert Uytterhoeven else
213833f50ffcSGeert Uytterhoeven data |= SCPDR_RTSD;
21396deab514SGeert Uytterhoeven sci_serial_out(port, SCPDR, data);
214033f50ffcSGeert Uytterhoeven
214133f50ffcSGeert Uytterhoeven /* RTS# is output */
21426deab514SGeert Uytterhoeven sci_serial_out(port, SCPCR,
21436deab514SGeert Uytterhoeven sci_serial_in(port, SCPCR) | SCPCR_RTSC);
214433f50ffcSGeert Uytterhoeven } else if (sci_getreg(port, SCSPTR)->size) {
21456deab514SGeert Uytterhoeven u16 ctrl = sci_serial_in(port, SCSPTR);
214633f50ffcSGeert Uytterhoeven
214733f50ffcSGeert Uytterhoeven /* Active low */
214833f50ffcSGeert Uytterhoeven if (state)
214933f50ffcSGeert Uytterhoeven ctrl &= ~SCSPTR_RTSDT;
215033f50ffcSGeert Uytterhoeven else
215133f50ffcSGeert Uytterhoeven ctrl |= SCSPTR_RTSDT;
21526deab514SGeert Uytterhoeven sci_serial_out(port, SCSPTR, ctrl);
215333f50ffcSGeert Uytterhoeven }
215433f50ffcSGeert Uytterhoeven }
215533f50ffcSGeert Uytterhoeven
sci_get_cts(struct uart_port * port)215633f50ffcSGeert Uytterhoeven static bool sci_get_cts(struct uart_port *port)
215733f50ffcSGeert Uytterhoeven {
215833f50ffcSGeert Uytterhoeven if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
215933f50ffcSGeert Uytterhoeven /* Active low */
21606deab514SGeert Uytterhoeven return !(sci_serial_in(port, SCPDR) & SCPDR_CTSD);
216133f50ffcSGeert Uytterhoeven } else if (sci_getreg(port, SCSPTR)->size) {
216233f50ffcSGeert Uytterhoeven /* Active low */
21636deab514SGeert Uytterhoeven return !(sci_serial_in(port, SCSPTR) & SCSPTR_CTSDT);
216433f50ffcSGeert Uytterhoeven }
216533f50ffcSGeert Uytterhoeven
216633f50ffcSGeert Uytterhoeven return true;
216733f50ffcSGeert Uytterhoeven }
216833f50ffcSGeert Uytterhoeven
2169cdf7c42fSPaul Mundt /*
2170cdf7c42fSPaul Mundt * Modem control is a bit of a mixed bag for SCI(F) ports. Generally
2171cdf7c42fSPaul Mundt * CTS/RTS is supported in hardware by at least one port and controlled
2172cdf7c42fSPaul Mundt * via SCSPTR (SCxPCR for SCIFA/B parts), or external pins (presently
2173cdf7c42fSPaul Mundt * handled via the ->init_pins() op, which is a bit of a one-way street,
2174cdf7c42fSPaul Mundt * lacking any ability to defer pin control -- this will later be
2175cdf7c42fSPaul Mundt * converted over to the GPIO framework).
2176dc7e3ef7SPaul Mundt *
2177dc7e3ef7SPaul Mundt * Other modes (such as loopback) are supported generically on certain
2178dc7e3ef7SPaul Mundt * port types, but not others. For these it's sufficient to test for the
2179dc7e3ef7SPaul Mundt * existence of the support register and simply ignore the port type.
2180cdf7c42fSPaul Mundt */
sci_set_mctrl(struct uart_port * port,unsigned int mctrl)2181ab4382d2SGreg Kroah-Hartman static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl)
2182ab4382d2SGreg Kroah-Hartman {
2183f907c9eaSGeert Uytterhoeven struct sci_port *s = to_sci_port(port);
2184f907c9eaSGeert Uytterhoeven
2185dc7e3ef7SPaul Mundt if (mctrl & TIOCM_LOOP) {
2186d3184e68SGeert Uytterhoeven const struct plat_sci_reg *reg;
2187dc7e3ef7SPaul Mundt
2188dc7e3ef7SPaul Mundt /*
2189dc7e3ef7SPaul Mundt * Standard loopback mode for SCFCR ports.
2190dc7e3ef7SPaul Mundt */
2191dc7e3ef7SPaul Mundt reg = sci_getreg(port, SCFCR);
2192dc7e3ef7SPaul Mundt if (reg->size)
21936deab514SGeert Uytterhoeven sci_serial_out(port, SCFCR,
21946deab514SGeert Uytterhoeven sci_serial_in(port, SCFCR) | SCFCR_LOOP);
2195dc7e3ef7SPaul Mundt }
2196f907c9eaSGeert Uytterhoeven
2197f907c9eaSGeert Uytterhoeven mctrl_gpio_set(s->gpios, mctrl);
219833f50ffcSGeert Uytterhoeven
219997ed9790SLaurent Pinchart if (!s->has_rtscts)
220033f50ffcSGeert Uytterhoeven return;
220133f50ffcSGeert Uytterhoeven
220233f50ffcSGeert Uytterhoeven if (!(mctrl & TIOCM_RTS)) {
220333f50ffcSGeert Uytterhoeven /* Disable Auto RTS */
22042f50304eSLad Prabhakar if (s->cfg->regtype != SCIx_RZV2H_SCIF_REGTYPE)
22056deab514SGeert Uytterhoeven sci_serial_out(port, SCFCR,
22066deab514SGeert Uytterhoeven sci_serial_in(port, SCFCR) & ~SCFCR_MCE);
220733f50ffcSGeert Uytterhoeven
220833f50ffcSGeert Uytterhoeven /* Clear RTS */
220933f50ffcSGeert Uytterhoeven sci_set_rts(port, 0);
221033f50ffcSGeert Uytterhoeven } else if (s->autorts) {
221133f50ffcSGeert Uytterhoeven if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
221233f50ffcSGeert Uytterhoeven /* Enable RTS# pin function */
22136deab514SGeert Uytterhoeven sci_serial_out(port, SCPCR,
22146deab514SGeert Uytterhoeven sci_serial_in(port, SCPCR) & ~SCPCR_RTSC);
221533f50ffcSGeert Uytterhoeven }
221633f50ffcSGeert Uytterhoeven
221733f50ffcSGeert Uytterhoeven /* Enable Auto RTS */
22182f50304eSLad Prabhakar if (s->cfg->regtype != SCIx_RZV2H_SCIF_REGTYPE)
22196deab514SGeert Uytterhoeven sci_serial_out(port, SCFCR,
22206deab514SGeert Uytterhoeven sci_serial_in(port, SCFCR) | SCFCR_MCE);
222133f50ffcSGeert Uytterhoeven } else {
222233f50ffcSGeert Uytterhoeven /* Set RTS */
222333f50ffcSGeert Uytterhoeven sci_set_rts(port, 1);
222433f50ffcSGeert Uytterhoeven }
2225ab4382d2SGreg Kroah-Hartman }
2226ab4382d2SGreg Kroah-Hartman
sci_get_mctrl(struct uart_port * port)2227ab4382d2SGreg Kroah-Hartman static unsigned int sci_get_mctrl(struct uart_port *port)
2228ab4382d2SGreg Kroah-Hartman {
2229f907c9eaSGeert Uytterhoeven struct sci_port *s = to_sci_port(port);
2230f907c9eaSGeert Uytterhoeven struct mctrl_gpios *gpios = s->gpios;
2231f907c9eaSGeert Uytterhoeven unsigned int mctrl = 0;
2232f907c9eaSGeert Uytterhoeven
2233f907c9eaSGeert Uytterhoeven mctrl_gpio_get(gpios, &mctrl);
2234f907c9eaSGeert Uytterhoeven
2235cdf7c42fSPaul Mundt /*
2236cdf7c42fSPaul Mundt * CTS/RTS is handled in hardware when supported, while nothing
223733f50ffcSGeert Uytterhoeven * else is wired up.
2238cdf7c42fSPaul Mundt */
223933f50ffcSGeert Uytterhoeven if (s->autorts) {
224033f50ffcSGeert Uytterhoeven if (sci_get_cts(port))
2241f907c9eaSGeert Uytterhoeven mctrl |= TIOCM_CTS;
2242a16c4c5aSGeert Uytterhoeven } else if (!mctrl_gpio_to_gpiod(gpios, UART_GPIO_CTS)) {
224333f50ffcSGeert Uytterhoeven mctrl |= TIOCM_CTS;
224433f50ffcSGeert Uytterhoeven }
2245a16c4c5aSGeert Uytterhoeven if (!mctrl_gpio_to_gpiod(gpios, UART_GPIO_DSR))
2246f907c9eaSGeert Uytterhoeven mctrl |= TIOCM_DSR;
2247a16c4c5aSGeert Uytterhoeven if (!mctrl_gpio_to_gpiod(gpios, UART_GPIO_DCD))
2248f907c9eaSGeert Uytterhoeven mctrl |= TIOCM_CAR;
2249f907c9eaSGeert Uytterhoeven
2250f907c9eaSGeert Uytterhoeven return mctrl;
2251f907c9eaSGeert Uytterhoeven }
2252f907c9eaSGeert Uytterhoeven
sci_enable_ms(struct uart_port * port)2253f907c9eaSGeert Uytterhoeven static void sci_enable_ms(struct uart_port *port)
2254f907c9eaSGeert Uytterhoeven {
2255f907c9eaSGeert Uytterhoeven mctrl_gpio_enable_ms(to_sci_port(port)->gpios);
2256ab4382d2SGreg Kroah-Hartman }
2257ab4382d2SGreg Kroah-Hartman
sci_break_ctl(struct uart_port * port,int break_state)2258ab4382d2SGreg Kroah-Hartman static void sci_break_ctl(struct uart_port *port, int break_state)
2259ab4382d2SGreg Kroah-Hartman {
2260bbb4ce50SShimoda, Yoshihiro unsigned short scscr, scsptr;
22611be22663STakatoshi Akiyama unsigned long flags;
2262bbb4ce50SShimoda, Yoshihiro
226377124a42SWang Qing /* check whether the port has SCSPTR */
2264abbf121fSGeert Uytterhoeven if (!sci_getreg(port, SCSPTR)->size) {
2265a4e02f6dSShimoda, Yoshihiro /*
2266a4e02f6dSShimoda, Yoshihiro * Not supported by hardware. Most parts couple break and rx
2267a4e02f6dSShimoda, Yoshihiro * interrupts together, with break detection always enabled.
2268a4e02f6dSShimoda, Yoshihiro */
2269a4e02f6dSShimoda, Yoshihiro return;
2270a4e02f6dSShimoda, Yoshihiro }
2271a4e02f6dSShimoda, Yoshihiro
227294c53770SThomas Gleixner uart_port_lock_irqsave(port, &flags);
22736deab514SGeert Uytterhoeven scsptr = sci_serial_in(port, SCSPTR);
22746deab514SGeert Uytterhoeven scscr = sci_serial_in(port, SCSCR);
2275bbb4ce50SShimoda, Yoshihiro
2276bbb4ce50SShimoda, Yoshihiro if (break_state == -1) {
2277bbb4ce50SShimoda, Yoshihiro scsptr = (scsptr | SCSPTR_SPB2IO) & ~SCSPTR_SPB2DT;
2278bbb4ce50SShimoda, Yoshihiro scscr &= ~SCSCR_TE;
2279bbb4ce50SShimoda, Yoshihiro } else {
2280bbb4ce50SShimoda, Yoshihiro scsptr = (scsptr | SCSPTR_SPB2DT) & ~SCSPTR_SPB2IO;
2281bbb4ce50SShimoda, Yoshihiro scscr |= SCSCR_TE;
2282bbb4ce50SShimoda, Yoshihiro }
2283bbb4ce50SShimoda, Yoshihiro
22846deab514SGeert Uytterhoeven sci_serial_out(port, SCSPTR, scsptr);
22856deab514SGeert Uytterhoeven sci_serial_out(port, SCSCR, scscr);
228694c53770SThomas Gleixner uart_port_unlock_irqrestore(port, flags);
2287ab4382d2SGreg Kroah-Hartman }
2288ab4382d2SGreg Kroah-Hartman
sci_startup(struct uart_port * port)2289ab4382d2SGreg Kroah-Hartman static int sci_startup(struct uart_port *port)
2290ab4382d2SGreg Kroah-Hartman {
2291ab4382d2SGreg Kroah-Hartman struct sci_port *s = to_sci_port(port);
22926b620478SPaul Mundt int ret;
2293ab4382d2SGreg Kroah-Hartman
2294ab4382d2SGreg Kroah-Hartman dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
2295ab4382d2SGreg Kroah-Hartman
22967cc0e0a4SClaudiu Beznea s->tx_occurred = false;
2297ab4382d2SGreg Kroah-Hartman sci_request_dma(port);
22986b620478SPaul Mundt
22993c910176STakatoshi Akiyama ret = sci_request_irq(s);
23003c910176STakatoshi Akiyama if (unlikely(ret < 0)) {
23013c910176STakatoshi Akiyama sci_free_dma(port);
23023c910176STakatoshi Akiyama return ret;
23033c910176STakatoshi Akiyama }
23043c910176STakatoshi Akiyama
2305ab4382d2SGreg Kroah-Hartman return 0;
2306ab4382d2SGreg Kroah-Hartman }
2307ab4382d2SGreg Kroah-Hartman
sci_shutdown(struct uart_port * port)2308ab4382d2SGreg Kroah-Hartman static void sci_shutdown(struct uart_port *port)
2309ab4382d2SGreg Kroah-Hartman {
2310ab4382d2SGreg Kroah-Hartman struct sci_port *s = to_sci_port(port);
231133b48e16SShinya Kuribayashi unsigned long flags;
23125fd2b6eeSGeert Uytterhoeven u16 scr;
2313ab4382d2SGreg Kroah-Hartman
2314ab4382d2SGreg Kroah-Hartman dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
2315ab4382d2SGreg Kroah-Hartman
231633f50ffcSGeert Uytterhoeven s->autorts = false;
23171bd2aad5SAlexis Lothoré mctrl_gpio_disable_ms_sync(to_sci_port(port)->gpios);
2318f907c9eaSGeert Uytterhoeven
231994c53770SThomas Gleixner uart_port_lock_irqsave(port, &flags);
2320ab4382d2SGreg Kroah-Hartman sci_stop_rx(port);
2321ab4382d2SGreg Kroah-Hartman sci_stop_tx(port);
2322fa2abb03SUlrich Hecht /*
2323fa2abb03SUlrich Hecht * Stop RX and TX, disable related interrupts, keep clock source
2324fa2abb03SUlrich Hecht * and HSCIF TOT bits
2325fa2abb03SUlrich Hecht */
23266deab514SGeert Uytterhoeven scr = sci_serial_in(port, SCSCR);
23276deab514SGeert Uytterhoeven sci_serial_out(port, SCSCR,
23286deab514SGeert Uytterhoeven scr & (SCSCR_CKE1 | SCSCR_CKE0 | s->hscif_tot));
232994c53770SThomas Gleixner uart_port_unlock_irqrestore(port, flags);
23306b620478SPaul Mundt
23319ab76556SAleksandar Mitev #ifdef CONFIG_SERIAL_SH_SCI_DMA
23322c4ee235SGeert Uytterhoeven if (s->chan_rx_saved) {
23339ab76556SAleksandar Mitev dev_dbg(port->dev, "%s(%d) deleting rx_timer\n", __func__,
23349ab76556SAleksandar Mitev port->line);
2335b96408b4SUlrich Hecht hrtimer_cancel(&s->rx_timer);
23369ab76556SAleksandar Mitev }
23379ab76556SAleksandar Mitev #endif
23389ab76556SAleksandar Mitev
2339c5a9262fSGeert Uytterhoeven if (s->rx_trigger > 1 && s->rx_fifo_timeout > 0)
2340*8fa7292fSThomas Gleixner timer_delete_sync(&s->rx_fifo_timer);
2341ab4382d2SGreg Kroah-Hartman sci_free_irq(s);
23423c910176STakatoshi Akiyama sci_free_dma(port);
2343ab4382d2SGreg Kroah-Hartman }
2344ab4382d2SGreg Kroah-Hartman
sci_sck_calc(struct sci_port * s,unsigned int bps,unsigned int * srr)23456af27bf2SGeert Uytterhoeven static int sci_sck_calc(struct sci_port *s, unsigned int bps,
23466af27bf2SGeert Uytterhoeven unsigned int *srr)
2347fc887b15SLinus Torvalds {
23486af27bf2SGeert Uytterhoeven unsigned long freq = s->clk_rates[SCI_SCK];
23496af27bf2SGeert Uytterhoeven int err, min_err = INT_MAX;
235069eee8e9SGeert Uytterhoeven unsigned int sr;
2351ec09c5ebSLaurent Pinchart
23527b5c0c08SGeert Uytterhoeven if (s->port.type != PORT_HSCIF)
23537b5c0c08SGeert Uytterhoeven freq *= 2;
2354fc887b15SLinus Torvalds
235569eee8e9SGeert Uytterhoeven for_each_sr(sr, s) {
23566af27bf2SGeert Uytterhoeven err = DIV_ROUND_CLOSEST(freq, sr) - bps;
23576af27bf2SGeert Uytterhoeven if (abs(err) >= abs(min_err))
23586af27bf2SGeert Uytterhoeven continue;
2359730c4e78SNobuhiro Iwamatsu
23606af27bf2SGeert Uytterhoeven min_err = err;
23616af27bf2SGeert Uytterhoeven *srr = sr - 1;
2362730c4e78SNobuhiro Iwamatsu
23636af27bf2SGeert Uytterhoeven if (!err)
23646af27bf2SGeert Uytterhoeven break;
2365730c4e78SNobuhiro Iwamatsu }
2366730c4e78SNobuhiro Iwamatsu
23676af27bf2SGeert Uytterhoeven dev_dbg(s->port.dev, "SCK: %u%+d bps using SR %u\n", bps, min_err,
23686af27bf2SGeert Uytterhoeven *srr + 1);
23696af27bf2SGeert Uytterhoeven return min_err;
23706af27bf2SGeert Uytterhoeven }
2371730c4e78SNobuhiro Iwamatsu
sci_brg_calc(struct sci_port * s,unsigned int bps,unsigned long freq,unsigned int * dlr,unsigned int * srr)23721270f865SGeert Uytterhoeven static int sci_brg_calc(struct sci_port *s, unsigned int bps,
23731270f865SGeert Uytterhoeven unsigned long freq, unsigned int *dlr,
23741270f865SGeert Uytterhoeven unsigned int *srr)
2375f303b364SUlrich Hecht {
23761270f865SGeert Uytterhoeven int err, min_err = INT_MAX;
237769eee8e9SGeert Uytterhoeven unsigned int sr, dl;
2378f303b364SUlrich Hecht
23797b5c0c08SGeert Uytterhoeven if (s->port.type != PORT_HSCIF)
23807b5c0c08SGeert Uytterhoeven freq *= 2;
23811270f865SGeert Uytterhoeven
238269eee8e9SGeert Uytterhoeven for_each_sr(sr, s) {
23831270f865SGeert Uytterhoeven dl = DIV_ROUND_CLOSEST(freq, sr * bps);
23841270f865SGeert Uytterhoeven dl = clamp(dl, 1U, 65535U);
23851270f865SGeert Uytterhoeven
23861270f865SGeert Uytterhoeven err = DIV_ROUND_CLOSEST(freq, sr * dl) - bps;
23871270f865SGeert Uytterhoeven if (abs(err) >= abs(min_err))
23881270f865SGeert Uytterhoeven continue;
23891270f865SGeert Uytterhoeven
23901270f865SGeert Uytterhoeven min_err = err;
23911270f865SGeert Uytterhoeven *dlr = dl;
23921270f865SGeert Uytterhoeven *srr = sr - 1;
23931270f865SGeert Uytterhoeven
23941270f865SGeert Uytterhoeven if (!err)
23951270f865SGeert Uytterhoeven break;
23961270f865SGeert Uytterhoeven }
23971270f865SGeert Uytterhoeven
23981270f865SGeert Uytterhoeven dev_dbg(s->port.dev, "BRG: %u%+d bps using DL %u SR %u\n", bps,
23991270f865SGeert Uytterhoeven min_err, *dlr, *srr + 1);
24001270f865SGeert Uytterhoeven return min_err;
24011270f865SGeert Uytterhoeven }
24021270f865SGeert Uytterhoeven
2403b4a5c459SGeert Uytterhoeven /* calculate sample rate, BRR, and clock select */
sci_scbrr_calc(struct sci_port * s,unsigned int bps,unsigned int * brr,unsigned int * srr,unsigned int * cks)2404f4998e55SGeert Uytterhoeven static int sci_scbrr_calc(struct sci_port *s, unsigned int bps,
2405f4998e55SGeert Uytterhoeven unsigned int *brr, unsigned int *srr,
2406b4a5c459SGeert Uytterhoeven unsigned int *cks)
2407ab4382d2SGreg Kroah-Hartman {
2408f4998e55SGeert Uytterhoeven unsigned long freq = s->clk_rates[SCI_FCK];
240969eee8e9SGeert Uytterhoeven unsigned int sr, br, prediv, scrate, c;
24106c51332dSGeert Uytterhoeven int err, min_err = INT_MAX;
2411f303b364SUlrich Hecht
24127b5c0c08SGeert Uytterhoeven if (s->port.type != PORT_HSCIF)
24137b5c0c08SGeert Uytterhoeven freq *= 2;
2414b4a5c459SGeert Uytterhoeven
24156c51332dSGeert Uytterhoeven /*
24166c51332dSGeert Uytterhoeven * Find the combination of sample rate and clock select with the
24176c51332dSGeert Uytterhoeven * smallest deviation from the desired baud rate.
24186c51332dSGeert Uytterhoeven * Prefer high sample rates to maximise the receive margin.
24196c51332dSGeert Uytterhoeven *
2420730c4e78SNobuhiro Iwamatsu * M: Receive margin (%)
2421730c4e78SNobuhiro Iwamatsu * N: Ratio of bit rate to clock (N = sampling rate)
2422730c4e78SNobuhiro Iwamatsu * D: Clock duty (D = 0 to 1.0)
2423730c4e78SNobuhiro Iwamatsu * L: Frame length (L = 9 to 12)
2424730c4e78SNobuhiro Iwamatsu * F: Absolute value of clock frequency deviation
2425730c4e78SNobuhiro Iwamatsu *
2426730c4e78SNobuhiro Iwamatsu * M = |(0.5 - 1 / 2 * N) - ((L - 0.5) * F) -
2427730c4e78SNobuhiro Iwamatsu * (|D - 0.5| / N * (1 + F))|
24286c51332dSGeert Uytterhoeven * NOTE: Usually, treat D for 0.5, F is 0 by this calculation.
2429730c4e78SNobuhiro Iwamatsu */
243069eee8e9SGeert Uytterhoeven for_each_sr(sr, s) {
2431b7d66397SNobuhiro Iwamatsu for (c = 0; c <= 3; c++) {
2432bcb9973aSNobuhiro Iwamatsu /* integerized formulas from HSCIF documentation */
243381ddb200SGeert Uytterhoeven prediv = sr << (2 * c + 1);
2434de01e6cdSGeert Uytterhoeven
2435de01e6cdSGeert Uytterhoeven /*
2436de01e6cdSGeert Uytterhoeven * We need to calculate:
2437de01e6cdSGeert Uytterhoeven *
2438de01e6cdSGeert Uytterhoeven * br = freq / (prediv * bps) clamped to [1..256]
2439881a7489SGeert Uytterhoeven * err = freq / (br * prediv) - bps
2440de01e6cdSGeert Uytterhoeven *
2441de01e6cdSGeert Uytterhoeven * Watch out for overflow when calculating the desired
2442de01e6cdSGeert Uytterhoeven * sampling clock rate!
2443de01e6cdSGeert Uytterhoeven */
2444de01e6cdSGeert Uytterhoeven if (bps > UINT_MAX / prediv)
2445de01e6cdSGeert Uytterhoeven break;
2446de01e6cdSGeert Uytterhoeven
2447de01e6cdSGeert Uytterhoeven scrate = prediv * bps;
2448de01e6cdSGeert Uytterhoeven br = DIV_ROUND_CLOSEST(freq, scrate);
244995a2703eSGeert Uytterhoeven br = clamp(br, 1U, 256U);
24506c51332dSGeert Uytterhoeven
2451881a7489SGeert Uytterhoeven err = DIV_ROUND_CLOSEST(freq, br * prediv) - bps;
24526c51332dSGeert Uytterhoeven if (abs(err) >= abs(min_err))
2453730c4e78SNobuhiro Iwamatsu continue;
2454730c4e78SNobuhiro Iwamatsu
24556c51332dSGeert Uytterhoeven min_err = err;
245695a2703eSGeert Uytterhoeven *brr = br - 1;
2457f303b364SUlrich Hecht *srr = sr - 1;
2458f303b364SUlrich Hecht *cks = c;
24596c51332dSGeert Uytterhoeven
24606c51332dSGeert Uytterhoeven if (!err)
24616c51332dSGeert Uytterhoeven goto found;
2462f303b364SUlrich Hecht }
2463f303b364SUlrich Hecht }
2464f303b364SUlrich Hecht
24656c51332dSGeert Uytterhoeven found:
2466881a7489SGeert Uytterhoeven dev_dbg(s->port.dev, "BRR: %u%+d bps using N %u SR %u cks %u\n", bps,
2467881a7489SGeert Uytterhoeven min_err, *brr, *srr + 1, *cks);
2468f4998e55SGeert Uytterhoeven return min_err;
2469f303b364SUlrich Hecht }
2470f303b364SUlrich Hecht
sci_reset(struct uart_port * port)24711ba76220SMagnus Damm static void sci_reset(struct uart_port *port)
24721ba76220SMagnus Damm {
2473d3184e68SGeert Uytterhoeven const struct plat_sci_reg *reg;
24741ba76220SMagnus Damm unsigned int status;
247518e8cf15SUlrich Hecht struct sci_port *s = to_sci_port(port);
24761ba76220SMagnus Damm
24776deab514SGeert Uytterhoeven sci_serial_out(port, SCSCR, s->hscif_tot); /* TE=0, RE=0, CKE1=0 */
24781ba76220SMagnus Damm
24790979e0e6SPaul Mundt reg = sci_getreg(port, SCFCR);
24800979e0e6SPaul Mundt if (reg->size)
24816deab514SGeert Uytterhoeven sci_serial_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST);
24822768cf42SGeert Uytterhoeven
24832768cf42SGeert Uytterhoeven sci_clear_SCxSR(port,
24842768cf42SGeert Uytterhoeven SCxSR_RDxF_CLEAR(port) & SCxSR_ERROR_CLEAR(port) &
24852768cf42SGeert Uytterhoeven SCxSR_BREAK_CLEAR(port));
2486fc2af334SGeert Uytterhoeven if (sci_getreg(port, SCLSR)->size) {
24876deab514SGeert Uytterhoeven status = sci_serial_in(port, SCLSR);
2488fc2af334SGeert Uytterhoeven status &= ~(SCLSR_TO | SCLSR_ORER);
24896deab514SGeert Uytterhoeven sci_serial_out(port, SCLSR, status);
2490fc2af334SGeert Uytterhoeven }
249118e8cf15SUlrich Hecht
249203940376SUlrich Hecht if (s->rx_trigger > 1) {
249303940376SUlrich Hecht if (s->rx_fifo_timeout) {
249403940376SUlrich Hecht scif_set_rtrg(port, 1);
2495e99e88a9SKees Cook timer_setup(&s->rx_fifo_timer, rx_fifo_timer_fn, 0);
249603940376SUlrich Hecht } else {
249790afa525SUlrich Hecht if (port->type == PORT_SCIFA ||
249890afa525SUlrich Hecht port->type == PORT_SCIFB)
249990afa525SUlrich Hecht scif_set_rtrg(port, 1);
250090afa525SUlrich Hecht else
250118e8cf15SUlrich Hecht scif_set_rtrg(port, s->rx_trigger);
25021ba76220SMagnus Damm }
250303940376SUlrich Hecht }
250403940376SUlrich Hecht }
25051ba76220SMagnus Damm
sci_set_termios(struct uart_port * port,struct ktermios * termios,const struct ktermios * old)2506ab4382d2SGreg Kroah-Hartman static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
2507bec5b814SIlpo Järvinen const struct ktermios *old)
2508ab4382d2SGreg Kroah-Hartman {
250903940376SUlrich Hecht unsigned int baud, smr_val = SCSMR_ASYNC, scr_val = 0, i, bits;
25101270f865SGeert Uytterhoeven unsigned int brr = 255, cks = 0, srr = 15, dl = 0, sccks = 0;
25111270f865SGeert Uytterhoeven unsigned int brr1 = 255, cks1 = 0, srr1 = 15, dl1 = 0;
2512ab4382d2SGreg Kroah-Hartman struct sci_port *s = to_sci_port(port);
2513d3184e68SGeert Uytterhoeven const struct plat_sci_reg *reg;
2514f4998e55SGeert Uytterhoeven int min_err = INT_MAX, err;
2515f4998e55SGeert Uytterhoeven unsigned long max_freq = 0;
2516f4998e55SGeert Uytterhoeven int best_clk = -1;
25171be22663STakatoshi Akiyama unsigned long flags;
2518ab4382d2SGreg Kroah-Hartman
25199b87162dSIlpo Järvinen if ((termios->c_cflag & CSIZE) == CS7) {
2520730c4e78SNobuhiro Iwamatsu smr_val |= SCSMR_CHR;
25219b87162dSIlpo Järvinen } else {
25229b87162dSIlpo Järvinen termios->c_cflag &= ~CSIZE;
25239b87162dSIlpo Järvinen termios->c_cflag |= CS8;
25249b87162dSIlpo Järvinen }
2525730c4e78SNobuhiro Iwamatsu if (termios->c_cflag & PARENB)
2526730c4e78SNobuhiro Iwamatsu smr_val |= SCSMR_PE;
2527730c4e78SNobuhiro Iwamatsu if (termios->c_cflag & PARODD)
2528730c4e78SNobuhiro Iwamatsu smr_val |= SCSMR_PE | SCSMR_ODD;
2529730c4e78SNobuhiro Iwamatsu if (termios->c_cflag & CSTOPB)
2530730c4e78SNobuhiro Iwamatsu smr_val |= SCSMR_STOP;
2531730c4e78SNobuhiro Iwamatsu
2532ab4382d2SGreg Kroah-Hartman /*
2533ab4382d2SGreg Kroah-Hartman * earlyprintk comes here early on with port->uartclk set to zero.
2534ab4382d2SGreg Kroah-Hartman * the clock framework is not up and running at this point so here
2535ab4382d2SGreg Kroah-Hartman * we assume that 115200 is the maximum baud rate. please note that
2536ab4382d2SGreg Kroah-Hartman * the baud rate is not programmed during earlyprintk - it is assumed
2537ab4382d2SGreg Kroah-Hartman * that the previous boot loader has enabled required clocks and
2538ab4382d2SGreg Kroah-Hartman * setup the baud rate generator hardware for us already.
2539ab4382d2SGreg Kroah-Hartman */
2540f4998e55SGeert Uytterhoeven if (!port->uartclk) {
2541f4998e55SGeert Uytterhoeven baud = uart_get_baud_rate(port, termios, old, 0, 115200);
2542f4998e55SGeert Uytterhoeven goto done;
2543f4998e55SGeert Uytterhoeven }
2544ab4382d2SGreg Kroah-Hartman
2545f4998e55SGeert Uytterhoeven for (i = 0; i < SCI_NUM_CLKS; i++)
2546f4998e55SGeert Uytterhoeven max_freq = max(max_freq, s->clk_rates[i]);
2547f4998e55SGeert Uytterhoeven
254869eee8e9SGeert Uytterhoeven baud = uart_get_baud_rate(port, termios, old, 0, max_freq / min_sr(s));
2549f4998e55SGeert Uytterhoeven if (!baud)
2550f4998e55SGeert Uytterhoeven goto done;
2551f4998e55SGeert Uytterhoeven
2552f4998e55SGeert Uytterhoeven /*
2553f4998e55SGeert Uytterhoeven * There can be multiple sources for the sampling clock. Find the one
2554f4998e55SGeert Uytterhoeven * that gives us the smallest deviation from the desired baud rate.
2555f4998e55SGeert Uytterhoeven */
2556f4998e55SGeert Uytterhoeven
25576af27bf2SGeert Uytterhoeven /* Optional Undivided External Clock */
25586af27bf2SGeert Uytterhoeven if (s->clk_rates[SCI_SCK] && port->type != PORT_SCIFA &&
25596af27bf2SGeert Uytterhoeven port->type != PORT_SCIFB) {
25606af27bf2SGeert Uytterhoeven err = sci_sck_calc(s, baud, &srr1);
25616af27bf2SGeert Uytterhoeven if (abs(err) < abs(min_err)) {
25626af27bf2SGeert Uytterhoeven best_clk = SCI_SCK;
25636af27bf2SGeert Uytterhoeven scr_val = SCSCR_CKE1;
25646af27bf2SGeert Uytterhoeven sccks = SCCKS_CKS;
25656af27bf2SGeert Uytterhoeven min_err = err;
25666af27bf2SGeert Uytterhoeven srr = srr1;
25676af27bf2SGeert Uytterhoeven if (!err)
25686af27bf2SGeert Uytterhoeven goto done;
2569f303b364SUlrich Hecht }
2570f303b364SUlrich Hecht }
2571ab4382d2SGreg Kroah-Hartman
25721270f865SGeert Uytterhoeven /* Optional BRG Frequency Divided External Clock */
25731270f865SGeert Uytterhoeven if (s->clk_rates[SCI_SCIF_CLK] && sci_getreg(port, SCDL)->size) {
25741270f865SGeert Uytterhoeven err = sci_brg_calc(s, baud, s->clk_rates[SCI_SCIF_CLK], &dl1,
25751270f865SGeert Uytterhoeven &srr1);
25761270f865SGeert Uytterhoeven if (abs(err) < abs(min_err)) {
25771270f865SGeert Uytterhoeven best_clk = SCI_SCIF_CLK;
25781270f865SGeert Uytterhoeven scr_val = SCSCR_CKE1;
25791270f865SGeert Uytterhoeven sccks = 0;
25801270f865SGeert Uytterhoeven min_err = err;
25811270f865SGeert Uytterhoeven dl = dl1;
25821270f865SGeert Uytterhoeven srr = srr1;
25831270f865SGeert Uytterhoeven if (!err)
25841270f865SGeert Uytterhoeven goto done;
25851270f865SGeert Uytterhoeven }
25861270f865SGeert Uytterhoeven }
25871270f865SGeert Uytterhoeven
25881270f865SGeert Uytterhoeven /* Optional BRG Frequency Divided Internal Clock */
25891270f865SGeert Uytterhoeven if (s->clk_rates[SCI_BRG_INT] && sci_getreg(port, SCDL)->size) {
25901270f865SGeert Uytterhoeven err = sci_brg_calc(s, baud, s->clk_rates[SCI_BRG_INT], &dl1,
25911270f865SGeert Uytterhoeven &srr1);
25921270f865SGeert Uytterhoeven if (abs(err) < abs(min_err)) {
25931270f865SGeert Uytterhoeven best_clk = SCI_BRG_INT;
25941270f865SGeert Uytterhoeven scr_val = SCSCR_CKE1;
25951270f865SGeert Uytterhoeven sccks = SCCKS_XIN;
25961270f865SGeert Uytterhoeven min_err = err;
25971270f865SGeert Uytterhoeven dl = dl1;
25981270f865SGeert Uytterhoeven srr = srr1;
25991270f865SGeert Uytterhoeven if (!min_err)
26001270f865SGeert Uytterhoeven goto done;
26011270f865SGeert Uytterhoeven }
26021270f865SGeert Uytterhoeven }
26031270f865SGeert Uytterhoeven
2604f4998e55SGeert Uytterhoeven /* Divided Functional Clock using standard Bit Rate Register */
2605f4998e55SGeert Uytterhoeven err = sci_scbrr_calc(s, baud, &brr1, &srr1, &cks1);
2606f4998e55SGeert Uytterhoeven if (abs(err) < abs(min_err)) {
2607f4998e55SGeert Uytterhoeven best_clk = SCI_FCK;
26086af27bf2SGeert Uytterhoeven scr_val = 0;
2609f4998e55SGeert Uytterhoeven min_err = err;
2610f4998e55SGeert Uytterhoeven brr = brr1;
2611f4998e55SGeert Uytterhoeven srr = srr1;
2612f4998e55SGeert Uytterhoeven cks = cks1;
2613f4998e55SGeert Uytterhoeven }
2614f4998e55SGeert Uytterhoeven
2615f4998e55SGeert Uytterhoeven done:
2616f4998e55SGeert Uytterhoeven if (best_clk >= 0)
2617f4998e55SGeert Uytterhoeven dev_dbg(port->dev, "Using clk %pC for %u%+d bps\n",
2618f4998e55SGeert Uytterhoeven s->clks[best_clk], baud, min_err);
2619ab4382d2SGreg Kroah-Hartman
262023241d43SPaul Mundt sci_port_enable(s);
262136003386SAlexandre Courbot
26226af27bf2SGeert Uytterhoeven /*
26236af27bf2SGeert Uytterhoeven * Program the optional External Baud Rate Generator (BRG) first.
26246af27bf2SGeert Uytterhoeven * It controls the mux to select (H)SCK or frequency divided clock.
26256af27bf2SGeert Uytterhoeven */
26261270f865SGeert Uytterhoeven if (best_clk >= 0 && sci_getreg(port, SCCKS)->size) {
26276deab514SGeert Uytterhoeven sci_serial_out(port, SCDL, dl);
26286deab514SGeert Uytterhoeven sci_serial_out(port, SCCKS, sccks);
26291270f865SGeert Uytterhoeven }
2630ab4382d2SGreg Kroah-Hartman
263194c53770SThomas Gleixner uart_port_lock_irqsave(port, &flags);
26321be22663STakatoshi Akiyama
2633ab4382d2SGreg Kroah-Hartman sci_reset(port);
2634ab4382d2SGreg Kroah-Hartman
2635ab4382d2SGreg Kroah-Hartman uart_update_timeout(port, termios->c_cflag, baud);
2636ab4382d2SGreg Kroah-Hartman
263763ba1e00SUlrich Hecht /* byte size and parity */
26383ec2ff37SJiri Slaby bits = tty_get_frame_size(termios->c_cflag);
263963ba1e00SUlrich Hecht
26403b2cd606SBiju Das if (sci_getreg(port, SEMR)->size)
26416deab514SGeert Uytterhoeven sci_serial_out(port, SEMR, 0);
26423b2cd606SBiju Das
2643f4998e55SGeert Uytterhoeven if (best_clk >= 0) {
264492a05748SGeert Uytterhoeven if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
264592a05748SGeert Uytterhoeven switch (srr + 1) {
264692a05748SGeert Uytterhoeven case 5: smr_val |= SCSMR_SRC_5; break;
264792a05748SGeert Uytterhoeven case 7: smr_val |= SCSMR_SRC_7; break;
264892a05748SGeert Uytterhoeven case 11: smr_val |= SCSMR_SRC_11; break;
264992a05748SGeert Uytterhoeven case 13: smr_val |= SCSMR_SRC_13; break;
265092a05748SGeert Uytterhoeven case 16: smr_val |= SCSMR_SRC_16; break;
265192a05748SGeert Uytterhoeven case 17: smr_val |= SCSMR_SRC_17; break;
265292a05748SGeert Uytterhoeven case 19: smr_val |= SCSMR_SRC_19; break;
265392a05748SGeert Uytterhoeven case 27: smr_val |= SCSMR_SRC_27; break;
265492a05748SGeert Uytterhoeven }
2655f4998e55SGeert Uytterhoeven smr_val |= cks;
26566deab514SGeert Uytterhoeven sci_serial_out(port, SCSCR, scr_val | s->hscif_tot);
26576deab514SGeert Uytterhoeven sci_serial_out(port, SCSMR, smr_val);
26586deab514SGeert Uytterhoeven sci_serial_out(port, SCBRR, brr);
265963ba1e00SUlrich Hecht if (sci_getreg(port, HSSRR)->size) {
266063ba1e00SUlrich Hecht unsigned int hssrr = srr | HSCIF_SRE;
266163ba1e00SUlrich Hecht /* Calculate deviation from intended rate at the
266263ba1e00SUlrich Hecht * center of the last stop bit in sampling clocks.
266363ba1e00SUlrich Hecht */
266463ba1e00SUlrich Hecht int last_stop = bits * 2 - 1;
2665ace96569SGeert Uytterhoeven int deviation = DIV_ROUND_CLOSEST(min_err * last_stop *
2666ace96569SGeert Uytterhoeven (int)(srr + 1),
2667ace96569SGeert Uytterhoeven 2 * (int)baud);
266863ba1e00SUlrich Hecht
266963ba1e00SUlrich Hecht if (abs(deviation) >= 2) {
267063ba1e00SUlrich Hecht /* At least two sampling clocks off at the
267163ba1e00SUlrich Hecht * last stop bit; we can increase the error
267263ba1e00SUlrich Hecht * margin by shifting the sampling point.
267363ba1e00SUlrich Hecht */
26746b87784bSGeert Uytterhoeven int shift = clamp(deviation / 2, -8, 7);
267563ba1e00SUlrich Hecht
267663ba1e00SUlrich Hecht hssrr |= (shift << HSCIF_SRHP_SHIFT) &
267763ba1e00SUlrich Hecht HSCIF_SRHP_MASK;
267863ba1e00SUlrich Hecht hssrr |= HSCIF_SRDE;
267963ba1e00SUlrich Hecht }
26806deab514SGeert Uytterhoeven sci_serial_out(port, HSSRR, hssrr);
268163ba1e00SUlrich Hecht }
2682f4998e55SGeert Uytterhoeven
2683f4998e55SGeert Uytterhoeven /* Wait one bit interval */
2684f4998e55SGeert Uytterhoeven udelay((1000000 + (baud - 1)) / baud);
2685f4998e55SGeert Uytterhoeven } else {
2686f4998e55SGeert Uytterhoeven /* Don't touch the bit rate configuration */
2687f4998e55SGeert Uytterhoeven scr_val = s->cfg->scscr & (SCSCR_CKE1 | SCSCR_CKE0);
26886deab514SGeert Uytterhoeven smr_val |= sci_serial_in(port, SCSMR) &
26893a964abeSGeert Uytterhoeven (SCSMR_CKEDG | SCSMR_SRC_MASK | SCSMR_CKS);
26906deab514SGeert Uytterhoeven sci_serial_out(port, SCSCR, scr_val | s->hscif_tot);
26916deab514SGeert Uytterhoeven sci_serial_out(port, SCSMR, smr_val);
2692f4998e55SGeert Uytterhoeven }
2693ab4382d2SGreg Kroah-Hartman
2694ab4382d2SGreg Kroah-Hartman sci_init_pins(port, termios->c_cflag);
26950979e0e6SPaul Mundt
269633f50ffcSGeert Uytterhoeven port->status &= ~UPSTAT_AUTOCTS;
269733f50ffcSGeert Uytterhoeven s->autorts = false;
26980979e0e6SPaul Mundt reg = sci_getreg(port, SCFCR);
26990979e0e6SPaul Mundt if (reg->size) {
27006deab514SGeert Uytterhoeven unsigned short ctrl = sci_serial_in(port, SCFCR);
27010979e0e6SPaul Mundt
270233f50ffcSGeert Uytterhoeven if ((port->flags & UPF_HARD_FLOW) &&
270333f50ffcSGeert Uytterhoeven (termios->c_cflag & CRTSCTS)) {
270433f50ffcSGeert Uytterhoeven /* There is no CTS interrupt to restart the hardware */
270533f50ffcSGeert Uytterhoeven port->status |= UPSTAT_AUTOCTS;
270633f50ffcSGeert Uytterhoeven /* MCE is enabled when RTS is raised */
270733f50ffcSGeert Uytterhoeven s->autorts = true;
27080979e0e6SPaul Mundt }
270973c3d53fSPaul Mundt
271073c3d53fSPaul Mundt /*
271173c3d53fSPaul Mundt * As we've done a sci_reset() above, ensure we don't
271273c3d53fSPaul Mundt * interfere with the FIFOs while toggling MCE. As the
271373c3d53fSPaul Mundt * reset values could still be set, simply mask them out.
271473c3d53fSPaul Mundt */
271573c3d53fSPaul Mundt ctrl &= ~(SCFCR_RFRST | SCFCR_TFRST);
271673c3d53fSPaul Mundt
27176deab514SGeert Uytterhoeven sci_serial_out(port, SCFCR, ctrl);
2718faf02f8fSPaul Mundt }
27195f76895eSGeert Uytterhoeven if (port->flags & UPF_HARD_FLOW) {
27205f76895eSGeert Uytterhoeven /* Refresh (Auto) RTS */
27215f76895eSGeert Uytterhoeven sci_set_mctrl(port, port->mctrl);
27225f76895eSGeert Uytterhoeven }
2723ab4382d2SGreg Kroah-Hartman
27241707ce2dSBiju Das /*
27251707ce2dSBiju Das * For SCI, TE (transmit enable) must be set after setting TIE
27261707ce2dSBiju Das * (transmit interrupt enable) or in the same instruction to
27271707ce2dSBiju Das * start the transmitting process. So skip setting TE here for SCI.
27281707ce2dSBiju Das */
27291707ce2dSBiju Das if (port->type != PORT_SCI)
27301707ce2dSBiju Das scr_val |= SCSCR_TE;
27311707ce2dSBiju Das scr_val |= SCSCR_RE | (s->cfg->scscr & ~(SCSCR_CKE1 | SCSCR_CKE0));
27326deab514SGeert Uytterhoeven sci_serial_out(port, SCSCR, scr_val | s->hscif_tot);
273392a05748SGeert Uytterhoeven if ((srr + 1 == 5) &&
273492a05748SGeert Uytterhoeven (port->type == PORT_SCIFA || port->type == PORT_SCIFB)) {
273592a05748SGeert Uytterhoeven /*
273692a05748SGeert Uytterhoeven * In asynchronous mode, when the sampling rate is 1/5, first
273792a05748SGeert Uytterhoeven * received data may become invalid on some SCIFA and SCIFB.
273892a05748SGeert Uytterhoeven * To avoid this problem wait more than 1 serial data time (1
273992a05748SGeert Uytterhoeven * bit time x serial data number) after setting SCSCR.RE = 1.
274092a05748SGeert Uytterhoeven */
274192a05748SGeert Uytterhoeven udelay(DIV_ROUND_UP(10 * 1000000, baud));
274292a05748SGeert Uytterhoeven }
2743ab4382d2SGreg Kroah-Hartman
2744f9f54983SUlrich Hecht /* Calculate delay for 2 DMA buffers (4 FIFO). */
2745b96408b4SUlrich Hecht s->rx_frame = (10000 * bits) / (baud / 100);
274603940376SUlrich Hecht #ifdef CONFIG_SERIAL_SH_SCI_DMA
2747b96408b4SUlrich Hecht s->rx_timeout = s->buf_len_rx * 2 * s->rx_frame;
2748ab4382d2SGreg Kroah-Hartman #endif
2749ab4382d2SGreg Kroah-Hartman
2750ab4382d2SGreg Kroah-Hartman if ((termios->c_cflag & CREAD) != 0)
2751ab4382d2SGreg Kroah-Hartman sci_start_rx(port);
275236003386SAlexandre Courbot
275394c53770SThomas Gleixner uart_port_unlock_irqrestore(port, flags);
27541be22663STakatoshi Akiyama
275523241d43SPaul Mundt sci_port_disable(s);
2756f907c9eaSGeert Uytterhoeven
2757f907c9eaSGeert Uytterhoeven if (UART_ENABLE_MS(port, termios->c_cflag))
2758f907c9eaSGeert Uytterhoeven sci_enable_ms(port);
2759ab4382d2SGreg Kroah-Hartman }
2760ab4382d2SGreg Kroah-Hartman
sci_pm(struct uart_port * port,unsigned int state,unsigned int oldstate)27610174e5caSTeppei Kamijou static void sci_pm(struct uart_port *port, unsigned int state,
27620174e5caSTeppei Kamijou unsigned int oldstate)
27630174e5caSTeppei Kamijou {
27640174e5caSTeppei Kamijou struct sci_port *sci_port = to_sci_port(port);
27650174e5caSTeppei Kamijou
27660174e5caSTeppei Kamijou switch (state) {
2767d3dfe5d9SGeert Uytterhoeven case UART_PM_STATE_OFF:
27680174e5caSTeppei Kamijou sci_port_disable(sci_port);
27690174e5caSTeppei Kamijou break;
27700174e5caSTeppei Kamijou default:
27710174e5caSTeppei Kamijou sci_port_enable(sci_port);
27720174e5caSTeppei Kamijou break;
27730174e5caSTeppei Kamijou }
27740174e5caSTeppei Kamijou }
27750174e5caSTeppei Kamijou
sci_type(struct uart_port * port)2776ab4382d2SGreg Kroah-Hartman static const char *sci_type(struct uart_port *port)
2777ab4382d2SGreg Kroah-Hartman {
2778ab4382d2SGreg Kroah-Hartman switch (port->type) {
2779ab4382d2SGreg Kroah-Hartman case PORT_IRDA:
2780ab4382d2SGreg Kroah-Hartman return "irda";
2781ab4382d2SGreg Kroah-Hartman case PORT_SCI:
2782ab4382d2SGreg Kroah-Hartman return "sci";
2783ab4382d2SGreg Kroah-Hartman case PORT_SCIF:
2784ab4382d2SGreg Kroah-Hartman return "scif";
2785ab4382d2SGreg Kroah-Hartman case PORT_SCIFA:
2786ab4382d2SGreg Kroah-Hartman return "scifa";
2787ab4382d2SGreg Kroah-Hartman case PORT_SCIFB:
2788ab4382d2SGreg Kroah-Hartman return "scifb";
2789f303b364SUlrich Hecht case PORT_HSCIF:
2790f303b364SUlrich Hecht return "hscif";
2791ab4382d2SGreg Kroah-Hartman }
2792ab4382d2SGreg Kroah-Hartman
2793ab4382d2SGreg Kroah-Hartman return NULL;
2794ab4382d2SGreg Kroah-Hartman }
2795ab4382d2SGreg Kroah-Hartman
sci_remap_port(struct uart_port * port)27966b620478SPaul Mundt static int sci_remap_port(struct uart_port *port)
2797ab4382d2SGreg Kroah-Hartman {
2798e4d6f911SYoshinori Sato struct sci_port *sport = to_sci_port(port);
2799ab4382d2SGreg Kroah-Hartman
28006b620478SPaul Mundt /*
28016b620478SPaul Mundt * Nothing to do if there's already an established membase.
28026b620478SPaul Mundt */
2803ab4382d2SGreg Kroah-Hartman if (port->membase)
28046b620478SPaul Mundt return 0;
2805ab4382d2SGreg Kroah-Hartman
28063d73f32bSLaurent Pinchart if (port->dev->of_node || (port->flags & UPF_IOREMAP)) {
28074bdc0d67SChristoph Hellwig port->membase = ioremap(port->mapbase, sport->reg_size);
28086b620478SPaul Mundt if (unlikely(!port->membase)) {
2809ab4382d2SGreg Kroah-Hartman dev_err(port->dev, "can't remap port#%d\n", port->line);
28106b620478SPaul Mundt return -ENXIO;
28116b620478SPaul Mundt }
2812ab4382d2SGreg Kroah-Hartman } else {
2813ab4382d2SGreg Kroah-Hartman /*
2814ab4382d2SGreg Kroah-Hartman * For the simple (and majority of) cases where we don't
2815ab4382d2SGreg Kroah-Hartman * need to do any remapping, just cast the cookie
2816ab4382d2SGreg Kroah-Hartman * directly.
2817ab4382d2SGreg Kroah-Hartman */
28183af4e960SJingoo Han port->membase = (void __iomem *)(uintptr_t)port->mapbase;
2819ab4382d2SGreg Kroah-Hartman }
28206b620478SPaul Mundt
28216b620478SPaul Mundt return 0;
28226b620478SPaul Mundt }
28236b620478SPaul Mundt
sci_release_port(struct uart_port * port)28246b620478SPaul Mundt static void sci_release_port(struct uart_port *port)
28256b620478SPaul Mundt {
2826e4d6f911SYoshinori Sato struct sci_port *sport = to_sci_port(port);
2827e4d6f911SYoshinori Sato
28283d73f32bSLaurent Pinchart if (port->dev->of_node || (port->flags & UPF_IOREMAP)) {
28296b620478SPaul Mundt iounmap(port->membase);
28306b620478SPaul Mundt port->membase = NULL;
28316b620478SPaul Mundt }
28326b620478SPaul Mundt
2833e4d6f911SYoshinori Sato release_mem_region(port->mapbase, sport->reg_size);
28346b620478SPaul Mundt }
28356b620478SPaul Mundt
sci_request_port(struct uart_port * port)28366b620478SPaul Mundt static int sci_request_port(struct uart_port *port)
28376b620478SPaul Mundt {
28386b620478SPaul Mundt struct resource *res;
2839e4d6f911SYoshinori Sato struct sci_port *sport = to_sci_port(port);
28406b620478SPaul Mundt int ret;
28416b620478SPaul Mundt
2842e4d6f911SYoshinori Sato res = request_mem_region(port->mapbase, sport->reg_size,
2843e4d6f911SYoshinori Sato dev_name(port->dev));
2844e4d6f911SYoshinori Sato if (unlikely(res == NULL)) {
2845e4d6f911SYoshinori Sato dev_err(port->dev, "request_mem_region failed.");
28466b620478SPaul Mundt return -EBUSY;
2847e4d6f911SYoshinori Sato }
28486b620478SPaul Mundt
28496b620478SPaul Mundt ret = sci_remap_port(port);
28506b620478SPaul Mundt if (unlikely(ret != 0)) {
28516b620478SPaul Mundt release_resource(res);
28526b620478SPaul Mundt return ret;
28536b620478SPaul Mundt }
28546b620478SPaul Mundt
28556b620478SPaul Mundt return 0;
28566b620478SPaul Mundt }
28576b620478SPaul Mundt
sci_config_port(struct uart_port * port,int flags)28586b620478SPaul Mundt static void sci_config_port(struct uart_port *port, int flags)
28596b620478SPaul Mundt {
28606b620478SPaul Mundt if (flags & UART_CONFIG_TYPE) {
28616b620478SPaul Mundt struct sci_port *sport = to_sci_port(port);
28626b620478SPaul Mundt
28636b620478SPaul Mundt port->type = sport->cfg->type;
28646b620478SPaul Mundt sci_request_port(port);
28656b620478SPaul Mundt }
2866ab4382d2SGreg Kroah-Hartman }
2867ab4382d2SGreg Kroah-Hartman
sci_verify_port(struct uart_port * port,struct serial_struct * ser)2868ab4382d2SGreg Kroah-Hartman static int sci_verify_port(struct uart_port *port, struct serial_struct *ser)
2869ab4382d2SGreg Kroah-Hartman {
2870ab4382d2SGreg Kroah-Hartman if (ser->baud_base < 2400)
2871ab4382d2SGreg Kroah-Hartman /* No paper tape reader for Mitch.. */
2872ab4382d2SGreg Kroah-Hartman return -EINVAL;
2873ab4382d2SGreg Kroah-Hartman
2874ab4382d2SGreg Kroah-Hartman return 0;
2875ab4382d2SGreg Kroah-Hartman }
2876ab4382d2SGreg Kroah-Hartman
2877069a47e5SJulia Lawall static const struct uart_ops sci_uart_ops = {
2878ab4382d2SGreg Kroah-Hartman .tx_empty = sci_tx_empty,
2879ab4382d2SGreg Kroah-Hartman .set_mctrl = sci_set_mctrl,
2880ab4382d2SGreg Kroah-Hartman .get_mctrl = sci_get_mctrl,
2881ab4382d2SGreg Kroah-Hartman .start_tx = sci_start_tx,
2882ab4382d2SGreg Kroah-Hartman .stop_tx = sci_stop_tx,
2883ab4382d2SGreg Kroah-Hartman .stop_rx = sci_stop_rx,
2884f907c9eaSGeert Uytterhoeven .enable_ms = sci_enable_ms,
2885ab4382d2SGreg Kroah-Hartman .break_ctl = sci_break_ctl,
2886ab4382d2SGreg Kroah-Hartman .startup = sci_startup,
2887ab4382d2SGreg Kroah-Hartman .shutdown = sci_shutdown,
28881cf4a7efSGeert Uytterhoeven .flush_buffer = sci_flush_buffer,
2889ab4382d2SGreg Kroah-Hartman .set_termios = sci_set_termios,
28900174e5caSTeppei Kamijou .pm = sci_pm,
2891ab4382d2SGreg Kroah-Hartman .type = sci_type,
2892ab4382d2SGreg Kroah-Hartman .release_port = sci_release_port,
2893ab4382d2SGreg Kroah-Hartman .request_port = sci_request_port,
2894ab4382d2SGreg Kroah-Hartman .config_port = sci_config_port,
2895ab4382d2SGreg Kroah-Hartman .verify_port = sci_verify_port,
2896ab4382d2SGreg Kroah-Hartman #ifdef CONFIG_CONSOLE_POLL
2897ab4382d2SGreg Kroah-Hartman .poll_get_char = sci_poll_get_char,
2898ab4382d2SGreg Kroah-Hartman .poll_put_char = sci_poll_put_char,
2899ab4382d2SGreg Kroah-Hartman #endif
2900ab4382d2SGreg Kroah-Hartman };
2901ab4382d2SGreg Kroah-Hartman
sci_init_clocks(struct sci_port * sci_port,struct device * dev)2902a9ec81f4SLaurent Pinchart static int sci_init_clocks(struct sci_port *sci_port, struct device *dev)
2903a9ec81f4SLaurent Pinchart {
2904f4998e55SGeert Uytterhoeven const char *clk_names[] = {
2905f4998e55SGeert Uytterhoeven [SCI_FCK] = "fck",
29066af27bf2SGeert Uytterhoeven [SCI_SCK] = "sck",
29071270f865SGeert Uytterhoeven [SCI_BRG_INT] = "brg_int",
29081270f865SGeert Uytterhoeven [SCI_SCIF_CLK] = "scif_clk",
2909f4998e55SGeert Uytterhoeven };
2910f4998e55SGeert Uytterhoeven struct clk *clk;
2911f4998e55SGeert Uytterhoeven unsigned int i;
2912a9ec81f4SLaurent Pinchart
29136af27bf2SGeert Uytterhoeven if (sci_port->cfg->type == PORT_HSCIF)
29146af27bf2SGeert Uytterhoeven clk_names[SCI_SCK] = "hsck";
29156af27bf2SGeert Uytterhoeven
2916f4998e55SGeert Uytterhoeven for (i = 0; i < SCI_NUM_CLKS; i++) {
29178a1dcae9SGeert Uytterhoeven clk = devm_clk_get_optional(dev, clk_names[i]);
29188a1dcae9SGeert Uytterhoeven if (IS_ERR(clk))
29198a1dcae9SGeert Uytterhoeven return PTR_ERR(clk);
2920f4998e55SGeert Uytterhoeven
29218a1dcae9SGeert Uytterhoeven if (!clk && i == SCI_FCK) {
2922f4998e55SGeert Uytterhoeven /*
2923f4998e55SGeert Uytterhoeven * Not all SH platforms declare a clock lookup entry
2924f4998e55SGeert Uytterhoeven * for SCI devices, in which case we need to get the
2925f4998e55SGeert Uytterhoeven * global "peripheral_clk" clock.
2926a9ec81f4SLaurent Pinchart */
2927f4998e55SGeert Uytterhoeven clk = devm_clk_get(dev, "peripheral_clk");
29280d1bc829SGeert Uytterhoeven if (IS_ERR(clk))
29290d1bc829SGeert Uytterhoeven return dev_err_probe(dev, PTR_ERR(clk),
29300d1bc829SGeert Uytterhoeven "failed to get %s\n",
29310d1bc829SGeert Uytterhoeven clk_names[i]);
2932f4998e55SGeert Uytterhoeven }
2933f4998e55SGeert Uytterhoeven
29348a1dcae9SGeert Uytterhoeven if (!clk)
29358a1dcae9SGeert Uytterhoeven dev_dbg(dev, "failed to get %s\n", clk_names[i]);
2936f4998e55SGeert Uytterhoeven else
2937d63c16f8SGeert Uytterhoeven dev_dbg(dev, "clk %s is %pC rate %lu\n", clk_names[i],
2938d63c16f8SGeert Uytterhoeven clk, clk_get_rate(clk));
29398a1dcae9SGeert Uytterhoeven sci_port->clks[i] = clk;
2940f4998e55SGeert Uytterhoeven }
2941f4998e55SGeert Uytterhoeven return 0;
2942a9ec81f4SLaurent Pinchart }
2943a9ec81f4SLaurent Pinchart
2944daf5a895SLaurent Pinchart static const struct sci_port_params *
sci_probe_regmap(const struct plat_sci_port * cfg)2945daf5a895SLaurent Pinchart sci_probe_regmap(const struct plat_sci_port *cfg)
2946daf5a895SLaurent Pinchart {
2947daf5a895SLaurent Pinchart unsigned int regtype;
2948daf5a895SLaurent Pinchart
2949daf5a895SLaurent Pinchart if (cfg->regtype != SCIx_PROBE_REGTYPE)
2950daf5a895SLaurent Pinchart return &sci_port_params[cfg->regtype];
2951daf5a895SLaurent Pinchart
2952daf5a895SLaurent Pinchart switch (cfg->type) {
2953daf5a895SLaurent Pinchart case PORT_SCI:
2954daf5a895SLaurent Pinchart regtype = SCIx_SCI_REGTYPE;
2955daf5a895SLaurent Pinchart break;
2956daf5a895SLaurent Pinchart case PORT_IRDA:
2957daf5a895SLaurent Pinchart regtype = SCIx_IRDA_REGTYPE;
2958daf5a895SLaurent Pinchart break;
2959daf5a895SLaurent Pinchart case PORT_SCIFA:
2960daf5a895SLaurent Pinchart regtype = SCIx_SCIFA_REGTYPE;
2961daf5a895SLaurent Pinchart break;
2962daf5a895SLaurent Pinchart case PORT_SCIFB:
2963daf5a895SLaurent Pinchart regtype = SCIx_SCIFB_REGTYPE;
2964daf5a895SLaurent Pinchart break;
2965daf5a895SLaurent Pinchart case PORT_SCIF:
2966daf5a895SLaurent Pinchart /*
2967daf5a895SLaurent Pinchart * The SH-4 is a bit of a misnomer here, although that's
2968daf5a895SLaurent Pinchart * where this particular port layout originated. This
2969daf5a895SLaurent Pinchart * configuration (or some slight variation thereof)
2970daf5a895SLaurent Pinchart * remains the dominant model for all SCIFs.
2971daf5a895SLaurent Pinchart */
2972daf5a895SLaurent Pinchart regtype = SCIx_SH4_SCIF_REGTYPE;
2973daf5a895SLaurent Pinchart break;
2974daf5a895SLaurent Pinchart case PORT_HSCIF:
2975daf5a895SLaurent Pinchart regtype = SCIx_HSCIF_REGTYPE;
2976daf5a895SLaurent Pinchart break;
2977daf5a895SLaurent Pinchart default:
2978daf5a895SLaurent Pinchart pr_err("Can't probe register map for given port\n");
2979daf5a895SLaurent Pinchart return NULL;
2980daf5a895SLaurent Pinchart }
2981daf5a895SLaurent Pinchart
2982daf5a895SLaurent Pinchart return &sci_port_params[regtype];
2983daf5a895SLaurent Pinchart }
2984daf5a895SLaurent Pinchart
sci_init_single(struct platform_device * dev,struct sci_port * sci_port,unsigned int index,const struct plat_sci_port * p,bool early)29859671f099SBill Pemberton static int sci_init_single(struct platform_device *dev,
29861fcc91a6SLaurent Pinchart struct sci_port *sci_port, unsigned int index,
2987daf5a895SLaurent Pinchart const struct plat_sci_port *p, bool early)
2988ab4382d2SGreg Kroah-Hartman {
2989ab4382d2SGreg Kroah-Hartman struct uart_port *port = &sci_port->port;
29901fcc91a6SLaurent Pinchart const struct resource *res;
2991a1c2fd7eSGeert Uytterhoeven unsigned int i;
29923127c6b2SPaul Mundt int ret;
2993ab4382d2SGreg Kroah-Hartman
299450f0959aSPaul Mundt sci_port->cfg = p;
299550f0959aSPaul Mundt
2996ab4382d2SGreg Kroah-Hartman port->ops = &sci_uart_ops;
2997ab4382d2SGreg Kroah-Hartman port->iotype = UPIO_MEM;
2998ab4382d2SGreg Kroah-Hartman port->line = index;
2999dc9a3254SDmitry Safonov port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_SH_SCI_CONSOLE);
3000ab4382d2SGreg Kroah-Hartman
30011fcc91a6SLaurent Pinchart res = platform_get_resource(dev, IORESOURCE_MEM, 0);
30021fcc91a6SLaurent Pinchart if (res == NULL)
30031fcc91a6SLaurent Pinchart return -ENOMEM;
30041fcc91a6SLaurent Pinchart
30051fcc91a6SLaurent Pinchart port->mapbase = res->start;
3006e4d6f911SYoshinori Sato sci_port->reg_size = resource_size(res);
30071fcc91a6SLaurent Pinchart
3008392fb8dfSGeert Uytterhoeven for (i = 0; i < ARRAY_SIZE(sci_port->irqs); ++i) {
3009392fb8dfSGeert Uytterhoeven if (i)
3010392fb8dfSGeert Uytterhoeven sci_port->irqs[i] = platform_get_irq_optional(dev, i);
3011392fb8dfSGeert Uytterhoeven else
30121fcc91a6SLaurent Pinchart sci_port->irqs[i] = platform_get_irq(dev, i);
3013392fb8dfSGeert Uytterhoeven }
30141fcc91a6SLaurent Pinchart
3015b43a1864SBiju Das /*
3016b43a1864SBiju Das * The fourth interrupt on SCI port is transmit end interrupt, so
3017b43a1864SBiju Das * shuffle the interrupts.
3018b43a1864SBiju Das */
3019b43a1864SBiju Das if (p->type == PORT_SCI)
3020b43a1864SBiju Das swap(sci_port->irqs[SCIx_BRI_IRQ], sci_port->irqs[SCIx_TEI_IRQ]);
3021b43a1864SBiju Das
302289b5c1abSLaurent Pinchart /* The SCI generates several interrupts. They can be muxed together or
302389b5c1abSLaurent Pinchart * connected to different interrupt lines. In the muxed case only one
3024628c534aSChris Brandt * interrupt resource is specified as there is only one interrupt ID.
3025628c534aSChris Brandt * In the non-muxed case, up to 6 interrupt signals might be generated
3026628c534aSChris Brandt * from the SCI, however those signals might have their own individual
3027628c534aSChris Brandt * interrupt ID numbers, or muxed together with another interrupt.
30281fcc91a6SLaurent Pinchart */
30291fcc91a6SLaurent Pinchart if (sci_port->irqs[0] < 0)
30301fcc91a6SLaurent Pinchart return -ENXIO;
30311fcc91a6SLaurent Pinchart
3032628c534aSChris Brandt if (sci_port->irqs[1] < 0)
3033628c534aSChris Brandt for (i = 1; i < ARRAY_SIZE(sci_port->irqs); i++)
3034628c534aSChris Brandt sci_port->irqs[i] = sci_port->irqs[0];
30351fcc91a6SLaurent Pinchart
3036daf5a895SLaurent Pinchart sci_port->params = sci_probe_regmap(p);
3037daf5a895SLaurent Pinchart if (unlikely(sci_port->params == NULL))
3038daf5a895SLaurent Pinchart return -EINVAL;
3039e095ee6bSLaurent Pinchart
304018e8cf15SUlrich Hecht switch (p->type) {
304118e8cf15SUlrich Hecht case PORT_SCIFB:
304218e8cf15SUlrich Hecht sci_port->rx_trigger = 48;
304318e8cf15SUlrich Hecht break;
304418e8cf15SUlrich Hecht case PORT_HSCIF:
304518e8cf15SUlrich Hecht sci_port->rx_trigger = 64;
304618e8cf15SUlrich Hecht break;
304718e8cf15SUlrich Hecht case PORT_SCIFA:
304818e8cf15SUlrich Hecht sci_port->rx_trigger = 32;
304918e8cf15SUlrich Hecht break;
305018e8cf15SUlrich Hecht case PORT_SCIF:
305118e8cf15SUlrich Hecht if (p->regtype == SCIx_SH7705_SCIF_REGTYPE)
305218e8cf15SUlrich Hecht /* RX triggering not implemented for this IP */
305318e8cf15SUlrich Hecht sci_port->rx_trigger = 1;
305418e8cf15SUlrich Hecht else
305518e8cf15SUlrich Hecht sci_port->rx_trigger = 8;
305618e8cf15SUlrich Hecht break;
305718e8cf15SUlrich Hecht default:
305818e8cf15SUlrich Hecht sci_port->rx_trigger = 1;
305918e8cf15SUlrich Hecht break;
306018e8cf15SUlrich Hecht }
306118e8cf15SUlrich Hecht
306203940376SUlrich Hecht sci_port->rx_fifo_timeout = 0;
3063fa2abb03SUlrich Hecht sci_port->hscif_tot = 0;
306403940376SUlrich Hecht
3065878fbb91SLaurent Pinchart /* SCIFA on sh7723 and sh7724 need a custom sampling rate that doesn't
3066878fbb91SLaurent Pinchart * match the SoC datasheet, this should be investigated. Let platform
3067878fbb91SLaurent Pinchart * data override the sampling rate for now.
3068ec09c5ebSLaurent Pinchart */
3069b2f20ed9SLaurent Pinchart sci_port->sampling_rate_mask = p->sampling_rate
3070b2f20ed9SLaurent Pinchart ? SCI_SR(p->sampling_rate)
3071b2f20ed9SLaurent Pinchart : sci_port->params->sampling_rate_mask;
3072ec09c5ebSLaurent Pinchart
30731fcc91a6SLaurent Pinchart if (!early) {
3074a9ec81f4SLaurent Pinchart ret = sci_init_clocks(sci_port, &dev->dev);
3075a9ec81f4SLaurent Pinchart if (ret < 0)
3076a9ec81f4SLaurent Pinchart return ret;
3077ab4382d2SGreg Kroah-Hartman }
3078ab4382d2SGreg Kroah-Hartman
30796b620478SPaul Mundt port->type = p->type;
30803d73f32bSLaurent Pinchart port->flags = UPF_FIXED_PORT | UPF_BOOT_AUTOCONF | p->flags;
3081b2f20ed9SLaurent Pinchart port->fifosize = sci_port->params->fifosize;
3082ab4382d2SGreg Kroah-Hartman
3083f92ed0cdSBiju Das if (port->type == PORT_SCI && !dev->dev.of_node) {
3084dfc80387SLaurent Pinchart if (sci_port->reg_size >= 0x20)
3085dfc80387SLaurent Pinchart port->regshift = 2;
3086dfc80387SLaurent Pinchart else
3087dfc80387SLaurent Pinchart port->regshift = 1;
3088dfc80387SLaurent Pinchart }
3089dfc80387SLaurent Pinchart
30906b620478SPaul Mundt /*
309161a6976bSPaul Mundt * The UART port needs an IRQ value, so we peg this to the RX IRQ
30926b620478SPaul Mundt * for the multi-IRQ ports, which is where we are primarily
30936b620478SPaul Mundt * concerned with the shutdown path synchronization.
30946b620478SPaul Mundt *
30956b620478SPaul Mundt * For the muxed case there's nothing more to do.
30966b620478SPaul Mundt */
30971fcc91a6SLaurent Pinchart port->irq = sci_port->irqs[SCIx_RXI_IRQ];
30989cfb5c05SYong Zhang port->irqflags = 0;
3099ab4382d2SGreg Kroah-Hartman
3100ab4382d2SGreg Kroah-Hartman return 0;
3101ab4382d2SGreg Kroah-Hartman }
3102ab4382d2SGreg Kroah-Hartman
31030b0cced1SYoshinori Sato #if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) || \
31040b0cced1SYoshinori Sato defined(CONFIG_SERIAL_SH_SCI_EARLYCON)
serial_console_putchar(struct uart_port * port,unsigned char ch)31053f8bab17SJiri Slaby static void serial_console_putchar(struct uart_port *port, unsigned char ch)
3106ab4382d2SGreg Kroah-Hartman {
3107ab4382d2SGreg Kroah-Hartman sci_poll_put_char(port, ch);
3108ab4382d2SGreg Kroah-Hartman }
3109ab4382d2SGreg Kroah-Hartman
3110ab4382d2SGreg Kroah-Hartman /*
3111ab4382d2SGreg Kroah-Hartman * Print a string to the serial port trying not to disturb
3112ab4382d2SGreg Kroah-Hartman * any possible real use of the port...
3113ab4382d2SGreg Kroah-Hartman */
serial_console_write(struct console * co,const char * s,unsigned count)3114ab4382d2SGreg Kroah-Hartman static void serial_console_write(struct console *co, const char *s,
3115ab4382d2SGreg Kroah-Hartman unsigned count)
3116ab4382d2SGreg Kroah-Hartman {
31176b620478SPaul Mundt struct sci_port *sci_port = &sci_ports[co->index];
31186b620478SPaul Mundt struct uart_port *port = &sci_port->port;
3119a67969b5SGeert Uytterhoeven unsigned short bits, ctrl, ctrl_temp;
312040f70c03SShinya Kuribayashi unsigned long flags;
312140f70c03SShinya Kuribayashi int locked = 1;
312240f70c03SShinya Kuribayashi
312340f70c03SShinya Kuribayashi if (port->sysrq)
312440f70c03SShinya Kuribayashi locked = 0;
3125dc9a3254SDmitry Safonov else if (oops_in_progress)
312694c53770SThomas Gleixner locked = uart_port_trylock_irqsave(port, &flags);
312740f70c03SShinya Kuribayashi else
312894c53770SThomas Gleixner uart_port_lock_irqsave(port, &flags);
312940f70c03SShinya Kuribayashi
3130a67969b5SGeert Uytterhoeven /* first save SCSCR then disable interrupts, keep clock source */
31316deab514SGeert Uytterhoeven ctrl = sci_serial_in(port, SCSCR);
31329f8325b3SLaurent Pinchart ctrl_temp = SCSCR_RE | SCSCR_TE |
31339f8325b3SLaurent Pinchart (sci_port->cfg->scscr & ~(SCSCR_CKE1 | SCSCR_CKE0)) |
3134a67969b5SGeert Uytterhoeven (ctrl & (SCSCR_CKE1 | SCSCR_CKE0));
31356deab514SGeert Uytterhoeven sci_serial_out(port, SCSCR, ctrl_temp | sci_port->hscif_tot);
3136ab4382d2SGreg Kroah-Hartman
3137ab4382d2SGreg Kroah-Hartman uart_console_write(port, s, count, serial_console_putchar);
3138ab4382d2SGreg Kroah-Hartman
3139ab4382d2SGreg Kroah-Hartman /* wait until fifo is empty and last bit has been transmitted */
3140ab4382d2SGreg Kroah-Hartman bits = SCxSR_TDxE(port) | SCxSR_TEND(port);
31416deab514SGeert Uytterhoeven while ((sci_serial_in(port, SCxSR) & bits) != bits)
3142ab4382d2SGreg Kroah-Hartman cpu_relax();
314340f70c03SShinya Kuribayashi
314440f70c03SShinya Kuribayashi /* restore the SCSCR */
31456deab514SGeert Uytterhoeven sci_serial_out(port, SCSCR, ctrl);
314640f70c03SShinya Kuribayashi
314740f70c03SShinya Kuribayashi if (locked)
314894c53770SThomas Gleixner uart_port_unlock_irqrestore(port, flags);
3149ab4382d2SGreg Kroah-Hartman }
3150ab4382d2SGreg Kroah-Hartman
serial_console_setup(struct console * co,char * options)31519671f099SBill Pemberton static int serial_console_setup(struct console *co, char *options)
3152ab4382d2SGreg Kroah-Hartman {
3153ab4382d2SGreg Kroah-Hartman struct sci_port *sci_port;
3154ab4382d2SGreg Kroah-Hartman struct uart_port *port;
3155ab4382d2SGreg Kroah-Hartman int baud = 115200;
3156ab4382d2SGreg Kroah-Hartman int bits = 8;
3157ab4382d2SGreg Kroah-Hartman int parity = 'n';
3158ab4382d2SGreg Kroah-Hartman int flow = 'n';
3159ab4382d2SGreg Kroah-Hartman int ret;
3160ab4382d2SGreg Kroah-Hartman
3161ab4382d2SGreg Kroah-Hartman /*
31626b620478SPaul Mundt * Refuse to handle any bogus ports.
3163ab4382d2SGreg Kroah-Hartman */
31646b620478SPaul Mundt if (co->index < 0 || co->index >= SCI_NPORTS)
3165ab4382d2SGreg Kroah-Hartman return -ENODEV;
3166ab4382d2SGreg Kroah-Hartman
31676b620478SPaul Mundt sci_port = &sci_ports[co->index];
31686b620478SPaul Mundt port = &sci_port->port;
31696b620478SPaul Mundt
3170b2267a6bSAlexandre Courbot /*
3171b2267a6bSAlexandre Courbot * Refuse to handle uninitialized ports.
3172b2267a6bSAlexandre Courbot */
3173b2267a6bSAlexandre Courbot if (!port->ops)
3174b2267a6bSAlexandre Courbot return -ENODEV;
3175b2267a6bSAlexandre Courbot
31766b620478SPaul Mundt ret = sci_remap_port(port);
31776b620478SPaul Mundt if (unlikely(ret != 0))
31786b620478SPaul Mundt return ret;
3179ab4382d2SGreg Kroah-Hartman
3180ab4382d2SGreg Kroah-Hartman if (options)
3181ab4382d2SGreg Kroah-Hartman uart_parse_options(options, &baud, &parity, &bits, &flow);
3182ab4382d2SGreg Kroah-Hartman
3183ab7cfb55SPaul Mundt return uart_set_options(port, co, baud, parity, bits, flow);
3184ab4382d2SGreg Kroah-Hartman }
3185ab4382d2SGreg Kroah-Hartman
3186ab4382d2SGreg Kroah-Hartman static struct console serial_console = {
3187ab4382d2SGreg Kroah-Hartman .name = "ttySC",
31886b620478SPaul Mundt .device = uart_console_device,
3189ab4382d2SGreg Kroah-Hartman .write = serial_console_write,
3190ab4382d2SGreg Kroah-Hartman .setup = serial_console_setup,
3191ab4382d2SGreg Kroah-Hartman .flags = CON_PRINTBUFFER,
3192ab4382d2SGreg Kroah-Hartman .index = -1,
31936b620478SPaul Mundt .data = &sci_uart_driver,
3194ab4382d2SGreg Kroah-Hartman };
3195ab4382d2SGreg Kroah-Hartman
3196507fd01dSBartosz Golaszewski #ifdef CONFIG_SUPERH
3197ff707dfdSJohn Ogness static char early_serial_buf[32];
3198ff707dfdSJohn Ogness
early_serial_console_setup(struct console * co,char * options)3199ff707dfdSJohn Ogness static int early_serial_console_setup(struct console *co, char *options)
3200ff707dfdSJohn Ogness {
3201ff707dfdSJohn Ogness /*
3202ff707dfdSJohn Ogness * This early console is always registered using the earlyprintk=
3203ff707dfdSJohn Ogness * parameter, which does not call add_preferred_console(). Thus
3204ff707dfdSJohn Ogness * @options is always NULL and the options for this early console
3205ff707dfdSJohn Ogness * are passed using a custom buffer.
3206ff707dfdSJohn Ogness */
3207ff707dfdSJohn Ogness WARN_ON(options);
3208ff707dfdSJohn Ogness
3209ff707dfdSJohn Ogness return serial_console_setup(co, early_serial_buf);
3210ff707dfdSJohn Ogness }
3211ff707dfdSJohn Ogness
3212ab4382d2SGreg Kroah-Hartman static struct console early_serial_console = {
3213ab4382d2SGreg Kroah-Hartman .name = "early_ttySC",
3214ab4382d2SGreg Kroah-Hartman .write = serial_console_write,
3215ff707dfdSJohn Ogness .setup = early_serial_console_setup,
3216ab4382d2SGreg Kroah-Hartman .flags = CON_PRINTBUFFER,
32176b620478SPaul Mundt .index = -1,
3218ab4382d2SGreg Kroah-Hartman };
32196b620478SPaul Mundt
sci_probe_earlyprintk(struct platform_device * pdev)32209671f099SBill Pemberton static int sci_probe_earlyprintk(struct platform_device *pdev)
32216b620478SPaul Mundt {
3222daf5a895SLaurent Pinchart const struct plat_sci_port *cfg = dev_get_platdata(&pdev->dev);
32236b620478SPaul Mundt
32246b620478SPaul Mundt if (early_serial_console.data)
32256b620478SPaul Mundt return -EEXIST;
32266b620478SPaul Mundt
32276b620478SPaul Mundt early_serial_console.index = pdev->id;
32286b620478SPaul Mundt
32291fcc91a6SLaurent Pinchart sci_init_single(pdev, &sci_ports[pdev->id], pdev->id, cfg, true);
32306b620478SPaul Mundt
32316b620478SPaul Mundt if (!strstr(early_serial_buf, "keep"))
32326b620478SPaul Mundt early_serial_console.flags |= CON_BOOT;
32336b620478SPaul Mundt
32346b620478SPaul Mundt register_console(&early_serial_console);
32356b620478SPaul Mundt return 0;
32366b620478SPaul Mundt }
3237507fd01dSBartosz Golaszewski #endif
32386a8c9799SNobuhiro Iwamatsu
32396a8c9799SNobuhiro Iwamatsu #define SCI_CONSOLE (&serial_console)
32406a8c9799SNobuhiro Iwamatsu
32416b620478SPaul Mundt #else
sci_probe_earlyprintk(struct platform_device * pdev)32429671f099SBill Pemberton static inline int sci_probe_earlyprintk(struct platform_device *pdev)
32436b620478SPaul Mundt {
32446b620478SPaul Mundt return -EINVAL;
32456b620478SPaul Mundt }
3246ab4382d2SGreg Kroah-Hartman
32476a8c9799SNobuhiro Iwamatsu #define SCI_CONSOLE NULL
32486a8c9799SNobuhiro Iwamatsu
32490b0cced1SYoshinori Sato #endif /* CONFIG_SERIAL_SH_SCI_CONSOLE || CONFIG_SERIAL_SH_SCI_EARLYCON */
3250ab4382d2SGreg Kroah-Hartman
32516c13d5d2SGeert Uytterhoeven static const char banner[] __initconst = "SuperH (H)SCI(F) driver initialized";
3252ab4382d2SGreg Kroah-Hartman
3253352b9266SSjoerd Simons static DEFINE_MUTEX(sci_uart_registration_lock);
3254ab4382d2SGreg Kroah-Hartman static struct uart_driver sci_uart_driver = {
3255ab4382d2SGreg Kroah-Hartman .owner = THIS_MODULE,
3256ab4382d2SGreg Kroah-Hartman .driver_name = "sci",
3257ab4382d2SGreg Kroah-Hartman .dev_name = "ttySC",
3258ab4382d2SGreg Kroah-Hartman .major = SCI_MAJOR,
3259ab4382d2SGreg Kroah-Hartman .minor = SCI_MINOR_START,
3260ab4382d2SGreg Kroah-Hartman .nr = SCI_NPORTS,
3261ab4382d2SGreg Kroah-Hartman .cons = SCI_CONSOLE,
3262ab4382d2SGreg Kroah-Hartman };
3263ab4382d2SGreg Kroah-Hartman
sci_remove(struct platform_device * dev)32645fc247bfSUwe Kleine-König static void sci_remove(struct platform_device *dev)
3265ab4382d2SGreg Kroah-Hartman {
32666b620478SPaul Mundt struct sci_port *port = platform_get_drvdata(dev);
3267641a41dbSYoshihiro Shimoda unsigned int type = port->port.type; /* uart_remove_... clears it */
3268ab4382d2SGreg Kroah-Hartman
32697678f4c2SGeert Uytterhoeven sci_ports_in_use &= ~BIT(port->port.line);
32706b620478SPaul Mundt uart_remove_one_port(&sci_uart_driver, &port->port);
3271ab4382d2SGreg Kroah-Hartman
32726aa57f16SGreg Kroah-Hartman if (port->port.fifosize > 1)
32736aa57f16SGreg Kroah-Hartman device_remove_file(&dev->dev, &dev_attr_rx_fifo_trigger);
32746aa57f16SGreg Kroah-Hartman if (type == PORT_SCIFA || type == PORT_SCIFB || type == PORT_HSCIF)
32756aa57f16SGreg Kroah-Hartman device_remove_file(&dev->dev, &dev_attr_rx_fifo_timeout);
3276ab4382d2SGreg Kroah-Hartman }
3277ab4382d2SGreg Kroah-Hartman
3278bd2238fbSGeert Uytterhoeven
3279bd2238fbSGeert Uytterhoeven #define SCI_OF_DATA(type, regtype) (void *)((type) << 16 | (regtype))
3280bd2238fbSGeert Uytterhoeven #define SCI_OF_TYPE(data) ((unsigned long)(data) >> 16)
3281bd2238fbSGeert Uytterhoeven #define SCI_OF_REGTYPE(data) ((unsigned long)(data) & 0xffff)
328220bdcab8SBastian Hecht
328388dcd07dSKrzysztof Kozlowski static const struct of_device_id of_sci_match[] __maybe_unused = {
3284f443ff80SGeert Uytterhoeven /* SoC-specific types */
3285f443ff80SGeert Uytterhoeven {
3286f443ff80SGeert Uytterhoeven .compatible = "renesas,scif-r7s72100",
3287f443ff80SGeert Uytterhoeven .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH2_SCIF_FIFODATA_REGTYPE),
3288f443ff80SGeert Uytterhoeven },
328910c63443SGeert Uytterhoeven {
329010c63443SGeert Uytterhoeven .compatible = "renesas,scif-r7s9210",
329110c63443SGeert Uytterhoeven .data = SCI_OF_DATA(PORT_SCIF, SCIx_RZ_SCIFA_REGTYPE),
329210c63443SGeert Uytterhoeven },
32933b2cd606SBiju Das {
32943b2cd606SBiju Das .compatible = "renesas,scif-r9a07g044",
32953b2cd606SBiju Das .data = SCI_OF_DATA(PORT_SCIF, SCIx_RZ_SCIFA_REGTYPE),
32963b2cd606SBiju Das },
32972f50304eSLad Prabhakar {
32982f50304eSLad Prabhakar .compatible = "renesas,scif-r9a09g057",
32992f50304eSLad Prabhakar .data = SCI_OF_DATA(PORT_SCIF, SCIx_RZV2H_SCIF_REGTYPE),
33002f50304eSLad Prabhakar },
33019ed44bb2SGeert Uytterhoeven /* Family-specific types */
33029ed44bb2SGeert Uytterhoeven {
33039ed44bb2SGeert Uytterhoeven .compatible = "renesas,rcar-gen1-scif",
33049ed44bb2SGeert Uytterhoeven .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_BRG_REGTYPE),
33059ed44bb2SGeert Uytterhoeven }, {
33069ed44bb2SGeert Uytterhoeven .compatible = "renesas,rcar-gen2-scif",
33079ed44bb2SGeert Uytterhoeven .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_BRG_REGTYPE),
33089ed44bb2SGeert Uytterhoeven }, {
33099ed44bb2SGeert Uytterhoeven .compatible = "renesas,rcar-gen3-scif",
33109ed44bb2SGeert Uytterhoeven .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_BRG_REGTYPE),
331126baf4b6SYoshihiro Shimoda }, {
331226baf4b6SYoshihiro Shimoda .compatible = "renesas,rcar-gen4-scif",
331326baf4b6SYoshihiro Shimoda .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_BRG_REGTYPE),
33149ed44bb2SGeert Uytterhoeven },
3315f443ff80SGeert Uytterhoeven /* Generic types */
331620bdcab8SBastian Hecht {
331720bdcab8SBastian Hecht .compatible = "renesas,scif",
3318bd2238fbSGeert Uytterhoeven .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_REGTYPE),
331920bdcab8SBastian Hecht }, {
332020bdcab8SBastian Hecht .compatible = "renesas,scifa",
3321bd2238fbSGeert Uytterhoeven .data = SCI_OF_DATA(PORT_SCIFA, SCIx_SCIFA_REGTYPE),
332220bdcab8SBastian Hecht }, {
332320bdcab8SBastian Hecht .compatible = "renesas,scifb",
3324bd2238fbSGeert Uytterhoeven .data = SCI_OF_DATA(PORT_SCIFB, SCIx_SCIFB_REGTYPE),
332520bdcab8SBastian Hecht }, {
332620bdcab8SBastian Hecht .compatible = "renesas,hscif",
3327bd2238fbSGeert Uytterhoeven .data = SCI_OF_DATA(PORT_HSCIF, SCIx_HSCIF_REGTYPE),
332820bdcab8SBastian Hecht }, {
3329e1d0be61SYoshinori Sato .compatible = "renesas,sci",
3330bd2238fbSGeert Uytterhoeven .data = SCI_OF_DATA(PORT_SCI, SCIx_SCI_REGTYPE),
3331e1d0be61SYoshinori Sato }, {
333220bdcab8SBastian Hecht /* Terminator */
333320bdcab8SBastian Hecht },
333420bdcab8SBastian Hecht };
333520bdcab8SBastian Hecht MODULE_DEVICE_TABLE(of, of_sci_match);
333620bdcab8SBastian Hecht
sci_reset_control_assert(void * data)3337862f7218SLad Prabhakar static void sci_reset_control_assert(void *data)
3338862f7218SLad Prabhakar {
3339862f7218SLad Prabhakar reset_control_assert(data);
3340862f7218SLad Prabhakar }
3341862f7218SLad Prabhakar
sci_parse_dt(struct platform_device * pdev,unsigned int * dev_id)334254b12c48SGeert Uytterhoeven static struct plat_sci_port *sci_parse_dt(struct platform_device *pdev,
334354b12c48SGeert Uytterhoeven unsigned int *dev_id)
334420bdcab8SBastian Hecht {
334520bdcab8SBastian Hecht struct device_node *np = pdev->dev.of_node;
3346862f7218SLad Prabhakar struct reset_control *rstc;
334720bdcab8SBastian Hecht struct plat_sci_port *p;
334897ed9790SLaurent Pinchart struct sci_port *sp;
33496e605a01SGeert Uytterhoeven const void *data;
3350862f7218SLad Prabhakar int id, ret;
335120bdcab8SBastian Hecht
335220bdcab8SBastian Hecht if (!IS_ENABLED(CONFIG_OF) || !np)
3353862f7218SLad Prabhakar return ERR_PTR(-EINVAL);
335420bdcab8SBastian Hecht
33556e605a01SGeert Uytterhoeven data = of_device_get_match_data(&pdev->dev);
335620bdcab8SBastian Hecht
3357862f7218SLad Prabhakar rstc = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL);
3358862f7218SLad Prabhakar if (IS_ERR(rstc))
3359862f7218SLad Prabhakar return ERR_PTR(dev_err_probe(&pdev->dev, PTR_ERR(rstc),
3360862f7218SLad Prabhakar "failed to get reset ctrl\n"));
3361862f7218SLad Prabhakar
3362862f7218SLad Prabhakar ret = reset_control_deassert(rstc);
3363862f7218SLad Prabhakar if (ret) {
3364862f7218SLad Prabhakar dev_err(&pdev->dev, "failed to deassert reset %d\n", ret);
3365862f7218SLad Prabhakar return ERR_PTR(ret);
3366862f7218SLad Prabhakar }
3367862f7218SLad Prabhakar
3368862f7218SLad Prabhakar ret = devm_add_action_or_reset(&pdev->dev, sci_reset_control_assert, rstc);
3369862f7218SLad Prabhakar if (ret) {
3370862f7218SLad Prabhakar dev_err(&pdev->dev, "failed to register assert devm action, %d\n",
3371862f7218SLad Prabhakar ret);
3372862f7218SLad Prabhakar return ERR_PTR(ret);
3373862f7218SLad Prabhakar }
3374862f7218SLad Prabhakar
337520bdcab8SBastian Hecht p = devm_kzalloc(&pdev->dev, sizeof(struct plat_sci_port), GFP_KERNEL);
33764205463cSGeert Uytterhoeven if (!p)
3377862f7218SLad Prabhakar return ERR_PTR(-ENOMEM);
337820bdcab8SBastian Hecht
33792095fc76SGeert Uytterhoeven /* Get the line number from the aliases node. */
338020bdcab8SBastian Hecht id = of_alias_get_id(np, "serial");
33817678f4c2SGeert Uytterhoeven if (id < 0 && ~sci_ports_in_use)
33827678f4c2SGeert Uytterhoeven id = ffz(sci_ports_in_use);
338320bdcab8SBastian Hecht if (id < 0) {
338420bdcab8SBastian Hecht dev_err(&pdev->dev, "failed to get alias id (%d)\n", id);
3385862f7218SLad Prabhakar return ERR_PTR(-EINVAL);
338620bdcab8SBastian Hecht }
3387090fa4b0SGeert Uytterhoeven if (id >= ARRAY_SIZE(sci_ports)) {
3388090fa4b0SGeert Uytterhoeven dev_err(&pdev->dev, "serial%d out of range\n", id);
3389862f7218SLad Prabhakar return ERR_PTR(-EINVAL);
3390090fa4b0SGeert Uytterhoeven }
339120bdcab8SBastian Hecht
339297ed9790SLaurent Pinchart sp = &sci_ports[id];
339322a6984cSClaudiu Beznea sp->rstc = rstc;
339420bdcab8SBastian Hecht *dev_id = id;
339520bdcab8SBastian Hecht
33966e605a01SGeert Uytterhoeven p->type = SCI_OF_TYPE(data);
33976e605a01SGeert Uytterhoeven p->regtype = SCI_OF_REGTYPE(data);
339820bdcab8SBastian Hecht
339943c61286SSergei Shtylyov sp->has_rtscts = of_property_read_bool(np, "uart-has-rtscts");
3400861a70abSGeert Uytterhoeven
340120bdcab8SBastian Hecht return p;
340220bdcab8SBastian Hecht }
340320bdcab8SBastian Hecht
sci_probe_single(struct platform_device * dev,unsigned int index,struct plat_sci_port * p,struct sci_port * sciport,struct resource * sci_res)34049671f099SBill Pemberton static int sci_probe_single(struct platform_device *dev,
3405ab4382d2SGreg Kroah-Hartman unsigned int index,
3406ab4382d2SGreg Kroah-Hartman struct plat_sci_port *p,
34075f101706SClaudiu Beznea struct sci_port *sciport,
34085f101706SClaudiu Beznea struct resource *sci_res)
3409ab4382d2SGreg Kroah-Hartman {
3410ab4382d2SGreg Kroah-Hartman int ret;
3411ab4382d2SGreg Kroah-Hartman
3412ab4382d2SGreg Kroah-Hartman /* Sanity check */
3413ab4382d2SGreg Kroah-Hartman if (unlikely(index >= SCI_NPORTS)) {
34149b971cd2SJoe Perches dev_notice(&dev->dev, "Attempting to register port %d when only %d are available\n",
3415ab4382d2SGreg Kroah-Hartman index+1, SCI_NPORTS);
34169b971cd2SJoe Perches dev_notice(&dev->dev, "Consider bumping CONFIG_SERIAL_SH_SCI_NR_UARTS!\n");
3417b6c5ef6fSLaurent Pinchart return -EINVAL;
3418ab4382d2SGreg Kroah-Hartman }
34197678f4c2SGeert Uytterhoeven BUILD_BUG_ON(SCI_NPORTS > sizeof(sci_ports_in_use) * 8);
34207678f4c2SGeert Uytterhoeven if (sci_ports_in_use & BIT(index))
34217678f4c2SGeert Uytterhoeven return -EBUSY;
3422ab4382d2SGreg Kroah-Hartman
3423352b9266SSjoerd Simons mutex_lock(&sci_uart_registration_lock);
3424352b9266SSjoerd Simons if (!sci_uart_driver.state) {
3425352b9266SSjoerd Simons ret = uart_register_driver(&sci_uart_driver);
3426352b9266SSjoerd Simons if (ret) {
3427352b9266SSjoerd Simons mutex_unlock(&sci_uart_registration_lock);
3428352b9266SSjoerd Simons return ret;
3429352b9266SSjoerd Simons }
3430352b9266SSjoerd Simons }
3431352b9266SSjoerd Simons mutex_unlock(&sci_uart_registration_lock);
3432352b9266SSjoerd Simons
34331fcc91a6SLaurent Pinchart ret = sci_init_single(dev, sciport, index, p, false);
3434ab4382d2SGreg Kroah-Hartman if (ret)
3435ab4382d2SGreg Kroah-Hartman return ret;
3436ab4382d2SGreg Kroah-Hartman
3437239f1120SClaudiu Beznea sciport->port.dev = &dev->dev;
3438239f1120SClaudiu Beznea ret = devm_pm_runtime_enable(&dev->dev);
3439239f1120SClaudiu Beznea if (ret)
3440239f1120SClaudiu Beznea return ret;
3441239f1120SClaudiu Beznea
3442f907c9eaSGeert Uytterhoeven sciport->gpios = mctrl_gpio_init(&sciport->port, 0);
3443e55a0973SFrieder Schrempf if (IS_ERR(sciport->gpios))
3444f907c9eaSGeert Uytterhoeven return PTR_ERR(sciport->gpios);
3445f907c9eaSGeert Uytterhoeven
344697ed9790SLaurent Pinchart if (sciport->has_rtscts) {
3447a16c4c5aSGeert Uytterhoeven if (mctrl_gpio_to_gpiod(sciport->gpios, UART_GPIO_CTS) ||
3448a16c4c5aSGeert Uytterhoeven mctrl_gpio_to_gpiod(sciport->gpios, UART_GPIO_RTS)) {
3449f907c9eaSGeert Uytterhoeven dev_err(&dev->dev, "Conflicting RTS/CTS config\n");
3450f907c9eaSGeert Uytterhoeven return -EINVAL;
3451f907c9eaSGeert Uytterhoeven }
345233f50ffcSGeert Uytterhoeven sciport->port.flags |= UPF_HARD_FLOW;
3453f907c9eaSGeert Uytterhoeven }
3454f907c9eaSGeert Uytterhoeven
34555f101706SClaudiu Beznea if (sci_uart_earlycon && sci_ports[0].port.mapbase == sci_res->start) {
34565f101706SClaudiu Beznea /*
3457651dee03SClaudiu Beznea * In case:
3458651dee03SClaudiu Beznea * - this is the earlycon port (mapped on index 0 in sci_ports[]) and
3459651dee03SClaudiu Beznea * - it now maps to an alias other than zero and
3460651dee03SClaudiu Beznea * - the earlycon is still alive (e.g., "earlycon keep_bootcon" is
3461651dee03SClaudiu Beznea * available in bootargs)
3462651dee03SClaudiu Beznea *
3463651dee03SClaudiu Beznea * we need to avoid disabling clocks and PM domains through the runtime
3464651dee03SClaudiu Beznea * PM APIs called in __device_attach(). For this, increment the runtime
3465651dee03SClaudiu Beznea * PM reference counter (the clocks and PM domains were already enabled
3466651dee03SClaudiu Beznea * by the bootloader). Otherwise the earlycon may access the HW when it
3467651dee03SClaudiu Beznea * has no clocks enabled leading to failures (infinite loop in
3468651dee03SClaudiu Beznea * sci_poll_put_char()).
3469651dee03SClaudiu Beznea */
3470651dee03SClaudiu Beznea pm_runtime_get_noresume(&dev->dev);
3471651dee03SClaudiu Beznea
3472651dee03SClaudiu Beznea /*
34735f101706SClaudiu Beznea * Skip cleanup the sci_port[0] in early_console_exit(), this
34745f101706SClaudiu Beznea * port is the same as the earlycon one.
34755f101706SClaudiu Beznea */
34765f101706SClaudiu Beznea sci_uart_earlycon_dev_probing = true;
34775f101706SClaudiu Beznea }
34785f101706SClaudiu Beznea
3479239f1120SClaudiu Beznea return uart_add_one_port(&sci_uart_driver, &sciport->port);
3480ab4382d2SGreg Kroah-Hartman }
3481ab4382d2SGreg Kroah-Hartman
sci_probe(struct platform_device * dev)34829671f099SBill Pemberton static int sci_probe(struct platform_device *dev)
3483ab4382d2SGreg Kroah-Hartman {
348420bdcab8SBastian Hecht struct plat_sci_port *p;
34859f7dea87SClaudiu Beznea struct resource *res;
348620bdcab8SBastian Hecht struct sci_port *sp;
348720bdcab8SBastian Hecht unsigned int dev_id;
34886b620478SPaul Mundt int ret;
3489ab4382d2SGreg Kroah-Hartman
34906b620478SPaul Mundt /*
34916b620478SPaul Mundt * If we've come here via earlyprintk initialization, head off to
34926b620478SPaul Mundt * the special early probe. We don't have sufficient device state
34936b620478SPaul Mundt * to make it beyond this yet.
34946b620478SPaul Mundt */
3495507fd01dSBartosz Golaszewski #ifdef CONFIG_SUPERH
3496201e9109SBartosz Golaszewski if (is_sh_early_platform_device(dev))
34976b620478SPaul Mundt return sci_probe_earlyprintk(dev);
3498507fd01dSBartosz Golaszewski #endif
3499ab4382d2SGreg Kroah-Hartman
350020bdcab8SBastian Hecht if (dev->dev.of_node) {
350120bdcab8SBastian Hecht p = sci_parse_dt(dev, &dev_id);
3502862f7218SLad Prabhakar if (IS_ERR(p))
3503862f7218SLad Prabhakar return PTR_ERR(p);
350420bdcab8SBastian Hecht } else {
350520bdcab8SBastian Hecht p = dev->dev.platform_data;
350620bdcab8SBastian Hecht if (p == NULL) {
350720bdcab8SBastian Hecht dev_err(&dev->dev, "no platform data supplied\n");
350820bdcab8SBastian Hecht return -EINVAL;
350920bdcab8SBastian Hecht }
351020bdcab8SBastian Hecht
351120bdcab8SBastian Hecht dev_id = dev->id;
351220bdcab8SBastian Hecht }
351320bdcab8SBastian Hecht
351420bdcab8SBastian Hecht sp = &sci_ports[dev_id];
35159f7dea87SClaudiu Beznea
35169f7dea87SClaudiu Beznea /*
35179f7dea87SClaudiu Beznea * In case:
35189f7dea87SClaudiu Beznea * - the probed port alias is zero (as the one used by earlycon), and
35199f7dea87SClaudiu Beznea * - the earlycon is still active (e.g., "earlycon keep_bootcon" in
35209f7dea87SClaudiu Beznea * bootargs)
35219f7dea87SClaudiu Beznea *
35229f7dea87SClaudiu Beznea * defer the probe of this serial. This is a debug scenario and the user
35239f7dea87SClaudiu Beznea * must be aware of it.
35249f7dea87SClaudiu Beznea *
35259f7dea87SClaudiu Beznea * Except when the probed port is the same as the earlycon port.
35269f7dea87SClaudiu Beznea */
35279f7dea87SClaudiu Beznea
35289f7dea87SClaudiu Beznea res = platform_get_resource(dev, IORESOURCE_MEM, 0);
35299f7dea87SClaudiu Beznea if (!res)
35309f7dea87SClaudiu Beznea return -ENODEV;
35319f7dea87SClaudiu Beznea
35329f7dea87SClaudiu Beznea if (sci_uart_earlycon && sp == &sci_ports[0] && sp->port.mapbase != res->start)
35339f7dea87SClaudiu Beznea return dev_err_probe(&dev->dev, -EBUSY, "sci_port[0] is used by earlycon!\n");
35349f7dea87SClaudiu Beznea
35356b620478SPaul Mundt platform_set_drvdata(dev, sp);
3536ab4382d2SGreg Kroah-Hartman
35375f101706SClaudiu Beznea ret = sci_probe_single(dev, dev_id, p, sp, res);
3538ab4382d2SGreg Kroah-Hartman if (ret)
35396dae1421SLaurent Pinchart return ret;
35406b620478SPaul Mundt
35415d23188aSUlrich Hecht if (sp->port.fifosize > 1) {
35426aa57f16SGreg Kroah-Hartman ret = device_create_file(&dev->dev, &dev_attr_rx_fifo_trigger);
35435d23188aSUlrich Hecht if (ret)
35445d23188aSUlrich Hecht return ret;
35455d23188aSUlrich Hecht }
3546fa2abb03SUlrich Hecht if (sp->port.type == PORT_SCIFA || sp->port.type == PORT_SCIFB ||
3547fa2abb03SUlrich Hecht sp->port.type == PORT_HSCIF) {
35486aa57f16SGreg Kroah-Hartman ret = device_create_file(&dev->dev, &dev_attr_rx_fifo_timeout);
35495d23188aSUlrich Hecht if (ret) {
35505d23188aSUlrich Hecht if (sp->port.fifosize > 1) {
35516aa57f16SGreg Kroah-Hartman device_remove_file(&dev->dev,
35526aa57f16SGreg Kroah-Hartman &dev_attr_rx_fifo_trigger);
35535d23188aSUlrich Hecht }
35545d23188aSUlrich Hecht return ret;
35555d23188aSUlrich Hecht }
35565d23188aSUlrich Hecht }
35575d23188aSUlrich Hecht
3558ab4382d2SGreg Kroah-Hartman #ifdef CONFIG_SH_STANDARD_BIOS
3559ab4382d2SGreg Kroah-Hartman sh_bios_gdb_detach();
3560ab4382d2SGreg Kroah-Hartman #endif
3561ab4382d2SGreg Kroah-Hartman
35627678f4c2SGeert Uytterhoeven sci_ports_in_use |= BIT(dev_id);
3563ab4382d2SGreg Kroah-Hartman return 0;
3564ab4382d2SGreg Kroah-Hartman }
3565ab4382d2SGreg Kroah-Hartman
sci_console_save(struct sci_port * s)356622a6984cSClaudiu Beznea static void sci_console_save(struct sci_port *s)
356722a6984cSClaudiu Beznea {
356822a6984cSClaudiu Beznea struct sci_suspend_regs *regs = &s->suspend_regs;
356922a6984cSClaudiu Beznea struct uart_port *port = &s->port;
357022a6984cSClaudiu Beznea
357181100b9aSGeert Uytterhoeven if (sci_getreg(port, SCDL)->size)
357281100b9aSGeert Uytterhoeven regs->scdl = sci_serial_in(port, SCDL);
357381100b9aSGeert Uytterhoeven if (sci_getreg(port, SCCKS)->size)
357481100b9aSGeert Uytterhoeven regs->sccks = sci_serial_in(port, SCCKS);
357522a6984cSClaudiu Beznea if (sci_getreg(port, SCSMR)->size)
357622a6984cSClaudiu Beznea regs->scsmr = sci_serial_in(port, SCSMR);
357722a6984cSClaudiu Beznea if (sci_getreg(port, SCSCR)->size)
357822a6984cSClaudiu Beznea regs->scscr = sci_serial_in(port, SCSCR);
357922a6984cSClaudiu Beznea if (sci_getreg(port, SCFCR)->size)
358022a6984cSClaudiu Beznea regs->scfcr = sci_serial_in(port, SCFCR);
358122a6984cSClaudiu Beznea if (sci_getreg(port, SCSPTR)->size)
358222a6984cSClaudiu Beznea regs->scsptr = sci_serial_in(port, SCSPTR);
358322a6984cSClaudiu Beznea if (sci_getreg(port, SCBRR)->size)
358422a6984cSClaudiu Beznea regs->scbrr = sci_serial_in(port, SCBRR);
358581100b9aSGeert Uytterhoeven if (sci_getreg(port, HSSRR)->size)
358681100b9aSGeert Uytterhoeven regs->hssrr = sci_serial_in(port, HSSRR);
358781100b9aSGeert Uytterhoeven if (sci_getreg(port, SCPCR)->size)
358881100b9aSGeert Uytterhoeven regs->scpcr = sci_serial_in(port, SCPCR);
358981100b9aSGeert Uytterhoeven if (sci_getreg(port, SCPDR)->size)
359081100b9aSGeert Uytterhoeven regs->scpdr = sci_serial_in(port, SCPDR);
359122a6984cSClaudiu Beznea if (sci_getreg(port, SEMR)->size)
359222a6984cSClaudiu Beznea regs->semr = sci_serial_in(port, SEMR);
359322a6984cSClaudiu Beznea }
359422a6984cSClaudiu Beznea
sci_console_restore(struct sci_port * s)359522a6984cSClaudiu Beznea static void sci_console_restore(struct sci_port *s)
359622a6984cSClaudiu Beznea {
359722a6984cSClaudiu Beznea struct sci_suspend_regs *regs = &s->suspend_regs;
359822a6984cSClaudiu Beznea struct uart_port *port = &s->port;
359922a6984cSClaudiu Beznea
360081100b9aSGeert Uytterhoeven if (sci_getreg(port, SCDL)->size)
360181100b9aSGeert Uytterhoeven sci_serial_out(port, SCDL, regs->scdl);
360281100b9aSGeert Uytterhoeven if (sci_getreg(port, SCCKS)->size)
360381100b9aSGeert Uytterhoeven sci_serial_out(port, SCCKS, regs->sccks);
360422a6984cSClaudiu Beznea if (sci_getreg(port, SCSMR)->size)
360522a6984cSClaudiu Beznea sci_serial_out(port, SCSMR, regs->scsmr);
360622a6984cSClaudiu Beznea if (sci_getreg(port, SCSCR)->size)
360722a6984cSClaudiu Beznea sci_serial_out(port, SCSCR, regs->scscr);
360822a6984cSClaudiu Beznea if (sci_getreg(port, SCFCR)->size)
360922a6984cSClaudiu Beznea sci_serial_out(port, SCFCR, regs->scfcr);
361022a6984cSClaudiu Beznea if (sci_getreg(port, SCSPTR)->size)
361122a6984cSClaudiu Beznea sci_serial_out(port, SCSPTR, regs->scsptr);
361222a6984cSClaudiu Beznea if (sci_getreg(port, SCBRR)->size)
361322a6984cSClaudiu Beznea sci_serial_out(port, SCBRR, regs->scbrr);
361481100b9aSGeert Uytterhoeven if (sci_getreg(port, HSSRR)->size)
361581100b9aSGeert Uytterhoeven sci_serial_out(port, HSSRR, regs->hssrr);
361681100b9aSGeert Uytterhoeven if (sci_getreg(port, SCPCR)->size)
361781100b9aSGeert Uytterhoeven sci_serial_out(port, SCPCR, regs->scpcr);
361881100b9aSGeert Uytterhoeven if (sci_getreg(port, SCPDR)->size)
361981100b9aSGeert Uytterhoeven sci_serial_out(port, SCPDR, regs->scpdr);
362022a6984cSClaudiu Beznea if (sci_getreg(port, SEMR)->size)
362122a6984cSClaudiu Beznea sci_serial_out(port, SEMR, regs->semr);
362222a6984cSClaudiu Beznea }
362322a6984cSClaudiu Beznea
sci_suspend(struct device * dev)3624cb876341SSergei Shtylyov static __maybe_unused int sci_suspend(struct device *dev)
3625ab4382d2SGreg Kroah-Hartman {
36266b620478SPaul Mundt struct sci_port *sport = dev_get_drvdata(dev);
3627ab4382d2SGreg Kroah-Hartman
362822a6984cSClaudiu Beznea if (sport) {
36296b620478SPaul Mundt uart_suspend_port(&sci_uart_driver, &sport->port);
3630ab4382d2SGreg Kroah-Hartman
363122a6984cSClaudiu Beznea if (!console_suspend_enabled && uart_console(&sport->port))
363222a6984cSClaudiu Beznea sci_console_save(sport);
363322a6984cSClaudiu Beznea else
363422a6984cSClaudiu Beznea return reset_control_assert(sport->rstc);
363522a6984cSClaudiu Beznea }
363622a6984cSClaudiu Beznea
3637ab4382d2SGreg Kroah-Hartman return 0;
3638ab4382d2SGreg Kroah-Hartman }
3639ab4382d2SGreg Kroah-Hartman
sci_resume(struct device * dev)3640cb876341SSergei Shtylyov static __maybe_unused int sci_resume(struct device *dev)
3641ab4382d2SGreg Kroah-Hartman {
36426b620478SPaul Mundt struct sci_port *sport = dev_get_drvdata(dev);
3643ab4382d2SGreg Kroah-Hartman
364422a6984cSClaudiu Beznea if (sport) {
364522a6984cSClaudiu Beznea if (!console_suspend_enabled && uart_console(&sport->port)) {
364622a6984cSClaudiu Beznea sci_console_restore(sport);
364722a6984cSClaudiu Beznea } else {
364822a6984cSClaudiu Beznea int ret = reset_control_deassert(sport->rstc);
364922a6984cSClaudiu Beznea
365022a6984cSClaudiu Beznea if (ret)
365122a6984cSClaudiu Beznea return ret;
365222a6984cSClaudiu Beznea }
365322a6984cSClaudiu Beznea
36546b620478SPaul Mundt uart_resume_port(&sci_uart_driver, &sport->port);
365522a6984cSClaudiu Beznea }
3656ab4382d2SGreg Kroah-Hartman
3657ab4382d2SGreg Kroah-Hartman return 0;
3658ab4382d2SGreg Kroah-Hartman }
3659ab4382d2SGreg Kroah-Hartman
3660cb876341SSergei Shtylyov static SIMPLE_DEV_PM_OPS(sci_dev_pm_ops, sci_suspend, sci_resume);
3661ab4382d2SGreg Kroah-Hartman
3662ab4382d2SGreg Kroah-Hartman static struct platform_driver sci_driver = {
3663ab4382d2SGreg Kroah-Hartman .probe = sci_probe,
36645cbb9b17SUwe Kleine-König .remove = sci_remove,
3665ab4382d2SGreg Kroah-Hartman .driver = {
3666ab4382d2SGreg Kroah-Hartman .name = "sh-sci",
3667ab4382d2SGreg Kroah-Hartman .pm = &sci_dev_pm_ops,
366820bdcab8SBastian Hecht .of_match_table = of_match_ptr(of_sci_match),
3669ab4382d2SGreg Kroah-Hartman },
3670ab4382d2SGreg Kroah-Hartman };
3671ab4382d2SGreg Kroah-Hartman
sci_init(void)3672ab4382d2SGreg Kroah-Hartman static int __init sci_init(void)
3673ab4382d2SGreg Kroah-Hartman {
36746c13d5d2SGeert Uytterhoeven pr_info("%s\n", banner);
3675ab4382d2SGreg Kroah-Hartman
3676352b9266SSjoerd Simons return platform_driver_register(&sci_driver);
3677ab4382d2SGreg Kroah-Hartman }
3678ab4382d2SGreg Kroah-Hartman
sci_exit(void)3679ab4382d2SGreg Kroah-Hartman static void __exit sci_exit(void)
3680ab4382d2SGreg Kroah-Hartman {
3681ab4382d2SGreg Kroah-Hartman platform_driver_unregister(&sci_driver);
3682352b9266SSjoerd Simons
3683352b9266SSjoerd Simons if (sci_uart_driver.state)
3684ab4382d2SGreg Kroah-Hartman uart_unregister_driver(&sci_uart_driver);
3685ab4382d2SGreg Kroah-Hartman }
3686ab4382d2SGreg Kroah-Hartman
3687507fd01dSBartosz Golaszewski #if defined(CONFIG_SUPERH) && defined(CONFIG_SERIAL_SH_SCI_CONSOLE)
3688201e9109SBartosz Golaszewski sh_early_platform_init_buffer("earlyprintk", &sci_driver,
3689ab4382d2SGreg Kroah-Hartman early_serial_buf, ARRAY_SIZE(early_serial_buf));
3690ab4382d2SGreg Kroah-Hartman #endif
36910b0cced1SYoshinori Sato #ifdef CONFIG_SERIAL_SH_SCI_EARLYCON
3692eaeee422SClaudiu Beznea static struct plat_sci_port port_cfg;
36930b0cced1SYoshinori Sato
early_console_exit(struct console * co)36945f101706SClaudiu Beznea static int early_console_exit(struct console *co)
36955f101706SClaudiu Beznea {
36965f101706SClaudiu Beznea struct sci_port *sci_port = &sci_ports[0];
36975f101706SClaudiu Beznea
36985f101706SClaudiu Beznea /*
36995f101706SClaudiu Beznea * Clean the slot used by earlycon. A new SCI device might
37005f101706SClaudiu Beznea * map to this slot.
37015f101706SClaudiu Beznea */
37025f101706SClaudiu Beznea if (!sci_uart_earlycon_dev_probing) {
37035f101706SClaudiu Beznea memset(sci_port, 0, sizeof(*sci_port));
37045f101706SClaudiu Beznea sci_uart_earlycon = false;
37055f101706SClaudiu Beznea }
37065f101706SClaudiu Beznea
37075f101706SClaudiu Beznea return 0;
37085f101706SClaudiu Beznea }
37095f101706SClaudiu Beznea
early_console_setup(struct earlycon_device * device,int type)37100b0cced1SYoshinori Sato static int __init early_console_setup(struct earlycon_device *device,
37110b0cced1SYoshinori Sato int type)
37120b0cced1SYoshinori Sato {
37130b0cced1SYoshinori Sato if (!device->port.membase)
37140b0cced1SYoshinori Sato return -ENODEV;
37150b0cced1SYoshinori Sato
37160b0cced1SYoshinori Sato device->port.type = type;
3717c1117a2fSGeert Uytterhoeven sci_ports[0].port = device->port;
3718daf5a895SLaurent Pinchart port_cfg.type = type;
37190b0cced1SYoshinori Sato sci_ports[0].cfg = &port_cfg;
3720daf5a895SLaurent Pinchart sci_ports[0].params = sci_probe_regmap(&port_cfg);
37219f7dea87SClaudiu Beznea sci_uart_earlycon = true;
37229f8325b3SLaurent Pinchart port_cfg.scscr = sci_serial_in(&sci_ports[0].port, SCSCR);
37239f8325b3SLaurent Pinchart sci_serial_out(&sci_ports[0].port, SCSCR,
37249f8325b3SLaurent Pinchart SCSCR_RE | SCSCR_TE | port_cfg.scscr);
37250b0cced1SYoshinori Sato
37260b0cced1SYoshinori Sato device->con->write = serial_console_write;
37275f101706SClaudiu Beznea device->con->exit = early_console_exit;
37285f101706SClaudiu Beznea
37290b0cced1SYoshinori Sato return 0;
37300b0cced1SYoshinori Sato }
sci_early_console_setup(struct earlycon_device * device,const char * opt)37310b0cced1SYoshinori Sato static int __init sci_early_console_setup(struct earlycon_device *device,
37320b0cced1SYoshinori Sato const char *opt)
37330b0cced1SYoshinori Sato {
37340b0cced1SYoshinori Sato return early_console_setup(device, PORT_SCI);
37350b0cced1SYoshinori Sato }
scif_early_console_setup(struct earlycon_device * device,const char * opt)37360b0cced1SYoshinori Sato static int __init scif_early_console_setup(struct earlycon_device *device,
37370b0cced1SYoshinori Sato const char *opt)
37380b0cced1SYoshinori Sato {
37390b0cced1SYoshinori Sato return early_console_setup(device, PORT_SCIF);
37400b0cced1SYoshinori Sato }
rzscifa_early_console_setup(struct earlycon_device * device,const char * opt)37413d8b43adSChris Brandt static int __init rzscifa_early_console_setup(struct earlycon_device *device,
37423d8b43adSChris Brandt const char *opt)
37433d8b43adSChris Brandt {
37443d8b43adSChris Brandt port_cfg.regtype = SCIx_RZ_SCIFA_REGTYPE;
37453d8b43adSChris Brandt return early_console_setup(device, PORT_SCIF);
37463d8b43adSChris Brandt }
37473b2cd606SBiju Das
rzv2hscif_early_console_setup(struct earlycon_device * device,const char * opt)37482f50304eSLad Prabhakar static int __init rzv2hscif_early_console_setup(struct earlycon_device *device,
37492f50304eSLad Prabhakar const char *opt)
37502f50304eSLad Prabhakar {
37512f50304eSLad Prabhakar port_cfg.regtype = SCIx_RZV2H_SCIF_REGTYPE;
37522f50304eSLad Prabhakar return early_console_setup(device, PORT_SCIF);
37532f50304eSLad Prabhakar }
37542f50304eSLad Prabhakar
scifa_early_console_setup(struct earlycon_device * device,const char * opt)37550b0cced1SYoshinori Sato static int __init scifa_early_console_setup(struct earlycon_device *device,
37560b0cced1SYoshinori Sato const char *opt)
37570b0cced1SYoshinori Sato {
37580b0cced1SYoshinori Sato return early_console_setup(device, PORT_SCIFA);
37590b0cced1SYoshinori Sato }
scifb_early_console_setup(struct earlycon_device * device,const char * opt)37600b0cced1SYoshinori Sato static int __init scifb_early_console_setup(struct earlycon_device *device,
37610b0cced1SYoshinori Sato const char *opt)
37620b0cced1SYoshinori Sato {
37630b0cced1SYoshinori Sato return early_console_setup(device, PORT_SCIFB);
37640b0cced1SYoshinori Sato }
hscif_early_console_setup(struct earlycon_device * device,const char * opt)37650b0cced1SYoshinori Sato static int __init hscif_early_console_setup(struct earlycon_device *device,
37660b0cced1SYoshinori Sato const char *opt)
37670b0cced1SYoshinori Sato {
37680b0cced1SYoshinori Sato return early_console_setup(device, PORT_HSCIF);
37690b0cced1SYoshinori Sato }
37700b0cced1SYoshinori Sato
37710b0cced1SYoshinori Sato OF_EARLYCON_DECLARE(sci, "renesas,sci", sci_early_console_setup);
37720b0cced1SYoshinori Sato OF_EARLYCON_DECLARE(scif, "renesas,scif", scif_early_console_setup);
37733d8b43adSChris Brandt OF_EARLYCON_DECLARE(scif, "renesas,scif-r7s9210", rzscifa_early_console_setup);
37743b2cd606SBiju Das OF_EARLYCON_DECLARE(scif, "renesas,scif-r9a07g044", rzscifa_early_console_setup);
37752f50304eSLad Prabhakar OF_EARLYCON_DECLARE(scif, "renesas,scif-r9a09g057", rzv2hscif_early_console_setup);
37760b0cced1SYoshinori Sato OF_EARLYCON_DECLARE(scifa, "renesas,scifa", scifa_early_console_setup);
37770b0cced1SYoshinori Sato OF_EARLYCON_DECLARE(scifb, "renesas,scifb", scifb_early_console_setup);
37780b0cced1SYoshinori Sato OF_EARLYCON_DECLARE(hscif, "renesas,hscif", hscif_early_console_setup);
37790b0cced1SYoshinori Sato #endif /* CONFIG_SERIAL_SH_SCI_EARLYCON */
37800b0cced1SYoshinori Sato
3781ab4382d2SGreg Kroah-Hartman module_init(sci_init);
3782ab4382d2SGreg Kroah-Hartman module_exit(sci_exit);
3783ab4382d2SGreg Kroah-Hartman
3784ab4382d2SGreg Kroah-Hartman MODULE_LICENSE("GPL");
3785ab4382d2SGreg Kroah-Hartman MODULE_ALIAS("platform:sh-sci");
37867f405f9cSPaul Mundt MODULE_AUTHOR("Paul Mundt");
3787f303b364SUlrich Hecht MODULE_DESCRIPTION("SuperH (H)SCI(F) serial driver");
3788