xref: /rk3399_rockchip-uboot/drivers/serial/serial_mvebu_a3700.c (revision a821c4af79e4f5ce9b629b20473863397bbe9b10)
16985d496SStefan Roese /*
26985d496SStefan Roese  * Copyright (C) 2016 Stefan Roese <sr@denx.de>
36985d496SStefan Roese  *
46985d496SStefan Roese  * SPDX-License-Identifier:	GPL-2.0+
56985d496SStefan Roese  */
66985d496SStefan Roese 
76985d496SStefan Roese #include <common.h>
86985d496SStefan Roese #include <dm.h>
96985d496SStefan Roese #include <serial.h>
106985d496SStefan Roese #include <asm/io.h>
116985d496SStefan Roese 
126985d496SStefan Roese struct mvebu_platdata {
136985d496SStefan Roese 	void __iomem *base;
146985d496SStefan Roese };
156985d496SStefan Roese 
166985d496SStefan Roese /*
176985d496SStefan Roese  * Register offset
186985d496SStefan Roese  */
196985d496SStefan Roese #define UART_RX_REG		0x00
206985d496SStefan Roese #define UART_TX_REG		0x04
216985d496SStefan Roese #define UART_CTRL_REG		0x08
226985d496SStefan Roese #define UART_STATUS_REG		0x0c
236985d496SStefan Roese #define UART_BAUD_REG		0x10
246985d496SStefan Roese #define UART_POSSR_REG		0x14
256985d496SStefan Roese 
266985d496SStefan Roese #define UART_STATUS_RX_RDY	0x10
276985d496SStefan Roese #define UART_STATUS_TXFIFO_FULL	0x800
286985d496SStefan Roese 
296985d496SStefan Roese #define UART_CTRL_RXFIFO_RESET	0x4000
306985d496SStefan Roese #define UART_CTRL_TXFIFO_RESET	0x8000
316985d496SStefan Roese 
326985d496SStefan Roese #define CONFIG_UART_BASE_CLOCK	25804800
336985d496SStefan Roese 
mvebu_serial_putc(struct udevice * dev,const char ch)346985d496SStefan Roese static int mvebu_serial_putc(struct udevice *dev, const char ch)
356985d496SStefan Roese {
366985d496SStefan Roese 	struct mvebu_platdata *plat = dev_get_platdata(dev);
376985d496SStefan Roese 	void __iomem *base = plat->base;
386985d496SStefan Roese 
396985d496SStefan Roese 	while (readl(base + UART_STATUS_REG) & UART_STATUS_TXFIFO_FULL)
406985d496SStefan Roese 		;
416985d496SStefan Roese 
426985d496SStefan Roese 	writel(ch, base + UART_TX_REG);
436985d496SStefan Roese 
446985d496SStefan Roese 	return 0;
456985d496SStefan Roese }
466985d496SStefan Roese 
mvebu_serial_getc(struct udevice * dev)476985d496SStefan Roese static int mvebu_serial_getc(struct udevice *dev)
486985d496SStefan Roese {
496985d496SStefan Roese 	struct mvebu_platdata *plat = dev_get_platdata(dev);
506985d496SStefan Roese 	void __iomem *base = plat->base;
516985d496SStefan Roese 
526985d496SStefan Roese 	while (!(readl(base + UART_STATUS_REG) & UART_STATUS_RX_RDY))
536985d496SStefan Roese 		;
546985d496SStefan Roese 
556985d496SStefan Roese 	return readl(base + UART_RX_REG) & 0xff;
566985d496SStefan Roese }
576985d496SStefan Roese 
mvebu_serial_pending(struct udevice * dev,bool input)586985d496SStefan Roese static int mvebu_serial_pending(struct udevice *dev, bool input)
596985d496SStefan Roese {
606985d496SStefan Roese 	struct mvebu_platdata *plat = dev_get_platdata(dev);
616985d496SStefan Roese 	void __iomem *base = plat->base;
626985d496SStefan Roese 
636985d496SStefan Roese 	if (readl(base + UART_STATUS_REG) & UART_STATUS_RX_RDY)
646985d496SStefan Roese 		return 1;
656985d496SStefan Roese 
666985d496SStefan Roese 	return 0;
676985d496SStefan Roese }
686985d496SStefan Roese 
mvebu_serial_setbrg(struct udevice * dev,int baudrate)696985d496SStefan Roese static int mvebu_serial_setbrg(struct udevice *dev, int baudrate)
706985d496SStefan Roese {
716985d496SStefan Roese 	struct mvebu_platdata *plat = dev_get_platdata(dev);
726985d496SStefan Roese 	void __iomem *base = plat->base;
736985d496SStefan Roese 
746985d496SStefan Roese 	/*
756985d496SStefan Roese 	 * Calculate divider
766985d496SStefan Roese 	 * baudrate = clock / 16 / divider
776985d496SStefan Roese 	 */
786985d496SStefan Roese 	writel(CONFIG_UART_BASE_CLOCK / baudrate / 16, base + UART_BAUD_REG);
796985d496SStefan Roese 
806985d496SStefan Roese 	/*
816985d496SStefan Roese 	 * Set Programmable Oversampling Stack to 0,
826985d496SStefan Roese 	 * UART defaults to 16x scheme
836985d496SStefan Roese 	 */
846985d496SStefan Roese 	writel(0, base + UART_POSSR_REG);
856985d496SStefan Roese 
866985d496SStefan Roese 	return 0;
876985d496SStefan Roese }
886985d496SStefan Roese 
mvebu_serial_probe(struct udevice * dev)896985d496SStefan Roese static int mvebu_serial_probe(struct udevice *dev)
906985d496SStefan Roese {
916985d496SStefan Roese 	struct mvebu_platdata *plat = dev_get_platdata(dev);
926985d496SStefan Roese 	void __iomem *base = plat->base;
936985d496SStefan Roese 
946985d496SStefan Roese 	/* reset FIFOs */
956985d496SStefan Roese 	writel(UART_CTRL_RXFIFO_RESET | UART_CTRL_TXFIFO_RESET,
966985d496SStefan Roese 	       base + UART_CTRL_REG);
976985d496SStefan Roese 
986985d496SStefan Roese 	/* No Parity, 1 Stop */
996985d496SStefan Roese 	writel(0, base + UART_CTRL_REG);
1006985d496SStefan Roese 
1016985d496SStefan Roese 	return 0;
1026985d496SStefan Roese }
1036985d496SStefan Roese 
mvebu_serial_ofdata_to_platdata(struct udevice * dev)1046985d496SStefan Roese static int mvebu_serial_ofdata_to_platdata(struct udevice *dev)
1056985d496SStefan Roese {
1066985d496SStefan Roese 	struct mvebu_platdata *plat = dev_get_platdata(dev);
1076985d496SStefan Roese 
108*a821c4afSSimon Glass 	plat->base = devfdt_get_addr_ptr(dev);
1096985d496SStefan Roese 
1106985d496SStefan Roese 	return 0;
1116985d496SStefan Roese }
1126985d496SStefan Roese 
1136985d496SStefan Roese static const struct dm_serial_ops mvebu_serial_ops = {
1146985d496SStefan Roese 	.putc = mvebu_serial_putc,
1156985d496SStefan Roese 	.pending = mvebu_serial_pending,
1166985d496SStefan Roese 	.getc = mvebu_serial_getc,
1176985d496SStefan Roese 	.setbrg = mvebu_serial_setbrg,
1186985d496SStefan Roese };
1196985d496SStefan Roese 
1206985d496SStefan Roese static const struct udevice_id mvebu_serial_ids[] = {
1216985d496SStefan Roese 	{ .compatible = "marvell,armada-3700-uart" },
1226985d496SStefan Roese 	{ }
1236985d496SStefan Roese };
1246985d496SStefan Roese 
1256985d496SStefan Roese U_BOOT_DRIVER(serial_mvebu) = {
1266985d496SStefan Roese 	.name	= "serial_mvebu",
1276985d496SStefan Roese 	.id	= UCLASS_SERIAL,
1286985d496SStefan Roese 	.of_match = mvebu_serial_ids,
1296985d496SStefan Roese 	.ofdata_to_platdata = mvebu_serial_ofdata_to_platdata,
1306985d496SStefan Roese 	.platdata_auto_alloc_size = sizeof(struct mvebu_platdata),
1316985d496SStefan Roese 	.probe	= mvebu_serial_probe,
1326985d496SStefan Roese 	.ops	= &mvebu_serial_ops,
1336985d496SStefan Roese 	.flags	= DM_FLAG_PRE_RELOC,
1346985d496SStefan Roese };
1356985d496SStefan Roese 
1366985d496SStefan Roese #ifdef CONFIG_DEBUG_MVEBU_A3700_UART
1376985d496SStefan Roese 
1386985d496SStefan Roese #include <debug_uart.h>
1396985d496SStefan Roese 
_debug_uart_init(void)1406985d496SStefan Roese static inline void _debug_uart_init(void)
1416985d496SStefan Roese {
1426985d496SStefan Roese 	void __iomem *base = (void __iomem *)CONFIG_DEBUG_UART_BASE;
1436985d496SStefan Roese 
1446985d496SStefan Roese 	/* reset FIFOs */
1456985d496SStefan Roese 	writel(UART_CTRL_RXFIFO_RESET | UART_CTRL_TXFIFO_RESET,
1466985d496SStefan Roese 	       base + UART_CTRL_REG);
1476985d496SStefan Roese 
1486985d496SStefan Roese 	/* No Parity, 1 Stop */
1496985d496SStefan Roese 	writel(0, base + UART_CTRL_REG);
1506985d496SStefan Roese 
1516985d496SStefan Roese 	/*
1526985d496SStefan Roese 	 * Calculate divider
1536985d496SStefan Roese 	 * baudrate = clock / 16 / divider
1546985d496SStefan Roese 	 */
1556985d496SStefan Roese 	writel(CONFIG_UART_BASE_CLOCK / 115200 / 16, base + UART_BAUD_REG);
1566985d496SStefan Roese 
1576985d496SStefan Roese 	/*
1586985d496SStefan Roese 	 * Set Programmable Oversampling Stack to 0,
1596985d496SStefan Roese 	 * UART defaults to 16x scheme
1606985d496SStefan Roese 	 */
1616985d496SStefan Roese 	writel(0, base + UART_POSSR_REG);
1626985d496SStefan Roese }
1636985d496SStefan Roese 
_debug_uart_putc(int ch)1646985d496SStefan Roese static inline void _debug_uart_putc(int ch)
1656985d496SStefan Roese {
1666985d496SStefan Roese 	void __iomem *base = (void __iomem *)CONFIG_DEBUG_UART_BASE;
1676985d496SStefan Roese 
1686985d496SStefan Roese 	while (readl(base + UART_STATUS_REG) & UART_STATUS_TXFIFO_FULL)
1696985d496SStefan Roese 		;
1706985d496SStefan Roese 
1716985d496SStefan Roese 	writel(ch, base + UART_TX_REG);
1726985d496SStefan Roese }
1736985d496SStefan Roese 
1746985d496SStefan Roese DEBUG_UART_FUNCS
1756985d496SStefan Roese #endif
176