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