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