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 }