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