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