xref: /rk3399_rockchip-uboot/drivers/serial/altera_uart.c (revision da2f838d8a6f72dfe4bdea529d3e98826fba5e8a)
1c9d4f46bSScott McNutt /*
2c9d4f46bSScott McNutt  * (C) Copyright 2004, Psyent Corporation <www.psyent.com>
3c9d4f46bSScott McNutt  * Scott McNutt <smcnutt@psyent.com>
4c9d4f46bSScott McNutt  *
51a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
6c9d4f46bSScott McNutt  */
7c9d4f46bSScott McNutt 
8c9d4f46bSScott McNutt #include <common.h>
9*da2f838dSThomas Chou #include <dm.h>
10*da2f838dSThomas Chou #include <errno.h>
11c9d4f46bSScott McNutt #include <asm/io.h>
12b207d645SMarek Vasut #include <linux/compiler.h>
13b207d645SMarek Vasut #include <serial.h>
14c9d4f46bSScott McNutt 
15*da2f838dSThomas Chou struct altera_uart_regs {
16*da2f838dSThomas Chou 	u32	rxdata;		/* Rx data reg */
17*da2f838dSThomas Chou 	u32	txdata;		/* Tx data reg */
18*da2f838dSThomas Chou 	u32	status;		/* Status reg */
19*da2f838dSThomas Chou 	u32	control;	/* Control reg */
20*da2f838dSThomas Chou 	u32	divisor;	/* Baud rate divisor reg */
21*da2f838dSThomas Chou 	u32	endofpacket;	/* End-of-packet reg */
22*da2f838dSThomas Chou };
23*da2f838dSThomas Chou 
24*da2f838dSThomas Chou struct altera_uart_platdata {
25*da2f838dSThomas Chou 	struct altera_uart_regs *regs;
26*da2f838dSThomas Chou 	unsigned int uartclk;
27*da2f838dSThomas Chou };
2886450710SThomas Chou 
2986450710SThomas Chou /* status register */
30*da2f838dSThomas Chou #define ALTERA_UART_TMT		(1 << 5)	/* tx empty */
31*da2f838dSThomas Chou #define ALTERA_UART_TRDY	(1 << 6)	/* tx ready */
32*da2f838dSThomas Chou #define ALTERA_UART_RRDY	(1 << 7)	/* rx ready */
3386450710SThomas Chou 
34c9d4f46bSScott McNutt DECLARE_GLOBAL_DATA_PTR;
35c9d4f46bSScott McNutt 
36*da2f838dSThomas Chou static int altera_uart_setbrg(struct udevice *dev, int baudrate)
37b207d645SMarek Vasut {
38*da2f838dSThomas Chou 	struct altera_uart_platdata *plat = dev->platdata;
39*da2f838dSThomas Chou 	struct altera_uart_regs *const regs = plat->regs;
40*da2f838dSThomas Chou 	u32 div;
41*da2f838dSThomas Chou 
42*da2f838dSThomas Chou 	div = (plat->uartclk / baudrate) - 1;
43*da2f838dSThomas Chou 	writel(div, &regs->divisor);
44*da2f838dSThomas Chou 
45*da2f838dSThomas Chou 	return 0;
46b207d645SMarek Vasut }
47b207d645SMarek Vasut 
48*da2f838dSThomas Chou static int altera_uart_putc(struct udevice *dev, const char ch)
49*da2f838dSThomas Chou {
50*da2f838dSThomas Chou 	struct altera_uart_platdata *plat = dev->platdata;
51*da2f838dSThomas Chou 	struct altera_uart_regs *const regs = plat->regs;
52*da2f838dSThomas Chou 
53*da2f838dSThomas Chou 	if (!(readl(&regs->status) & ALTERA_UART_TRDY))
54*da2f838dSThomas Chou 		return -EAGAIN;
55*da2f838dSThomas Chou 
56*da2f838dSThomas Chou 	writel(ch, &regs->txdata);
57*da2f838dSThomas Chou 
58*da2f838dSThomas Chou 	return 0;
59*da2f838dSThomas Chou }
60*da2f838dSThomas Chou 
61*da2f838dSThomas Chou static int altera_uart_pending(struct udevice *dev, bool input)
62*da2f838dSThomas Chou {
63*da2f838dSThomas Chou 	struct altera_uart_platdata *plat = dev->platdata;
64*da2f838dSThomas Chou 	struct altera_uart_regs *const regs = plat->regs;
65*da2f838dSThomas Chou 	u32 st = readl(&regs->status);
66*da2f838dSThomas Chou 
67*da2f838dSThomas Chou 	if (input)
68*da2f838dSThomas Chou 		return st & ALTERA_UART_RRDY ? 1 : 0;
69*da2f838dSThomas Chou 	else
70*da2f838dSThomas Chou 		return !(st & ALTERA_UART_TMT);
71*da2f838dSThomas Chou }
72*da2f838dSThomas Chou 
73*da2f838dSThomas Chou static int altera_uart_getc(struct udevice *dev)
74*da2f838dSThomas Chou {
75*da2f838dSThomas Chou 	struct altera_uart_platdata *plat = dev->platdata;
76*da2f838dSThomas Chou 	struct altera_uart_regs *const regs = plat->regs;
77*da2f838dSThomas Chou 
78*da2f838dSThomas Chou 	if (!(readl(&regs->status) & ALTERA_UART_RRDY))
79*da2f838dSThomas Chou 		return -EAGAIN;
80*da2f838dSThomas Chou 
81*da2f838dSThomas Chou 	return readl(&regs->rxdata) & 0xff;
82*da2f838dSThomas Chou }
83*da2f838dSThomas Chou 
84*da2f838dSThomas Chou static int altera_uart_probe(struct udevice *dev)
85b207d645SMarek Vasut {
86b207d645SMarek Vasut 	return 0;
87b207d645SMarek Vasut }
88c9d4f46bSScott McNutt 
89*da2f838dSThomas Chou static int altera_uart_ofdata_to_platdata(struct udevice *dev)
90c9d4f46bSScott McNutt {
91*da2f838dSThomas Chou 	struct altera_uart_platdata *plat = dev_get_platdata(dev);
92c9d4f46bSScott McNutt 
93*da2f838dSThomas Chou 	plat->regs = ioremap(dev_get_addr(dev),
94*da2f838dSThomas Chou 		sizeof(struct altera_uart_regs));
95*da2f838dSThomas Chou 	plat->uartclk = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
96*da2f838dSThomas Chou 		"clock-frequency", 0);
97c9d4f46bSScott McNutt 
98b207d645SMarek Vasut 	return 0;
99c9d4f46bSScott McNutt }
100c9d4f46bSScott McNutt 
101*da2f838dSThomas Chou static const struct dm_serial_ops altera_uart_ops = {
102*da2f838dSThomas Chou 	.putc = altera_uart_putc,
103*da2f838dSThomas Chou 	.pending = altera_uart_pending,
104*da2f838dSThomas Chou 	.getc = altera_uart_getc,
105*da2f838dSThomas Chou 	.setbrg = altera_uart_setbrg,
106b207d645SMarek Vasut };
107b207d645SMarek Vasut 
108*da2f838dSThomas Chou static const struct udevice_id altera_uart_ids[] = {
109*da2f838dSThomas Chou 	{ .compatible = "altr,uart-1.0", },
110*da2f838dSThomas Chou 	{ }
111*da2f838dSThomas Chou };
112*da2f838dSThomas Chou 
113*da2f838dSThomas Chou U_BOOT_DRIVER(altera_uart) = {
114*da2f838dSThomas Chou 	.name	= "altera_uart",
115*da2f838dSThomas Chou 	.id	= UCLASS_SERIAL,
116*da2f838dSThomas Chou 	.of_match = altera_uart_ids,
117*da2f838dSThomas Chou 	.ofdata_to_platdata = altera_uart_ofdata_to_platdata,
118*da2f838dSThomas Chou 	.platdata_auto_alloc_size = sizeof(struct altera_uart_platdata),
119*da2f838dSThomas Chou 	.probe = altera_uart_probe,
120*da2f838dSThomas Chou 	.ops	= &altera_uart_ops,
121*da2f838dSThomas Chou 	.flags = DM_FLAG_PRE_RELOC,
122*da2f838dSThomas Chou };
123*da2f838dSThomas Chou 
124*da2f838dSThomas Chou #ifdef CONFIG_DEBUG_UART_ALTERA_UART
125*da2f838dSThomas Chou 
126*da2f838dSThomas Chou #include <debug_uart.h>
127*da2f838dSThomas Chou 
128*da2f838dSThomas Chou void debug_uart_init(void)
129b207d645SMarek Vasut {
130*da2f838dSThomas Chou 	struct altera_uart_regs *regs = (void *)CONFIG_DEBUG_UART_BASE;
131*da2f838dSThomas Chou 	u32 div;
132*da2f838dSThomas Chou 
133*da2f838dSThomas Chou 	div = (CONFIG_DEBUG_UART_CLOCK / CONFIG_BAUDRATE) - 1;
134*da2f838dSThomas Chou 	writel(div, &regs->divisor);
135b207d645SMarek Vasut }
136b207d645SMarek Vasut 
137*da2f838dSThomas Chou static inline void _debug_uart_putc(int ch)
138b207d645SMarek Vasut {
139*da2f838dSThomas Chou 	struct altera_uart_regs *regs = (void *)CONFIG_DEBUG_UART_BASE;
140*da2f838dSThomas Chou 
141*da2f838dSThomas Chou 	while (1) {
142*da2f838dSThomas Chou 		u32 st = readl(&regs->status);
143*da2f838dSThomas Chou 
144*da2f838dSThomas Chou 		if (st & ALTERA_UART_TRDY)
145*da2f838dSThomas Chou 			break;
146b207d645SMarek Vasut 	}
147*da2f838dSThomas Chou 
148*da2f838dSThomas Chou 	writel(ch, &regs->txdata);
149*da2f838dSThomas Chou }
150*da2f838dSThomas Chou 
151*da2f838dSThomas Chou DEBUG_UART_FUNCS
152*da2f838dSThomas Chou 
153*da2f838dSThomas Chou #endif
154