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