xref: /rk3399_rockchip-uboot/drivers/serial/serial_ar933x.c (revision a821c4af79e4f5ce9b629b20473863397bbe9b10)
160b49761SWills Wang /*
260b49761SWills Wang  * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
360b49761SWills Wang  *
460b49761SWills Wang  * SPDX-License-Identifier: GPL-2.0+
560b49761SWills Wang  */
660b49761SWills Wang 
760b49761SWills Wang #include <common.h>
860b49761SWills Wang #include <dm.h>
960b49761SWills Wang #include <div64.h>
1060b49761SWills Wang #include <errno.h>
1160b49761SWills Wang #include <serial.h>
1260b49761SWills Wang #include <asm/io.h>
1360b49761SWills Wang #include <asm/addrspace.h>
1460b49761SWills Wang #include <asm/types.h>
1560b49761SWills Wang #include <dm/pinctrl.h>
1660b49761SWills Wang #include <mach/ar71xx_regs.h>
1760b49761SWills Wang 
1860b49761SWills Wang #define AR933X_UART_DATA_REG            0x00
1960b49761SWills Wang #define AR933X_UART_CS_REG              0x04
2060b49761SWills Wang #define AR933X_UART_CLK_REG             0x08
2160b49761SWills Wang 
2260b49761SWills Wang #define AR933X_UART_DATA_TX_RX_MASK     0xff
2360b49761SWills Wang #define AR933X_UART_DATA_RX_CSR         BIT(8)
2460b49761SWills Wang #define AR933X_UART_DATA_TX_CSR         BIT(9)
2560b49761SWills Wang #define AR933X_UART_CS_IF_MODE_S        2
2660b49761SWills Wang #define AR933X_UART_CS_IF_MODE_M        0x3
2760b49761SWills Wang #define AR933X_UART_CS_IF_MODE_DTE      1
2860b49761SWills Wang #define AR933X_UART_CS_IF_MODE_DCE      2
2960b49761SWills Wang #define AR933X_UART_CS_TX_RDY_ORIDE     BIT(7)
3060b49761SWills Wang #define AR933X_UART_CS_RX_RDY_ORIDE     BIT(8)
3160b49761SWills Wang #define AR933X_UART_CLK_STEP_M          0xffff
3260b49761SWills Wang #define AR933X_UART_CLK_SCALE_M         0xfff
3360b49761SWills Wang #define AR933X_UART_CLK_SCALE_S         16
3460b49761SWills Wang #define AR933X_UART_CLK_STEP_S          0
3560b49761SWills Wang 
3660b49761SWills Wang struct ar933x_serial_priv {
3760b49761SWills Wang 	void __iomem *regs;
3860b49761SWills Wang };
3960b49761SWills Wang 
4060b49761SWills Wang /*
41773f3b25SWills Wang  * Baudrate algorithm come from Linux/drivers/tty/serial/ar933x_uart.c
4260b49761SWills Wang  * baudrate = (clk / (scale + 1)) * (step * (1 / 2^17))
4360b49761SWills Wang  */
ar933x_serial_get_baud(u32 clk,u32 scale,u32 step)4460b49761SWills Wang static u32 ar933x_serial_get_baud(u32 clk, u32 scale, u32 step)
4560b49761SWills Wang {
4660b49761SWills Wang 	u64 t;
4760b49761SWills Wang 	u32 div;
4860b49761SWills Wang 
4960b49761SWills Wang 	div = (2 << 16) * (scale + 1);
5060b49761SWills Wang 	t = clk;
5160b49761SWills Wang 	t *= step;
5260b49761SWills Wang 	t += (div / 2);
5360b49761SWills Wang 	do_div(t, div);
5460b49761SWills Wang 
5560b49761SWills Wang 	return t;
5660b49761SWills Wang }
5760b49761SWills Wang 
ar933x_serial_get_scale_step(u32 clk,u32 baud,u32 * scale,u32 * step)5860b49761SWills Wang static void ar933x_serial_get_scale_step(u32 clk, u32 baud,
5960b49761SWills Wang 					 u32 *scale, u32 *step)
6060b49761SWills Wang {
6160b49761SWills Wang 	u32 tscale, baudrate;
6260b49761SWills Wang 	long min_diff;
6360b49761SWills Wang 
6460b49761SWills Wang 	*scale = 0;
6560b49761SWills Wang 	*step = 0;
6660b49761SWills Wang 
6760b49761SWills Wang 	min_diff = baud;
6860b49761SWills Wang 	for (tscale = 0; tscale < AR933X_UART_CLK_SCALE_M; tscale++) {
6960b49761SWills Wang 		u64 tstep;
7060b49761SWills Wang 		int diff;
7160b49761SWills Wang 
7260b49761SWills Wang 		tstep = baud * (tscale + 1);
7360b49761SWills Wang 		tstep *= (2 << 16);
7460b49761SWills Wang 		do_div(tstep, clk);
7560b49761SWills Wang 
7660b49761SWills Wang 		if (tstep > AR933X_UART_CLK_STEP_M)
7760b49761SWills Wang 			break;
7860b49761SWills Wang 
7960b49761SWills Wang 		baudrate = ar933x_serial_get_baud(clk, tscale, tstep);
8060b49761SWills Wang 		diff = abs(baudrate - baud);
8160b49761SWills Wang 		if (diff < min_diff) {
8260b49761SWills Wang 			min_diff = diff;
8360b49761SWills Wang 			*scale = tscale;
8460b49761SWills Wang 			*step = tstep;
8560b49761SWills Wang 		}
8660b49761SWills Wang 	}
8760b49761SWills Wang }
8860b49761SWills Wang 
ar933x_serial_setbrg(struct udevice * dev,int baudrate)8960b49761SWills Wang static int ar933x_serial_setbrg(struct udevice *dev, int baudrate)
9060b49761SWills Wang {
9160b49761SWills Wang 	struct ar933x_serial_priv *priv = dev_get_priv(dev);
9260b49761SWills Wang 	u32 val, scale, step;
9360b49761SWills Wang 
9460b49761SWills Wang 	val = get_serial_clock();
9560b49761SWills Wang 	ar933x_serial_get_scale_step(val, baudrate, &scale, &step);
9660b49761SWills Wang 
9760b49761SWills Wang 	val  = (scale & AR933X_UART_CLK_SCALE_M)
9860b49761SWills Wang 			<< AR933X_UART_CLK_SCALE_S;
9960b49761SWills Wang 	val |= (step & AR933X_UART_CLK_STEP_M)
10060b49761SWills Wang 			<< AR933X_UART_CLK_STEP_S;
10160b49761SWills Wang 	writel(val, priv->regs + AR933X_UART_CLK_REG);
10260b49761SWills Wang 
10360b49761SWills Wang 	return 0;
10460b49761SWills Wang }
10560b49761SWills Wang 
ar933x_serial_putc(struct udevice * dev,const char c)10660b49761SWills Wang static int ar933x_serial_putc(struct udevice *dev, const char c)
10760b49761SWills Wang {
10860b49761SWills Wang 	struct ar933x_serial_priv *priv = dev_get_priv(dev);
10960b49761SWills Wang 	u32 data;
11060b49761SWills Wang 
11160b49761SWills Wang 	data = readl(priv->regs + AR933X_UART_DATA_REG);
11260b49761SWills Wang 	if (!(data & AR933X_UART_DATA_TX_CSR))
11360b49761SWills Wang 		return -EAGAIN;
11460b49761SWills Wang 
11560b49761SWills Wang 	data  = (u32)c | AR933X_UART_DATA_TX_CSR;
11660b49761SWills Wang 	writel(data, priv->regs + AR933X_UART_DATA_REG);
11760b49761SWills Wang 
11860b49761SWills Wang 	return 0;
11960b49761SWills Wang }
12060b49761SWills Wang 
ar933x_serial_getc(struct udevice * dev)12160b49761SWills Wang static int ar933x_serial_getc(struct udevice *dev)
12260b49761SWills Wang {
12360b49761SWills Wang 	struct ar933x_serial_priv *priv = dev_get_priv(dev);
12460b49761SWills Wang 	u32 data;
12560b49761SWills Wang 
12660b49761SWills Wang 	data = readl(priv->regs + AR933X_UART_DATA_REG);
12760b49761SWills Wang 	if (!(data & AR933X_UART_DATA_RX_CSR))
12860b49761SWills Wang 		return -EAGAIN;
12960b49761SWills Wang 
13060b49761SWills Wang 	writel(AR933X_UART_DATA_RX_CSR, priv->regs + AR933X_UART_DATA_REG);
13160b49761SWills Wang 	return data & AR933X_UART_DATA_TX_RX_MASK;
13260b49761SWills Wang }
13360b49761SWills Wang 
ar933x_serial_pending(struct udevice * dev,bool input)13460b49761SWills Wang static int ar933x_serial_pending(struct udevice *dev, bool input)
13560b49761SWills Wang {
13660b49761SWills Wang 	struct ar933x_serial_priv *priv = dev_get_priv(dev);
13760b49761SWills Wang 	u32 data;
13860b49761SWills Wang 
13960b49761SWills Wang 	data = readl(priv->regs + AR933X_UART_DATA_REG);
14060b49761SWills Wang 	if (input)
14160b49761SWills Wang 		return (data & AR933X_UART_DATA_RX_CSR) ? 1 : 0;
14260b49761SWills Wang 	else
14360b49761SWills Wang 		return (data & AR933X_UART_DATA_TX_CSR) ? 0 : 1;
14460b49761SWills Wang }
14560b49761SWills Wang 
ar933x_serial_probe(struct udevice * dev)14660b49761SWills Wang static int ar933x_serial_probe(struct udevice *dev)
14760b49761SWills Wang {
14860b49761SWills Wang 	struct ar933x_serial_priv *priv = dev_get_priv(dev);
14960b49761SWills Wang 	fdt_addr_t addr;
15060b49761SWills Wang 	u32 val;
15160b49761SWills Wang 
152*a821c4afSSimon Glass 	addr = devfdt_get_addr(dev);
15360b49761SWills Wang 	if (addr == FDT_ADDR_T_NONE)
15460b49761SWills Wang 		return -EINVAL;
15560b49761SWills Wang 
156773f3b25SWills Wang 	priv->regs = map_physmem(addr, AR933X_UART_SIZE,
15760b49761SWills Wang 				 MAP_NOCACHE);
15860b49761SWills Wang 
15960b49761SWills Wang 	/*
16060b49761SWills Wang 	 * UART controller configuration:
16160b49761SWills Wang 	 * - no DMA
16260b49761SWills Wang 	 * - no interrupt
16360b49761SWills Wang 	 * - DCE mode
16460b49761SWills Wang 	 * - no flow control
16560b49761SWills Wang 	 * - set RX ready oride
16660b49761SWills Wang 	 * - set TX ready oride
16760b49761SWills Wang 	 */
16860b49761SWills Wang 	val = (AR933X_UART_CS_IF_MODE_DCE << AR933X_UART_CS_IF_MODE_S) |
16960b49761SWills Wang 	      AR933X_UART_CS_TX_RDY_ORIDE | AR933X_UART_CS_RX_RDY_ORIDE;
17060b49761SWills Wang 	writel(val, priv->regs + AR933X_UART_CS_REG);
17160b49761SWills Wang 	return 0;
17260b49761SWills Wang }
17360b49761SWills Wang 
17460b49761SWills Wang static const struct dm_serial_ops ar933x_serial_ops = {
17560b49761SWills Wang 	.putc = ar933x_serial_putc,
17660b49761SWills Wang 	.pending = ar933x_serial_pending,
17760b49761SWills Wang 	.getc = ar933x_serial_getc,
17860b49761SWills Wang 	.setbrg = ar933x_serial_setbrg,
17960b49761SWills Wang };
18060b49761SWills Wang 
18160b49761SWills Wang static const struct udevice_id ar933x_serial_ids[] = {
18260b49761SWills Wang 	{ .compatible = "qca,ar9330-uart" },
18360b49761SWills Wang 	{ }
18460b49761SWills Wang };
18560b49761SWills Wang 
18660b49761SWills Wang U_BOOT_DRIVER(serial_ar933x) = {
18760b49761SWills Wang 	.name   = "serial_ar933x",
18860b49761SWills Wang 	.id = UCLASS_SERIAL,
18960b49761SWills Wang 	.of_match = ar933x_serial_ids,
19060b49761SWills Wang 	.priv_auto_alloc_size = sizeof(struct ar933x_serial_priv),
19160b49761SWills Wang 	.probe = ar933x_serial_probe,
19260b49761SWills Wang 	.ops    = &ar933x_serial_ops,
19360b49761SWills Wang 	.flags = DM_FLAG_PRE_RELOC,
19460b49761SWills Wang };
19560b49761SWills Wang 
19660b49761SWills Wang #ifdef CONFIG_DEBUG_UART_AR933X
19760b49761SWills Wang 
19860b49761SWills Wang #include <debug_uart.h>
19960b49761SWills Wang 
_debug_uart_init(void)20060b49761SWills Wang static inline void _debug_uart_init(void)
20160b49761SWills Wang {
20260b49761SWills Wang 	void __iomem *regs = (void *)CONFIG_DEBUG_UART_BASE;
20360b49761SWills Wang 	u32 val, scale, step;
20460b49761SWills Wang 
20560b49761SWills Wang 	/*
20660b49761SWills Wang 	 * UART controller configuration:
20760b49761SWills Wang 	 * - no DMA
20860b49761SWills Wang 	 * - no interrupt
20960b49761SWills Wang 	 * - DCE mode
21060b49761SWills Wang 	 * - no flow control
21160b49761SWills Wang 	 * - set RX ready oride
21260b49761SWills Wang 	 * - set TX ready oride
21360b49761SWills Wang 	 */
21460b49761SWills Wang 	val = (AR933X_UART_CS_IF_MODE_DCE << AR933X_UART_CS_IF_MODE_S) |
21560b49761SWills Wang 	      AR933X_UART_CS_TX_RDY_ORIDE | AR933X_UART_CS_RX_RDY_ORIDE;
21660b49761SWills Wang 	writel(val, regs + AR933X_UART_CS_REG);
21760b49761SWills Wang 
21860b49761SWills Wang 	ar933x_serial_get_scale_step(CONFIG_DEBUG_UART_CLOCK,
21960b49761SWills Wang 				     CONFIG_BAUDRATE, &scale, &step);
22060b49761SWills Wang 
22160b49761SWills Wang 	val  = (scale & AR933X_UART_CLK_SCALE_M)
22260b49761SWills Wang 			<< AR933X_UART_CLK_SCALE_S;
22360b49761SWills Wang 	val |= (step & AR933X_UART_CLK_STEP_M)
22460b49761SWills Wang 			<< AR933X_UART_CLK_STEP_S;
22560b49761SWills Wang 	writel(val, regs + AR933X_UART_CLK_REG);
22660b49761SWills Wang }
22760b49761SWills Wang 
_debug_uart_putc(int c)22860b49761SWills Wang static inline void _debug_uart_putc(int c)
22960b49761SWills Wang {
23060b49761SWills Wang 	void __iomem *regs = (void *)CONFIG_DEBUG_UART_BASE;
23160b49761SWills Wang 	u32 data;
23260b49761SWills Wang 
23360b49761SWills Wang 	do {
23460b49761SWills Wang 		data = readl(regs + AR933X_UART_DATA_REG);
23560b49761SWills Wang 	} while (!(data & AR933X_UART_DATA_TX_CSR));
23660b49761SWills Wang 
23760b49761SWills Wang 	data  = (u32)c | AR933X_UART_DATA_TX_CSR;
23860b49761SWills Wang 	writel(data, regs + AR933X_UART_DATA_REG);
23960b49761SWills Wang }
24060b49761SWills Wang 
24160b49761SWills Wang DEBUG_UART_FUNCS
24260b49761SWills Wang 
24360b49761SWills Wang #endif
244