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