109864c1cSStefan-gabriel Mirea // SPDX-License-Identifier: GPL-2.0-or-later 209864c1cSStefan-gabriel Mirea /* 309864c1cSStefan-gabriel Mirea * Freescale linflexuart serial port driver 409864c1cSStefan-gabriel Mirea * 509864c1cSStefan-gabriel Mirea * Copyright 2012-2016 Freescale Semiconductor, Inc. 609864c1cSStefan-gabriel Mirea * Copyright 2017-2018 NXP 709864c1cSStefan-gabriel Mirea */ 809864c1cSStefan-gabriel Mirea 909864c1cSStefan-gabriel Mirea #if defined(CONFIG_SERIAL_FSL_LINFLEXUART_CONSOLE) && \ 1009864c1cSStefan-gabriel Mirea defined(CONFIG_MAGIC_SYSRQ) 1109864c1cSStefan-gabriel Mirea #define SUPPORT_SYSRQ 1209864c1cSStefan-gabriel Mirea #endif 1309864c1cSStefan-gabriel Mirea 1409864c1cSStefan-gabriel Mirea #include <linux/console.h> 1509864c1cSStefan-gabriel Mirea #include <linux/io.h> 1609864c1cSStefan-gabriel Mirea #include <linux/irq.h> 1709864c1cSStefan-gabriel Mirea #include <linux/module.h> 1809864c1cSStefan-gabriel Mirea #include <linux/of.h> 1909864c1cSStefan-gabriel Mirea #include <linux/of_device.h> 2009864c1cSStefan-gabriel Mirea #include <linux/serial_core.h> 2109864c1cSStefan-gabriel Mirea #include <linux/slab.h> 2209864c1cSStefan-gabriel Mirea #include <linux/tty_flip.h> 2309864c1cSStefan-gabriel Mirea #include <linux/delay.h> 2409864c1cSStefan-gabriel Mirea 2509864c1cSStefan-gabriel Mirea /* All registers are 32-bit width */ 2609864c1cSStefan-gabriel Mirea 2709864c1cSStefan-gabriel Mirea #define LINCR1 0x0000 /* LIN control register */ 2809864c1cSStefan-gabriel Mirea #define LINIER 0x0004 /* LIN interrupt enable register */ 2909864c1cSStefan-gabriel Mirea #define LINSR 0x0008 /* LIN status register */ 3009864c1cSStefan-gabriel Mirea #define LINESR 0x000C /* LIN error status register */ 3109864c1cSStefan-gabriel Mirea #define UARTCR 0x0010 /* UART mode control register */ 3209864c1cSStefan-gabriel Mirea #define UARTSR 0x0014 /* UART mode status register */ 3309864c1cSStefan-gabriel Mirea #define LINTCSR 0x0018 /* LIN timeout control status register */ 3409864c1cSStefan-gabriel Mirea #define LINOCR 0x001C /* LIN output compare register */ 3509864c1cSStefan-gabriel Mirea #define LINTOCR 0x0020 /* LIN timeout control register */ 3609864c1cSStefan-gabriel Mirea #define LINFBRR 0x0024 /* LIN fractional baud rate register */ 3709864c1cSStefan-gabriel Mirea #define LINIBRR 0x0028 /* LIN integer baud rate register */ 3809864c1cSStefan-gabriel Mirea #define LINCFR 0x002C /* LIN checksum field register */ 3909864c1cSStefan-gabriel Mirea #define LINCR2 0x0030 /* LIN control register 2 */ 4009864c1cSStefan-gabriel Mirea #define BIDR 0x0034 /* Buffer identifier register */ 4109864c1cSStefan-gabriel Mirea #define BDRL 0x0038 /* Buffer data register least significant */ 4209864c1cSStefan-gabriel Mirea #define BDRM 0x003C /* Buffer data register most significant */ 4309864c1cSStefan-gabriel Mirea #define IFER 0x0040 /* Identifier filter enable register */ 4409864c1cSStefan-gabriel Mirea #define IFMI 0x0044 /* Identifier filter match index */ 4509864c1cSStefan-gabriel Mirea #define IFMR 0x0048 /* Identifier filter mode register */ 4609864c1cSStefan-gabriel Mirea #define GCR 0x004C /* Global control register */ 4709864c1cSStefan-gabriel Mirea #define UARTPTO 0x0050 /* UART preset timeout register */ 4809864c1cSStefan-gabriel Mirea #define UARTCTO 0x0054 /* UART current timeout register */ 4909864c1cSStefan-gabriel Mirea 5009864c1cSStefan-gabriel Mirea /* 5109864c1cSStefan-gabriel Mirea * Register field definitions 5209864c1cSStefan-gabriel Mirea */ 5309864c1cSStefan-gabriel Mirea 5409864c1cSStefan-gabriel Mirea #define LINFLEXD_LINCR1_INIT BIT(0) 5509864c1cSStefan-gabriel Mirea #define LINFLEXD_LINCR1_MME BIT(4) 5609864c1cSStefan-gabriel Mirea #define LINFLEXD_LINCR1_BF BIT(7) 5709864c1cSStefan-gabriel Mirea 5809864c1cSStefan-gabriel Mirea #define LINFLEXD_LINSR_LINS_INITMODE BIT(12) 5909864c1cSStefan-gabriel Mirea #define LINFLEXD_LINSR_LINS_MASK (0xF << 12) 6009864c1cSStefan-gabriel Mirea 6109864c1cSStefan-gabriel Mirea #define LINFLEXD_LINIER_SZIE BIT(15) 6209864c1cSStefan-gabriel Mirea #define LINFLEXD_LINIER_OCIE BIT(14) 6309864c1cSStefan-gabriel Mirea #define LINFLEXD_LINIER_BEIE BIT(13) 6409864c1cSStefan-gabriel Mirea #define LINFLEXD_LINIER_CEIE BIT(12) 6509864c1cSStefan-gabriel Mirea #define LINFLEXD_LINIER_HEIE BIT(11) 6609864c1cSStefan-gabriel Mirea #define LINFLEXD_LINIER_FEIE BIT(8) 6709864c1cSStefan-gabriel Mirea #define LINFLEXD_LINIER_BOIE BIT(7) 6809864c1cSStefan-gabriel Mirea #define LINFLEXD_LINIER_LSIE BIT(6) 6909864c1cSStefan-gabriel Mirea #define LINFLEXD_LINIER_WUIE BIT(5) 7009864c1cSStefan-gabriel Mirea #define LINFLEXD_LINIER_DBFIE BIT(4) 7109864c1cSStefan-gabriel Mirea #define LINFLEXD_LINIER_DBEIETOIE BIT(3) 7209864c1cSStefan-gabriel Mirea #define LINFLEXD_LINIER_DRIE BIT(2) 7309864c1cSStefan-gabriel Mirea #define LINFLEXD_LINIER_DTIE BIT(1) 7409864c1cSStefan-gabriel Mirea #define LINFLEXD_LINIER_HRIE BIT(0) 7509864c1cSStefan-gabriel Mirea 7609864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTCR_OSR_MASK (0xF << 24) 7709864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTCR_OSR(uartcr) (((uartcr) \ 7809864c1cSStefan-gabriel Mirea & LINFLEXD_UARTCR_OSR_MASK) >> 24) 7909864c1cSStefan-gabriel Mirea 8009864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTCR_ROSE BIT(23) 8109864c1cSStefan-gabriel Mirea 8209864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTCR_RFBM BIT(9) 8309864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTCR_TFBM BIT(8) 8409864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTCR_WL1 BIT(7) 8509864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTCR_PC1 BIT(6) 8609864c1cSStefan-gabriel Mirea 8709864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTCR_RXEN BIT(5) 8809864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTCR_TXEN BIT(4) 8909864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTCR_PC0 BIT(3) 9009864c1cSStefan-gabriel Mirea 9109864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTCR_PCE BIT(2) 9209864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTCR_WL0 BIT(1) 9309864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTCR_UART BIT(0) 9409864c1cSStefan-gabriel Mirea 9509864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTSR_SZF BIT(15) 9609864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTSR_OCF BIT(14) 9709864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTSR_PE3 BIT(13) 9809864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTSR_PE2 BIT(12) 9909864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTSR_PE1 BIT(11) 10009864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTSR_PE0 BIT(10) 10109864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTSR_RMB BIT(9) 10209864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTSR_FEF BIT(8) 10309864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTSR_BOF BIT(7) 10409864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTSR_RPS BIT(6) 10509864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTSR_WUF BIT(5) 10609864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTSR_4 BIT(4) 10709864c1cSStefan-gabriel Mirea 10809864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTSR_TO BIT(3) 10909864c1cSStefan-gabriel Mirea 11009864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTSR_DRFRFE BIT(2) 11109864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTSR_DTFTFF BIT(1) 11209864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTSR_NF BIT(0) 11309864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTSR_PE (LINFLEXD_UARTSR_PE0 |\ 11409864c1cSStefan-gabriel Mirea LINFLEXD_UARTSR_PE1 |\ 11509864c1cSStefan-gabriel Mirea LINFLEXD_UARTSR_PE2 |\ 11609864c1cSStefan-gabriel Mirea LINFLEXD_UARTSR_PE3) 11709864c1cSStefan-gabriel Mirea 11809864c1cSStefan-gabriel Mirea #define LINFLEX_LDIV_MULTIPLIER (16) 11909864c1cSStefan-gabriel Mirea 12009864c1cSStefan-gabriel Mirea #define DRIVER_NAME "fsl-linflexuart" 12109864c1cSStefan-gabriel Mirea #define DEV_NAME "ttyLF" 12209864c1cSStefan-gabriel Mirea #define UART_NR 4 12309864c1cSStefan-gabriel Mirea 12409864c1cSStefan-gabriel Mirea #define EARLYCON_BUFFER_INITIAL_CAP 8 12509864c1cSStefan-gabriel Mirea 12609864c1cSStefan-gabriel Mirea #define PREINIT_DELAY 2000 /* us */ 12709864c1cSStefan-gabriel Mirea 12809864c1cSStefan-gabriel Mirea static const struct of_device_id linflex_dt_ids[] = { 12909864c1cSStefan-gabriel Mirea { 13009864c1cSStefan-gabriel Mirea .compatible = "fsl,s32-linflexuart", 13109864c1cSStefan-gabriel Mirea }, 13209864c1cSStefan-gabriel Mirea { /* sentinel */ } 13309864c1cSStefan-gabriel Mirea }; 13409864c1cSStefan-gabriel Mirea MODULE_DEVICE_TABLE(of, linflex_dt_ids); 13509864c1cSStefan-gabriel Mirea 13609864c1cSStefan-gabriel Mirea #ifdef CONFIG_SERIAL_FSL_LINFLEXUART_CONSOLE 13709864c1cSStefan-gabriel Mirea static struct uart_port *earlycon_port; 13809864c1cSStefan-gabriel Mirea static bool linflex_earlycon_same_instance; 139*06e9b2feSWei Yongjun static DEFINE_SPINLOCK(init_lock); 14009864c1cSStefan-gabriel Mirea static bool during_init; 14109864c1cSStefan-gabriel Mirea 14209864c1cSStefan-gabriel Mirea static struct { 14309864c1cSStefan-gabriel Mirea char *content; 14409864c1cSStefan-gabriel Mirea unsigned int len, cap; 14509864c1cSStefan-gabriel Mirea } earlycon_buf; 14609864c1cSStefan-gabriel Mirea #endif 14709864c1cSStefan-gabriel Mirea 14809864c1cSStefan-gabriel Mirea static void linflex_stop_tx(struct uart_port *port) 14909864c1cSStefan-gabriel Mirea { 15009864c1cSStefan-gabriel Mirea unsigned long ier; 15109864c1cSStefan-gabriel Mirea 15209864c1cSStefan-gabriel Mirea ier = readl(port->membase + LINIER); 15309864c1cSStefan-gabriel Mirea ier &= ~(LINFLEXD_LINIER_DTIE); 15409864c1cSStefan-gabriel Mirea writel(ier, port->membase + LINIER); 15509864c1cSStefan-gabriel Mirea } 15609864c1cSStefan-gabriel Mirea 15709864c1cSStefan-gabriel Mirea static void linflex_stop_rx(struct uart_port *port) 15809864c1cSStefan-gabriel Mirea { 15909864c1cSStefan-gabriel Mirea unsigned long ier; 16009864c1cSStefan-gabriel Mirea 16109864c1cSStefan-gabriel Mirea ier = readl(port->membase + LINIER); 16209864c1cSStefan-gabriel Mirea writel(ier & ~LINFLEXD_LINIER_DRIE, port->membase + LINIER); 16309864c1cSStefan-gabriel Mirea } 16409864c1cSStefan-gabriel Mirea 16509864c1cSStefan-gabriel Mirea static inline void linflex_transmit_buffer(struct uart_port *sport) 16609864c1cSStefan-gabriel Mirea { 16709864c1cSStefan-gabriel Mirea struct circ_buf *xmit = &sport->state->xmit; 16809864c1cSStefan-gabriel Mirea unsigned char c; 16909864c1cSStefan-gabriel Mirea unsigned long status; 17009864c1cSStefan-gabriel Mirea 17109864c1cSStefan-gabriel Mirea while (!uart_circ_empty(xmit)) { 17209864c1cSStefan-gabriel Mirea c = xmit->buf[xmit->tail]; 17309864c1cSStefan-gabriel Mirea writeb(c, sport->membase + BDRL); 17409864c1cSStefan-gabriel Mirea 17509864c1cSStefan-gabriel Mirea /* Waiting for data transmission completed. */ 17609864c1cSStefan-gabriel Mirea while (((status = readl(sport->membase + UARTSR)) & 17709864c1cSStefan-gabriel Mirea LINFLEXD_UARTSR_DTFTFF) != 17809864c1cSStefan-gabriel Mirea LINFLEXD_UARTSR_DTFTFF) 17909864c1cSStefan-gabriel Mirea ; 18009864c1cSStefan-gabriel Mirea 18109864c1cSStefan-gabriel Mirea xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); 18209864c1cSStefan-gabriel Mirea sport->icount.tx++; 18309864c1cSStefan-gabriel Mirea 18409864c1cSStefan-gabriel Mirea writel(status | LINFLEXD_UARTSR_DTFTFF, 18509864c1cSStefan-gabriel Mirea sport->membase + UARTSR); 18609864c1cSStefan-gabriel Mirea } 18709864c1cSStefan-gabriel Mirea 18809864c1cSStefan-gabriel Mirea if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) 18909864c1cSStefan-gabriel Mirea uart_write_wakeup(sport); 19009864c1cSStefan-gabriel Mirea 19109864c1cSStefan-gabriel Mirea if (uart_circ_empty(xmit)) 19209864c1cSStefan-gabriel Mirea linflex_stop_tx(sport); 19309864c1cSStefan-gabriel Mirea } 19409864c1cSStefan-gabriel Mirea 19509864c1cSStefan-gabriel Mirea static void linflex_start_tx(struct uart_port *port) 19609864c1cSStefan-gabriel Mirea { 19709864c1cSStefan-gabriel Mirea unsigned long ier; 19809864c1cSStefan-gabriel Mirea 19909864c1cSStefan-gabriel Mirea linflex_transmit_buffer(port); 20009864c1cSStefan-gabriel Mirea ier = readl(port->membase + LINIER); 20109864c1cSStefan-gabriel Mirea writel(ier | LINFLEXD_LINIER_DTIE, port->membase + LINIER); 20209864c1cSStefan-gabriel Mirea } 20309864c1cSStefan-gabriel Mirea 20409864c1cSStefan-gabriel Mirea static irqreturn_t linflex_txint(int irq, void *dev_id) 20509864c1cSStefan-gabriel Mirea { 20609864c1cSStefan-gabriel Mirea struct uart_port *sport = dev_id; 20709864c1cSStefan-gabriel Mirea struct circ_buf *xmit = &sport->state->xmit; 20809864c1cSStefan-gabriel Mirea unsigned long flags; 20909864c1cSStefan-gabriel Mirea unsigned long status; 21009864c1cSStefan-gabriel Mirea 21109864c1cSStefan-gabriel Mirea spin_lock_irqsave(&sport->lock, flags); 21209864c1cSStefan-gabriel Mirea 21309864c1cSStefan-gabriel Mirea if (sport->x_char) { 21409864c1cSStefan-gabriel Mirea writeb(sport->x_char, sport->membase + BDRL); 21509864c1cSStefan-gabriel Mirea 21609864c1cSStefan-gabriel Mirea /* waiting for data transmission completed */ 21709864c1cSStefan-gabriel Mirea while (((status = readl(sport->membase + UARTSR)) & 21809864c1cSStefan-gabriel Mirea LINFLEXD_UARTSR_DTFTFF) != LINFLEXD_UARTSR_DTFTFF) 21909864c1cSStefan-gabriel Mirea ; 22009864c1cSStefan-gabriel Mirea 22109864c1cSStefan-gabriel Mirea writel(status | LINFLEXD_UARTSR_DTFTFF, 22209864c1cSStefan-gabriel Mirea sport->membase + UARTSR); 22309864c1cSStefan-gabriel Mirea 22409864c1cSStefan-gabriel Mirea goto out; 22509864c1cSStefan-gabriel Mirea } 22609864c1cSStefan-gabriel Mirea 22709864c1cSStefan-gabriel Mirea if (uart_circ_empty(xmit) || uart_tx_stopped(sport)) { 22809864c1cSStefan-gabriel Mirea linflex_stop_tx(sport); 22909864c1cSStefan-gabriel Mirea goto out; 23009864c1cSStefan-gabriel Mirea } 23109864c1cSStefan-gabriel Mirea 23209864c1cSStefan-gabriel Mirea linflex_transmit_buffer(sport); 23309864c1cSStefan-gabriel Mirea 23409864c1cSStefan-gabriel Mirea if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) 23509864c1cSStefan-gabriel Mirea uart_write_wakeup(sport); 23609864c1cSStefan-gabriel Mirea 23709864c1cSStefan-gabriel Mirea out: 23809864c1cSStefan-gabriel Mirea spin_unlock_irqrestore(&sport->lock, flags); 23909864c1cSStefan-gabriel Mirea return IRQ_HANDLED; 24009864c1cSStefan-gabriel Mirea } 24109864c1cSStefan-gabriel Mirea 24209864c1cSStefan-gabriel Mirea static irqreturn_t linflex_rxint(int irq, void *dev_id) 24309864c1cSStefan-gabriel Mirea { 24409864c1cSStefan-gabriel Mirea struct uart_port *sport = dev_id; 24509864c1cSStefan-gabriel Mirea unsigned int flg; 24609864c1cSStefan-gabriel Mirea struct tty_port *port = &sport->state->port; 24709864c1cSStefan-gabriel Mirea unsigned long flags, status; 24809864c1cSStefan-gabriel Mirea unsigned char rx; 24909864c1cSStefan-gabriel Mirea 25009864c1cSStefan-gabriel Mirea spin_lock_irqsave(&sport->lock, flags); 25109864c1cSStefan-gabriel Mirea 25209864c1cSStefan-gabriel Mirea status = readl(sport->membase + UARTSR); 25309864c1cSStefan-gabriel Mirea while (status & LINFLEXD_UARTSR_RMB) { 25409864c1cSStefan-gabriel Mirea rx = readb(sport->membase + BDRM); 25509864c1cSStefan-gabriel Mirea flg = TTY_NORMAL; 25609864c1cSStefan-gabriel Mirea sport->icount.rx++; 25709864c1cSStefan-gabriel Mirea 25809864c1cSStefan-gabriel Mirea if (status & (LINFLEXD_UARTSR_BOF | LINFLEXD_UARTSR_SZF | 25909864c1cSStefan-gabriel Mirea LINFLEXD_UARTSR_FEF | LINFLEXD_UARTSR_PE)) { 26009864c1cSStefan-gabriel Mirea if (status & LINFLEXD_UARTSR_SZF) 26109864c1cSStefan-gabriel Mirea status |= LINFLEXD_UARTSR_SZF; 26209864c1cSStefan-gabriel Mirea if (status & LINFLEXD_UARTSR_BOF) 26309864c1cSStefan-gabriel Mirea status |= LINFLEXD_UARTSR_BOF; 26409864c1cSStefan-gabriel Mirea if (status & LINFLEXD_UARTSR_FEF) 26509864c1cSStefan-gabriel Mirea status |= LINFLEXD_UARTSR_FEF; 26609864c1cSStefan-gabriel Mirea if (status & LINFLEXD_UARTSR_PE) 26709864c1cSStefan-gabriel Mirea status |= LINFLEXD_UARTSR_PE; 26809864c1cSStefan-gabriel Mirea } 26909864c1cSStefan-gabriel Mirea 27009864c1cSStefan-gabriel Mirea writel(status | LINFLEXD_UARTSR_RMB | LINFLEXD_UARTSR_DRFRFE, 27109864c1cSStefan-gabriel Mirea sport->membase + UARTSR); 27209864c1cSStefan-gabriel Mirea status = readl(sport->membase + UARTSR); 27309864c1cSStefan-gabriel Mirea 27409864c1cSStefan-gabriel Mirea if (uart_handle_sysrq_char(sport, (unsigned char)rx)) 27509864c1cSStefan-gabriel Mirea continue; 27609864c1cSStefan-gabriel Mirea 27709864c1cSStefan-gabriel Mirea #ifdef SUPPORT_SYSRQ 27809864c1cSStefan-gabriel Mirea sport->sysrq = 0; 27909864c1cSStefan-gabriel Mirea #endif 28009864c1cSStefan-gabriel Mirea tty_insert_flip_char(port, rx, flg); 28109864c1cSStefan-gabriel Mirea } 28209864c1cSStefan-gabriel Mirea 28309864c1cSStefan-gabriel Mirea spin_unlock_irqrestore(&sport->lock, flags); 28409864c1cSStefan-gabriel Mirea 28509864c1cSStefan-gabriel Mirea tty_flip_buffer_push(port); 28609864c1cSStefan-gabriel Mirea 28709864c1cSStefan-gabriel Mirea return IRQ_HANDLED; 28809864c1cSStefan-gabriel Mirea } 28909864c1cSStefan-gabriel Mirea 29009864c1cSStefan-gabriel Mirea static irqreturn_t linflex_int(int irq, void *dev_id) 29109864c1cSStefan-gabriel Mirea { 29209864c1cSStefan-gabriel Mirea struct uart_port *sport = dev_id; 29309864c1cSStefan-gabriel Mirea unsigned long status; 29409864c1cSStefan-gabriel Mirea 29509864c1cSStefan-gabriel Mirea status = readl(sport->membase + UARTSR); 29609864c1cSStefan-gabriel Mirea 29709864c1cSStefan-gabriel Mirea if (status & LINFLEXD_UARTSR_DRFRFE) 29809864c1cSStefan-gabriel Mirea linflex_rxint(irq, dev_id); 29909864c1cSStefan-gabriel Mirea if (status & LINFLEXD_UARTSR_DTFTFF) 30009864c1cSStefan-gabriel Mirea linflex_txint(irq, dev_id); 30109864c1cSStefan-gabriel Mirea 30209864c1cSStefan-gabriel Mirea return IRQ_HANDLED; 30309864c1cSStefan-gabriel Mirea } 30409864c1cSStefan-gabriel Mirea 30509864c1cSStefan-gabriel Mirea /* return TIOCSER_TEMT when transmitter is not busy */ 30609864c1cSStefan-gabriel Mirea static unsigned int linflex_tx_empty(struct uart_port *port) 30709864c1cSStefan-gabriel Mirea { 30809864c1cSStefan-gabriel Mirea unsigned long status; 30909864c1cSStefan-gabriel Mirea 31009864c1cSStefan-gabriel Mirea status = readl(port->membase + UARTSR) & LINFLEXD_UARTSR_DTFTFF; 31109864c1cSStefan-gabriel Mirea 31209864c1cSStefan-gabriel Mirea return status ? TIOCSER_TEMT : 0; 31309864c1cSStefan-gabriel Mirea } 31409864c1cSStefan-gabriel Mirea 31509864c1cSStefan-gabriel Mirea static unsigned int linflex_get_mctrl(struct uart_port *port) 31609864c1cSStefan-gabriel Mirea { 31709864c1cSStefan-gabriel Mirea return 0; 31809864c1cSStefan-gabriel Mirea } 31909864c1cSStefan-gabriel Mirea 32009864c1cSStefan-gabriel Mirea static void linflex_set_mctrl(struct uart_port *port, unsigned int mctrl) 32109864c1cSStefan-gabriel Mirea { 32209864c1cSStefan-gabriel Mirea } 32309864c1cSStefan-gabriel Mirea 32409864c1cSStefan-gabriel Mirea static void linflex_break_ctl(struct uart_port *port, int break_state) 32509864c1cSStefan-gabriel Mirea { 32609864c1cSStefan-gabriel Mirea } 32709864c1cSStefan-gabriel Mirea 32809864c1cSStefan-gabriel Mirea static void linflex_setup_watermark(struct uart_port *sport) 32909864c1cSStefan-gabriel Mirea { 33009864c1cSStefan-gabriel Mirea unsigned long cr, ier, cr1; 33109864c1cSStefan-gabriel Mirea 33209864c1cSStefan-gabriel Mirea /* Disable transmission/reception */ 33309864c1cSStefan-gabriel Mirea ier = readl(sport->membase + LINIER); 33409864c1cSStefan-gabriel Mirea ier &= ~(LINFLEXD_LINIER_DRIE | LINFLEXD_LINIER_DTIE); 33509864c1cSStefan-gabriel Mirea writel(ier, sport->membase + LINIER); 33609864c1cSStefan-gabriel Mirea 33709864c1cSStefan-gabriel Mirea cr = readl(sport->membase + UARTCR); 33809864c1cSStefan-gabriel Mirea cr &= ~(LINFLEXD_UARTCR_RXEN | LINFLEXD_UARTCR_TXEN); 33909864c1cSStefan-gabriel Mirea writel(cr, sport->membase + UARTCR); 34009864c1cSStefan-gabriel Mirea 34109864c1cSStefan-gabriel Mirea /* Enter initialization mode by setting INIT bit */ 34209864c1cSStefan-gabriel Mirea 34309864c1cSStefan-gabriel Mirea /* set the Linflex in master mode and activate by-pass filter */ 34409864c1cSStefan-gabriel Mirea cr1 = LINFLEXD_LINCR1_BF | LINFLEXD_LINCR1_MME 34509864c1cSStefan-gabriel Mirea | LINFLEXD_LINCR1_INIT; 34609864c1cSStefan-gabriel Mirea writel(cr1, sport->membase + LINCR1); 34709864c1cSStefan-gabriel Mirea 34809864c1cSStefan-gabriel Mirea /* wait for init mode entry */ 34909864c1cSStefan-gabriel Mirea while ((readl(sport->membase + LINSR) 35009864c1cSStefan-gabriel Mirea & LINFLEXD_LINSR_LINS_MASK) 35109864c1cSStefan-gabriel Mirea != LINFLEXD_LINSR_LINS_INITMODE) 35209864c1cSStefan-gabriel Mirea ; 35309864c1cSStefan-gabriel Mirea 35409864c1cSStefan-gabriel Mirea /* 35509864c1cSStefan-gabriel Mirea * UART = 0x1; - Linflex working in UART mode 35609864c1cSStefan-gabriel Mirea * TXEN = 0x1; - Enable transmission of data now 35709864c1cSStefan-gabriel Mirea * RXEn = 0x1; - Receiver enabled 35809864c1cSStefan-gabriel Mirea * WL0 = 0x1; - 8 bit data 35909864c1cSStefan-gabriel Mirea * PCE = 0x0; - No parity 36009864c1cSStefan-gabriel Mirea */ 36109864c1cSStefan-gabriel Mirea 36209864c1cSStefan-gabriel Mirea /* set UART bit to allow writing other bits */ 36309864c1cSStefan-gabriel Mirea writel(LINFLEXD_UARTCR_UART, sport->membase + UARTCR); 36409864c1cSStefan-gabriel Mirea 36509864c1cSStefan-gabriel Mirea cr = (LINFLEXD_UARTCR_RXEN | LINFLEXD_UARTCR_TXEN | 36609864c1cSStefan-gabriel Mirea LINFLEXD_UARTCR_WL0 | LINFLEXD_UARTCR_UART); 36709864c1cSStefan-gabriel Mirea 36809864c1cSStefan-gabriel Mirea writel(cr, sport->membase + UARTCR); 36909864c1cSStefan-gabriel Mirea 37009864c1cSStefan-gabriel Mirea cr1 &= ~(LINFLEXD_LINCR1_INIT); 37109864c1cSStefan-gabriel Mirea 37209864c1cSStefan-gabriel Mirea writel(cr1, sport->membase + LINCR1); 37309864c1cSStefan-gabriel Mirea 37409864c1cSStefan-gabriel Mirea ier = readl(sport->membase + LINIER); 37509864c1cSStefan-gabriel Mirea ier |= LINFLEXD_LINIER_DRIE; 37609864c1cSStefan-gabriel Mirea ier |= LINFLEXD_LINIER_DTIE; 37709864c1cSStefan-gabriel Mirea 37809864c1cSStefan-gabriel Mirea writel(ier, sport->membase + LINIER); 37909864c1cSStefan-gabriel Mirea } 38009864c1cSStefan-gabriel Mirea 38109864c1cSStefan-gabriel Mirea static int linflex_startup(struct uart_port *port) 38209864c1cSStefan-gabriel Mirea { 38309864c1cSStefan-gabriel Mirea int ret = 0; 38409864c1cSStefan-gabriel Mirea unsigned long flags; 38509864c1cSStefan-gabriel Mirea 38609864c1cSStefan-gabriel Mirea spin_lock_irqsave(&port->lock, flags); 38709864c1cSStefan-gabriel Mirea 38809864c1cSStefan-gabriel Mirea linflex_setup_watermark(port); 38909864c1cSStefan-gabriel Mirea 39009864c1cSStefan-gabriel Mirea spin_unlock_irqrestore(&port->lock, flags); 39109864c1cSStefan-gabriel Mirea 39209864c1cSStefan-gabriel Mirea ret = devm_request_irq(port->dev, port->irq, linflex_int, 0, 39309864c1cSStefan-gabriel Mirea DRIVER_NAME, port); 39409864c1cSStefan-gabriel Mirea 39509864c1cSStefan-gabriel Mirea return ret; 39609864c1cSStefan-gabriel Mirea } 39709864c1cSStefan-gabriel Mirea 39809864c1cSStefan-gabriel Mirea static void linflex_shutdown(struct uart_port *port) 39909864c1cSStefan-gabriel Mirea { 40009864c1cSStefan-gabriel Mirea unsigned long ier; 40109864c1cSStefan-gabriel Mirea unsigned long flags; 40209864c1cSStefan-gabriel Mirea 40309864c1cSStefan-gabriel Mirea spin_lock_irqsave(&port->lock, flags); 40409864c1cSStefan-gabriel Mirea 40509864c1cSStefan-gabriel Mirea /* disable interrupts */ 40609864c1cSStefan-gabriel Mirea ier = readl(port->membase + LINIER); 40709864c1cSStefan-gabriel Mirea ier &= ~(LINFLEXD_LINIER_DRIE | LINFLEXD_LINIER_DTIE); 40809864c1cSStefan-gabriel Mirea writel(ier, port->membase + LINIER); 40909864c1cSStefan-gabriel Mirea 41009864c1cSStefan-gabriel Mirea spin_unlock_irqrestore(&port->lock, flags); 41109864c1cSStefan-gabriel Mirea 41209864c1cSStefan-gabriel Mirea devm_free_irq(port->dev, port->irq, port); 41309864c1cSStefan-gabriel Mirea } 41409864c1cSStefan-gabriel Mirea 41509864c1cSStefan-gabriel Mirea static void 41609864c1cSStefan-gabriel Mirea linflex_set_termios(struct uart_port *port, struct ktermios *termios, 41709864c1cSStefan-gabriel Mirea struct ktermios *old) 41809864c1cSStefan-gabriel Mirea { 41909864c1cSStefan-gabriel Mirea unsigned long flags; 42009864c1cSStefan-gabriel Mirea unsigned long cr, old_cr, cr1; 42109864c1cSStefan-gabriel Mirea unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; 42209864c1cSStefan-gabriel Mirea 42309864c1cSStefan-gabriel Mirea cr = readl(port->membase + UARTCR); 42409864c1cSStefan-gabriel Mirea old_cr = cr; 42509864c1cSStefan-gabriel Mirea 42609864c1cSStefan-gabriel Mirea /* Enter initialization mode by setting INIT bit */ 42709864c1cSStefan-gabriel Mirea cr1 = readl(port->membase + LINCR1); 42809864c1cSStefan-gabriel Mirea cr1 |= LINFLEXD_LINCR1_INIT; 42909864c1cSStefan-gabriel Mirea writel(cr1, port->membase + LINCR1); 43009864c1cSStefan-gabriel Mirea 43109864c1cSStefan-gabriel Mirea /* wait for init mode entry */ 43209864c1cSStefan-gabriel Mirea while ((readl(port->membase + LINSR) 43309864c1cSStefan-gabriel Mirea & LINFLEXD_LINSR_LINS_MASK) 43409864c1cSStefan-gabriel Mirea != LINFLEXD_LINSR_LINS_INITMODE) 43509864c1cSStefan-gabriel Mirea ; 43609864c1cSStefan-gabriel Mirea 43709864c1cSStefan-gabriel Mirea /* 43809864c1cSStefan-gabriel Mirea * only support CS8 and CS7, and for CS7 must enable PE. 43909864c1cSStefan-gabriel Mirea * supported mode: 44009864c1cSStefan-gabriel Mirea * - (7,e/o,1) 44109864c1cSStefan-gabriel Mirea * - (8,n,1) 44209864c1cSStefan-gabriel Mirea * - (8,e/o,1) 44309864c1cSStefan-gabriel Mirea */ 44409864c1cSStefan-gabriel Mirea /* enter the UART into configuration mode */ 44509864c1cSStefan-gabriel Mirea 44609864c1cSStefan-gabriel Mirea while ((termios->c_cflag & CSIZE) != CS8 && 44709864c1cSStefan-gabriel Mirea (termios->c_cflag & CSIZE) != CS7) { 44809864c1cSStefan-gabriel Mirea termios->c_cflag &= ~CSIZE; 44909864c1cSStefan-gabriel Mirea termios->c_cflag |= old_csize; 45009864c1cSStefan-gabriel Mirea old_csize = CS8; 45109864c1cSStefan-gabriel Mirea } 45209864c1cSStefan-gabriel Mirea 45309864c1cSStefan-gabriel Mirea if ((termios->c_cflag & CSIZE) == CS7) { 45409864c1cSStefan-gabriel Mirea /* Word length: WL1WL0:00 */ 45509864c1cSStefan-gabriel Mirea cr = old_cr & ~LINFLEXD_UARTCR_WL1 & ~LINFLEXD_UARTCR_WL0; 45609864c1cSStefan-gabriel Mirea } 45709864c1cSStefan-gabriel Mirea 45809864c1cSStefan-gabriel Mirea if ((termios->c_cflag & CSIZE) == CS8) { 45909864c1cSStefan-gabriel Mirea /* Word length: WL1WL0:01 */ 46009864c1cSStefan-gabriel Mirea cr = (old_cr | LINFLEXD_UARTCR_WL0) & ~LINFLEXD_UARTCR_WL1; 46109864c1cSStefan-gabriel Mirea } 46209864c1cSStefan-gabriel Mirea 46309864c1cSStefan-gabriel Mirea if (termios->c_cflag & CMSPAR) { 46409864c1cSStefan-gabriel Mirea if ((termios->c_cflag & CSIZE) != CS8) { 46509864c1cSStefan-gabriel Mirea termios->c_cflag &= ~CSIZE; 46609864c1cSStefan-gabriel Mirea termios->c_cflag |= CS8; 46709864c1cSStefan-gabriel Mirea } 46809864c1cSStefan-gabriel Mirea /* has a space/sticky bit */ 46909864c1cSStefan-gabriel Mirea cr |= LINFLEXD_UARTCR_WL0; 47009864c1cSStefan-gabriel Mirea } 47109864c1cSStefan-gabriel Mirea 47209864c1cSStefan-gabriel Mirea if (termios->c_cflag & CSTOPB) 47309864c1cSStefan-gabriel Mirea termios->c_cflag &= ~CSTOPB; 47409864c1cSStefan-gabriel Mirea 47509864c1cSStefan-gabriel Mirea /* parity must be enabled when CS7 to match 8-bits format */ 47609864c1cSStefan-gabriel Mirea if ((termios->c_cflag & CSIZE) == CS7) 47709864c1cSStefan-gabriel Mirea termios->c_cflag |= PARENB; 47809864c1cSStefan-gabriel Mirea 47909864c1cSStefan-gabriel Mirea if ((termios->c_cflag & PARENB)) { 48009864c1cSStefan-gabriel Mirea cr |= LINFLEXD_UARTCR_PCE; 48109864c1cSStefan-gabriel Mirea if (termios->c_cflag & PARODD) 48209864c1cSStefan-gabriel Mirea cr = (cr | LINFLEXD_UARTCR_PC0) & 48309864c1cSStefan-gabriel Mirea (~LINFLEXD_UARTCR_PC1); 48409864c1cSStefan-gabriel Mirea else 48509864c1cSStefan-gabriel Mirea cr = cr & (~LINFLEXD_UARTCR_PC1 & 48609864c1cSStefan-gabriel Mirea ~LINFLEXD_UARTCR_PC0); 48709864c1cSStefan-gabriel Mirea } else { 48809864c1cSStefan-gabriel Mirea cr &= ~LINFLEXD_UARTCR_PCE; 48909864c1cSStefan-gabriel Mirea } 49009864c1cSStefan-gabriel Mirea 49109864c1cSStefan-gabriel Mirea spin_lock_irqsave(&port->lock, flags); 49209864c1cSStefan-gabriel Mirea 49309864c1cSStefan-gabriel Mirea port->read_status_mask = 0; 49409864c1cSStefan-gabriel Mirea 49509864c1cSStefan-gabriel Mirea if (termios->c_iflag & INPCK) 49609864c1cSStefan-gabriel Mirea port->read_status_mask |= (LINFLEXD_UARTSR_FEF | 49709864c1cSStefan-gabriel Mirea LINFLEXD_UARTSR_PE0 | 49809864c1cSStefan-gabriel Mirea LINFLEXD_UARTSR_PE1 | 49909864c1cSStefan-gabriel Mirea LINFLEXD_UARTSR_PE2 | 50009864c1cSStefan-gabriel Mirea LINFLEXD_UARTSR_PE3); 50109864c1cSStefan-gabriel Mirea if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) 50209864c1cSStefan-gabriel Mirea port->read_status_mask |= LINFLEXD_UARTSR_FEF; 50309864c1cSStefan-gabriel Mirea 50409864c1cSStefan-gabriel Mirea /* characters to ignore */ 50509864c1cSStefan-gabriel Mirea port->ignore_status_mask = 0; 50609864c1cSStefan-gabriel Mirea if (termios->c_iflag & IGNPAR) 50709864c1cSStefan-gabriel Mirea port->ignore_status_mask |= LINFLEXD_UARTSR_PE; 50809864c1cSStefan-gabriel Mirea if (termios->c_iflag & IGNBRK) { 50909864c1cSStefan-gabriel Mirea port->ignore_status_mask |= LINFLEXD_UARTSR_PE; 51009864c1cSStefan-gabriel Mirea /* 51109864c1cSStefan-gabriel Mirea * if we're ignoring parity and break indicators, 51209864c1cSStefan-gabriel Mirea * ignore overruns too (for real raw support). 51309864c1cSStefan-gabriel Mirea */ 51409864c1cSStefan-gabriel Mirea if (termios->c_iflag & IGNPAR) 51509864c1cSStefan-gabriel Mirea port->ignore_status_mask |= LINFLEXD_UARTSR_BOF; 51609864c1cSStefan-gabriel Mirea } 51709864c1cSStefan-gabriel Mirea 51809864c1cSStefan-gabriel Mirea writel(cr, port->membase + UARTCR); 51909864c1cSStefan-gabriel Mirea 52009864c1cSStefan-gabriel Mirea cr1 &= ~(LINFLEXD_LINCR1_INIT); 52109864c1cSStefan-gabriel Mirea 52209864c1cSStefan-gabriel Mirea writel(cr1, port->membase + LINCR1); 52309864c1cSStefan-gabriel Mirea 52409864c1cSStefan-gabriel Mirea spin_unlock_irqrestore(&port->lock, flags); 52509864c1cSStefan-gabriel Mirea } 52609864c1cSStefan-gabriel Mirea 52709864c1cSStefan-gabriel Mirea static const char *linflex_type(struct uart_port *port) 52809864c1cSStefan-gabriel Mirea { 52909864c1cSStefan-gabriel Mirea return "FSL_LINFLEX"; 53009864c1cSStefan-gabriel Mirea } 53109864c1cSStefan-gabriel Mirea 53209864c1cSStefan-gabriel Mirea static void linflex_release_port(struct uart_port *port) 53309864c1cSStefan-gabriel Mirea { 53409864c1cSStefan-gabriel Mirea /* nothing to do */ 53509864c1cSStefan-gabriel Mirea } 53609864c1cSStefan-gabriel Mirea 53709864c1cSStefan-gabriel Mirea static int linflex_request_port(struct uart_port *port) 53809864c1cSStefan-gabriel Mirea { 53909864c1cSStefan-gabriel Mirea return 0; 54009864c1cSStefan-gabriel Mirea } 54109864c1cSStefan-gabriel Mirea 54209864c1cSStefan-gabriel Mirea /* configure/auto-configure the port */ 54309864c1cSStefan-gabriel Mirea static void linflex_config_port(struct uart_port *port, int flags) 54409864c1cSStefan-gabriel Mirea { 54509864c1cSStefan-gabriel Mirea if (flags & UART_CONFIG_TYPE) 54609864c1cSStefan-gabriel Mirea port->type = PORT_LINFLEXUART; 54709864c1cSStefan-gabriel Mirea } 54809864c1cSStefan-gabriel Mirea 54909864c1cSStefan-gabriel Mirea static const struct uart_ops linflex_pops = { 55009864c1cSStefan-gabriel Mirea .tx_empty = linflex_tx_empty, 55109864c1cSStefan-gabriel Mirea .set_mctrl = linflex_set_mctrl, 55209864c1cSStefan-gabriel Mirea .get_mctrl = linflex_get_mctrl, 55309864c1cSStefan-gabriel Mirea .stop_tx = linflex_stop_tx, 55409864c1cSStefan-gabriel Mirea .start_tx = linflex_start_tx, 55509864c1cSStefan-gabriel Mirea .stop_rx = linflex_stop_rx, 55609864c1cSStefan-gabriel Mirea .break_ctl = linflex_break_ctl, 55709864c1cSStefan-gabriel Mirea .startup = linflex_startup, 55809864c1cSStefan-gabriel Mirea .shutdown = linflex_shutdown, 55909864c1cSStefan-gabriel Mirea .set_termios = linflex_set_termios, 56009864c1cSStefan-gabriel Mirea .type = linflex_type, 56109864c1cSStefan-gabriel Mirea .request_port = linflex_request_port, 56209864c1cSStefan-gabriel Mirea .release_port = linflex_release_port, 56309864c1cSStefan-gabriel Mirea .config_port = linflex_config_port, 56409864c1cSStefan-gabriel Mirea }; 56509864c1cSStefan-gabriel Mirea 56609864c1cSStefan-gabriel Mirea static struct uart_port *linflex_ports[UART_NR]; 56709864c1cSStefan-gabriel Mirea 56809864c1cSStefan-gabriel Mirea #ifdef CONFIG_SERIAL_FSL_LINFLEXUART_CONSOLE 56909864c1cSStefan-gabriel Mirea static void linflex_console_putchar(struct uart_port *port, int ch) 57009864c1cSStefan-gabriel Mirea { 57109864c1cSStefan-gabriel Mirea unsigned long cr; 57209864c1cSStefan-gabriel Mirea 57309864c1cSStefan-gabriel Mirea cr = readl(port->membase + UARTCR); 57409864c1cSStefan-gabriel Mirea 57509864c1cSStefan-gabriel Mirea writeb(ch, port->membase + BDRL); 57609864c1cSStefan-gabriel Mirea 57709864c1cSStefan-gabriel Mirea if (!(cr & LINFLEXD_UARTCR_TFBM)) 57809864c1cSStefan-gabriel Mirea while ((readl(port->membase + UARTSR) & 57909864c1cSStefan-gabriel Mirea LINFLEXD_UARTSR_DTFTFF) 58009864c1cSStefan-gabriel Mirea != LINFLEXD_UARTSR_DTFTFF) 58109864c1cSStefan-gabriel Mirea ; 58209864c1cSStefan-gabriel Mirea else 58309864c1cSStefan-gabriel Mirea while (readl(port->membase + UARTSR) & 58409864c1cSStefan-gabriel Mirea LINFLEXD_UARTSR_DTFTFF) 58509864c1cSStefan-gabriel Mirea ; 58609864c1cSStefan-gabriel Mirea 58709864c1cSStefan-gabriel Mirea if (!(cr & LINFLEXD_UARTCR_TFBM)) { 58809864c1cSStefan-gabriel Mirea writel((readl(port->membase + UARTSR) | 58909864c1cSStefan-gabriel Mirea LINFLEXD_UARTSR_DTFTFF), 59009864c1cSStefan-gabriel Mirea port->membase + UARTSR); 59109864c1cSStefan-gabriel Mirea } 59209864c1cSStefan-gabriel Mirea } 59309864c1cSStefan-gabriel Mirea 59409864c1cSStefan-gabriel Mirea static void linflex_earlycon_putchar(struct uart_port *port, int ch) 59509864c1cSStefan-gabriel Mirea { 59609864c1cSStefan-gabriel Mirea unsigned long flags; 59709864c1cSStefan-gabriel Mirea char *ret; 59809864c1cSStefan-gabriel Mirea 59909864c1cSStefan-gabriel Mirea if (!linflex_earlycon_same_instance) { 60009864c1cSStefan-gabriel Mirea linflex_console_putchar(port, ch); 60109864c1cSStefan-gabriel Mirea return; 60209864c1cSStefan-gabriel Mirea } 60309864c1cSStefan-gabriel Mirea 60409864c1cSStefan-gabriel Mirea spin_lock_irqsave(&init_lock, flags); 60509864c1cSStefan-gabriel Mirea if (!during_init) 60609864c1cSStefan-gabriel Mirea goto outside_init; 60709864c1cSStefan-gabriel Mirea 60809864c1cSStefan-gabriel Mirea if (earlycon_buf.len >= 1 << CONFIG_LOG_BUF_SHIFT) 60909864c1cSStefan-gabriel Mirea goto init_release; 61009864c1cSStefan-gabriel Mirea 61109864c1cSStefan-gabriel Mirea if (!earlycon_buf.cap) { 61209864c1cSStefan-gabriel Mirea earlycon_buf.content = kmalloc(EARLYCON_BUFFER_INITIAL_CAP, 61309864c1cSStefan-gabriel Mirea GFP_ATOMIC); 61409864c1cSStefan-gabriel Mirea earlycon_buf.cap = earlycon_buf.content ? 61509864c1cSStefan-gabriel Mirea EARLYCON_BUFFER_INITIAL_CAP : 0; 61609864c1cSStefan-gabriel Mirea } else if (earlycon_buf.len == earlycon_buf.cap) { 61709864c1cSStefan-gabriel Mirea ret = krealloc(earlycon_buf.content, earlycon_buf.cap << 1, 61809864c1cSStefan-gabriel Mirea GFP_ATOMIC); 61909864c1cSStefan-gabriel Mirea if (ret) { 62009864c1cSStefan-gabriel Mirea earlycon_buf.content = ret; 62109864c1cSStefan-gabriel Mirea earlycon_buf.cap <<= 1; 62209864c1cSStefan-gabriel Mirea } 62309864c1cSStefan-gabriel Mirea } 62409864c1cSStefan-gabriel Mirea 62509864c1cSStefan-gabriel Mirea if (earlycon_buf.len < earlycon_buf.cap) 62609864c1cSStefan-gabriel Mirea earlycon_buf.content[earlycon_buf.len++] = ch; 62709864c1cSStefan-gabriel Mirea 62809864c1cSStefan-gabriel Mirea goto init_release; 62909864c1cSStefan-gabriel Mirea 63009864c1cSStefan-gabriel Mirea outside_init: 63109864c1cSStefan-gabriel Mirea linflex_console_putchar(port, ch); 63209864c1cSStefan-gabriel Mirea init_release: 63309864c1cSStefan-gabriel Mirea spin_unlock_irqrestore(&init_lock, flags); 63409864c1cSStefan-gabriel Mirea } 63509864c1cSStefan-gabriel Mirea 63609864c1cSStefan-gabriel Mirea static void linflex_string_write(struct uart_port *sport, const char *s, 63709864c1cSStefan-gabriel Mirea unsigned int count) 63809864c1cSStefan-gabriel Mirea { 63909864c1cSStefan-gabriel Mirea unsigned long cr, ier = 0; 64009864c1cSStefan-gabriel Mirea 64109864c1cSStefan-gabriel Mirea ier = readl(sport->membase + LINIER); 64209864c1cSStefan-gabriel Mirea linflex_stop_tx(sport); 64309864c1cSStefan-gabriel Mirea 64409864c1cSStefan-gabriel Mirea cr = readl(sport->membase + UARTCR); 64509864c1cSStefan-gabriel Mirea cr |= (LINFLEXD_UARTCR_TXEN); 64609864c1cSStefan-gabriel Mirea writel(cr, sport->membase + UARTCR); 64709864c1cSStefan-gabriel Mirea 64809864c1cSStefan-gabriel Mirea uart_console_write(sport, s, count, linflex_console_putchar); 64909864c1cSStefan-gabriel Mirea 65009864c1cSStefan-gabriel Mirea writel(ier, sport->membase + LINIER); 65109864c1cSStefan-gabriel Mirea } 65209864c1cSStefan-gabriel Mirea 65309864c1cSStefan-gabriel Mirea static void 65409864c1cSStefan-gabriel Mirea linflex_console_write(struct console *co, const char *s, unsigned int count) 65509864c1cSStefan-gabriel Mirea { 65609864c1cSStefan-gabriel Mirea struct uart_port *sport = linflex_ports[co->index]; 65709864c1cSStefan-gabriel Mirea unsigned long flags; 65809864c1cSStefan-gabriel Mirea int locked = 1; 65909864c1cSStefan-gabriel Mirea 66009864c1cSStefan-gabriel Mirea if (sport->sysrq) 66109864c1cSStefan-gabriel Mirea locked = 0; 66209864c1cSStefan-gabriel Mirea else if (oops_in_progress) 66309864c1cSStefan-gabriel Mirea locked = spin_trylock_irqsave(&sport->lock, flags); 66409864c1cSStefan-gabriel Mirea else 66509864c1cSStefan-gabriel Mirea spin_lock_irqsave(&sport->lock, flags); 66609864c1cSStefan-gabriel Mirea 66709864c1cSStefan-gabriel Mirea linflex_string_write(sport, s, count); 66809864c1cSStefan-gabriel Mirea 66909864c1cSStefan-gabriel Mirea if (locked) 67009864c1cSStefan-gabriel Mirea spin_unlock_irqrestore(&sport->lock, flags); 67109864c1cSStefan-gabriel Mirea } 67209864c1cSStefan-gabriel Mirea 67309864c1cSStefan-gabriel Mirea /* 67409864c1cSStefan-gabriel Mirea * if the port was already initialised (eg, by a boot loader), 67509864c1cSStefan-gabriel Mirea * try to determine the current setup. 67609864c1cSStefan-gabriel Mirea */ 67709864c1cSStefan-gabriel Mirea static void __init 67809864c1cSStefan-gabriel Mirea linflex_console_get_options(struct uart_port *sport, int *parity, int *bits) 67909864c1cSStefan-gabriel Mirea { 68009864c1cSStefan-gabriel Mirea unsigned long cr; 68109864c1cSStefan-gabriel Mirea 68209864c1cSStefan-gabriel Mirea cr = readl(sport->membase + UARTCR); 68309864c1cSStefan-gabriel Mirea cr &= LINFLEXD_UARTCR_RXEN | LINFLEXD_UARTCR_TXEN; 68409864c1cSStefan-gabriel Mirea 68509864c1cSStefan-gabriel Mirea if (!cr) 68609864c1cSStefan-gabriel Mirea return; 68709864c1cSStefan-gabriel Mirea 68809864c1cSStefan-gabriel Mirea /* ok, the port was enabled */ 68909864c1cSStefan-gabriel Mirea 69009864c1cSStefan-gabriel Mirea *parity = 'n'; 69109864c1cSStefan-gabriel Mirea if (cr & LINFLEXD_UARTCR_PCE) { 69209864c1cSStefan-gabriel Mirea if (cr & LINFLEXD_UARTCR_PC0) 69309864c1cSStefan-gabriel Mirea *parity = 'o'; 69409864c1cSStefan-gabriel Mirea else 69509864c1cSStefan-gabriel Mirea *parity = 'e'; 69609864c1cSStefan-gabriel Mirea } 69709864c1cSStefan-gabriel Mirea 69809864c1cSStefan-gabriel Mirea if ((cr & LINFLEXD_UARTCR_WL0) && ((cr & LINFLEXD_UARTCR_WL1) == 0)) { 69909864c1cSStefan-gabriel Mirea if (cr & LINFLEXD_UARTCR_PCE) 70009864c1cSStefan-gabriel Mirea *bits = 9; 70109864c1cSStefan-gabriel Mirea else 70209864c1cSStefan-gabriel Mirea *bits = 8; 70309864c1cSStefan-gabriel Mirea } 70409864c1cSStefan-gabriel Mirea } 70509864c1cSStefan-gabriel Mirea 70609864c1cSStefan-gabriel Mirea static int __init linflex_console_setup(struct console *co, char *options) 70709864c1cSStefan-gabriel Mirea { 70809864c1cSStefan-gabriel Mirea struct uart_port *sport; 70909864c1cSStefan-gabriel Mirea int baud = 115200; 71009864c1cSStefan-gabriel Mirea int bits = 8; 71109864c1cSStefan-gabriel Mirea int parity = 'n'; 71209864c1cSStefan-gabriel Mirea int flow = 'n'; 71309864c1cSStefan-gabriel Mirea int ret; 71409864c1cSStefan-gabriel Mirea int i; 71509864c1cSStefan-gabriel Mirea unsigned long flags; 71609864c1cSStefan-gabriel Mirea /* 71709864c1cSStefan-gabriel Mirea * check whether an invalid uart number has been specified, and 71809864c1cSStefan-gabriel Mirea * if so, search for the first available port that does have 71909864c1cSStefan-gabriel Mirea * console support. 72009864c1cSStefan-gabriel Mirea */ 72109864c1cSStefan-gabriel Mirea if (co->index == -1 || co->index >= ARRAY_SIZE(linflex_ports)) 72209864c1cSStefan-gabriel Mirea co->index = 0; 72309864c1cSStefan-gabriel Mirea 72409864c1cSStefan-gabriel Mirea sport = linflex_ports[co->index]; 72509864c1cSStefan-gabriel Mirea if (!sport) 72609864c1cSStefan-gabriel Mirea return -ENODEV; 72709864c1cSStefan-gabriel Mirea 72809864c1cSStefan-gabriel Mirea if (options) 72909864c1cSStefan-gabriel Mirea uart_parse_options(options, &baud, &parity, &bits, &flow); 73009864c1cSStefan-gabriel Mirea else 73109864c1cSStefan-gabriel Mirea linflex_console_get_options(sport, &parity, &bits); 73209864c1cSStefan-gabriel Mirea 73309864c1cSStefan-gabriel Mirea if (earlycon_port && sport->mapbase == earlycon_port->mapbase) { 73409864c1cSStefan-gabriel Mirea linflex_earlycon_same_instance = true; 73509864c1cSStefan-gabriel Mirea 73609864c1cSStefan-gabriel Mirea spin_lock_irqsave(&init_lock, flags); 73709864c1cSStefan-gabriel Mirea during_init = true; 73809864c1cSStefan-gabriel Mirea spin_unlock_irqrestore(&init_lock, flags); 73909864c1cSStefan-gabriel Mirea 74009864c1cSStefan-gabriel Mirea /* Workaround for character loss or output of many invalid 74109864c1cSStefan-gabriel Mirea * characters, when INIT mode is entered shortly after a 74209864c1cSStefan-gabriel Mirea * character has just been printed. 74309864c1cSStefan-gabriel Mirea */ 74409864c1cSStefan-gabriel Mirea udelay(PREINIT_DELAY); 74509864c1cSStefan-gabriel Mirea } 74609864c1cSStefan-gabriel Mirea 74709864c1cSStefan-gabriel Mirea linflex_setup_watermark(sport); 74809864c1cSStefan-gabriel Mirea 74909864c1cSStefan-gabriel Mirea ret = uart_set_options(sport, co, baud, parity, bits, flow); 75009864c1cSStefan-gabriel Mirea 75109864c1cSStefan-gabriel Mirea if (!linflex_earlycon_same_instance) 75209864c1cSStefan-gabriel Mirea goto done; 75309864c1cSStefan-gabriel Mirea 75409864c1cSStefan-gabriel Mirea spin_lock_irqsave(&init_lock, flags); 75509864c1cSStefan-gabriel Mirea 75609864c1cSStefan-gabriel Mirea /* Emptying buffer */ 75709864c1cSStefan-gabriel Mirea if (earlycon_buf.len) { 75809864c1cSStefan-gabriel Mirea for (i = 0; i < earlycon_buf.len; i++) 75909864c1cSStefan-gabriel Mirea linflex_console_putchar(earlycon_port, 76009864c1cSStefan-gabriel Mirea earlycon_buf.content[i]); 76109864c1cSStefan-gabriel Mirea 76209864c1cSStefan-gabriel Mirea kfree(earlycon_buf.content); 76309864c1cSStefan-gabriel Mirea earlycon_buf.len = 0; 76409864c1cSStefan-gabriel Mirea } 76509864c1cSStefan-gabriel Mirea 76609864c1cSStefan-gabriel Mirea during_init = false; 76709864c1cSStefan-gabriel Mirea spin_unlock_irqrestore(&init_lock, flags); 76809864c1cSStefan-gabriel Mirea 76909864c1cSStefan-gabriel Mirea done: 77009864c1cSStefan-gabriel Mirea return ret; 77109864c1cSStefan-gabriel Mirea } 77209864c1cSStefan-gabriel Mirea 77309864c1cSStefan-gabriel Mirea static struct uart_driver linflex_reg; 77409864c1cSStefan-gabriel Mirea static struct console linflex_console = { 77509864c1cSStefan-gabriel Mirea .name = DEV_NAME, 77609864c1cSStefan-gabriel Mirea .write = linflex_console_write, 77709864c1cSStefan-gabriel Mirea .device = uart_console_device, 77809864c1cSStefan-gabriel Mirea .setup = linflex_console_setup, 77909864c1cSStefan-gabriel Mirea .flags = CON_PRINTBUFFER, 78009864c1cSStefan-gabriel Mirea .index = -1, 78109864c1cSStefan-gabriel Mirea .data = &linflex_reg, 78209864c1cSStefan-gabriel Mirea }; 78309864c1cSStefan-gabriel Mirea 78409864c1cSStefan-gabriel Mirea static void linflex_earlycon_write(struct console *con, const char *s, 78509864c1cSStefan-gabriel Mirea unsigned int n) 78609864c1cSStefan-gabriel Mirea { 78709864c1cSStefan-gabriel Mirea struct earlycon_device *dev = con->data; 78809864c1cSStefan-gabriel Mirea 78909864c1cSStefan-gabriel Mirea uart_console_write(&dev->port, s, n, linflex_earlycon_putchar); 79009864c1cSStefan-gabriel Mirea } 79109864c1cSStefan-gabriel Mirea 79209864c1cSStefan-gabriel Mirea static int __init linflex_early_console_setup(struct earlycon_device *device, 79309864c1cSStefan-gabriel Mirea const char *options) 79409864c1cSStefan-gabriel Mirea { 79509864c1cSStefan-gabriel Mirea if (!device->port.membase) 79609864c1cSStefan-gabriel Mirea return -ENODEV; 79709864c1cSStefan-gabriel Mirea 79809864c1cSStefan-gabriel Mirea device->con->write = linflex_earlycon_write; 79909864c1cSStefan-gabriel Mirea earlycon_port = &device->port; 80009864c1cSStefan-gabriel Mirea 80109864c1cSStefan-gabriel Mirea return 0; 80209864c1cSStefan-gabriel Mirea } 80309864c1cSStefan-gabriel Mirea 80409864c1cSStefan-gabriel Mirea OF_EARLYCON_DECLARE(linflex, "fsl,s32-linflexuart", 80509864c1cSStefan-gabriel Mirea linflex_early_console_setup); 80609864c1cSStefan-gabriel Mirea 80709864c1cSStefan-gabriel Mirea #define LINFLEX_CONSOLE (&linflex_console) 80809864c1cSStefan-gabriel Mirea #else 80909864c1cSStefan-gabriel Mirea #define LINFLEX_CONSOLE NULL 81009864c1cSStefan-gabriel Mirea #endif 81109864c1cSStefan-gabriel Mirea 81209864c1cSStefan-gabriel Mirea static struct uart_driver linflex_reg = { 81309864c1cSStefan-gabriel Mirea .owner = THIS_MODULE, 81409864c1cSStefan-gabriel Mirea .driver_name = DRIVER_NAME, 81509864c1cSStefan-gabriel Mirea .dev_name = DEV_NAME, 81609864c1cSStefan-gabriel Mirea .nr = ARRAY_SIZE(linflex_ports), 81709864c1cSStefan-gabriel Mirea .cons = LINFLEX_CONSOLE, 81809864c1cSStefan-gabriel Mirea }; 81909864c1cSStefan-gabriel Mirea 82009864c1cSStefan-gabriel Mirea static int linflex_probe(struct platform_device *pdev) 82109864c1cSStefan-gabriel Mirea { 82209864c1cSStefan-gabriel Mirea struct device_node *np = pdev->dev.of_node; 82309864c1cSStefan-gabriel Mirea struct uart_port *sport; 82409864c1cSStefan-gabriel Mirea struct resource *res; 82509864c1cSStefan-gabriel Mirea int ret; 82609864c1cSStefan-gabriel Mirea 82709864c1cSStefan-gabriel Mirea sport = devm_kzalloc(&pdev->dev, sizeof(*sport), GFP_KERNEL); 82809864c1cSStefan-gabriel Mirea if (!sport) 82909864c1cSStefan-gabriel Mirea return -ENOMEM; 83009864c1cSStefan-gabriel Mirea 83109864c1cSStefan-gabriel Mirea ret = of_alias_get_id(np, "serial"); 83209864c1cSStefan-gabriel Mirea if (ret < 0) { 83309864c1cSStefan-gabriel Mirea dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret); 83409864c1cSStefan-gabriel Mirea return ret; 83509864c1cSStefan-gabriel Mirea } 83609864c1cSStefan-gabriel Mirea if (ret >= UART_NR) { 83709864c1cSStefan-gabriel Mirea dev_err(&pdev->dev, "driver limited to %d serial ports\n", 83809864c1cSStefan-gabriel Mirea UART_NR); 83909864c1cSStefan-gabriel Mirea return -ENOMEM; 84009864c1cSStefan-gabriel Mirea } 84109864c1cSStefan-gabriel Mirea 84209864c1cSStefan-gabriel Mirea sport->line = ret; 84309864c1cSStefan-gabriel Mirea 84409864c1cSStefan-gabriel Mirea res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 84509864c1cSStefan-gabriel Mirea if (!res) 84609864c1cSStefan-gabriel Mirea return -ENODEV; 84709864c1cSStefan-gabriel Mirea 84809864c1cSStefan-gabriel Mirea sport->mapbase = res->start; 84909864c1cSStefan-gabriel Mirea sport->membase = devm_ioremap_resource(&pdev->dev, res); 85009864c1cSStefan-gabriel Mirea if (IS_ERR(sport->membase)) 85109864c1cSStefan-gabriel Mirea return PTR_ERR(sport->membase); 85209864c1cSStefan-gabriel Mirea 85309864c1cSStefan-gabriel Mirea sport->dev = &pdev->dev; 85409864c1cSStefan-gabriel Mirea sport->type = PORT_LINFLEXUART; 85509864c1cSStefan-gabriel Mirea sport->iotype = UPIO_MEM; 85609864c1cSStefan-gabriel Mirea sport->irq = platform_get_irq(pdev, 0); 85709864c1cSStefan-gabriel Mirea sport->ops = &linflex_pops; 85809864c1cSStefan-gabriel Mirea sport->flags = UPF_BOOT_AUTOCONF; 85909864c1cSStefan-gabriel Mirea 86009864c1cSStefan-gabriel Mirea linflex_ports[sport->line] = sport; 86109864c1cSStefan-gabriel Mirea 86209864c1cSStefan-gabriel Mirea platform_set_drvdata(pdev, sport); 86309864c1cSStefan-gabriel Mirea 86409864c1cSStefan-gabriel Mirea ret = uart_add_one_port(&linflex_reg, sport); 86509864c1cSStefan-gabriel Mirea if (ret) 86609864c1cSStefan-gabriel Mirea return ret; 86709864c1cSStefan-gabriel Mirea 86809864c1cSStefan-gabriel Mirea return 0; 86909864c1cSStefan-gabriel Mirea } 87009864c1cSStefan-gabriel Mirea 87109864c1cSStefan-gabriel Mirea static int linflex_remove(struct platform_device *pdev) 87209864c1cSStefan-gabriel Mirea { 87309864c1cSStefan-gabriel Mirea struct uart_port *sport = platform_get_drvdata(pdev); 87409864c1cSStefan-gabriel Mirea 87509864c1cSStefan-gabriel Mirea uart_remove_one_port(&linflex_reg, sport); 87609864c1cSStefan-gabriel Mirea 87709864c1cSStefan-gabriel Mirea return 0; 87809864c1cSStefan-gabriel Mirea } 87909864c1cSStefan-gabriel Mirea 88009864c1cSStefan-gabriel Mirea #ifdef CONFIG_PM_SLEEP 88109864c1cSStefan-gabriel Mirea static int linflex_suspend(struct device *dev) 88209864c1cSStefan-gabriel Mirea { 88309864c1cSStefan-gabriel Mirea struct uart_port *sport = dev_get_drvdata(dev); 88409864c1cSStefan-gabriel Mirea 88509864c1cSStefan-gabriel Mirea uart_suspend_port(&linflex_reg, sport); 88609864c1cSStefan-gabriel Mirea 88709864c1cSStefan-gabriel Mirea return 0; 88809864c1cSStefan-gabriel Mirea } 88909864c1cSStefan-gabriel Mirea 89009864c1cSStefan-gabriel Mirea static int linflex_resume(struct device *dev) 89109864c1cSStefan-gabriel Mirea { 89209864c1cSStefan-gabriel Mirea struct uart_port *sport = dev_get_drvdata(dev); 89309864c1cSStefan-gabriel Mirea 89409864c1cSStefan-gabriel Mirea uart_resume_port(&linflex_reg, sport); 89509864c1cSStefan-gabriel Mirea 89609864c1cSStefan-gabriel Mirea return 0; 89709864c1cSStefan-gabriel Mirea } 89809864c1cSStefan-gabriel Mirea #endif 89909864c1cSStefan-gabriel Mirea 90009864c1cSStefan-gabriel Mirea static SIMPLE_DEV_PM_OPS(linflex_pm_ops, linflex_suspend, linflex_resume); 90109864c1cSStefan-gabriel Mirea 90209864c1cSStefan-gabriel Mirea static struct platform_driver linflex_driver = { 90309864c1cSStefan-gabriel Mirea .probe = linflex_probe, 90409864c1cSStefan-gabriel Mirea .remove = linflex_remove, 90509864c1cSStefan-gabriel Mirea .driver = { 90609864c1cSStefan-gabriel Mirea .name = DRIVER_NAME, 90709864c1cSStefan-gabriel Mirea .owner = THIS_MODULE, 90809864c1cSStefan-gabriel Mirea .of_match_table = linflex_dt_ids, 90909864c1cSStefan-gabriel Mirea .pm = &linflex_pm_ops, 91009864c1cSStefan-gabriel Mirea }, 91109864c1cSStefan-gabriel Mirea }; 91209864c1cSStefan-gabriel Mirea 91309864c1cSStefan-gabriel Mirea static int __init linflex_serial_init(void) 91409864c1cSStefan-gabriel Mirea { 91509864c1cSStefan-gabriel Mirea int ret; 91609864c1cSStefan-gabriel Mirea 91709864c1cSStefan-gabriel Mirea ret = uart_register_driver(&linflex_reg); 91809864c1cSStefan-gabriel Mirea if (ret) 91909864c1cSStefan-gabriel Mirea return ret; 92009864c1cSStefan-gabriel Mirea 92109864c1cSStefan-gabriel Mirea ret = platform_driver_register(&linflex_driver); 92209864c1cSStefan-gabriel Mirea if (ret) 92309864c1cSStefan-gabriel Mirea uart_unregister_driver(&linflex_reg); 92409864c1cSStefan-gabriel Mirea 92509864c1cSStefan-gabriel Mirea return ret; 92609864c1cSStefan-gabriel Mirea } 92709864c1cSStefan-gabriel Mirea 92809864c1cSStefan-gabriel Mirea static void __exit linflex_serial_exit(void) 92909864c1cSStefan-gabriel Mirea { 93009864c1cSStefan-gabriel Mirea platform_driver_unregister(&linflex_driver); 93109864c1cSStefan-gabriel Mirea uart_unregister_driver(&linflex_reg); 93209864c1cSStefan-gabriel Mirea } 93309864c1cSStefan-gabriel Mirea 93409864c1cSStefan-gabriel Mirea module_init(linflex_serial_init); 93509864c1cSStefan-gabriel Mirea module_exit(linflex_serial_exit); 93609864c1cSStefan-gabriel Mirea 93709864c1cSStefan-gabriel Mirea MODULE_DESCRIPTION("Freescale linflex serial port driver"); 93809864c1cSStefan-gabriel Mirea MODULE_LICENSE("GPL v2"); 939