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