162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Mediatek 8250 driver. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2014 MundoReader S.L. 662306a36Sopenharmony_ci * Author: Matthias Brugger <matthias.bgg@gmail.com> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci#include <linux/clk.h> 962306a36Sopenharmony_ci#include <linux/io.h> 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci#include <linux/of_irq.h> 1262306a36Sopenharmony_ci#include <linux/of_platform.h> 1362306a36Sopenharmony_ci#include <linux/pinctrl/consumer.h> 1462306a36Sopenharmony_ci#include <linux/platform_device.h> 1562306a36Sopenharmony_ci#include <linux/pm_runtime.h> 1662306a36Sopenharmony_ci#include <linux/serial_8250.h> 1762306a36Sopenharmony_ci#include <linux/serial_reg.h> 1862306a36Sopenharmony_ci#include <linux/console.h> 1962306a36Sopenharmony_ci#include <linux/dma-mapping.h> 2062306a36Sopenharmony_ci#include <linux/tty.h> 2162306a36Sopenharmony_ci#include <linux/tty_flip.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include "8250.h" 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#define MTK_UART_HIGHS 0x09 /* Highspeed register */ 2662306a36Sopenharmony_ci#define MTK_UART_SAMPLE_COUNT 0x0a /* Sample count register */ 2762306a36Sopenharmony_ci#define MTK_UART_SAMPLE_POINT 0x0b /* Sample point register */ 2862306a36Sopenharmony_ci#define MTK_UART_RATE_FIX 0x0d /* UART Rate Fix Register */ 2962306a36Sopenharmony_ci#define MTK_UART_ESCAPE_DAT 0x10 /* Escape Character register */ 3062306a36Sopenharmony_ci#define MTK_UART_ESCAPE_EN 0x11 /* Escape Enable register */ 3162306a36Sopenharmony_ci#define MTK_UART_DMA_EN 0x13 /* DMA Enable register */ 3262306a36Sopenharmony_ci#define MTK_UART_RXTRI_AD 0x14 /* RX Trigger address */ 3362306a36Sopenharmony_ci#define MTK_UART_FRACDIV_L 0x15 /* Fractional divider LSB address */ 3462306a36Sopenharmony_ci#define MTK_UART_FRACDIV_M 0x16 /* Fractional divider MSB address */ 3562306a36Sopenharmony_ci#define MTK_UART_DEBUG0 0x18 3662306a36Sopenharmony_ci#define MTK_UART_IER_XOFFI 0x20 /* Enable XOFF character interrupt */ 3762306a36Sopenharmony_ci#define MTK_UART_IER_RTSI 0x40 /* Enable RTS Modem status interrupt */ 3862306a36Sopenharmony_ci#define MTK_UART_IER_CTSI 0x80 /* Enable CTS Modem status interrupt */ 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#define MTK_UART_EFR 38 /* I/O: Extended Features Register */ 4162306a36Sopenharmony_ci#define MTK_UART_EFR_EN 0x10 /* Enable enhancement feature */ 4262306a36Sopenharmony_ci#define MTK_UART_EFR_RTS 0x40 /* Enable hardware rx flow control */ 4362306a36Sopenharmony_ci#define MTK_UART_EFR_CTS 0x80 /* Enable hardware tx flow control */ 4462306a36Sopenharmony_ci#define MTK_UART_EFR_NO_SW_FC 0x0 /* no sw flow control */ 4562306a36Sopenharmony_ci#define MTK_UART_EFR_XON1_XOFF1 0xa /* XON1/XOFF1 as sw flow control */ 4662306a36Sopenharmony_ci#define MTK_UART_EFR_XON2_XOFF2 0x5 /* XON2/XOFF2 as sw flow control */ 4762306a36Sopenharmony_ci#define MTK_UART_EFR_SW_FC_MASK 0xf /* Enable CTS Modem status interrupt */ 4862306a36Sopenharmony_ci#define MTK_UART_EFR_HW_FC (MTK_UART_EFR_RTS | MTK_UART_EFR_CTS) 4962306a36Sopenharmony_ci#define MTK_UART_DMA_EN_TX 0x2 5062306a36Sopenharmony_ci#define MTK_UART_DMA_EN_RX 0x5 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci#define MTK_UART_ESCAPE_CHAR 0x77 /* Escape char added under sw fc */ 5362306a36Sopenharmony_ci#define MTK_UART_RX_SIZE 0x8000 5462306a36Sopenharmony_ci#define MTK_UART_TX_TRIGGER 1 5562306a36Sopenharmony_ci#define MTK_UART_RX_TRIGGER MTK_UART_RX_SIZE 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci#define MTK_UART_XON1 40 /* I/O: Xon character 1 */ 5862306a36Sopenharmony_ci#define MTK_UART_XOFF1 42 /* I/O: Xoff character 1 */ 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci#ifdef CONFIG_SERIAL_8250_DMA 6162306a36Sopenharmony_cienum dma_rx_status { 6262306a36Sopenharmony_ci DMA_RX_START = 0, 6362306a36Sopenharmony_ci DMA_RX_RUNNING = 1, 6462306a36Sopenharmony_ci DMA_RX_SHUTDOWN = 2, 6562306a36Sopenharmony_ci}; 6662306a36Sopenharmony_ci#endif 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistruct mtk8250_data { 6962306a36Sopenharmony_ci int line; 7062306a36Sopenharmony_ci unsigned int rx_pos; 7162306a36Sopenharmony_ci unsigned int clk_count; 7262306a36Sopenharmony_ci struct clk *uart_clk; 7362306a36Sopenharmony_ci struct clk *bus_clk; 7462306a36Sopenharmony_ci struct uart_8250_dma *dma; 7562306a36Sopenharmony_ci#ifdef CONFIG_SERIAL_8250_DMA 7662306a36Sopenharmony_ci enum dma_rx_status rx_status; 7762306a36Sopenharmony_ci#endif 7862306a36Sopenharmony_ci int rx_wakeup_irq; 7962306a36Sopenharmony_ci}; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci/* flow control mode */ 8262306a36Sopenharmony_cienum { 8362306a36Sopenharmony_ci MTK_UART_FC_NONE, 8462306a36Sopenharmony_ci MTK_UART_FC_SW, 8562306a36Sopenharmony_ci MTK_UART_FC_HW, 8662306a36Sopenharmony_ci}; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci#ifdef CONFIG_SERIAL_8250_DMA 8962306a36Sopenharmony_cistatic void mtk8250_rx_dma(struct uart_8250_port *up); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic void mtk8250_dma_rx_complete(void *param) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci struct uart_8250_port *up = param; 9462306a36Sopenharmony_ci struct uart_8250_dma *dma = up->dma; 9562306a36Sopenharmony_ci struct mtk8250_data *data = up->port.private_data; 9662306a36Sopenharmony_ci struct tty_port *tty_port = &up->port.state->port; 9762306a36Sopenharmony_ci struct dma_tx_state state; 9862306a36Sopenharmony_ci int copied, total, cnt; 9962306a36Sopenharmony_ci unsigned char *ptr; 10062306a36Sopenharmony_ci unsigned long flags; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci if (data->rx_status == DMA_RX_SHUTDOWN) 10362306a36Sopenharmony_ci return; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci spin_lock_irqsave(&up->port.lock, flags); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state); 10862306a36Sopenharmony_ci total = dma->rx_size - state.residue; 10962306a36Sopenharmony_ci cnt = total; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci if ((data->rx_pos + cnt) > dma->rx_size) 11262306a36Sopenharmony_ci cnt = dma->rx_size - data->rx_pos; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci ptr = (unsigned char *)(data->rx_pos + dma->rx_buf); 11562306a36Sopenharmony_ci copied = tty_insert_flip_string(tty_port, ptr, cnt); 11662306a36Sopenharmony_ci data->rx_pos += cnt; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci if (total > cnt) { 11962306a36Sopenharmony_ci ptr = (unsigned char *)(dma->rx_buf); 12062306a36Sopenharmony_ci cnt = total - cnt; 12162306a36Sopenharmony_ci copied += tty_insert_flip_string(tty_port, ptr, cnt); 12262306a36Sopenharmony_ci data->rx_pos = cnt; 12362306a36Sopenharmony_ci } 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci up->port.icount.rx += copied; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci tty_flip_buffer_push(tty_port); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci mtk8250_rx_dma(up); 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci spin_unlock_irqrestore(&up->port.lock, flags); 13262306a36Sopenharmony_ci} 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_cistatic void mtk8250_rx_dma(struct uart_8250_port *up) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci struct uart_8250_dma *dma = up->dma; 13762306a36Sopenharmony_ci struct dma_async_tx_descriptor *desc; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci desc = dmaengine_prep_slave_single(dma->rxchan, dma->rx_addr, 14062306a36Sopenharmony_ci dma->rx_size, DMA_DEV_TO_MEM, 14162306a36Sopenharmony_ci DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 14262306a36Sopenharmony_ci if (!desc) { 14362306a36Sopenharmony_ci pr_err("failed to prepare rx slave single\n"); 14462306a36Sopenharmony_ci return; 14562306a36Sopenharmony_ci } 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci desc->callback = mtk8250_dma_rx_complete; 14862306a36Sopenharmony_ci desc->callback_param = up; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci dma->rx_cookie = dmaengine_submit(desc); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci dma_async_issue_pending(dma->rxchan); 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_cistatic void mtk8250_dma_enable(struct uart_8250_port *up) 15662306a36Sopenharmony_ci{ 15762306a36Sopenharmony_ci struct uart_8250_dma *dma = up->dma; 15862306a36Sopenharmony_ci struct mtk8250_data *data = up->port.private_data; 15962306a36Sopenharmony_ci int lcr = serial_in(up, UART_LCR); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci if (data->rx_status != DMA_RX_START) 16262306a36Sopenharmony_ci return; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci dma->rxconf.src_port_window_size = dma->rx_size; 16562306a36Sopenharmony_ci dma->rxconf.src_addr = dma->rx_addr; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci dma->txconf.dst_port_window_size = UART_XMIT_SIZE; 16862306a36Sopenharmony_ci dma->txconf.dst_addr = dma->tx_addr; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | 17162306a36Sopenharmony_ci UART_FCR_CLEAR_XMIT); 17262306a36Sopenharmony_ci serial_out(up, MTK_UART_DMA_EN, 17362306a36Sopenharmony_ci MTK_UART_DMA_EN_RX | MTK_UART_DMA_EN_TX); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); 17662306a36Sopenharmony_ci serial_out(up, MTK_UART_EFR, UART_EFR_ECB); 17762306a36Sopenharmony_ci serial_out(up, UART_LCR, lcr); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci if (dmaengine_slave_config(dma->rxchan, &dma->rxconf) != 0) 18062306a36Sopenharmony_ci pr_err("failed to configure rx dma channel\n"); 18162306a36Sopenharmony_ci if (dmaengine_slave_config(dma->txchan, &dma->txconf) != 0) 18262306a36Sopenharmony_ci pr_err("failed to configure tx dma channel\n"); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci data->rx_status = DMA_RX_RUNNING; 18562306a36Sopenharmony_ci data->rx_pos = 0; 18662306a36Sopenharmony_ci mtk8250_rx_dma(up); 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ci#endif 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_cistatic int mtk8250_startup(struct uart_port *port) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci#ifdef CONFIG_SERIAL_8250_DMA 19362306a36Sopenharmony_ci struct uart_8250_port *up = up_to_u8250p(port); 19462306a36Sopenharmony_ci struct mtk8250_data *data = port->private_data; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci /* disable DMA for console */ 19762306a36Sopenharmony_ci if (uart_console(port)) 19862306a36Sopenharmony_ci up->dma = NULL; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci if (up->dma) { 20162306a36Sopenharmony_ci data->rx_status = DMA_RX_START; 20262306a36Sopenharmony_ci uart_circ_clear(&port->state->xmit); 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci#endif 20562306a36Sopenharmony_ci memset(&port->icount, 0, sizeof(port->icount)); 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci return serial8250_do_startup(port); 20862306a36Sopenharmony_ci} 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_cistatic void mtk8250_shutdown(struct uart_port *port) 21162306a36Sopenharmony_ci{ 21262306a36Sopenharmony_ci#ifdef CONFIG_SERIAL_8250_DMA 21362306a36Sopenharmony_ci struct uart_8250_port *up = up_to_u8250p(port); 21462306a36Sopenharmony_ci struct mtk8250_data *data = port->private_data; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci if (up->dma) 21762306a36Sopenharmony_ci data->rx_status = DMA_RX_SHUTDOWN; 21862306a36Sopenharmony_ci#endif 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci return serial8250_do_shutdown(port); 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_cistatic void mtk8250_disable_intrs(struct uart_8250_port *up, int mask) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci /* Port locked to synchronize UART_IER access against the console. */ 22662306a36Sopenharmony_ci lockdep_assert_held_once(&up->port.lock); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci serial_out(up, UART_IER, serial_in(up, UART_IER) & (~mask)); 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_cistatic void mtk8250_enable_intrs(struct uart_8250_port *up, int mask) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci /* Port locked to synchronize UART_IER access against the console. */ 23462306a36Sopenharmony_ci lockdep_assert_held_once(&up->port.lock); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci serial_out(up, UART_IER, serial_in(up, UART_IER) | mask); 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cistatic void mtk8250_set_flow_ctrl(struct uart_8250_port *up, int mode) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci struct uart_port *port = &up->port; 24262306a36Sopenharmony_ci int lcr = serial_in(up, UART_LCR); 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci /* Port locked to synchronize UART_IER access against the console. */ 24562306a36Sopenharmony_ci lockdep_assert_held_once(&port->lock); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); 24862306a36Sopenharmony_ci serial_out(up, MTK_UART_EFR, UART_EFR_ECB); 24962306a36Sopenharmony_ci serial_out(up, UART_LCR, lcr); 25062306a36Sopenharmony_ci lcr = serial_in(up, UART_LCR); 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci switch (mode) { 25362306a36Sopenharmony_ci case MTK_UART_FC_NONE: 25462306a36Sopenharmony_ci serial_out(up, MTK_UART_ESCAPE_DAT, MTK_UART_ESCAPE_CHAR); 25562306a36Sopenharmony_ci serial_out(up, MTK_UART_ESCAPE_EN, 0x00); 25662306a36Sopenharmony_ci serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); 25762306a36Sopenharmony_ci serial_out(up, MTK_UART_EFR, serial_in(up, MTK_UART_EFR) & 25862306a36Sopenharmony_ci (~(MTK_UART_EFR_HW_FC | MTK_UART_EFR_SW_FC_MASK))); 25962306a36Sopenharmony_ci serial_out(up, UART_LCR, lcr); 26062306a36Sopenharmony_ci mtk8250_disable_intrs(up, MTK_UART_IER_XOFFI | 26162306a36Sopenharmony_ci MTK_UART_IER_RTSI | MTK_UART_IER_CTSI); 26262306a36Sopenharmony_ci break; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci case MTK_UART_FC_HW: 26562306a36Sopenharmony_ci serial_out(up, MTK_UART_ESCAPE_DAT, MTK_UART_ESCAPE_CHAR); 26662306a36Sopenharmony_ci serial_out(up, MTK_UART_ESCAPE_EN, 0x00); 26762306a36Sopenharmony_ci serial_out(up, UART_MCR, UART_MCR_RTS); 26862306a36Sopenharmony_ci serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci /*enable hw flow control*/ 27162306a36Sopenharmony_ci serial_out(up, MTK_UART_EFR, MTK_UART_EFR_HW_FC | 27262306a36Sopenharmony_ci (serial_in(up, MTK_UART_EFR) & 27362306a36Sopenharmony_ci (~(MTK_UART_EFR_HW_FC | MTK_UART_EFR_SW_FC_MASK)))); 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci serial_out(up, UART_LCR, lcr); 27662306a36Sopenharmony_ci mtk8250_disable_intrs(up, MTK_UART_IER_XOFFI); 27762306a36Sopenharmony_ci mtk8250_enable_intrs(up, MTK_UART_IER_CTSI | MTK_UART_IER_RTSI); 27862306a36Sopenharmony_ci break; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci case MTK_UART_FC_SW: /*MTK software flow control */ 28162306a36Sopenharmony_ci serial_out(up, MTK_UART_ESCAPE_DAT, MTK_UART_ESCAPE_CHAR); 28262306a36Sopenharmony_ci serial_out(up, MTK_UART_ESCAPE_EN, 0x01); 28362306a36Sopenharmony_ci serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci /*enable sw flow control */ 28662306a36Sopenharmony_ci serial_out(up, MTK_UART_EFR, MTK_UART_EFR_XON1_XOFF1 | 28762306a36Sopenharmony_ci (serial_in(up, MTK_UART_EFR) & 28862306a36Sopenharmony_ci (~(MTK_UART_EFR_HW_FC | MTK_UART_EFR_SW_FC_MASK)))); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci serial_out(up, MTK_UART_XON1, START_CHAR(port->state->port.tty)); 29162306a36Sopenharmony_ci serial_out(up, MTK_UART_XOFF1, STOP_CHAR(port->state->port.tty)); 29262306a36Sopenharmony_ci serial_out(up, UART_LCR, lcr); 29362306a36Sopenharmony_ci mtk8250_disable_intrs(up, MTK_UART_IER_CTSI|MTK_UART_IER_RTSI); 29462306a36Sopenharmony_ci mtk8250_enable_intrs(up, MTK_UART_IER_XOFFI); 29562306a36Sopenharmony_ci break; 29662306a36Sopenharmony_ci default: 29762306a36Sopenharmony_ci break; 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci} 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_cistatic void 30262306a36Sopenharmony_cimtk8250_set_termios(struct uart_port *port, struct ktermios *termios, 30362306a36Sopenharmony_ci const struct ktermios *old) 30462306a36Sopenharmony_ci{ 30562306a36Sopenharmony_ci static const unsigned short fraction_L_mapping[] = { 30662306a36Sopenharmony_ci 0, 1, 0x5, 0x15, 0x55, 0x57, 0x57, 0x77, 0x7F, 0xFF, 0xFF 30762306a36Sopenharmony_ci }; 30862306a36Sopenharmony_ci static const unsigned short fraction_M_mapping[] = { 30962306a36Sopenharmony_ci 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 3 31062306a36Sopenharmony_ci }; 31162306a36Sopenharmony_ci struct uart_8250_port *up = up_to_u8250p(port); 31262306a36Sopenharmony_ci unsigned int baud, quot, fraction; 31362306a36Sopenharmony_ci unsigned long flags; 31462306a36Sopenharmony_ci int mode; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci#ifdef CONFIG_SERIAL_8250_DMA 31762306a36Sopenharmony_ci if (up->dma) { 31862306a36Sopenharmony_ci if (uart_console(port)) { 31962306a36Sopenharmony_ci devm_kfree(up->port.dev, up->dma); 32062306a36Sopenharmony_ci up->dma = NULL; 32162306a36Sopenharmony_ci } else { 32262306a36Sopenharmony_ci mtk8250_dma_enable(up); 32362306a36Sopenharmony_ci } 32462306a36Sopenharmony_ci } 32562306a36Sopenharmony_ci#endif 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci /* 32862306a36Sopenharmony_ci * Store the requested baud rate before calling the generic 8250 32962306a36Sopenharmony_ci * set_termios method. Standard 8250 port expects bauds to be 33062306a36Sopenharmony_ci * no higher than (uartclk / 16) so the baud will be clamped if it 33162306a36Sopenharmony_ci * gets out of that bound. Mediatek 8250 port supports speed 33262306a36Sopenharmony_ci * higher than that, therefore we'll get original baud rate back 33362306a36Sopenharmony_ci * after calling the generic set_termios method and recalculate 33462306a36Sopenharmony_ci * the speed later in this method. 33562306a36Sopenharmony_ci */ 33662306a36Sopenharmony_ci baud = tty_termios_baud_rate(termios); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci serial8250_do_set_termios(port, termios, NULL); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci tty_termios_encode_baud_rate(termios, baud, baud); 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci /* 34362306a36Sopenharmony_ci * Mediatek UARTs use an extra highspeed register (MTK_UART_HIGHS) 34462306a36Sopenharmony_ci * 34562306a36Sopenharmony_ci * We need to recalcualte the quot register, as the claculation depends 34662306a36Sopenharmony_ci * on the vaule in the highspeed register. 34762306a36Sopenharmony_ci * 34862306a36Sopenharmony_ci * Some baudrates are not supported by the chip, so we use the next 34962306a36Sopenharmony_ci * lower rate supported and update termios c_flag. 35062306a36Sopenharmony_ci * 35162306a36Sopenharmony_ci * If highspeed register is set to 3, we need to specify sample count 35262306a36Sopenharmony_ci * and sample point to increase accuracy. If not, we reset the 35362306a36Sopenharmony_ci * registers to their default values. 35462306a36Sopenharmony_ci */ 35562306a36Sopenharmony_ci baud = uart_get_baud_rate(port, termios, old, 35662306a36Sopenharmony_ci port->uartclk / 16 / UART_DIV_MAX, 35762306a36Sopenharmony_ci port->uartclk); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci if (baud < 115200) { 36062306a36Sopenharmony_ci serial_port_out(port, MTK_UART_HIGHS, 0x0); 36162306a36Sopenharmony_ci quot = uart_get_divisor(port, baud); 36262306a36Sopenharmony_ci } else { 36362306a36Sopenharmony_ci serial_port_out(port, MTK_UART_HIGHS, 0x3); 36462306a36Sopenharmony_ci quot = DIV_ROUND_UP(port->uartclk, 256 * baud); 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci /* 36862306a36Sopenharmony_ci * Ok, we're now changing the port state. Do it with 36962306a36Sopenharmony_ci * interrupts disabled. 37062306a36Sopenharmony_ci */ 37162306a36Sopenharmony_ci spin_lock_irqsave(&port->lock, flags); 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci /* 37462306a36Sopenharmony_ci * Update the per-port timeout. 37562306a36Sopenharmony_ci */ 37662306a36Sopenharmony_ci uart_update_timeout(port, termios->c_cflag, baud); 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci /* set DLAB we have cval saved in up->lcr from the call to the core */ 37962306a36Sopenharmony_ci serial_port_out(port, UART_LCR, up->lcr | UART_LCR_DLAB); 38062306a36Sopenharmony_ci serial_dl_write(up, quot); 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci /* reset DLAB */ 38362306a36Sopenharmony_ci serial_port_out(port, UART_LCR, up->lcr); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci if (baud >= 115200) { 38662306a36Sopenharmony_ci unsigned int tmp; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci tmp = (port->uartclk / (baud * quot)) - 1; 38962306a36Sopenharmony_ci serial_port_out(port, MTK_UART_SAMPLE_COUNT, tmp); 39062306a36Sopenharmony_ci serial_port_out(port, MTK_UART_SAMPLE_POINT, 39162306a36Sopenharmony_ci (tmp >> 1) - 1); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci /*count fraction to set fractoin register */ 39462306a36Sopenharmony_ci fraction = ((port->uartclk * 100) / baud / quot) % 100; 39562306a36Sopenharmony_ci fraction = DIV_ROUND_CLOSEST(fraction, 10); 39662306a36Sopenharmony_ci serial_port_out(port, MTK_UART_FRACDIV_L, 39762306a36Sopenharmony_ci fraction_L_mapping[fraction]); 39862306a36Sopenharmony_ci serial_port_out(port, MTK_UART_FRACDIV_M, 39962306a36Sopenharmony_ci fraction_M_mapping[fraction]); 40062306a36Sopenharmony_ci } else { 40162306a36Sopenharmony_ci serial_port_out(port, MTK_UART_SAMPLE_COUNT, 0x00); 40262306a36Sopenharmony_ci serial_port_out(port, MTK_UART_SAMPLE_POINT, 0xff); 40362306a36Sopenharmony_ci serial_port_out(port, MTK_UART_FRACDIV_L, 0x00); 40462306a36Sopenharmony_ci serial_port_out(port, MTK_UART_FRACDIV_M, 0x00); 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci if ((termios->c_cflag & CRTSCTS) && (!(termios->c_iflag & CRTSCTS))) 40862306a36Sopenharmony_ci mode = MTK_UART_FC_HW; 40962306a36Sopenharmony_ci else if (termios->c_iflag & CRTSCTS) 41062306a36Sopenharmony_ci mode = MTK_UART_FC_SW; 41162306a36Sopenharmony_ci else 41262306a36Sopenharmony_ci mode = MTK_UART_FC_NONE; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci mtk8250_set_flow_ctrl(up, mode); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci if (uart_console(port)) 41762306a36Sopenharmony_ci up->port.cons->cflag = termios->c_cflag; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci spin_unlock_irqrestore(&port->lock, flags); 42062306a36Sopenharmony_ci /* Don't rewrite B0 */ 42162306a36Sopenharmony_ci if (tty_termios_baud_rate(termios)) 42262306a36Sopenharmony_ci tty_termios_encode_baud_rate(termios, baud, baud); 42362306a36Sopenharmony_ci} 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_cistatic int __maybe_unused mtk8250_runtime_suspend(struct device *dev) 42662306a36Sopenharmony_ci{ 42762306a36Sopenharmony_ci struct mtk8250_data *data = dev_get_drvdata(dev); 42862306a36Sopenharmony_ci struct uart_8250_port *up = serial8250_get_port(data->line); 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci /* wait until UART in idle status */ 43162306a36Sopenharmony_ci while 43262306a36Sopenharmony_ci (serial_in(up, MTK_UART_DEBUG0)); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci clk_disable_unprepare(data->bus_clk); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci return 0; 43762306a36Sopenharmony_ci} 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_cistatic int __maybe_unused mtk8250_runtime_resume(struct device *dev) 44062306a36Sopenharmony_ci{ 44162306a36Sopenharmony_ci struct mtk8250_data *data = dev_get_drvdata(dev); 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci clk_prepare_enable(data->bus_clk); 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci return 0; 44662306a36Sopenharmony_ci} 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_cistatic void 44962306a36Sopenharmony_cimtk8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old) 45062306a36Sopenharmony_ci{ 45162306a36Sopenharmony_ci if (!state) 45262306a36Sopenharmony_ci pm_runtime_get_sync(port->dev); 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci serial8250_do_pm(port, state, old); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci if (state) 45762306a36Sopenharmony_ci pm_runtime_put_sync_suspend(port->dev); 45862306a36Sopenharmony_ci} 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci#ifdef CONFIG_SERIAL_8250_DMA 46162306a36Sopenharmony_cistatic bool mtk8250_dma_filter(struct dma_chan *chan, void *param) 46262306a36Sopenharmony_ci{ 46362306a36Sopenharmony_ci return false; 46462306a36Sopenharmony_ci} 46562306a36Sopenharmony_ci#endif 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_cistatic int mtk8250_probe_of(struct platform_device *pdev, struct uart_port *p, 46862306a36Sopenharmony_ci struct mtk8250_data *data) 46962306a36Sopenharmony_ci{ 47062306a36Sopenharmony_ci#ifdef CONFIG_SERIAL_8250_DMA 47162306a36Sopenharmony_ci int dmacnt; 47262306a36Sopenharmony_ci#endif 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci data->uart_clk = devm_clk_get(&pdev->dev, "baud"); 47562306a36Sopenharmony_ci if (IS_ERR(data->uart_clk)) { 47662306a36Sopenharmony_ci /* 47762306a36Sopenharmony_ci * For compatibility with older device trees try unnamed 47862306a36Sopenharmony_ci * clk when no baud clk can be found. 47962306a36Sopenharmony_ci */ 48062306a36Sopenharmony_ci data->uart_clk = devm_clk_get(&pdev->dev, NULL); 48162306a36Sopenharmony_ci if (IS_ERR(data->uart_clk)) { 48262306a36Sopenharmony_ci dev_warn(&pdev->dev, "Can't get uart clock\n"); 48362306a36Sopenharmony_ci return PTR_ERR(data->uart_clk); 48462306a36Sopenharmony_ci } 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci return 0; 48762306a36Sopenharmony_ci } 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci data->bus_clk = devm_clk_get_enabled(&pdev->dev, "bus"); 49062306a36Sopenharmony_ci if (IS_ERR(data->bus_clk)) 49162306a36Sopenharmony_ci return PTR_ERR(data->bus_clk); 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci data->dma = NULL; 49462306a36Sopenharmony_ci#ifdef CONFIG_SERIAL_8250_DMA 49562306a36Sopenharmony_ci dmacnt = of_property_count_strings(pdev->dev.of_node, "dma-names"); 49662306a36Sopenharmony_ci if (dmacnt == 2) { 49762306a36Sopenharmony_ci data->dma = devm_kzalloc(&pdev->dev, sizeof(*data->dma), 49862306a36Sopenharmony_ci GFP_KERNEL); 49962306a36Sopenharmony_ci if (!data->dma) 50062306a36Sopenharmony_ci return -ENOMEM; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci data->dma->fn = mtk8250_dma_filter; 50362306a36Sopenharmony_ci data->dma->rx_size = MTK_UART_RX_SIZE; 50462306a36Sopenharmony_ci data->dma->rxconf.src_maxburst = MTK_UART_RX_TRIGGER; 50562306a36Sopenharmony_ci data->dma->txconf.dst_maxburst = MTK_UART_TX_TRIGGER; 50662306a36Sopenharmony_ci } 50762306a36Sopenharmony_ci#endif 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci return 0; 51062306a36Sopenharmony_ci} 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_cistatic int mtk8250_probe(struct platform_device *pdev) 51362306a36Sopenharmony_ci{ 51462306a36Sopenharmony_ci struct uart_8250_port uart = {}; 51562306a36Sopenharmony_ci struct mtk8250_data *data; 51662306a36Sopenharmony_ci struct resource *regs; 51762306a36Sopenharmony_ci int irq, err; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci irq = platform_get_irq(pdev, 0); 52062306a36Sopenharmony_ci if (irq < 0) 52162306a36Sopenharmony_ci return irq; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); 52462306a36Sopenharmony_ci if (!regs) { 52562306a36Sopenharmony_ci dev_err(&pdev->dev, "no registers defined\n"); 52662306a36Sopenharmony_ci return -EINVAL; 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci uart.port.membase = devm_ioremap(&pdev->dev, regs->start, 53062306a36Sopenharmony_ci resource_size(regs)); 53162306a36Sopenharmony_ci if (!uart.port.membase) 53262306a36Sopenharmony_ci return -ENOMEM; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); 53562306a36Sopenharmony_ci if (!data) 53662306a36Sopenharmony_ci return -ENOMEM; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci data->clk_count = 0; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci if (pdev->dev.of_node) { 54162306a36Sopenharmony_ci err = mtk8250_probe_of(pdev, &uart.port, data); 54262306a36Sopenharmony_ci if (err) 54362306a36Sopenharmony_ci return err; 54462306a36Sopenharmony_ci } else 54562306a36Sopenharmony_ci return -ENODEV; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci spin_lock_init(&uart.port.lock); 54862306a36Sopenharmony_ci uart.port.mapbase = regs->start; 54962306a36Sopenharmony_ci uart.port.irq = irq; 55062306a36Sopenharmony_ci uart.port.pm = mtk8250_do_pm; 55162306a36Sopenharmony_ci uart.port.type = PORT_16550; 55262306a36Sopenharmony_ci uart.port.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT; 55362306a36Sopenharmony_ci uart.port.dev = &pdev->dev; 55462306a36Sopenharmony_ci uart.port.iotype = UPIO_MEM32; 55562306a36Sopenharmony_ci uart.port.regshift = 2; 55662306a36Sopenharmony_ci uart.port.private_data = data; 55762306a36Sopenharmony_ci uart.port.shutdown = mtk8250_shutdown; 55862306a36Sopenharmony_ci uart.port.startup = mtk8250_startup; 55962306a36Sopenharmony_ci uart.port.set_termios = mtk8250_set_termios; 56062306a36Sopenharmony_ci uart.port.uartclk = clk_get_rate(data->uart_clk); 56162306a36Sopenharmony_ci#ifdef CONFIG_SERIAL_8250_DMA 56262306a36Sopenharmony_ci if (data->dma) 56362306a36Sopenharmony_ci uart.dma = data->dma; 56462306a36Sopenharmony_ci#endif 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci /* Disable Rate Fix function */ 56762306a36Sopenharmony_ci writel(0x0, uart.port.membase + 56862306a36Sopenharmony_ci (MTK_UART_RATE_FIX << uart.port.regshift)); 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci platform_set_drvdata(pdev, data); 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci data->line = serial8250_register_8250_port(&uart); 57362306a36Sopenharmony_ci if (data->line < 0) 57462306a36Sopenharmony_ci return data->line; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci data->rx_wakeup_irq = platform_get_irq_optional(pdev, 1); 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci pm_runtime_set_active(&pdev->dev); 57962306a36Sopenharmony_ci pm_runtime_enable(&pdev->dev); 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci return 0; 58262306a36Sopenharmony_ci} 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_cistatic int mtk8250_remove(struct platform_device *pdev) 58562306a36Sopenharmony_ci{ 58662306a36Sopenharmony_ci struct mtk8250_data *data = platform_get_drvdata(pdev); 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci pm_runtime_get_sync(&pdev->dev); 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci serial8250_unregister_port(data->line); 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci pm_runtime_disable(&pdev->dev); 59362306a36Sopenharmony_ci pm_runtime_put_noidle(&pdev->dev); 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci return 0; 59662306a36Sopenharmony_ci} 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_cistatic int __maybe_unused mtk8250_suspend(struct device *dev) 59962306a36Sopenharmony_ci{ 60062306a36Sopenharmony_ci struct mtk8250_data *data = dev_get_drvdata(dev); 60162306a36Sopenharmony_ci int irq = data->rx_wakeup_irq; 60262306a36Sopenharmony_ci int err; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci serial8250_suspend_port(data->line); 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci pinctrl_pm_select_sleep_state(dev); 60762306a36Sopenharmony_ci if (irq >= 0) { 60862306a36Sopenharmony_ci err = enable_irq_wake(irq); 60962306a36Sopenharmony_ci if (err) { 61062306a36Sopenharmony_ci dev_err(dev, 61162306a36Sopenharmony_ci "failed to enable irq wake on IRQ %d: %d\n", 61262306a36Sopenharmony_ci irq, err); 61362306a36Sopenharmony_ci pinctrl_pm_select_default_state(dev); 61462306a36Sopenharmony_ci serial8250_resume_port(data->line); 61562306a36Sopenharmony_ci return err; 61662306a36Sopenharmony_ci } 61762306a36Sopenharmony_ci } 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci return 0; 62062306a36Sopenharmony_ci} 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_cistatic int __maybe_unused mtk8250_resume(struct device *dev) 62362306a36Sopenharmony_ci{ 62462306a36Sopenharmony_ci struct mtk8250_data *data = dev_get_drvdata(dev); 62562306a36Sopenharmony_ci int irq = data->rx_wakeup_irq; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci if (irq >= 0) 62862306a36Sopenharmony_ci disable_irq_wake(irq); 62962306a36Sopenharmony_ci pinctrl_pm_select_default_state(dev); 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci serial8250_resume_port(data->line); 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci return 0; 63462306a36Sopenharmony_ci} 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_cistatic const struct dev_pm_ops mtk8250_pm_ops = { 63762306a36Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(mtk8250_suspend, mtk8250_resume) 63862306a36Sopenharmony_ci SET_RUNTIME_PM_OPS(mtk8250_runtime_suspend, mtk8250_runtime_resume, 63962306a36Sopenharmony_ci NULL) 64062306a36Sopenharmony_ci}; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_cistatic const struct of_device_id mtk8250_of_match[] = { 64362306a36Sopenharmony_ci { .compatible = "mediatek,mt6577-uart" }, 64462306a36Sopenharmony_ci { /* Sentinel */ } 64562306a36Sopenharmony_ci}; 64662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, mtk8250_of_match); 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_cistatic struct platform_driver mtk8250_platform_driver = { 64962306a36Sopenharmony_ci .driver = { 65062306a36Sopenharmony_ci .name = "mt6577-uart", 65162306a36Sopenharmony_ci .pm = &mtk8250_pm_ops, 65262306a36Sopenharmony_ci .of_match_table = mtk8250_of_match, 65362306a36Sopenharmony_ci }, 65462306a36Sopenharmony_ci .probe = mtk8250_probe, 65562306a36Sopenharmony_ci .remove = mtk8250_remove, 65662306a36Sopenharmony_ci}; 65762306a36Sopenharmony_cimodule_platform_driver(mtk8250_platform_driver); 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci#ifdef CONFIG_SERIAL_8250_CONSOLE 66062306a36Sopenharmony_cistatic int __init early_mtk8250_setup(struct earlycon_device *device, 66162306a36Sopenharmony_ci const char *options) 66262306a36Sopenharmony_ci{ 66362306a36Sopenharmony_ci if (!device->port.membase) 66462306a36Sopenharmony_ci return -ENODEV; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci device->port.iotype = UPIO_MEM32; 66762306a36Sopenharmony_ci device->port.regshift = 2; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci return early_serial8250_setup(device, NULL); 67062306a36Sopenharmony_ci} 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ciOF_EARLYCON_DECLARE(mtk8250, "mediatek,mt6577-uart", early_mtk8250_setup); 67362306a36Sopenharmony_ci#endif 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ciMODULE_AUTHOR("Matthias Brugger"); 67662306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 67762306a36Sopenharmony_ciMODULE_DESCRIPTION("Mediatek 8250 serial port driver"); 678