1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Texas Instruments' OMAP serial driver 4 * 5 * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ 6 * Lokesh Vutla <lokeshvutla@ti.com> 7 */ 8 9 #include <common.h> 10 #include <dm.h> 11 #include <dt-structs.h> 12 #include <ns16550.h> 13 #include <serial.h> 14 #include <clk.h> 15 16 #ifndef CONFIG_SYS_NS16550_CLK 17 #define CONFIG_SYS_NS16550_CLK 0 18 #endif 19 20 #ifdef CONFIG_DEBUG_UART_OMAP 21 22 #ifndef CONFIG_SYS_NS16550_IER 23 #define CONFIG_SYS_NS16550_IER 0x00 24 #endif 25 26 #define UART_MCRVAL 0x00 27 #define UART_LCRVAL UART_LCR_8N1 28 29 static inline void serial_out_shift(void *addr, int shift, int value) 30 { 31 #ifdef CONFIG_SYS_NS16550_PORT_MAPPED 32 outb(value, (ulong)addr); 33 #elif defined(CONFIG_SYS_NS16550_MEM32) && defined(CONFIG_SYS_LITTLE_ENDIAN) 34 out_le32(addr, value); 35 #elif defined(CONFIG_SYS_NS16550_MEM32) && defined(CONFIG_SYS_BIG_ENDIAN) 36 out_be32(addr, value); 37 #elif defined(CONFIG_SYS_NS16550_MEM32) 38 writel(value, addr); 39 #elif defined(CONFIG_SYS_BIG_ENDIAN) 40 writeb(value, addr + (1 << shift) - 1); 41 #else 42 writeb(value, addr); 43 #endif 44 } 45 46 static inline int serial_in_shift(void *addr, int shift) 47 { 48 #ifdef CONFIG_SYS_NS16550_PORT_MAPPED 49 return inb((ulong)addr); 50 #elif defined(CONFIG_SYS_NS16550_MEM32) && defined(CONFIG_SYS_LITTLE_ENDIAN) 51 return in_le32(addr); 52 #elif defined(CONFIG_SYS_NS16550_MEM32) && defined(CONFIG_SYS_BIG_ENDIAN) 53 return in_be32(addr); 54 #elif defined(CONFIG_SYS_NS16550_MEM32) 55 return readl(addr); 56 #elif defined(CONFIG_SYS_BIG_ENDIAN) 57 return readb(addr + (1 << shift) - 1); 58 #else 59 return readb(addr); 60 #endif 61 } 62 63 #include <debug_uart.h> 64 65 static inline void _debug_uart_init(void) 66 { 67 struct NS16550 *com_port = (struct NS16550 *)CONFIG_DEBUG_UART_BASE; 68 int baud_divisor; 69 70 baud_divisor = ns16550_calc_divisor(com_port, CONFIG_DEBUG_UART_CLOCK, 71 CONFIG_BAUDRATE); 72 serial_dout(&com_port->ier, CONFIG_SYS_NS16550_IER); 73 serial_dout(&com_port->mdr1, 0x7); 74 serial_dout(&com_port->mcr, UART_MCRVAL); 75 serial_dout(&com_port->fcr, UART_FCR_DEFVAL); 76 77 serial_dout(&com_port->lcr, UART_LCR_BKSE | UART_LCRVAL); 78 serial_dout(&com_port->dll, baud_divisor & 0xff); 79 serial_dout(&com_port->dlm, (baud_divisor >> 8) & 0xff); 80 serial_dout(&com_port->lcr, UART_LCRVAL); 81 serial_dout(&com_port->mdr1, 0x0); 82 } 83 84 static inline void _debug_uart_putc(int ch) 85 { 86 struct NS16550 *com_port = (struct NS16550 *)CONFIG_DEBUG_UART_BASE; 87 88 while (!(serial_din(&com_port->lsr) & UART_LSR_THRE)) 89 ; 90 serial_dout(&com_port->thr, ch); 91 } 92 93 DEBUG_UART_FUNCS 94 95 #endif 96 97 #if CONFIG_IS_ENABLED(DM_SERIAL) 98 99 #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA) 100 static int omap_serial_ofdata_to_platdata(struct udevice *dev) 101 { 102 struct ns16550_platdata *plat = dev->platdata; 103 fdt_addr_t addr; 104 struct clk clk; 105 int err; 106 107 /* try Processor Local Bus device first */ 108 addr = dev_read_addr(dev); 109 if (addr == FDT_ADDR_T_NONE) 110 return -EINVAL; 111 112 plat->base = (unsigned long)map_physmem(addr, 0, MAP_NOCACHE); 113 114 plat->reg_offset = dev_read_u32_default(dev, "reg-offset", 0); 115 plat->reg_shift = 2; 116 117 err = clk_get_by_index(dev, 0, &clk); 118 if (!err) { 119 err = clk_get_rate(&clk); 120 if (!IS_ERR_VALUE(err)) 121 plat->clock = err; 122 } else if (err != -ENOENT && err != -ENODEV && err != -ENOSYS) { 123 debug("omap serial failed to get clock\n"); 124 return err; 125 } 126 127 if (!plat->clock) 128 plat->clock = dev_read_u32_default(dev, "clock-frequency", 129 CONFIG_SYS_NS16550_CLK); 130 if (!plat->clock) { 131 debug("omap serial clock not defined\n"); 132 return -EINVAL; 133 } 134 135 plat->fcr = UART_FCR_DEFVAL; 136 137 return 0; 138 } 139 140 static const struct udevice_id omap_serial_ids[] = { 141 { .compatible = "ti,omap2-uart", }, 142 { .compatible = "ti,omap3-uart", }, 143 { .compatible = "ti,omap4-uart", }, 144 { .compatible = "ti,am3352-uart", }, 145 { .compatible = "ti,am4372-uart", }, 146 { .compatible = "ti,dra742-uart", }, 147 { .compatible = "ti,am654-uart", }, 148 {} 149 }; 150 #endif /* OF_CONTROL && !OF_PLATDATA */ 151 152 #if CONFIG_IS_ENABLED(SERIAL_PRESENT) 153 U_BOOT_DRIVER(omap_serial) = { 154 .name = "omap_serial", 155 .id = UCLASS_SERIAL, 156 #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA) 157 .of_match = omap_serial_ids, 158 .ofdata_to_platdata = omap_serial_ofdata_to_platdata, 159 .platdata_auto_alloc_size = sizeof(struct ns16550_platdata), 160 #endif 161 .priv_auto_alloc_size = sizeof(struct NS16550), 162 .probe = ns16550_serial_probe, 163 .ops = &ns16550_serial_ops, 164 #if !CONFIG_IS_ENABLED(OF_CONTROL) 165 .flags = DM_FLAG_PRE_RELOC, 166 #endif 167 }; 168 #endif 169 #endif /* DM_SERIAL */ 170