109864c1cSStefan-gabriel Mirea // SPDX-License-Identifier: GPL-2.0-or-later 209864c1cSStefan-gabriel Mirea /* 3*9905f32aSStefan-Gabriel Mirea * Freescale LINFlexD UART serial port driver 409864c1cSStefan-gabriel Mirea * 509864c1cSStefan-gabriel Mirea * Copyright 2012-2016 Freescale Semiconductor, Inc. 690500797SStefan-gabriel Mirea * Copyright 2017-2019 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 { 1302bd3661eSStefan-gabriel Mirea .compatible = "fsl,s32v234-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; 13906e9b2feSWei 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; 24990500797SStefan-gabriel Mirea bool brk; 25009864c1cSStefan-gabriel Mirea 25109864c1cSStefan-gabriel Mirea spin_lock_irqsave(&sport->lock, flags); 25209864c1cSStefan-gabriel Mirea 25309864c1cSStefan-gabriel Mirea status = readl(sport->membase + UARTSR); 25409864c1cSStefan-gabriel Mirea while (status & LINFLEXD_UARTSR_RMB) { 25509864c1cSStefan-gabriel Mirea rx = readb(sport->membase + BDRM); 25690500797SStefan-gabriel Mirea brk = false; 25709864c1cSStefan-gabriel Mirea flg = TTY_NORMAL; 25809864c1cSStefan-gabriel Mirea sport->icount.rx++; 25909864c1cSStefan-gabriel Mirea 26009864c1cSStefan-gabriel Mirea if (status & (LINFLEXD_UARTSR_BOF | LINFLEXD_UARTSR_SZF | 26109864c1cSStefan-gabriel Mirea LINFLEXD_UARTSR_FEF | LINFLEXD_UARTSR_PE)) { 26209864c1cSStefan-gabriel Mirea if (status & LINFLEXD_UARTSR_SZF) 26309864c1cSStefan-gabriel Mirea status |= LINFLEXD_UARTSR_SZF; 26409864c1cSStefan-gabriel Mirea if (status & LINFLEXD_UARTSR_BOF) 26509864c1cSStefan-gabriel Mirea status |= LINFLEXD_UARTSR_BOF; 26690500797SStefan-gabriel Mirea if (status & LINFLEXD_UARTSR_FEF) { 26790500797SStefan-gabriel Mirea if (!rx) 26890500797SStefan-gabriel Mirea brk = true; 26909864c1cSStefan-gabriel Mirea status |= LINFLEXD_UARTSR_FEF; 27090500797SStefan-gabriel Mirea } 27109864c1cSStefan-gabriel Mirea if (status & LINFLEXD_UARTSR_PE) 27209864c1cSStefan-gabriel Mirea status |= LINFLEXD_UARTSR_PE; 27309864c1cSStefan-gabriel Mirea } 27409864c1cSStefan-gabriel Mirea 27509864c1cSStefan-gabriel Mirea writel(status | LINFLEXD_UARTSR_RMB | LINFLEXD_UARTSR_DRFRFE, 27609864c1cSStefan-gabriel Mirea sport->membase + UARTSR); 27709864c1cSStefan-gabriel Mirea status = readl(sport->membase + UARTSR); 27809864c1cSStefan-gabriel Mirea 27990500797SStefan-gabriel Mirea if (brk) { 28090500797SStefan-gabriel Mirea uart_handle_break(sport); 28190500797SStefan-gabriel Mirea } else { 28290500797SStefan-gabriel Mirea #ifdef SUPPORT_SYSRQ 28309864c1cSStefan-gabriel Mirea if (uart_handle_sysrq_char(sport, (unsigned char)rx)) 28409864c1cSStefan-gabriel Mirea continue; 28509864c1cSStefan-gabriel Mirea #endif 28609864c1cSStefan-gabriel Mirea tty_insert_flip_char(port, rx, flg); 28709864c1cSStefan-gabriel Mirea } 28890500797SStefan-gabriel Mirea } 28909864c1cSStefan-gabriel Mirea 29009864c1cSStefan-gabriel Mirea spin_unlock_irqrestore(&sport->lock, flags); 29109864c1cSStefan-gabriel Mirea 29209864c1cSStefan-gabriel Mirea tty_flip_buffer_push(port); 29309864c1cSStefan-gabriel Mirea 29409864c1cSStefan-gabriel Mirea return IRQ_HANDLED; 29509864c1cSStefan-gabriel Mirea } 29609864c1cSStefan-gabriel Mirea 29709864c1cSStefan-gabriel Mirea static irqreturn_t linflex_int(int irq, void *dev_id) 29809864c1cSStefan-gabriel Mirea { 29909864c1cSStefan-gabriel Mirea struct uart_port *sport = dev_id; 30009864c1cSStefan-gabriel Mirea unsigned long status; 30109864c1cSStefan-gabriel Mirea 30209864c1cSStefan-gabriel Mirea status = readl(sport->membase + UARTSR); 30309864c1cSStefan-gabriel Mirea 30409864c1cSStefan-gabriel Mirea if (status & LINFLEXD_UARTSR_DRFRFE) 30509864c1cSStefan-gabriel Mirea linflex_rxint(irq, dev_id); 30609864c1cSStefan-gabriel Mirea if (status & LINFLEXD_UARTSR_DTFTFF) 30709864c1cSStefan-gabriel Mirea linflex_txint(irq, dev_id); 30809864c1cSStefan-gabriel Mirea 30909864c1cSStefan-gabriel Mirea return IRQ_HANDLED; 31009864c1cSStefan-gabriel Mirea } 31109864c1cSStefan-gabriel Mirea 31209864c1cSStefan-gabriel Mirea /* return TIOCSER_TEMT when transmitter is not busy */ 31309864c1cSStefan-gabriel Mirea static unsigned int linflex_tx_empty(struct uart_port *port) 31409864c1cSStefan-gabriel Mirea { 31509864c1cSStefan-gabriel Mirea unsigned long status; 31609864c1cSStefan-gabriel Mirea 31709864c1cSStefan-gabriel Mirea status = readl(port->membase + UARTSR) & LINFLEXD_UARTSR_DTFTFF; 31809864c1cSStefan-gabriel Mirea 31909864c1cSStefan-gabriel Mirea return status ? TIOCSER_TEMT : 0; 32009864c1cSStefan-gabriel Mirea } 32109864c1cSStefan-gabriel Mirea 32209864c1cSStefan-gabriel Mirea static unsigned int linflex_get_mctrl(struct uart_port *port) 32309864c1cSStefan-gabriel Mirea { 32409864c1cSStefan-gabriel Mirea return 0; 32509864c1cSStefan-gabriel Mirea } 32609864c1cSStefan-gabriel Mirea 32709864c1cSStefan-gabriel Mirea static void linflex_set_mctrl(struct uart_port *port, unsigned int mctrl) 32809864c1cSStefan-gabriel Mirea { 32909864c1cSStefan-gabriel Mirea } 33009864c1cSStefan-gabriel Mirea 33109864c1cSStefan-gabriel Mirea static void linflex_break_ctl(struct uart_port *port, int break_state) 33209864c1cSStefan-gabriel Mirea { 33309864c1cSStefan-gabriel Mirea } 33409864c1cSStefan-gabriel Mirea 33509864c1cSStefan-gabriel Mirea static void linflex_setup_watermark(struct uart_port *sport) 33609864c1cSStefan-gabriel Mirea { 33709864c1cSStefan-gabriel Mirea unsigned long cr, ier, cr1; 33809864c1cSStefan-gabriel Mirea 33909864c1cSStefan-gabriel Mirea /* Disable transmission/reception */ 34009864c1cSStefan-gabriel Mirea ier = readl(sport->membase + LINIER); 34109864c1cSStefan-gabriel Mirea ier &= ~(LINFLEXD_LINIER_DRIE | LINFLEXD_LINIER_DTIE); 34209864c1cSStefan-gabriel Mirea writel(ier, sport->membase + LINIER); 34309864c1cSStefan-gabriel Mirea 34409864c1cSStefan-gabriel Mirea cr = readl(sport->membase + UARTCR); 34509864c1cSStefan-gabriel Mirea cr &= ~(LINFLEXD_UARTCR_RXEN | LINFLEXD_UARTCR_TXEN); 34609864c1cSStefan-gabriel Mirea writel(cr, sport->membase + UARTCR); 34709864c1cSStefan-gabriel Mirea 34809864c1cSStefan-gabriel Mirea /* Enter initialization mode by setting INIT bit */ 34909864c1cSStefan-gabriel Mirea 35009864c1cSStefan-gabriel Mirea /* set the Linflex in master mode and activate by-pass filter */ 35109864c1cSStefan-gabriel Mirea cr1 = LINFLEXD_LINCR1_BF | LINFLEXD_LINCR1_MME 35209864c1cSStefan-gabriel Mirea | LINFLEXD_LINCR1_INIT; 35309864c1cSStefan-gabriel Mirea writel(cr1, sport->membase + LINCR1); 35409864c1cSStefan-gabriel Mirea 35509864c1cSStefan-gabriel Mirea /* wait for init mode entry */ 35609864c1cSStefan-gabriel Mirea while ((readl(sport->membase + LINSR) 35709864c1cSStefan-gabriel Mirea & LINFLEXD_LINSR_LINS_MASK) 35809864c1cSStefan-gabriel Mirea != LINFLEXD_LINSR_LINS_INITMODE) 35909864c1cSStefan-gabriel Mirea ; 36009864c1cSStefan-gabriel Mirea 36109864c1cSStefan-gabriel Mirea /* 36209864c1cSStefan-gabriel Mirea * UART = 0x1; - Linflex working in UART mode 36309864c1cSStefan-gabriel Mirea * TXEN = 0x1; - Enable transmission of data now 36409864c1cSStefan-gabriel Mirea * RXEn = 0x1; - Receiver enabled 36509864c1cSStefan-gabriel Mirea * WL0 = 0x1; - 8 bit data 36609864c1cSStefan-gabriel Mirea * PCE = 0x0; - No parity 36709864c1cSStefan-gabriel Mirea */ 36809864c1cSStefan-gabriel Mirea 36909864c1cSStefan-gabriel Mirea /* set UART bit to allow writing other bits */ 37009864c1cSStefan-gabriel Mirea writel(LINFLEXD_UARTCR_UART, sport->membase + UARTCR); 37109864c1cSStefan-gabriel Mirea 37209864c1cSStefan-gabriel Mirea cr = (LINFLEXD_UARTCR_RXEN | LINFLEXD_UARTCR_TXEN | 37309864c1cSStefan-gabriel Mirea LINFLEXD_UARTCR_WL0 | LINFLEXD_UARTCR_UART); 37409864c1cSStefan-gabriel Mirea 37509864c1cSStefan-gabriel Mirea writel(cr, sport->membase + UARTCR); 37609864c1cSStefan-gabriel Mirea 37709864c1cSStefan-gabriel Mirea cr1 &= ~(LINFLEXD_LINCR1_INIT); 37809864c1cSStefan-gabriel Mirea 37909864c1cSStefan-gabriel Mirea writel(cr1, sport->membase + LINCR1); 38009864c1cSStefan-gabriel Mirea 38109864c1cSStefan-gabriel Mirea ier = readl(sport->membase + LINIER); 38209864c1cSStefan-gabriel Mirea ier |= LINFLEXD_LINIER_DRIE; 38309864c1cSStefan-gabriel Mirea ier |= LINFLEXD_LINIER_DTIE; 38409864c1cSStefan-gabriel Mirea 38509864c1cSStefan-gabriel Mirea writel(ier, sport->membase + LINIER); 38609864c1cSStefan-gabriel Mirea } 38709864c1cSStefan-gabriel Mirea 38809864c1cSStefan-gabriel Mirea static int linflex_startup(struct uart_port *port) 38909864c1cSStefan-gabriel Mirea { 39009864c1cSStefan-gabriel Mirea int ret = 0; 39109864c1cSStefan-gabriel Mirea unsigned long flags; 39209864c1cSStefan-gabriel Mirea 39309864c1cSStefan-gabriel Mirea spin_lock_irqsave(&port->lock, flags); 39409864c1cSStefan-gabriel Mirea 39509864c1cSStefan-gabriel Mirea linflex_setup_watermark(port); 39609864c1cSStefan-gabriel Mirea 39709864c1cSStefan-gabriel Mirea spin_unlock_irqrestore(&port->lock, flags); 39809864c1cSStefan-gabriel Mirea 39909864c1cSStefan-gabriel Mirea ret = devm_request_irq(port->dev, port->irq, linflex_int, 0, 40009864c1cSStefan-gabriel Mirea DRIVER_NAME, port); 40109864c1cSStefan-gabriel Mirea 40209864c1cSStefan-gabriel Mirea return ret; 40309864c1cSStefan-gabriel Mirea } 40409864c1cSStefan-gabriel Mirea 40509864c1cSStefan-gabriel Mirea static void linflex_shutdown(struct uart_port *port) 40609864c1cSStefan-gabriel Mirea { 40709864c1cSStefan-gabriel Mirea unsigned long ier; 40809864c1cSStefan-gabriel Mirea unsigned long flags; 40909864c1cSStefan-gabriel Mirea 41009864c1cSStefan-gabriel Mirea spin_lock_irqsave(&port->lock, flags); 41109864c1cSStefan-gabriel Mirea 41209864c1cSStefan-gabriel Mirea /* disable interrupts */ 41309864c1cSStefan-gabriel Mirea ier = readl(port->membase + LINIER); 41409864c1cSStefan-gabriel Mirea ier &= ~(LINFLEXD_LINIER_DRIE | LINFLEXD_LINIER_DTIE); 41509864c1cSStefan-gabriel Mirea writel(ier, port->membase + LINIER); 41609864c1cSStefan-gabriel Mirea 41709864c1cSStefan-gabriel Mirea spin_unlock_irqrestore(&port->lock, flags); 41809864c1cSStefan-gabriel Mirea 41909864c1cSStefan-gabriel Mirea devm_free_irq(port->dev, port->irq, port); 42009864c1cSStefan-gabriel Mirea } 42109864c1cSStefan-gabriel Mirea 42209864c1cSStefan-gabriel Mirea static void 42309864c1cSStefan-gabriel Mirea linflex_set_termios(struct uart_port *port, struct ktermios *termios, 42409864c1cSStefan-gabriel Mirea struct ktermios *old) 42509864c1cSStefan-gabriel Mirea { 42609864c1cSStefan-gabriel Mirea unsigned long flags; 42709864c1cSStefan-gabriel Mirea unsigned long cr, old_cr, cr1; 42809864c1cSStefan-gabriel Mirea unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; 42909864c1cSStefan-gabriel Mirea 43009864c1cSStefan-gabriel Mirea cr = readl(port->membase + UARTCR); 43109864c1cSStefan-gabriel Mirea old_cr = cr; 43209864c1cSStefan-gabriel Mirea 43309864c1cSStefan-gabriel Mirea /* Enter initialization mode by setting INIT bit */ 43409864c1cSStefan-gabriel Mirea cr1 = readl(port->membase + LINCR1); 43509864c1cSStefan-gabriel Mirea cr1 |= LINFLEXD_LINCR1_INIT; 43609864c1cSStefan-gabriel Mirea writel(cr1, port->membase + LINCR1); 43709864c1cSStefan-gabriel Mirea 43809864c1cSStefan-gabriel Mirea /* wait for init mode entry */ 43909864c1cSStefan-gabriel Mirea while ((readl(port->membase + LINSR) 44009864c1cSStefan-gabriel Mirea & LINFLEXD_LINSR_LINS_MASK) 44109864c1cSStefan-gabriel Mirea != LINFLEXD_LINSR_LINS_INITMODE) 44209864c1cSStefan-gabriel Mirea ; 44309864c1cSStefan-gabriel Mirea 44409864c1cSStefan-gabriel Mirea /* 44509864c1cSStefan-gabriel Mirea * only support CS8 and CS7, and for CS7 must enable PE. 44609864c1cSStefan-gabriel Mirea * supported mode: 44709864c1cSStefan-gabriel Mirea * - (7,e/o,1) 44809864c1cSStefan-gabriel Mirea * - (8,n,1) 44909864c1cSStefan-gabriel Mirea * - (8,e/o,1) 45009864c1cSStefan-gabriel Mirea */ 45109864c1cSStefan-gabriel Mirea /* enter the UART into configuration mode */ 45209864c1cSStefan-gabriel Mirea 45309864c1cSStefan-gabriel Mirea while ((termios->c_cflag & CSIZE) != CS8 && 45409864c1cSStefan-gabriel Mirea (termios->c_cflag & CSIZE) != CS7) { 45509864c1cSStefan-gabriel Mirea termios->c_cflag &= ~CSIZE; 45609864c1cSStefan-gabriel Mirea termios->c_cflag |= old_csize; 45709864c1cSStefan-gabriel Mirea old_csize = CS8; 45809864c1cSStefan-gabriel Mirea } 45909864c1cSStefan-gabriel Mirea 46009864c1cSStefan-gabriel Mirea if ((termios->c_cflag & CSIZE) == CS7) { 46109864c1cSStefan-gabriel Mirea /* Word length: WL1WL0:00 */ 46209864c1cSStefan-gabriel Mirea cr = old_cr & ~LINFLEXD_UARTCR_WL1 & ~LINFLEXD_UARTCR_WL0; 46309864c1cSStefan-gabriel Mirea } 46409864c1cSStefan-gabriel Mirea 46509864c1cSStefan-gabriel Mirea if ((termios->c_cflag & CSIZE) == CS8) { 46609864c1cSStefan-gabriel Mirea /* Word length: WL1WL0:01 */ 46709864c1cSStefan-gabriel Mirea cr = (old_cr | LINFLEXD_UARTCR_WL0) & ~LINFLEXD_UARTCR_WL1; 46809864c1cSStefan-gabriel Mirea } 46909864c1cSStefan-gabriel Mirea 47009864c1cSStefan-gabriel Mirea if (termios->c_cflag & CMSPAR) { 47109864c1cSStefan-gabriel Mirea if ((termios->c_cflag & CSIZE) != CS8) { 47209864c1cSStefan-gabriel Mirea termios->c_cflag &= ~CSIZE; 47309864c1cSStefan-gabriel Mirea termios->c_cflag |= CS8; 47409864c1cSStefan-gabriel Mirea } 47509864c1cSStefan-gabriel Mirea /* has a space/sticky bit */ 47609864c1cSStefan-gabriel Mirea cr |= LINFLEXD_UARTCR_WL0; 47709864c1cSStefan-gabriel Mirea } 47809864c1cSStefan-gabriel Mirea 47909864c1cSStefan-gabriel Mirea if (termios->c_cflag & CSTOPB) 48009864c1cSStefan-gabriel Mirea termios->c_cflag &= ~CSTOPB; 48109864c1cSStefan-gabriel Mirea 48209864c1cSStefan-gabriel Mirea /* parity must be enabled when CS7 to match 8-bits format */ 48309864c1cSStefan-gabriel Mirea if ((termios->c_cflag & CSIZE) == CS7) 48409864c1cSStefan-gabriel Mirea termios->c_cflag |= PARENB; 48509864c1cSStefan-gabriel Mirea 48609864c1cSStefan-gabriel Mirea if ((termios->c_cflag & PARENB)) { 48709864c1cSStefan-gabriel Mirea cr |= LINFLEXD_UARTCR_PCE; 48809864c1cSStefan-gabriel Mirea if (termios->c_cflag & PARODD) 48909864c1cSStefan-gabriel Mirea cr = (cr | LINFLEXD_UARTCR_PC0) & 49009864c1cSStefan-gabriel Mirea (~LINFLEXD_UARTCR_PC1); 49109864c1cSStefan-gabriel Mirea else 49209864c1cSStefan-gabriel Mirea cr = cr & (~LINFLEXD_UARTCR_PC1 & 49309864c1cSStefan-gabriel Mirea ~LINFLEXD_UARTCR_PC0); 49409864c1cSStefan-gabriel Mirea } else { 49509864c1cSStefan-gabriel Mirea cr &= ~LINFLEXD_UARTCR_PCE; 49609864c1cSStefan-gabriel Mirea } 49709864c1cSStefan-gabriel Mirea 49809864c1cSStefan-gabriel Mirea spin_lock_irqsave(&port->lock, flags); 49909864c1cSStefan-gabriel Mirea 50009864c1cSStefan-gabriel Mirea port->read_status_mask = 0; 50109864c1cSStefan-gabriel Mirea 50209864c1cSStefan-gabriel Mirea if (termios->c_iflag & INPCK) 50309864c1cSStefan-gabriel Mirea port->read_status_mask |= (LINFLEXD_UARTSR_FEF | 50409864c1cSStefan-gabriel Mirea LINFLEXD_UARTSR_PE0 | 50509864c1cSStefan-gabriel Mirea LINFLEXD_UARTSR_PE1 | 50609864c1cSStefan-gabriel Mirea LINFLEXD_UARTSR_PE2 | 50709864c1cSStefan-gabriel Mirea LINFLEXD_UARTSR_PE3); 50809864c1cSStefan-gabriel Mirea if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) 50909864c1cSStefan-gabriel Mirea port->read_status_mask |= LINFLEXD_UARTSR_FEF; 51009864c1cSStefan-gabriel Mirea 51109864c1cSStefan-gabriel Mirea /* characters to ignore */ 51209864c1cSStefan-gabriel Mirea port->ignore_status_mask = 0; 51309864c1cSStefan-gabriel Mirea if (termios->c_iflag & IGNPAR) 51409864c1cSStefan-gabriel Mirea port->ignore_status_mask |= LINFLEXD_UARTSR_PE; 51509864c1cSStefan-gabriel Mirea if (termios->c_iflag & IGNBRK) { 51609864c1cSStefan-gabriel Mirea port->ignore_status_mask |= LINFLEXD_UARTSR_PE; 51709864c1cSStefan-gabriel Mirea /* 51809864c1cSStefan-gabriel Mirea * if we're ignoring parity and break indicators, 51909864c1cSStefan-gabriel Mirea * ignore overruns too (for real raw support). 52009864c1cSStefan-gabriel Mirea */ 52109864c1cSStefan-gabriel Mirea if (termios->c_iflag & IGNPAR) 52209864c1cSStefan-gabriel Mirea port->ignore_status_mask |= LINFLEXD_UARTSR_BOF; 52309864c1cSStefan-gabriel Mirea } 52409864c1cSStefan-gabriel Mirea 52509864c1cSStefan-gabriel Mirea writel(cr, port->membase + UARTCR); 52609864c1cSStefan-gabriel Mirea 52709864c1cSStefan-gabriel Mirea cr1 &= ~(LINFLEXD_LINCR1_INIT); 52809864c1cSStefan-gabriel Mirea 52909864c1cSStefan-gabriel Mirea writel(cr1, port->membase + LINCR1); 53009864c1cSStefan-gabriel Mirea 53109864c1cSStefan-gabriel Mirea spin_unlock_irqrestore(&port->lock, flags); 53209864c1cSStefan-gabriel Mirea } 53309864c1cSStefan-gabriel Mirea 53409864c1cSStefan-gabriel Mirea static const char *linflex_type(struct uart_port *port) 53509864c1cSStefan-gabriel Mirea { 53609864c1cSStefan-gabriel Mirea return "FSL_LINFLEX"; 53709864c1cSStefan-gabriel Mirea } 53809864c1cSStefan-gabriel Mirea 53909864c1cSStefan-gabriel Mirea static void linflex_release_port(struct uart_port *port) 54009864c1cSStefan-gabriel Mirea { 54109864c1cSStefan-gabriel Mirea /* nothing to do */ 54209864c1cSStefan-gabriel Mirea } 54309864c1cSStefan-gabriel Mirea 54409864c1cSStefan-gabriel Mirea static int linflex_request_port(struct uart_port *port) 54509864c1cSStefan-gabriel Mirea { 54609864c1cSStefan-gabriel Mirea return 0; 54709864c1cSStefan-gabriel Mirea } 54809864c1cSStefan-gabriel Mirea 54909864c1cSStefan-gabriel Mirea /* configure/auto-configure the port */ 55009864c1cSStefan-gabriel Mirea static void linflex_config_port(struct uart_port *port, int flags) 55109864c1cSStefan-gabriel Mirea { 55209864c1cSStefan-gabriel Mirea if (flags & UART_CONFIG_TYPE) 55309864c1cSStefan-gabriel Mirea port->type = PORT_LINFLEXUART; 55409864c1cSStefan-gabriel Mirea } 55509864c1cSStefan-gabriel Mirea 55609864c1cSStefan-gabriel Mirea static const struct uart_ops linflex_pops = { 55709864c1cSStefan-gabriel Mirea .tx_empty = linflex_tx_empty, 55809864c1cSStefan-gabriel Mirea .set_mctrl = linflex_set_mctrl, 55909864c1cSStefan-gabriel Mirea .get_mctrl = linflex_get_mctrl, 56009864c1cSStefan-gabriel Mirea .stop_tx = linflex_stop_tx, 56109864c1cSStefan-gabriel Mirea .start_tx = linflex_start_tx, 56209864c1cSStefan-gabriel Mirea .stop_rx = linflex_stop_rx, 56309864c1cSStefan-gabriel Mirea .break_ctl = linflex_break_ctl, 56409864c1cSStefan-gabriel Mirea .startup = linflex_startup, 56509864c1cSStefan-gabriel Mirea .shutdown = linflex_shutdown, 56609864c1cSStefan-gabriel Mirea .set_termios = linflex_set_termios, 56709864c1cSStefan-gabriel Mirea .type = linflex_type, 56809864c1cSStefan-gabriel Mirea .request_port = linflex_request_port, 56909864c1cSStefan-gabriel Mirea .release_port = linflex_release_port, 57009864c1cSStefan-gabriel Mirea .config_port = linflex_config_port, 57109864c1cSStefan-gabriel Mirea }; 57209864c1cSStefan-gabriel Mirea 57309864c1cSStefan-gabriel Mirea static struct uart_port *linflex_ports[UART_NR]; 57409864c1cSStefan-gabriel Mirea 57509864c1cSStefan-gabriel Mirea #ifdef CONFIG_SERIAL_FSL_LINFLEXUART_CONSOLE 57609864c1cSStefan-gabriel Mirea static void linflex_console_putchar(struct uart_port *port, int ch) 57709864c1cSStefan-gabriel Mirea { 57809864c1cSStefan-gabriel Mirea unsigned long cr; 57909864c1cSStefan-gabriel Mirea 58009864c1cSStefan-gabriel Mirea cr = readl(port->membase + UARTCR); 58109864c1cSStefan-gabriel Mirea 58209864c1cSStefan-gabriel Mirea writeb(ch, port->membase + BDRL); 58309864c1cSStefan-gabriel Mirea 58409864c1cSStefan-gabriel Mirea if (!(cr & LINFLEXD_UARTCR_TFBM)) 58509864c1cSStefan-gabriel Mirea while ((readl(port->membase + UARTSR) & 58609864c1cSStefan-gabriel Mirea LINFLEXD_UARTSR_DTFTFF) 58709864c1cSStefan-gabriel Mirea != LINFLEXD_UARTSR_DTFTFF) 58809864c1cSStefan-gabriel Mirea ; 58909864c1cSStefan-gabriel Mirea else 59009864c1cSStefan-gabriel Mirea while (readl(port->membase + UARTSR) & 59109864c1cSStefan-gabriel Mirea LINFLEXD_UARTSR_DTFTFF) 59209864c1cSStefan-gabriel Mirea ; 59309864c1cSStefan-gabriel Mirea 59409864c1cSStefan-gabriel Mirea if (!(cr & LINFLEXD_UARTCR_TFBM)) { 59509864c1cSStefan-gabriel Mirea writel((readl(port->membase + UARTSR) | 59609864c1cSStefan-gabriel Mirea LINFLEXD_UARTSR_DTFTFF), 59709864c1cSStefan-gabriel Mirea port->membase + UARTSR); 59809864c1cSStefan-gabriel Mirea } 59909864c1cSStefan-gabriel Mirea } 60009864c1cSStefan-gabriel Mirea 60109864c1cSStefan-gabriel Mirea static void linflex_earlycon_putchar(struct uart_port *port, int ch) 60209864c1cSStefan-gabriel Mirea { 60309864c1cSStefan-gabriel Mirea unsigned long flags; 60409864c1cSStefan-gabriel Mirea char *ret; 60509864c1cSStefan-gabriel Mirea 60609864c1cSStefan-gabriel Mirea if (!linflex_earlycon_same_instance) { 60709864c1cSStefan-gabriel Mirea linflex_console_putchar(port, ch); 60809864c1cSStefan-gabriel Mirea return; 60909864c1cSStefan-gabriel Mirea } 61009864c1cSStefan-gabriel Mirea 61109864c1cSStefan-gabriel Mirea spin_lock_irqsave(&init_lock, flags); 61209864c1cSStefan-gabriel Mirea if (!during_init) 61309864c1cSStefan-gabriel Mirea goto outside_init; 61409864c1cSStefan-gabriel Mirea 61509864c1cSStefan-gabriel Mirea if (earlycon_buf.len >= 1 << CONFIG_LOG_BUF_SHIFT) 61609864c1cSStefan-gabriel Mirea goto init_release; 61709864c1cSStefan-gabriel Mirea 61809864c1cSStefan-gabriel Mirea if (!earlycon_buf.cap) { 61909864c1cSStefan-gabriel Mirea earlycon_buf.content = kmalloc(EARLYCON_BUFFER_INITIAL_CAP, 62009864c1cSStefan-gabriel Mirea GFP_ATOMIC); 62109864c1cSStefan-gabriel Mirea earlycon_buf.cap = earlycon_buf.content ? 62209864c1cSStefan-gabriel Mirea EARLYCON_BUFFER_INITIAL_CAP : 0; 62309864c1cSStefan-gabriel Mirea } else if (earlycon_buf.len == earlycon_buf.cap) { 62409864c1cSStefan-gabriel Mirea ret = krealloc(earlycon_buf.content, earlycon_buf.cap << 1, 62509864c1cSStefan-gabriel Mirea GFP_ATOMIC); 62609864c1cSStefan-gabriel Mirea if (ret) { 62709864c1cSStefan-gabriel Mirea earlycon_buf.content = ret; 62809864c1cSStefan-gabriel Mirea earlycon_buf.cap <<= 1; 62909864c1cSStefan-gabriel Mirea } 63009864c1cSStefan-gabriel Mirea } 63109864c1cSStefan-gabriel Mirea 63209864c1cSStefan-gabriel Mirea if (earlycon_buf.len < earlycon_buf.cap) 63309864c1cSStefan-gabriel Mirea earlycon_buf.content[earlycon_buf.len++] = ch; 63409864c1cSStefan-gabriel Mirea 63509864c1cSStefan-gabriel Mirea goto init_release; 63609864c1cSStefan-gabriel Mirea 63709864c1cSStefan-gabriel Mirea outside_init: 63809864c1cSStefan-gabriel Mirea linflex_console_putchar(port, ch); 63909864c1cSStefan-gabriel Mirea init_release: 64009864c1cSStefan-gabriel Mirea spin_unlock_irqrestore(&init_lock, flags); 64109864c1cSStefan-gabriel Mirea } 64209864c1cSStefan-gabriel Mirea 64309864c1cSStefan-gabriel Mirea static void linflex_string_write(struct uart_port *sport, const char *s, 64409864c1cSStefan-gabriel Mirea unsigned int count) 64509864c1cSStefan-gabriel Mirea { 64609864c1cSStefan-gabriel Mirea unsigned long cr, ier = 0; 64709864c1cSStefan-gabriel Mirea 64809864c1cSStefan-gabriel Mirea ier = readl(sport->membase + LINIER); 64909864c1cSStefan-gabriel Mirea linflex_stop_tx(sport); 65009864c1cSStefan-gabriel Mirea 65109864c1cSStefan-gabriel Mirea cr = readl(sport->membase + UARTCR); 65209864c1cSStefan-gabriel Mirea cr |= (LINFLEXD_UARTCR_TXEN); 65309864c1cSStefan-gabriel Mirea writel(cr, sport->membase + UARTCR); 65409864c1cSStefan-gabriel Mirea 65509864c1cSStefan-gabriel Mirea uart_console_write(sport, s, count, linflex_console_putchar); 65609864c1cSStefan-gabriel Mirea 65709864c1cSStefan-gabriel Mirea writel(ier, sport->membase + LINIER); 65809864c1cSStefan-gabriel Mirea } 65909864c1cSStefan-gabriel Mirea 66009864c1cSStefan-gabriel Mirea static void 66109864c1cSStefan-gabriel Mirea linflex_console_write(struct console *co, const char *s, unsigned int count) 66209864c1cSStefan-gabriel Mirea { 66309864c1cSStefan-gabriel Mirea struct uart_port *sport = linflex_ports[co->index]; 66409864c1cSStefan-gabriel Mirea unsigned long flags; 66509864c1cSStefan-gabriel Mirea int locked = 1; 66609864c1cSStefan-gabriel Mirea 66709864c1cSStefan-gabriel Mirea if (sport->sysrq) 66809864c1cSStefan-gabriel Mirea locked = 0; 66909864c1cSStefan-gabriel Mirea else if (oops_in_progress) 67009864c1cSStefan-gabriel Mirea locked = spin_trylock_irqsave(&sport->lock, flags); 67109864c1cSStefan-gabriel Mirea else 67209864c1cSStefan-gabriel Mirea spin_lock_irqsave(&sport->lock, flags); 67309864c1cSStefan-gabriel Mirea 67409864c1cSStefan-gabriel Mirea linflex_string_write(sport, s, count); 67509864c1cSStefan-gabriel Mirea 67609864c1cSStefan-gabriel Mirea if (locked) 67709864c1cSStefan-gabriel Mirea spin_unlock_irqrestore(&sport->lock, flags); 67809864c1cSStefan-gabriel Mirea } 67909864c1cSStefan-gabriel Mirea 68009864c1cSStefan-gabriel Mirea /* 68109864c1cSStefan-gabriel Mirea * if the port was already initialised (eg, by a boot loader), 68209864c1cSStefan-gabriel Mirea * try to determine the current setup. 68309864c1cSStefan-gabriel Mirea */ 68409864c1cSStefan-gabriel Mirea static void __init 68509864c1cSStefan-gabriel Mirea linflex_console_get_options(struct uart_port *sport, int *parity, int *bits) 68609864c1cSStefan-gabriel Mirea { 68709864c1cSStefan-gabriel Mirea unsigned long cr; 68809864c1cSStefan-gabriel Mirea 68909864c1cSStefan-gabriel Mirea cr = readl(sport->membase + UARTCR); 69009864c1cSStefan-gabriel Mirea cr &= LINFLEXD_UARTCR_RXEN | LINFLEXD_UARTCR_TXEN; 69109864c1cSStefan-gabriel Mirea 69209864c1cSStefan-gabriel Mirea if (!cr) 69309864c1cSStefan-gabriel Mirea return; 69409864c1cSStefan-gabriel Mirea 69509864c1cSStefan-gabriel Mirea /* ok, the port was enabled */ 69609864c1cSStefan-gabriel Mirea 69709864c1cSStefan-gabriel Mirea *parity = 'n'; 69809864c1cSStefan-gabriel Mirea if (cr & LINFLEXD_UARTCR_PCE) { 69909864c1cSStefan-gabriel Mirea if (cr & LINFLEXD_UARTCR_PC0) 70009864c1cSStefan-gabriel Mirea *parity = 'o'; 70109864c1cSStefan-gabriel Mirea else 70209864c1cSStefan-gabriel Mirea *parity = 'e'; 70309864c1cSStefan-gabriel Mirea } 70409864c1cSStefan-gabriel Mirea 70509864c1cSStefan-gabriel Mirea if ((cr & LINFLEXD_UARTCR_WL0) && ((cr & LINFLEXD_UARTCR_WL1) == 0)) { 70609864c1cSStefan-gabriel Mirea if (cr & LINFLEXD_UARTCR_PCE) 70709864c1cSStefan-gabriel Mirea *bits = 9; 70809864c1cSStefan-gabriel Mirea else 70909864c1cSStefan-gabriel Mirea *bits = 8; 71009864c1cSStefan-gabriel Mirea } 71109864c1cSStefan-gabriel Mirea } 71209864c1cSStefan-gabriel Mirea 71309864c1cSStefan-gabriel Mirea static int __init linflex_console_setup(struct console *co, char *options) 71409864c1cSStefan-gabriel Mirea { 71509864c1cSStefan-gabriel Mirea struct uart_port *sport; 71609864c1cSStefan-gabriel Mirea int baud = 115200; 71709864c1cSStefan-gabriel Mirea int bits = 8; 71809864c1cSStefan-gabriel Mirea int parity = 'n'; 71909864c1cSStefan-gabriel Mirea int flow = 'n'; 72009864c1cSStefan-gabriel Mirea int ret; 72109864c1cSStefan-gabriel Mirea int i; 72209864c1cSStefan-gabriel Mirea unsigned long flags; 72309864c1cSStefan-gabriel Mirea /* 72409864c1cSStefan-gabriel Mirea * check whether an invalid uart number has been specified, and 72509864c1cSStefan-gabriel Mirea * if so, search for the first available port that does have 72609864c1cSStefan-gabriel Mirea * console support. 72709864c1cSStefan-gabriel Mirea */ 72809864c1cSStefan-gabriel Mirea if (co->index == -1 || co->index >= ARRAY_SIZE(linflex_ports)) 72909864c1cSStefan-gabriel Mirea co->index = 0; 73009864c1cSStefan-gabriel Mirea 73109864c1cSStefan-gabriel Mirea sport = linflex_ports[co->index]; 73209864c1cSStefan-gabriel Mirea if (!sport) 73309864c1cSStefan-gabriel Mirea return -ENODEV; 73409864c1cSStefan-gabriel Mirea 73509864c1cSStefan-gabriel Mirea if (options) 73609864c1cSStefan-gabriel Mirea uart_parse_options(options, &baud, &parity, &bits, &flow); 73709864c1cSStefan-gabriel Mirea else 73809864c1cSStefan-gabriel Mirea linflex_console_get_options(sport, &parity, &bits); 73909864c1cSStefan-gabriel Mirea 74009864c1cSStefan-gabriel Mirea if (earlycon_port && sport->mapbase == earlycon_port->mapbase) { 74109864c1cSStefan-gabriel Mirea linflex_earlycon_same_instance = true; 74209864c1cSStefan-gabriel Mirea 74309864c1cSStefan-gabriel Mirea spin_lock_irqsave(&init_lock, flags); 74409864c1cSStefan-gabriel Mirea during_init = true; 74509864c1cSStefan-gabriel Mirea spin_unlock_irqrestore(&init_lock, flags); 74609864c1cSStefan-gabriel Mirea 74709864c1cSStefan-gabriel Mirea /* Workaround for character loss or output of many invalid 74809864c1cSStefan-gabriel Mirea * characters, when INIT mode is entered shortly after a 74909864c1cSStefan-gabriel Mirea * character has just been printed. 75009864c1cSStefan-gabriel Mirea */ 75109864c1cSStefan-gabriel Mirea udelay(PREINIT_DELAY); 75209864c1cSStefan-gabriel Mirea } 75309864c1cSStefan-gabriel Mirea 75409864c1cSStefan-gabriel Mirea linflex_setup_watermark(sport); 75509864c1cSStefan-gabriel Mirea 75609864c1cSStefan-gabriel Mirea ret = uart_set_options(sport, co, baud, parity, bits, flow); 75709864c1cSStefan-gabriel Mirea 75809864c1cSStefan-gabriel Mirea if (!linflex_earlycon_same_instance) 75909864c1cSStefan-gabriel Mirea goto done; 76009864c1cSStefan-gabriel Mirea 76109864c1cSStefan-gabriel Mirea spin_lock_irqsave(&init_lock, flags); 76209864c1cSStefan-gabriel Mirea 76309864c1cSStefan-gabriel Mirea /* Emptying buffer */ 76409864c1cSStefan-gabriel Mirea if (earlycon_buf.len) { 76509864c1cSStefan-gabriel Mirea for (i = 0; i < earlycon_buf.len; i++) 76609864c1cSStefan-gabriel Mirea linflex_console_putchar(earlycon_port, 76709864c1cSStefan-gabriel Mirea earlycon_buf.content[i]); 76809864c1cSStefan-gabriel Mirea 76909864c1cSStefan-gabriel Mirea kfree(earlycon_buf.content); 77009864c1cSStefan-gabriel Mirea earlycon_buf.len = 0; 77109864c1cSStefan-gabriel Mirea } 77209864c1cSStefan-gabriel Mirea 77309864c1cSStefan-gabriel Mirea during_init = false; 77409864c1cSStefan-gabriel Mirea spin_unlock_irqrestore(&init_lock, flags); 77509864c1cSStefan-gabriel Mirea 77609864c1cSStefan-gabriel Mirea done: 77709864c1cSStefan-gabriel Mirea return ret; 77809864c1cSStefan-gabriel Mirea } 77909864c1cSStefan-gabriel Mirea 78009864c1cSStefan-gabriel Mirea static struct uart_driver linflex_reg; 78109864c1cSStefan-gabriel Mirea static struct console linflex_console = { 78209864c1cSStefan-gabriel Mirea .name = DEV_NAME, 78309864c1cSStefan-gabriel Mirea .write = linflex_console_write, 78409864c1cSStefan-gabriel Mirea .device = uart_console_device, 78509864c1cSStefan-gabriel Mirea .setup = linflex_console_setup, 78609864c1cSStefan-gabriel Mirea .flags = CON_PRINTBUFFER, 78709864c1cSStefan-gabriel Mirea .index = -1, 78809864c1cSStefan-gabriel Mirea .data = &linflex_reg, 78909864c1cSStefan-gabriel Mirea }; 79009864c1cSStefan-gabriel Mirea 79109864c1cSStefan-gabriel Mirea static void linflex_earlycon_write(struct console *con, const char *s, 79209864c1cSStefan-gabriel Mirea unsigned int n) 79309864c1cSStefan-gabriel Mirea { 79409864c1cSStefan-gabriel Mirea struct earlycon_device *dev = con->data; 79509864c1cSStefan-gabriel Mirea 79609864c1cSStefan-gabriel Mirea uart_console_write(&dev->port, s, n, linflex_earlycon_putchar); 79709864c1cSStefan-gabriel Mirea } 79809864c1cSStefan-gabriel Mirea 79909864c1cSStefan-gabriel Mirea static int __init linflex_early_console_setup(struct earlycon_device *device, 80009864c1cSStefan-gabriel Mirea const char *options) 80109864c1cSStefan-gabriel Mirea { 80209864c1cSStefan-gabriel Mirea if (!device->port.membase) 80309864c1cSStefan-gabriel Mirea return -ENODEV; 80409864c1cSStefan-gabriel Mirea 80509864c1cSStefan-gabriel Mirea device->con->write = linflex_earlycon_write; 80609864c1cSStefan-gabriel Mirea earlycon_port = &device->port; 80709864c1cSStefan-gabriel Mirea 80809864c1cSStefan-gabriel Mirea return 0; 80909864c1cSStefan-gabriel Mirea } 81009864c1cSStefan-gabriel Mirea 8112bd3661eSStefan-gabriel Mirea OF_EARLYCON_DECLARE(linflex, "fsl,s32v234-linflexuart", 81209864c1cSStefan-gabriel Mirea linflex_early_console_setup); 81309864c1cSStefan-gabriel Mirea 81409864c1cSStefan-gabriel Mirea #define LINFLEX_CONSOLE (&linflex_console) 81509864c1cSStefan-gabriel Mirea #else 81609864c1cSStefan-gabriel Mirea #define LINFLEX_CONSOLE NULL 81709864c1cSStefan-gabriel Mirea #endif 81809864c1cSStefan-gabriel Mirea 81909864c1cSStefan-gabriel Mirea static struct uart_driver linflex_reg = { 82009864c1cSStefan-gabriel Mirea .owner = THIS_MODULE, 82109864c1cSStefan-gabriel Mirea .driver_name = DRIVER_NAME, 82209864c1cSStefan-gabriel Mirea .dev_name = DEV_NAME, 82309864c1cSStefan-gabriel Mirea .nr = ARRAY_SIZE(linflex_ports), 82409864c1cSStefan-gabriel Mirea .cons = LINFLEX_CONSOLE, 82509864c1cSStefan-gabriel Mirea }; 82609864c1cSStefan-gabriel Mirea 82709864c1cSStefan-gabriel Mirea static int linflex_probe(struct platform_device *pdev) 82809864c1cSStefan-gabriel Mirea { 82909864c1cSStefan-gabriel Mirea struct device_node *np = pdev->dev.of_node; 83009864c1cSStefan-gabriel Mirea struct uart_port *sport; 83109864c1cSStefan-gabriel Mirea struct resource *res; 83209864c1cSStefan-gabriel Mirea int ret; 83309864c1cSStefan-gabriel Mirea 83409864c1cSStefan-gabriel Mirea sport = devm_kzalloc(&pdev->dev, sizeof(*sport), GFP_KERNEL); 83509864c1cSStefan-gabriel Mirea if (!sport) 83609864c1cSStefan-gabriel Mirea return -ENOMEM; 83709864c1cSStefan-gabriel Mirea 83809864c1cSStefan-gabriel Mirea ret = of_alias_get_id(np, "serial"); 83909864c1cSStefan-gabriel Mirea if (ret < 0) { 84009864c1cSStefan-gabriel Mirea dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret); 84109864c1cSStefan-gabriel Mirea return ret; 84209864c1cSStefan-gabriel Mirea } 84309864c1cSStefan-gabriel Mirea if (ret >= UART_NR) { 84409864c1cSStefan-gabriel Mirea dev_err(&pdev->dev, "driver limited to %d serial ports\n", 84509864c1cSStefan-gabriel Mirea UART_NR); 84609864c1cSStefan-gabriel Mirea return -ENOMEM; 84709864c1cSStefan-gabriel Mirea } 84809864c1cSStefan-gabriel Mirea 84909864c1cSStefan-gabriel Mirea sport->line = ret; 85009864c1cSStefan-gabriel Mirea 85109864c1cSStefan-gabriel Mirea res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 85209864c1cSStefan-gabriel Mirea if (!res) 85309864c1cSStefan-gabriel Mirea return -ENODEV; 85409864c1cSStefan-gabriel Mirea 85509864c1cSStefan-gabriel Mirea sport->mapbase = res->start; 85609864c1cSStefan-gabriel Mirea sport->membase = devm_ioremap_resource(&pdev->dev, res); 85709864c1cSStefan-gabriel Mirea if (IS_ERR(sport->membase)) 85809864c1cSStefan-gabriel Mirea return PTR_ERR(sport->membase); 85909864c1cSStefan-gabriel Mirea 86009864c1cSStefan-gabriel Mirea sport->dev = &pdev->dev; 86109864c1cSStefan-gabriel Mirea sport->type = PORT_LINFLEXUART; 86209864c1cSStefan-gabriel Mirea sport->iotype = UPIO_MEM; 86309864c1cSStefan-gabriel Mirea sport->irq = platform_get_irq(pdev, 0); 86409864c1cSStefan-gabriel Mirea sport->ops = &linflex_pops; 86509864c1cSStefan-gabriel Mirea sport->flags = UPF_BOOT_AUTOCONF; 86609864c1cSStefan-gabriel Mirea 86709864c1cSStefan-gabriel Mirea linflex_ports[sport->line] = sport; 86809864c1cSStefan-gabriel Mirea 86909864c1cSStefan-gabriel Mirea platform_set_drvdata(pdev, sport); 87009864c1cSStefan-gabriel Mirea 87109864c1cSStefan-gabriel Mirea ret = uart_add_one_port(&linflex_reg, sport); 87209864c1cSStefan-gabriel Mirea if (ret) 87309864c1cSStefan-gabriel Mirea return ret; 87409864c1cSStefan-gabriel Mirea 87509864c1cSStefan-gabriel Mirea return 0; 87609864c1cSStefan-gabriel Mirea } 87709864c1cSStefan-gabriel Mirea 87809864c1cSStefan-gabriel Mirea static int linflex_remove(struct platform_device *pdev) 87909864c1cSStefan-gabriel Mirea { 88009864c1cSStefan-gabriel Mirea struct uart_port *sport = platform_get_drvdata(pdev); 88109864c1cSStefan-gabriel Mirea 88209864c1cSStefan-gabriel Mirea uart_remove_one_port(&linflex_reg, sport); 88309864c1cSStefan-gabriel Mirea 88409864c1cSStefan-gabriel Mirea return 0; 88509864c1cSStefan-gabriel Mirea } 88609864c1cSStefan-gabriel Mirea 88709864c1cSStefan-gabriel Mirea #ifdef CONFIG_PM_SLEEP 88809864c1cSStefan-gabriel Mirea static int linflex_suspend(struct device *dev) 88909864c1cSStefan-gabriel Mirea { 89009864c1cSStefan-gabriel Mirea struct uart_port *sport = dev_get_drvdata(dev); 89109864c1cSStefan-gabriel Mirea 89209864c1cSStefan-gabriel Mirea uart_suspend_port(&linflex_reg, sport); 89309864c1cSStefan-gabriel Mirea 89409864c1cSStefan-gabriel Mirea return 0; 89509864c1cSStefan-gabriel Mirea } 89609864c1cSStefan-gabriel Mirea 89709864c1cSStefan-gabriel Mirea static int linflex_resume(struct device *dev) 89809864c1cSStefan-gabriel Mirea { 89909864c1cSStefan-gabriel Mirea struct uart_port *sport = dev_get_drvdata(dev); 90009864c1cSStefan-gabriel Mirea 90109864c1cSStefan-gabriel Mirea uart_resume_port(&linflex_reg, sport); 90209864c1cSStefan-gabriel Mirea 90309864c1cSStefan-gabriel Mirea return 0; 90409864c1cSStefan-gabriel Mirea } 90509864c1cSStefan-gabriel Mirea #endif 90609864c1cSStefan-gabriel Mirea 90709864c1cSStefan-gabriel Mirea static SIMPLE_DEV_PM_OPS(linflex_pm_ops, linflex_suspend, linflex_resume); 90809864c1cSStefan-gabriel Mirea 90909864c1cSStefan-gabriel Mirea static struct platform_driver linflex_driver = { 91009864c1cSStefan-gabriel Mirea .probe = linflex_probe, 91109864c1cSStefan-gabriel Mirea .remove = linflex_remove, 91209864c1cSStefan-gabriel Mirea .driver = { 91309864c1cSStefan-gabriel Mirea .name = DRIVER_NAME, 91409864c1cSStefan-gabriel Mirea .of_match_table = linflex_dt_ids, 91509864c1cSStefan-gabriel Mirea .pm = &linflex_pm_ops, 91609864c1cSStefan-gabriel Mirea }, 91709864c1cSStefan-gabriel Mirea }; 91809864c1cSStefan-gabriel Mirea 91909864c1cSStefan-gabriel Mirea static int __init linflex_serial_init(void) 92009864c1cSStefan-gabriel Mirea { 92109864c1cSStefan-gabriel Mirea int ret; 92209864c1cSStefan-gabriel Mirea 92309864c1cSStefan-gabriel Mirea ret = uart_register_driver(&linflex_reg); 92409864c1cSStefan-gabriel Mirea if (ret) 92509864c1cSStefan-gabriel Mirea return ret; 92609864c1cSStefan-gabriel Mirea 92709864c1cSStefan-gabriel Mirea ret = platform_driver_register(&linflex_driver); 92809864c1cSStefan-gabriel Mirea if (ret) 92909864c1cSStefan-gabriel Mirea uart_unregister_driver(&linflex_reg); 93009864c1cSStefan-gabriel Mirea 93109864c1cSStefan-gabriel Mirea return ret; 93209864c1cSStefan-gabriel Mirea } 93309864c1cSStefan-gabriel Mirea 93409864c1cSStefan-gabriel Mirea static void __exit linflex_serial_exit(void) 93509864c1cSStefan-gabriel Mirea { 93609864c1cSStefan-gabriel Mirea platform_driver_unregister(&linflex_driver); 93709864c1cSStefan-gabriel Mirea uart_unregister_driver(&linflex_reg); 93809864c1cSStefan-gabriel Mirea } 93909864c1cSStefan-gabriel Mirea 94009864c1cSStefan-gabriel Mirea module_init(linflex_serial_init); 94109864c1cSStefan-gabriel Mirea module_exit(linflex_serial_exit); 94209864c1cSStefan-gabriel Mirea 943*9905f32aSStefan-Gabriel Mirea MODULE_DESCRIPTION("Freescale LINFlexD serial port driver"); 94409864c1cSStefan-gabriel Mirea MODULE_LICENSE("GPL v2"); 945