1 /*
2  * Copyright (c) 2019 omSquare s.r.o.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/drivers/uart.h>
8 #include <zephyr/kernel.h>
9 #include <SEGGER_RTT.h>
10 
11 #define DT_DRV_COMPAT segger_rtt_uart
12 
13 struct uart_rtt_config {
14 	void *up_buffer;
15 	size_t up_size;
16 	void *down_buffer;
17 	size_t down_size;
18 	uint8_t channel;
19 };
20 
21 struct uart_rtt_data {
22 #ifdef CONFIG_UART_ASYNC_API
23 	uart_callback_t callback;
24 	void *user_data;
25 #endif /* CONFIG_UART_ASYNC_API */
26 };
27 
uart_rtt_init(const struct device * dev)28 static int uart_rtt_init(const struct device *dev)
29 {
30 	/*
31 	 * Channel 0 is initialized at compile-time, Kconfig ensures that
32 	 * it is configured in correct, non-blocking mode. Other channels
33 	 * need to be configured at run-time.
34 	 */
35 	if (dev->config) {
36 		const struct uart_rtt_config *cfg = dev->config;
37 
38 		SEGGER_RTT_ConfigUpBuffer(cfg->channel, dev->name,
39 					  cfg->up_buffer, cfg->up_size,
40 					  SEGGER_RTT_MODE_NO_BLOCK_SKIP);
41 		SEGGER_RTT_ConfigDownBuffer(cfg->channel, dev->name,
42 					    cfg->down_buffer, cfg->down_size,
43 					    SEGGER_RTT_MODE_NO_BLOCK_SKIP);
44 	}
45 	return 0;
46 }
47 
48 /**
49  * @brief Poll the device for input.
50  *
51  * @param dev UART device struct
52  * @param c Pointer to character
53  *
54  * @return 0 if a character arrived, -1 if the input buffer if empty.
55  */
56 
uart_rtt_poll_in(const struct device * dev,unsigned char * c)57 static int uart_rtt_poll_in(const struct device *dev, unsigned char *c)
58 {
59 	const struct uart_rtt_config *config = dev->config;
60 	unsigned int ch = config ? config->channel : 0;
61 	unsigned int ret = SEGGER_RTT_Read(ch, c, 1);
62 
63 	return ret ? 0 : -1;
64 }
65 
66 /**
67  * @brief Output a character in polled mode.
68  *
69  * @param dev UART device struct
70  * @param c Character to send
71  */
uart_rtt_poll_out(const struct device * dev,unsigned char c)72 static void uart_rtt_poll_out(const struct device *dev, unsigned char c)
73 {
74 	const struct uart_rtt_config *config = dev->config;
75 	unsigned int ch = config ? config->channel : 0;
76 
77 	SEGGER_RTT_Write(ch, &c, 1);
78 }
79 
80 #ifdef CONFIG_UART_ASYNC_API
81 
uart_rtt_callback_set(const struct device * dev,uart_callback_t callback,void * user_data)82 static int uart_rtt_callback_set(const struct device *dev,
83 				 uart_callback_t callback, void *user_data)
84 {
85 	struct uart_rtt_data *data = dev->data;
86 
87 	data->callback = callback;
88 	data->user_data = user_data;
89 	return 0;
90 }
91 
uart_rtt_tx(const struct device * dev,const uint8_t * buf,size_t len,int32_t timeout)92 static int uart_rtt_tx(const struct device *dev,
93 		       const uint8_t *buf, size_t len, int32_t timeout)
94 {
95 	const struct uart_rtt_config *cfg = dev->config;
96 	struct uart_rtt_data *data = dev->data;
97 	unsigned int ch = cfg ? cfg->channel : 0;
98 
99 	ARG_UNUSED(timeout);
100 
101 	/* Output the buffer */
102 	SEGGER_RTT_Write(ch, buf, len);
103 
104 	/* Send the TX complete callback */
105 	if (data->callback) {
106 		struct uart_event evt = {
107 			.type = UART_TX_DONE,
108 			.data.tx.buf = buf,
109 			.data.tx.len = len
110 		};
111 		data->callback(dev, &evt, data->user_data);
112 	}
113 
114 	return 0;
115 }
116 
uart_rtt_tx_abort(const struct device * dev)117 static int uart_rtt_tx_abort(const struct device *dev)
118 {
119 	/* RTT TX is a memcpy, there is never a transmission to abort */
120 	ARG_UNUSED(dev);
121 
122 	return -EFAULT;
123 }
124 
uart_rtt_rx_enable(const struct device * dev,uint8_t * buf,size_t len,int32_t timeout)125 static int uart_rtt_rx_enable(const struct device *dev,
126 			      uint8_t *buf, size_t len, int32_t timeout)
127 {
128 	/* SEGGER RTT reception is implemented as a direct memory write to RAM
129 	 * by a connected debugger. As such there is no hardware interrupt
130 	 * or other mechanism to know when the debugger has added data to be
131 	 * read. Asynchronous RX does not make sense in such a context, and is
132 	 * therefore not supported.
133 	 */
134 	ARG_UNUSED(dev);
135 	ARG_UNUSED(buf);
136 	ARG_UNUSED(len);
137 	ARG_UNUSED(timeout);
138 
139 	return -ENOTSUP;
140 }
141 
uart_rtt_rx_disable(const struct device * dev)142 static int uart_rtt_rx_disable(const struct device *dev)
143 {
144 	/* Asynchronous RX not supported, see uart_rtt_rx_enable */
145 	ARG_UNUSED(dev);
146 
147 	return -EFAULT;
148 }
149 
uart_rtt_rx_buf_rsp(const struct device * dev,uint8_t * buf,size_t len)150 static int uart_rtt_rx_buf_rsp(const struct device *dev,
151 			       uint8_t *buf, size_t len)
152 {
153 	/* Asynchronous RX not supported, see uart_rtt_rx_enable */
154 	ARG_UNUSED(dev);
155 	ARG_UNUSED(buf);
156 	ARG_UNUSED(len);
157 
158 	return -ENOTSUP;
159 }
160 
161 #endif /* CONFIG_UART_ASYNC_API */
162 
163 static DEVICE_API(uart, uart_rtt_driver_api) = {
164 	.poll_in = uart_rtt_poll_in,
165 	.poll_out = uart_rtt_poll_out,
166 #ifdef CONFIG_UART_ASYNC_API
167 	.callback_set = uart_rtt_callback_set,
168 	.tx = uart_rtt_tx,
169 	.tx_abort = uart_rtt_tx_abort,
170 	.rx_enable = uart_rtt_rx_enable,
171 	.rx_buf_rsp = uart_rtt_rx_buf_rsp,
172 	.rx_disable = uart_rtt_rx_disable,
173 #endif /* CONFIG_UART_ASYNC_API */
174 };
175 
176 #define UART_RTT(idx)                   DT_NODELABEL(rtt##idx)
177 #define UART_RTT_PROP(idx, prop)        DT_PROP(UART_RTT(idx), prop)
178 #define UART_RTT_CONFIG_NAME(idx)       uart_rtt##idx##_config
179 
180 #define UART_RTT_CONFIG(idx)						    \
181 	static								    \
182 	uint8_t uart_rtt##idx##_tx_buf[UART_RTT_PROP(idx, tx_buffer_size)]; \
183 	static								    \
184 	uint8_t uart_rtt##idx##_rx_buf[UART_RTT_PROP(idx, rx_buffer_size)]; \
185 									    \
186 	static const struct uart_rtt_config UART_RTT_CONFIG_NAME(idx) = {   \
187 		.up_buffer = uart_rtt##idx##_tx_buf,			    \
188 		.up_size = sizeof(uart_rtt##idx##_tx_buf),		    \
189 		.down_buffer = uart_rtt##idx##_rx_buf,			    \
190 		.down_size = sizeof(uart_rtt##idx##_rx_buf),		    \
191 		.channel = idx,						    \
192 	}
193 
194 #define UART_RTT_INIT(idx, config)					      \
195 	struct uart_rtt_data uart_rtt##idx##_data;			      \
196 									      \
197 	DEVICE_DT_DEFINE(UART_RTT(idx), uart_rtt_init, NULL, \
198 			    &uart_rtt##idx##_data, config,		      \
199 			    PRE_KERNEL_2, CONFIG_SERIAL_INIT_PRIORITY,	      \
200 			    &uart_rtt_driver_api)
201 
202 #ifdef CONFIG_UART_RTT_0
203 UART_RTT_INIT(0, NULL);
204 #endif
205 
206 #ifdef CONFIG_UART_RTT_1
207 UART_RTT_CONFIG(1);
208 UART_RTT_INIT(1, &UART_RTT_CONFIG_NAME(1));
209 #endif
210 
211 #ifdef CONFIG_UART_RTT_2
212 UART_RTT_CONFIG(2);
213 UART_RTT_INIT(2, &UART_RTT_CONFIG_NAME(2));
214 #endif
215 
216 #ifdef CONFIG_UART_RTT_3
217 UART_RTT_CONFIG(3);
218 UART_RTT_INIT(3, &UART_RTT_CONFIG_NAME(3));
219 #endif
220