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