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