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