1 /*
2 * Copyright (c) 2021-2024 HPMicro
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8 #include "hpm_common.h"
9 #include "hpm_uart_drv.h"
10
11 #define HPM_UART_DRV_RETRY_COUNT (5000U)
12 #define HPM_UART_MINIMUM_BAUDRATE (200U)
13
14 #ifndef HPM_UART_BAUDRATE_TOLERANCE
15 #define HPM_UART_BAUDRATE_TOLERANCE (3)
16 #endif
17
18 #define HPM_UART_OSC_MAX (32U)
19 #define HPM_UART_OSC_MIN (8U)
20 #define HPM_UART_BAUDRATE_DIV_MAX (0xFFFFU)
21 #define HPM_UART_BAUDRATE_DIV_MIN (1U)
22
23 #ifndef UART_SOC_OVERSAMPLE_MAX
24 #define UART_SOC_OVERSAMPLE_MAX HPM_UART_OSC_MAX
25 #endif
26
uart_default_config(UART_Type * ptr,uart_config_t * config)27 void uart_default_config(UART_Type *ptr, uart_config_t *config)
28 {
29 (void) ptr;
30 config->baudrate = 115200;
31 config->word_length = word_length_8_bits;
32 config->parity = parity_none;
33 config->num_of_stop_bits = stop_bits_1;
34 config->fifo_enable = true;
35 config->rx_fifo_level = uart_rx_fifo_trg_not_empty;
36 config->tx_fifo_level = uart_tx_fifo_trg_not_full;
37 config->dma_enable = false;
38 config->modem_config.auto_flow_ctrl_en = false;
39 config->modem_config.loop_back_en = false;
40 config->modem_config.set_rts_high = false;
41 #if defined(HPM_IP_FEATURE_UART_RX_IDLE_DETECT) && (HPM_IP_FEATURE_UART_RX_IDLE_DETECT == 1)
42 config->rxidle_config.detect_enable = false;
43 config->rxidle_config.detect_irq_enable = false;
44 config->rxidle_config.idle_cond = uart_rxline_idle_cond_rxline_logic_one;
45 config->rxidle_config.threshold = 10; /* 10-bit for typical UART configuration (8-N-1) */
46 #endif
47 /* if have 9bit_mode function, it's has be tx_idle function */
48 #if defined(HPM_IP_FEATURE_UART_9BIT_MODE) && (HPM_IP_FEATURE_UART_9BIT_MODE == 1)
49 config->txidle_config.detect_enable = false;
50 config->txidle_config.detect_irq_enable = false;
51 config->txidle_config.idle_cond = uart_rxline_idle_cond_rxline_logic_one;
52 config->txidle_config.threshold = 10; /* 10-bit for typical UART configuration (8-N-1) */
53 #endif
54 #if defined(HPM_IP_FEATURE_UART_RX_EN) && (HPM_IP_FEATURE_UART_RX_EN == 1)
55 config->rx_enable = true;
56 #endif
57 }
58
uart_calculate_baudrate(uint32_t freq,uint32_t baudrate,uint16_t * div_out,uint8_t * osc_out)59 static bool uart_calculate_baudrate(uint32_t freq, uint32_t baudrate, uint16_t *div_out, uint8_t *osc_out)
60 {
61 uint16_t div, osc, delta;
62 float tmp;
63 if ((div_out == NULL) || (!freq) || (!baudrate)
64 || (baudrate < HPM_UART_MINIMUM_BAUDRATE)
65 || (freq / HPM_UART_BAUDRATE_DIV_MIN < baudrate * HPM_UART_OSC_MIN)
66 || (freq / HPM_UART_BAUDRATE_DIV_MAX > (baudrate * HPM_UART_OSC_MAX))) {
67 return 0;
68 }
69
70 tmp = (float) freq / baudrate;
71
72 for (osc = HPM_UART_OSC_MIN; osc <= UART_SOC_OVERSAMPLE_MAX; osc += 2) {
73 /* osc range: HPM_UART_OSC_MIN - UART_SOC_OVERSAMPLE_MAX, even number */
74 delta = 0;
75 div = (uint16_t)(tmp / osc);
76 if (div < HPM_UART_BAUDRATE_DIV_MIN) {
77 /* invalid div */
78 continue;
79 }
80 if (div * osc > tmp) {
81 delta = (uint16_t)(div * osc - tmp);
82 } else if (div * osc < tmp) {
83 delta = (uint16_t)(tmp - div * osc);
84 }
85 if (delta && ((delta * 100 / tmp) > HPM_UART_BAUDRATE_TOLERANCE)) {
86 continue;
87 } else {
88 *div_out = div;
89 *osc_out = (osc == HPM_UART_OSC_MAX) ? 0 : osc; /* osc == 0 in bitfield, oversample rate is 32 */
90 return true;
91 }
92 }
93 return false;
94 }
95
uart_init(UART_Type * ptr,uart_config_t * config)96 hpm_stat_t uart_init(UART_Type *ptr, uart_config_t *config)
97 {
98 uint32_t tmp;
99 uint8_t osc;
100 uint16_t div;
101
102 /* disable all interrupts */
103 ptr->IER = 0;
104 /* Set DLAB to 1 */
105 ptr->LCR |= UART_LCR_DLAB_MASK;
106
107 if (!uart_calculate_baudrate(config->src_freq_in_hz, config->baudrate, &div, &osc)) {
108 return status_uart_no_suitable_baudrate_parameter_found;
109 }
110
111 ptr->OSCR = (ptr->OSCR & ~UART_OSCR_OSC_MASK)
112 | UART_OSCR_OSC_SET(osc);
113 ptr->DLL = UART_DLL_DLL_SET(div >> 0);
114 ptr->DLM = UART_DLM_DLM_SET(div >> 8);
115
116 /* DLAB bit needs to be cleared once baudrate is configured */
117 tmp = ptr->LCR & (~UART_LCR_DLAB_MASK);
118
119 tmp &= ~(UART_LCR_SPS_MASK | UART_LCR_EPS_MASK | UART_LCR_PEN_MASK);
120 switch (config->parity) {
121 case parity_none:
122 break;
123 case parity_odd:
124 tmp |= UART_LCR_PEN_MASK;
125 break;
126 case parity_even:
127 tmp |= UART_LCR_PEN_MASK | UART_LCR_EPS_MASK;
128 break;
129 case parity_always_1:
130 tmp |= UART_LCR_PEN_MASK | UART_LCR_SPS_MASK;
131 break;
132 case parity_always_0:
133 tmp |= UART_LCR_EPS_MASK | UART_LCR_PEN_MASK
134 | UART_LCR_SPS_MASK;
135 break;
136 default:
137 /* invalid configuration */
138 return status_invalid_argument;
139 }
140
141 tmp &= ~(UART_LCR_STB_MASK | UART_LCR_WLS_MASK);
142 switch (config->num_of_stop_bits) {
143 case stop_bits_1:
144 break;
145 case stop_bits_1_5:
146 tmp |= UART_LCR_STB_MASK;
147 break;
148 case stop_bits_2:
149 if (config->word_length < word_length_6_bits) {
150 /* invalid configuration */
151 return status_invalid_argument;
152 }
153 tmp |= UART_LCR_STB_MASK;
154 break;
155 default:
156 /* invalid configuration */
157 return status_invalid_argument;
158 }
159
160 ptr->LCR = tmp | UART_LCR_WLS_SET(config->word_length);
161
162 #if defined(HPM_IP_FEATURE_UART_FINE_FIFO_THRLD) && (HPM_IP_FEATURE_UART_FINE_FIFO_THRLD == 1)
163 /* reset TX and RX fifo */
164 ptr->FCRR = UART_FCRR_TFIFORST_MASK | UART_FCRR_RFIFORST_MASK;
165 /* Enable FIFO */
166 ptr->FCRR = UART_FCRR_FIFOT4EN_MASK
167 | UART_FCRR_FIFOE_SET(config->fifo_enable)
168 | UART_FCRR_TFIFOT4_SET(config->tx_fifo_level)
169 | UART_FCRR_RFIFOT4_SET(config->rx_fifo_level)
170 | UART_FCRR_DMAE_SET(config->dma_enable);
171
172 #else
173 /* reset TX and RX fifo */
174 ptr->FCR = UART_FCR_TFIFORST_MASK | UART_FCR_RFIFORST_MASK;
175 /* Enable FIFO */
176 tmp = UART_FCR_FIFOE_SET(config->fifo_enable)
177 | UART_FCR_TFIFOT_SET(config->tx_fifo_level)
178 | UART_FCR_RFIFOT_SET(config->rx_fifo_level)
179 | UART_FCR_DMAE_SET(config->dma_enable);
180 ptr->FCR = tmp;
181 /* store FCR register value */
182 ptr->GPR = tmp;
183 #endif
184
185 uart_modem_config(ptr, &config->modem_config);
186
187 #if defined(HPM_IP_FEATURE_UART_RX_IDLE_DETECT) && (HPM_IP_FEATURE_UART_RX_IDLE_DETECT == 1)
188 uart_init_rxline_idle_detection(ptr, config->rxidle_config);
189 #endif
190 #if defined(HPM_IP_FEATURE_UART_RX_EN) && (HPM_IP_FEATURE_UART_RX_EN == 1)
191 if (config->rx_enable) {
192 ptr->IDLE_CFG |= UART_IDLE_CFG_RXEN_MASK;
193 }
194 #endif
195 return status_success;
196 }
197
uart_set_baudrate(UART_Type * ptr,uint32_t baudrate,uint32_t src_clock_hz)198 hpm_stat_t uart_set_baudrate(UART_Type *ptr, uint32_t baudrate, uint32_t src_clock_hz)
199 {
200 uint8_t osc;
201 uint16_t div;
202
203 /* Set DLAB to 1 */
204 ptr->LCR |= UART_LCR_DLAB_MASK;
205
206 if (!uart_calculate_baudrate(src_clock_hz, baudrate, &div, &osc)) {
207 return status_uart_no_suitable_baudrate_parameter_found;
208 }
209
210 ptr->OSCR = (ptr->OSCR & ~UART_OSCR_OSC_MASK) | UART_OSCR_OSC_SET(osc);
211 ptr->DLL = UART_DLL_DLL_SET(div >> 0);
212 ptr->DLM = UART_DLM_DLM_SET(div >> 8);
213
214 /* DLAB bit needs to be cleared once baudrate is configured */
215 ptr->LCR &= ~UART_LCR_DLAB_MASK;
216
217 return status_success;
218 }
219
uart_send_byte(UART_Type * ptr,uint8_t c)220 hpm_stat_t uart_send_byte(UART_Type *ptr, uint8_t c)
221 {
222 uint32_t retry = 0;
223
224 while (!(ptr->LSR & UART_LSR_THRE_MASK)) {
225 if (retry > HPM_UART_DRV_RETRY_COUNT) {
226 break;
227 }
228 retry++;
229 }
230
231 if (retry > HPM_UART_DRV_RETRY_COUNT) {
232 return status_timeout;
233 }
234
235 ptr->THR = UART_THR_THR_SET(c);
236 return status_success;
237 }
238
uart_flush(UART_Type * ptr)239 hpm_stat_t uart_flush(UART_Type *ptr)
240 {
241 uint32_t retry = 0;
242
243 while (!(ptr->LSR & UART_LSR_TEMT_MASK)) {
244 if (retry > HPM_UART_DRV_RETRY_COUNT) {
245 break;
246 }
247 retry++;
248 }
249 if (retry > HPM_UART_DRV_RETRY_COUNT) {
250 return status_timeout;
251 }
252
253 return status_success;
254 }
255
uart_receive_byte(UART_Type * ptr,uint8_t * byte)256 hpm_stat_t uart_receive_byte(UART_Type *ptr, uint8_t *byte)
257 {
258 uint32_t retry = 0;
259
260 while (!(ptr->LSR & UART_LSR_DR_MASK)) {
261 if (retry > HPM_UART_DRV_RETRY_COUNT) {
262 break;
263 }
264 retry++;
265 }
266
267 if (retry > HPM_UART_DRV_RETRY_COUNT) {
268 return status_timeout;
269 }
270
271 *byte = ptr->RBR & UART_RBR_RBR_MASK;
272 return status_success;
273 }
274
uart_try_receive_byte(UART_Type * ptr,uint8_t * byte)275 hpm_stat_t uart_try_receive_byte(UART_Type *ptr, uint8_t *byte)
276 {
277 if (!(ptr->LSR & UART_LSR_DR_MASK)) {
278 return status_fail;
279 } else {
280 *byte = ptr->RBR & UART_RBR_RBR_MASK;
281 return status_success;
282 }
283 }
284
uart_set_signal_level(UART_Type * ptr,uart_signal_t signal,uart_signal_level_t level)285 void uart_set_signal_level(UART_Type *ptr, uart_signal_t signal, uart_signal_level_t level)
286 {
287 if (level == uart_signal_level_low) {
288 ptr->MCR = (ptr->MCR | signal);
289 } else {
290 ptr->MCR = (ptr->MCR & ~signal);
291 }
292 }
293
uart_receive_data(UART_Type * ptr,uint8_t * source,uint32_t size_in_byte)294 hpm_stat_t uart_receive_data(UART_Type *ptr, uint8_t *source, uint32_t size_in_byte)
295 {
296 for (uint32_t i = 0; i < size_in_byte; i++) {
297 if (status_success != uart_receive_byte(ptr, source + i)) {
298 return status_fail;
299 }
300 }
301 return status_success;
302 }
303
uart_send_data(UART_Type * ptr,uint8_t * source,uint32_t size_in_byte)304 hpm_stat_t uart_send_data(UART_Type *ptr, uint8_t *source, uint32_t size_in_byte)
305 {
306 for (uint32_t i = 0; i < size_in_byte; i++) {
307 if (status_success != uart_send_byte(ptr, *(source + i))) {
308 return status_fail;
309 }
310 }
311 return status_success;
312 }
313
314
315 #if defined(HPM_IP_FEATURE_UART_RX_IDLE_DETECT) && (HPM_IP_FEATURE_UART_RX_IDLE_DETECT == 1)
uart_init_rxline_idle_detection(UART_Type * ptr,uart_rxline_idle_config_t rxidle_config)316 hpm_stat_t uart_init_rxline_idle_detection(UART_Type *ptr, uart_rxline_idle_config_t rxidle_config)
317 {
318 ptr->IDLE_CFG &= ~(UART_IDLE_CFG_RX_IDLE_EN_MASK
319 | UART_IDLE_CFG_RX_IDLE_THR_MASK
320 | UART_IDLE_CFG_RX_IDLE_COND_MASK);
321 ptr->IDLE_CFG |= UART_IDLE_CFG_RX_IDLE_EN_SET(rxidle_config.detect_enable)
322 | UART_IDLE_CFG_RX_IDLE_THR_SET(rxidle_config.threshold)
323 | UART_IDLE_CFG_RX_IDLE_COND_SET(rxidle_config.idle_cond);
324
325 if (rxidle_config.detect_irq_enable) {
326 uart_enable_irq(ptr, uart_intr_rx_line_idle);
327 } else {
328 uart_disable_irq(ptr, uart_intr_rx_line_idle);
329 }
330
331 return status_success;
332 }
333 #endif
334
335 /* if have 9bit_mode function, it's has be tx_idle function */
336 #if defined(HPM_IP_FEATURE_UART_9BIT_MODE) && (HPM_IP_FEATURE_UART_9BIT_MODE == 1)
uart_init_txline_idle_detection(UART_Type * ptr,uart_rxline_idle_config_t txidle_config)337 hpm_stat_t uart_init_txline_idle_detection(UART_Type *ptr, uart_rxline_idle_config_t txidle_config)
338 {
339 ptr->IDLE_CFG &= ~(UART_IDLE_CFG_TX_IDLE_EN_MASK
340 | UART_IDLE_CFG_TX_IDLE_THR_MASK
341 | UART_IDLE_CFG_TX_IDLE_COND_MASK);
342 ptr->IDLE_CFG |= UART_IDLE_CFG_TX_IDLE_EN_SET(txidle_config.detect_enable)
343 | UART_IDLE_CFG_TX_IDLE_THR_SET(txidle_config.threshold)
344 | UART_IDLE_CFG_TX_IDLE_COND_SET(txidle_config.idle_cond);
345
346 if (txidle_config.detect_irq_enable) {
347 uart_enable_irq(ptr, uart_intr_tx_line_idle);
348 } else {
349 uart_disable_irq(ptr, uart_intr_tx_line_idle);
350 }
351
352 return status_success;
353 }
354 #endif
355
356 #if defined(HPM_IP_FEATURE_UART_TRIG_MODE) && (HPM_IP_FEATURE_UART_TRIG_MODE == 1)
uart_config_transfer_trig_mode(UART_Type * ptr,uart_trig_config_t * config)357 void uart_config_transfer_trig_mode(UART_Type *ptr, uart_trig_config_t *config)
358 {
359 ptr->MOTO_CFG = UART_MOTO_CFG_TXSTP_BITS_SET(config->stop_bit_len)
360 | UART_MOTO_CFG_HWTRG_EN_SET(config->hardware_trig)
361 | UART_MOTO_CFG_TRG_MODE_SET(config->trig_mode)
362 | UART_MOTO_CFG_TRG_CLR_RFIFO_SET(config->trig_clr_rxfifo)
363 | UART_MOTO_CFG_TXSTOP_INSERT_SET(config->en_stop_bit_insert);
364 }
365 #endif
366
367 /* fifo control register(FCR) is WO access, if support FCCR register, it is RW access. */
uart_config_fifo_ctrl(UART_Type * ptr,uart_fifo_ctrl_t * ctrl)368 void uart_config_fifo_ctrl(UART_Type *ptr, uart_fifo_ctrl_t *ctrl)
369 {
370 #if defined(HPM_IP_FEATURE_UART_FINE_FIFO_THRLD) && (HPM_IP_FEATURE_UART_FINE_FIFO_THRLD == 1)
371 ptr->FCRR = UART_FCRR_FIFOT4EN_MASK
372 | UART_FCRR_TFIFOT4_SET(ctrl->tx_fifo_level)
373 | UART_FCRR_RFIFOT4_SET(ctrl->rx_fifo_level)
374 | UART_FCRR_DMAE_SET(ctrl->dma_enable)
375 | UART_FCRR_TFIFORST_SET(ctrl->reset_tx_fifo)
376 | UART_FCRR_RFIFORST_SET(ctrl->reset_rx_fifo)
377 | UART_FCRR_FIFOE_SET(ctrl->fifo_enable);
378 #else
379 ptr->FCR = UART_FCR_TFIFOT_SET(ctrl->tx_fifo_level)
380 | UART_FCR_RFIFOT_SET(ctrl->rx_fifo_level)
381 | UART_FCR_TFIFORST_SET(ctrl->reset_tx_fifo)
382 | UART_FCR_RFIFORST_SET(ctrl->reset_rx_fifo)
383 | UART_FCR_DMAE_SET(ctrl->dma_enable)
384 | UART_FCR_FIFOE_SET(ctrl->fifo_enable);
385 /* store FCR to GPR */
386 ptr->GPR = UART_FCR_TFIFOT_SET(ctrl->tx_fifo_level)
387 | UART_FCR_RFIFOT_SET(ctrl->rx_fifo_level)
388 | UART_FCR_DMAE_SET(ctrl->dma_enable)
389 | UART_FCR_FIFOE_SET(ctrl->fifo_enable);
390 #endif
391 }