1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * (C) Copyright 2016 Beniamino Galvani <b.galvani@gmail.com> 4 */ 5 6 #include <common.h> 7 #include <dm.h> 8 #include <errno.h> 9 #include <fdtdec.h> 10 #include <linux/compiler.h> 11 #include <serial.h> 12 13 struct meson_uart { 14 u32 wfifo; 15 u32 rfifo; 16 u32 control; 17 u32 status; 18 u32 misc; 19 }; 20 21 struct meson_serial_platdata { 22 struct meson_uart *reg; 23 }; 24 25 /* AML_UART_STATUS bits */ 26 #define AML_UART_PARITY_ERR BIT(16) 27 #define AML_UART_FRAME_ERR BIT(17) 28 #define AML_UART_TX_FIFO_WERR BIT(18) 29 #define AML_UART_RX_EMPTY BIT(20) 30 #define AML_UART_TX_FULL BIT(21) 31 #define AML_UART_TX_EMPTY BIT(22) 32 #define AML_UART_XMIT_BUSY BIT(25) 33 #define AML_UART_ERR (AML_UART_PARITY_ERR | \ 34 AML_UART_FRAME_ERR | \ 35 AML_UART_TX_FIFO_WERR) 36 37 /* AML_UART_CONTROL bits */ 38 #define AML_UART_TX_EN BIT(12) 39 #define AML_UART_RX_EN BIT(13) 40 #define AML_UART_TX_RST BIT(22) 41 #define AML_UART_RX_RST BIT(23) 42 #define AML_UART_CLR_ERR BIT(24) 43 44 static void meson_serial_init(struct meson_uart *uart) 45 { 46 u32 val; 47 48 val = readl(&uart->control); 49 val |= (AML_UART_RX_RST | AML_UART_TX_RST | AML_UART_CLR_ERR); 50 writel(val, &uart->control); 51 val &= ~(AML_UART_RX_RST | AML_UART_TX_RST | AML_UART_CLR_ERR); 52 writel(val, &uart->control); 53 val |= (AML_UART_RX_EN | AML_UART_TX_EN); 54 writel(val, &uart->control); 55 } 56 57 static int meson_serial_probe(struct udevice *dev) 58 { 59 struct meson_serial_platdata *plat = dev->platdata; 60 struct meson_uart *const uart = plat->reg; 61 62 meson_serial_init(uart); 63 64 return 0; 65 } 66 67 static int meson_serial_getc(struct udevice *dev) 68 { 69 struct meson_serial_platdata *plat = dev->platdata; 70 struct meson_uart *const uart = plat->reg; 71 72 if (readl(&uart->status) & AML_UART_RX_EMPTY) 73 return -EAGAIN; 74 75 return readl(&uart->rfifo) & 0xff; 76 } 77 78 static int meson_serial_putc(struct udevice *dev, const char ch) 79 { 80 struct meson_serial_platdata *plat = dev->platdata; 81 struct meson_uart *const uart = plat->reg; 82 83 if (readl(&uart->status) & AML_UART_TX_FULL) 84 return -EAGAIN; 85 86 writel(ch, &uart->wfifo); 87 88 return 0; 89 } 90 91 static int meson_serial_pending(struct udevice *dev, bool input) 92 { 93 struct meson_serial_platdata *plat = dev->platdata; 94 struct meson_uart *const uart = plat->reg; 95 uint32_t status = readl(&uart->status); 96 97 if (input) 98 return !(status & AML_UART_RX_EMPTY); 99 else 100 return !(status & AML_UART_TX_FULL); 101 } 102 103 static int meson_serial_ofdata_to_platdata(struct udevice *dev) 104 { 105 struct meson_serial_platdata *plat = dev->platdata; 106 fdt_addr_t addr; 107 108 addr = devfdt_get_addr(dev); 109 if (addr == FDT_ADDR_T_NONE) 110 return -EINVAL; 111 112 plat->reg = (struct meson_uart *)addr; 113 114 return 0; 115 } 116 117 static const struct dm_serial_ops meson_serial_ops = { 118 .putc = meson_serial_putc, 119 .pending = meson_serial_pending, 120 .getc = meson_serial_getc, 121 }; 122 123 static const struct udevice_id meson_serial_ids[] = { 124 { .compatible = "amlogic,meson-uart" }, 125 { .compatible = "amlogic,meson-gx-uart" }, 126 { } 127 }; 128 129 U_BOOT_DRIVER(serial_meson) = { 130 .name = "serial_meson", 131 .id = UCLASS_SERIAL, 132 .of_match = meson_serial_ids, 133 .probe = meson_serial_probe, 134 .ops = &meson_serial_ops, 135 .flags = DM_FLAG_PRE_RELOC, 136 .ofdata_to_platdata = meson_serial_ofdata_to_platdata, 137 .platdata_auto_alloc_size = sizeof(struct meson_serial_platdata), 138 }; 139 140 #ifdef CONFIG_DEBUG_UART_MESON 141 142 #include <debug_uart.h> 143 144 static inline void _debug_uart_init(void) 145 { 146 } 147 148 static inline void _debug_uart_putc(int ch) 149 { 150 struct meson_uart *regs = (struct meson_uart *)CONFIG_DEBUG_UART_BASE; 151 152 while (readl(®s->status) & AML_UART_TX_FULL) 153 ; 154 155 writel(ch, ®s->wfifo); 156 } 157 158 DEBUG_UART_FUNCS 159 160 #endif 161