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