]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_A9_Cyclone_V_SoC_DK/Altera_Code/HardwareLibrary/alt_16550_uart.c
Added project for Altera Cyclone V SoC, currently running from internal RAM.
[freertos] / FreeRTOS / Demo / CORTEX_A9_Cyclone_V_SoC_DK / Altera_Code / HardwareLibrary / alt_16550_uart.c
1 /******************************************************************************\r
2  *\r
3  * Copyright 2013 Altera Corporation. All Rights Reserved.\r
4  * \r
5  * Redistribution and use in source and binary forms, with or without\r
6  * modification, are permitted provided that the following conditions are met:\r
7  * \r
8  * 1. Redistributions of source code must retain the above copyright notice,\r
9  * this list of conditions and the following disclaimer.\r
10  * \r
11  * 2. Redistributions in binary form must reproduce the above copyright notice,\r
12  * this list of conditions and the following disclaimer in the documentation\r
13  * and/or other materials provided with the distribution.\r
14  * \r
15  * 3. The name of the author may not be used to endorse or promote products\r
16  * derived from this software without specific prior written permission.\r
17  * \r
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS OR\r
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
20  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO\r
21  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\r
22  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\r
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;\r
24  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\r
25  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\r
26  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\r
27  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
28  * \r
29  ******************************************************************************/\r
30 \r
31 #include "alt_16550_uart.h"\r
32 #include "alt_clock_manager.h"\r
33 #include "socal/alt_rstmgr.h"\r
34 #include "socal/alt_uart.h"\r
35 #include "socal/hps.h"\r
36 #include "socal/socal.h"\r
37 \r
38 /////\r
39 \r
40 #define ALT_16550_HANDLE_DATA_UART_ENABLED_MSK   (1UL << 31)\r
41 #define ALT_16550_HANDLE_DATA_DIVISOR_VALUE_GET(value) (value & 0xffff)\r
42 \r
43 #define ALT_ALTERA_16550_CPR_OFST        (0xF4)\r
44 #define ALT_ALTERA_16550_CPR_ADDR(base)  ALT_CAST(void *, (ALT_CAST(char *, (base)) + ALT_ALTERA_16550_CPR_OFST))\r
45 #define ALT_ALTERA_16550_CPR_FIFO_MODE_GET(value) (((value) >> 16) & 0xff)\r
46 #define ALT_ALTERA_16550_CPR_AFCE_MODE_SET_MSK (1 << 4)\r
47 \r
48 /////\r
49 \r
50 // Remove these macros as part of case:123835.\r
51 #define ALT_UART_IER_DLH_VALUE_SET(value) ((value) & 0xff)\r
52 #define ALT_UART_IER_DLH_ETBEI_DLH1_SET_MSK ALT_UART_IER_DLH_ETBEI_DLHL_SET_MSK\r
53 \r
54 /////\r
55 \r
56 //\r
57 // Helper function which resets the UART and if requested, initializes the UART\r
58 // to the default settings. Currently the default settings are:\r
59 //  - 8 databits\r
60 //  - no parity\r
61 //  - 1 stopbit\r
62 //  - 57600 baudrate\r
63 // The reset routines depends on the hardware implementation of the UART.\r
64 //\r
65 \r
66 // This helper is needed because the regular alt_read_word(src) essentially\r
67 // resolves to "*(volatile uint32_t *)src". As there is no assignment, this\r
68 // could potentially be optimized away. With the helper, the actual register\r
69 // read should occur and be returned (and subsequently discarded).\r
70 static inline uint32_t alt_read_word_helper(const void * addr)\r
71 {\r
72     return alt_read_word(addr);\r
73 }\r
74 \r
75 //\r
76 // Helper function write the divisor in hardware.\r
77 //\r
78 static ALT_STATUS_CODE alt_16550_write_divisor_helper(ALT_16550_HANDLE_t * handle,\r
79                                                       uint32_t divisor)\r
80 {\r
81     // Validate the divisor parameter.\r
82     if (divisor > 0xffff)\r
83     {\r
84         // This should never happen as it is verified in divisor_set.\r
85         return ALT_E_ERROR;\r
86     }\r
87 \r
88     switch (handle->device)\r
89     {\r
90     case ALT_16550_DEVICE_SOCFPGA_UART0:\r
91     case ALT_16550_DEVICE_SOCFPGA_UART1:\r
92     case ALT_16550_DEVICE_ALTERA_16550_UART:\r
93         // Set LCR::DLAB (Line Control Register :: Divisor Latch Access Bit)\r
94         alt_setbits_word(ALT_UART_LCR_ADDR(handle->location), ALT_UART_LCR_DLAB_SET_MSK);\r
95 \r
96         // Write DLL (Divisor Latch Low).\r
97         alt_write_word(ALT_UART_RBR_THR_DLL_ADDR(handle->location), ALT_UART_RBR_THR_DLL_VALUE_SET(divisor));\r
98 \r
99         // Write DLH (Divisor Latch High).\r
100         alt_write_word(ALT_UART_IER_DLH_ADDR(handle->location), ALT_UART_IER_DLH_VALUE_SET(divisor >> 8));\r
101 \r
102         // Clear LCR::DLAB (Line Control Register :: Divisor Latch Access Bit)\r
103         alt_clrbits_word(ALT_UART_LCR_ADDR(handle->location), ALT_UART_LCR_DLAB_SET_MSK);\r
104 \r
105         break;\r
106 \r
107     default:\r
108         return ALT_E_ERROR;\r
109     }\r
110 \r
111     // Update the enabled state in the handle data.\r
112     if (divisor != 0)\r
113     {\r
114         handle->data |= ALT_16550_HANDLE_DATA_UART_ENABLED_MSK;\r
115     }\r
116     else\r
117     {\r
118         handle->data &= ~ALT_16550_HANDLE_DATA_UART_ENABLED_MSK;\r
119     }\r
120 \r
121     return ALT_E_SUCCESS;\r
122 }\r
123 \r
124 //\r
125 // Helper function to reset the UART.\r
126 //\r
127 static ALT_STATUS_CODE alt_16550_reset_helper(ALT_16550_HANDLE_t * handle, bool enable_init)\r
128 {\r
129     switch (handle->device)\r
130     {\r
131     case ALT_16550_DEVICE_SOCFPGA_UART0:\r
132     case ALT_16550_DEVICE_SOCFPGA_UART1:\r
133         // Write SRR::UR (Shadow Reset Register :: UART Reset)\r
134         alt_write_word(ALT_UART_SRR_ADDR(handle->location), ALT_UART_SRR_UR_SET_MSK);\r
135 \r
136         // Read the MSR to work around case:119085.\r
137         alt_read_word_helper(ALT_UART_MSR_ADDR(handle->location));\r
138         break;\r
139 \r
140     case ALT_16550_DEVICE_ALTERA_16550_UART:\r
141         alt_16550_write_divisor_helper(handle, 0); // Disable UART\r
142         alt_16550_int_disable_all(handle);         // Disable interrupts\r
143         alt_16550_fifo_disable(handle);            // Disable FIFOs\r
144         alt_write_word(ALT_UART_MCR_ADDR(handle->location), 0); // 0 -> MCR (AFCE, LP, OUT2, OUT1, RTS, DTR)\r
145         break;\r
146 \r
147     default:\r
148         return ALT_E_ERROR;\r
149     }\r
150 \r
151     // If we are initializing (as opposed to just uninitializing)\r
152     if (enable_init)\r
153     {\r
154         ALT_STATUS_CODE status;\r
155 \r
156         // Set bit IER::PTIME (Interrupt Enable Register :: Programmable THRE Mode Enable)\r
157         alt_setbits_word(ALT_UART_IER_DLH_ADDR(handle->location), ALT_UART_IER_DLH_PTIME_DLH7_SET_MSK);\r
158 \r
159         // Set the line configuration to use 8-N-1.\r
160         status = alt_16550_line_config_set(handle, ALT_16550_DATABITS_8,\r
161                                                    ALT_16550_PARITY_DISABLE,\r
162                                                    ALT_16550_STOPBITS_1);\r
163         if (status != ALT_E_SUCCESS)\r
164         {\r
165             return status;\r
166         }\r
167 \r
168         uint32_t divisor = ALT_16550_HANDLE_DATA_DIVISOR_VALUE_GET(handle->data);\r
169         if (divisor == 0)\r
170         {\r
171             // Set the default baudrate to 57600.\r
172             status = alt_16550_baudrate_set(handle, ALT_16550_BAUDRATE_57600);\r
173             if (status != ALT_E_SUCCESS)\r
174             {\r
175                 return status;\r
176             }\r
177         }\r
178     }\r
179 \r
180     return ALT_E_SUCCESS;\r
181 }\r
182 \r
183 ALT_STATUS_CODE alt_16550_init(ALT_16550_DEVICE_t device,\r
184                                void * location,\r
185                                alt_freq_t clock_freq,\r
186                                ALT_16550_HANDLE_t * handle)\r
187 {\r
188     handle->device = device;\r
189     handle->data   = 0;\r
190     handle->fcr    = 0;\r
191 \r
192     switch (device)\r
193     {\r
194     case ALT_16550_DEVICE_SOCFPGA_UART0:\r
195     case ALT_16550_DEVICE_SOCFPGA_UART1:\r
196         // The ALT_CLK_L4_SP is required for all SoCFPGA UARTs. Check that it's enabled.\r
197         if (alt_clk_is_enabled(ALT_CLK_L4_SP) != ALT_E_TRUE)\r
198         {\r
199             return ALT_E_BAD_CLK;\r
200         }\r
201         else\r
202         {\r
203             ALT_STATUS_CODE status;\r
204             status = alt_clk_freq_get(ALT_CLK_L4_SP, &handle->clock_freq);\r
205             if (status != ALT_E_SUCCESS)\r
206             {\r
207                 return status;\r
208             }\r
209 \r
210             if (device == ALT_16550_DEVICE_SOCFPGA_UART0)\r
211             {\r
212                 handle->location = ALT_UART0_ADDR;\r
213 \r
214                 // Bring UART0 out of reset.\r
215                 alt_clrbits_word(ALT_RSTMGR_PERMODRST_ADDR, ALT_RSTMGR_PERMODRST_UART0_SET_MSK);\r
216             }\r
217             else // device == ALT_16550_DEVICE_SOCFPGA_UART1\r
218             {\r
219                 handle->location = ALT_UART1_ADDR;\r
220 \r
221                 // Bring UART1 out of reset.\r
222                 alt_clrbits_word(ALT_RSTMGR_PERMODRST_ADDR, ALT_RSTMGR_PERMODRST_UART1_SET_MSK);\r
223             } \r
224 \r
225             // Verify the UCR (UART Component Version)\r
226             uint32_t ucr = alt_read_word(ALT_UART_UCV_ADDR(handle->location));\r
227             if (ucr != ALT_UART_UCV_UART_COMPONENT_VER_RESET)\r
228             {\r
229                 return ALT_E_ERROR;\r
230             }\r
231         }\r
232         break;\r
233     case ALT_16550_DEVICE_ALTERA_16550_UART:\r
234         handle->location   = location;\r
235         handle->clock_freq = clock_freq;\r
236         break;\r
237     default:\r
238         return ALT_E_BAD_ARG;\r
239     }\r
240 \r
241     return alt_16550_reset_helper(handle, true);\r
242 }\r
243 \r
244 ALT_STATUS_CODE alt_16550_uninit(ALT_16550_HANDLE_t * handle)\r
245 {\r
246     switch (handle->device)\r
247     {\r
248     case ALT_16550_DEVICE_SOCFPGA_UART0:\r
249         alt_setbits_word(ALT_RSTMGR_PERMODRST_ADDR, ALT_RSTMGR_PERMODRST_UART0_SET_MSK);\r
250         return ALT_E_SUCCESS;\r
251     case ALT_16550_DEVICE_SOCFPGA_UART1:\r
252         alt_setbits_word(ALT_RSTMGR_PERMODRST_ADDR, ALT_RSTMGR_PERMODRST_UART1_SET_MSK);\r
253         return ALT_E_SUCCESS;\r
254     case ALT_16550_DEVICE_ALTERA_16550_UART:\r
255     default:\r
256         return alt_16550_reset_helper(handle, false);\r
257     }\r
258 }\r
259 \r
260 ALT_STATUS_CODE alt_16550_reset(ALT_16550_HANDLE_t * handle)\r
261 {\r
262     return alt_16550_reset_helper(handle, true);\r
263 }\r
264 \r
265 ALT_STATUS_CODE alt_16550_enable(ALT_16550_HANDLE_t * handle)\r
266 {\r
267     // Write the divisor cached in the handle data to the divisor registers.\r
268     // This will effectively enable the UART.\r
269     return alt_16550_write_divisor_helper(handle,\r
270                                           ALT_16550_HANDLE_DATA_DIVISOR_VALUE_GET(handle->data));\r
271 }\r
272 \r
273 ALT_STATUS_CODE alt_16550_disable(ALT_16550_HANDLE_t * handle)\r
274 {\r
275     // Write 0 to the divisor the divisor registers. This will effectively\r
276     // disable the UART.\r
277     return alt_16550_write_divisor_helper(handle, 0);\r
278 }\r
279 \r
280 ALT_STATUS_CODE alt_16550_read(ALT_16550_HANDLE_t * handle,\r
281                                char * item)\r
282 {\r
283     // Verify that the UART is enabled\r
284     if (!(handle->data & ALT_16550_HANDLE_DATA_UART_ENABLED_MSK))\r
285     {\r
286         return ALT_E_ERROR;\r
287     }\r
288 \r
289     // Verify that the FIFO is disabled\r
290     if (handle->fcr & ALT_UART_FCR_FIFOE_SET_MSK)\r
291     {\r
292         return ALT_E_ERROR;\r
293     }\r
294 \r
295     switch (handle->device)\r
296     {\r
297     case ALT_16550_DEVICE_SOCFPGA_UART0:\r
298     case ALT_16550_DEVICE_SOCFPGA_UART1:\r
299     case ALT_16550_DEVICE_ALTERA_16550_UART:\r
300         // Read the RBR (Receive Buffer Register) into *item.\r
301         *item = ALT_UART_RBR_THR_DLL_VALUE_GET(alt_read_word(ALT_UART_RBR_THR_DLL_ADDR(handle->location)));\r
302         break;\r
303     default:\r
304         return ALT_E_ERROR;\r
305     }\r
306     return ALT_E_SUCCESS;\r
307 }\r
308 \r
309 ALT_STATUS_CODE alt_16550_write(ALT_16550_HANDLE_t * handle,\r
310                                 char item)\r
311 {\r
312     // Verify that the UART is enabled\r
313     if (!(handle->data & ALT_16550_HANDLE_DATA_UART_ENABLED_MSK))\r
314     {\r
315         return ALT_E_ERROR;\r
316     }\r
317 \r
318     // Verify that the FIFO is disabled\r
319     if (handle->fcr & ALT_UART_FCR_FIFOE_SET_MSK)\r
320     {\r
321         return ALT_E_ERROR;\r
322     }\r
323 \r
324     switch (handle->device)\r
325     {\r
326     case ALT_16550_DEVICE_SOCFPGA_UART0:\r
327     case ALT_16550_DEVICE_SOCFPGA_UART1:\r
328     case ALT_16550_DEVICE_ALTERA_16550_UART:\r
329         // Write the buffer into the THR (Transmit Holding Register)\r
330         alt_write_word(ALT_UART_RBR_THR_DLL_ADDR(handle->location), item);\r
331         break;\r
332     default:\r
333         return ALT_E_ERROR;\r
334     }\r
335 \r
336     return ALT_E_SUCCESS;\r
337 }\r
338 \r
339 /////\r
340 \r
341 ALT_STATUS_CODE alt_16550_fifo_enable(ALT_16550_HANDLE_t * handle)\r
342 {\r
343     switch (handle->device)\r
344     {\r
345     case ALT_16550_DEVICE_SOCFPGA_UART0:\r
346     case ALT_16550_DEVICE_SOCFPGA_UART1:\r
347     case ALT_16550_DEVICE_ALTERA_16550_UART:\r
348         // Set FCR::FIFOE (FIFO Control Register :: FIFO Enable) bit.\r
349         handle->fcr |= ALT_UART_FCR_FIFOE_SET_MSK;\r
350         alt_write_word(ALT_UART_FCR_ADDR(handle->location), handle->fcr);\r
351         break;\r
352     default:\r
353         return ALT_E_ERROR;\r
354     }\r
355 \r
356     // No need to reset / clear the FIFOs. This is done automatically when\r
357     // FCR::FIFOE is changed.\r
358     return ALT_E_SUCCESS;\r
359 }\r
360 \r
361 ALT_STATUS_CODE alt_16550_fifo_disable(ALT_16550_HANDLE_t * handle)\r
362 {\r
363     switch (handle->device)\r
364     {\r
365     case ALT_16550_DEVICE_SOCFPGA_UART0:\r
366     case ALT_16550_DEVICE_SOCFPGA_UART1:\r
367     case ALT_16550_DEVICE_ALTERA_16550_UART:\r
368         // Clear FCR::FIFOE (FIFO Control Register :: FIFO Enable) bit.\r
369         handle->fcr &= ~ALT_UART_FCR_FIFOE_SET_MSK;\r
370         alt_write_word(ALT_UART_FCR_ADDR(handle->location), handle->fcr);\r
371         break;\r
372     default:\r
373         return ALT_E_ERROR;\r
374     }\r
375 \r
376     return ALT_E_SUCCESS;\r
377 }\r
378 \r
379 ALT_STATUS_CODE alt_16550_fifo_read(ALT_16550_HANDLE_t * handle,\r
380                                     char * buffer,\r
381                                     size_t count)\r
382 {\r
383     // Verify that the UART is enabled\r
384     if (!(handle->data & ALT_16550_HANDLE_DATA_UART_ENABLED_MSK))\r
385     {\r
386         return ALT_E_ERROR;\r
387     }\r
388 \r
389     // Verify that the FIFO is enabled\r
390     if (!(handle->fcr & ALT_UART_FCR_FIFOE_SET_MSK))\r
391     {\r
392         return ALT_E_ERROR;\r
393     }\r
394 \r
395     switch (handle->device)\r
396     {\r
397     case ALT_16550_DEVICE_SOCFPGA_UART0:\r
398     case ALT_16550_DEVICE_SOCFPGA_UART1:\r
399     case ALT_16550_DEVICE_ALTERA_16550_UART:\r
400         // Read the RBR (Receive Buffer Register) into the buffer\r
401         for (size_t i = 0; i < count; ++i)\r
402         {\r
403             buffer[i] = ALT_UART_RBR_THR_DLL_VALUE_GET(alt_read_word(ALT_UART_RBR_THR_DLL_ADDR(handle->location)));\r
404         }\r
405         break;\r
406     default:\r
407         return ALT_E_ERROR;\r
408     }\r
409 \r
410     return ALT_E_SUCCESS;\r
411 }\r
412 \r
413 ALT_STATUS_CODE alt_16550_fifo_write(ALT_16550_HANDLE_t * handle,\r
414                                      const char * buffer,\r
415                                      size_t count)\r
416 {\r
417     // Verify that the UART is enabled\r
418     if (!(handle->data & ALT_16550_HANDLE_DATA_UART_ENABLED_MSK))\r
419     {\r
420         return ALT_E_ERROR;\r
421     }\r
422 \r
423     // Verify that the FIFO is enabled\r
424     if (!(handle->fcr & ALT_UART_FCR_FIFOE_SET_MSK))\r
425     {\r
426         return ALT_E_ERROR;\r
427     }\r
428 \r
429     switch (handle->device)\r
430     {\r
431     case ALT_16550_DEVICE_SOCFPGA_UART0:\r
432     case ALT_16550_DEVICE_SOCFPGA_UART1:\r
433     case ALT_16550_DEVICE_ALTERA_16550_UART:\r
434         // Write the buffer into the THR (Transmit Holding Register)\r
435         for (size_t i = 0; i < count; ++i)\r
436         {\r
437             alt_write_word(ALT_UART_RBR_THR_DLL_ADDR(handle->location), buffer[i]);\r
438         }\r
439         break;\r
440     default:\r
441         return ALT_E_ERROR;\r
442     }\r
443 \r
444     return ALT_E_SUCCESS;\r
445 }\r
446 \r
447 ALT_STATUS_CODE alt_16550_fifo_clear_rx(ALT_16550_HANDLE_t * handle)\r
448 {\r
449     // Verify that the FIFO is enabled\r
450     if (!(handle->fcr & ALT_UART_FCR_FIFOE_SET_MSK))\r
451     {\r
452         return ALT_E_ERROR;\r
453     }\r
454 \r
455     switch (handle->device)\r
456     {\r
457     case ALT_16550_DEVICE_SOCFPGA_UART0:\r
458     case ALT_16550_DEVICE_SOCFPGA_UART1:\r
459         // Write SRR::RFR (Shadow Reset Register :: Receiver FIFO Reset) bit.\r
460         alt_write_word(ALT_UART_SRR_ADDR(handle->location), ALT_UART_SRR_RFR_SET_MSK);\r
461         break;\r
462     case ALT_16550_DEVICE_ALTERA_16550_UART:\r
463         // Write FCR::RFIFOR (FIFO Control Register :: Receiver FIFO Reset) bit.\r
464         alt_write_word(ALT_UART_FCR_ADDR(handle->location), handle->fcr | ALT_UART_FCR_RFIFOR_SET_MSK);\r
465         break;\r
466     default:\r
467         return ALT_E_ERROR;\r
468     }\r
469 \r
470     return ALT_E_SUCCESS;\r
471 }\r
472 \r
473 ALT_STATUS_CODE alt_16550_fifo_clear_tx(ALT_16550_HANDLE_t * handle)\r
474 {\r
475     // Verify that the FIFO is enabled\r
476     if (!(handle->fcr & ALT_UART_FCR_FIFOE_SET_MSK))\r
477     {\r
478         return ALT_E_ERROR;\r
479     }\r
480 \r
481     switch (handle->device)\r
482     {\r
483     case ALT_16550_DEVICE_SOCFPGA_UART0:\r
484     case ALT_16550_DEVICE_SOCFPGA_UART1:\r
485         // Write SRR::XFR (Shadow Reset Register :: Xmitter FIFO Reset) bit.\r
486         alt_write_word(ALT_UART_SRR_ADDR(handle->location), ALT_UART_SRR_XFR_SET_MSK);\r
487         break;\r
488     case ALT_16550_DEVICE_ALTERA_16550_UART:\r
489         // Write FCR::XFIFOR (FIFO Control Register :: Xmitter FIFO Reset) bit.\r
490         alt_write_word(ALT_UART_FCR_ADDR(handle->location), handle->fcr | ALT_UART_FCR_XFIFOR_SET_MSK);\r
491         break;\r
492     default:\r
493         return ALT_E_ERROR;\r
494     }\r
495 \r
496     return ALT_E_SUCCESS;\r
497 }\r
498 \r
499 ALT_STATUS_CODE alt_16550_fifo_clear_all(ALT_16550_HANDLE_t * handle)\r
500 {\r
501     // Verify that the FIFO is enabled\r
502     if (!(handle->fcr & ALT_UART_FCR_FIFOE_SET_MSK))\r
503     {\r
504         return ALT_E_ERROR;\r
505     }\r
506 \r
507     switch (handle->device)\r
508     {\r
509     case ALT_16550_DEVICE_SOCFPGA_UART0:\r
510     case ALT_16550_DEVICE_SOCFPGA_UART1:\r
511         // Write SRR::(RFR | XFR)\r
512         //   (Shadow Reset Register :: (Receiver FIFO Reset | Xmitter FIFO Reset)) bits.\r
513         alt_write_word(ALT_UART_SRR_ADDR(handle->location),\r
514                        ALT_UART_SRR_RFR_SET_MSK | ALT_UART_SRR_XFR_SET_MSK);\r
515         break;\r
516     case ALT_16550_DEVICE_ALTERA_16550_UART:\r
517         // Write FCR::(RFIFOR |XFIFOR)\r
518         //   (FIFO Control Register :: (Receiver FIFO Reset | Xmitter FIFO Reset)) bits.\r
519         alt_write_word(ALT_UART_FCR_ADDR(handle->location),\r
520                        handle->fcr | ALT_UART_FCR_RFIFOR_SET_MSK | ALT_UART_FCR_XFIFOR_SET_MSK);\r
521         break;\r
522     default:\r
523         return ALT_E_ERROR;\r
524     }\r
525 \r
526     return ALT_E_SUCCESS;\r
527 }\r
528 \r
529 ALT_STATUS_CODE alt_16550_fifo_size_get_rx(ALT_16550_HANDLE_t * handle,\r
530                                            uint32_t * size)\r
531 {\r
532     switch (handle->device)\r
533     {\r
534     case ALT_16550_DEVICE_SOCFPGA_UART0:\r
535     case ALT_16550_DEVICE_SOCFPGA_UART1:\r
536         // Read the CPR::FIFO_Mod (Component Parameter Register :: FIFO Mode).\r
537         // The FIFO size is 16x this value.\r
538         *size = ALT_UART_CPR_FIFO_MOD_GET(alt_read_word(ALT_UART_CPR_ADDR(handle->location))) << 4;\r
539         break;\r
540     case ALT_16550_DEVICE_ALTERA_16550_UART:\r
541         // Altera 16550 Compatible Soft UARTs have a configurable size and is\r
542         // stored in the CPR::FIFO_Mode (Component Parameter Register :: FIFO Depth).\r
543         *size = ALT_ALTERA_16550_CPR_FIFO_MODE_GET(alt_read_word(ALT_ALTERA_16550_CPR_ADDR(handle->location))) << 4;\r
544         break;\r
545     default:\r
546         return ALT_E_ERROR;\r
547     }\r
548 \r
549     return ALT_E_SUCCESS;\r
550 }\r
551 \r
552 ALT_STATUS_CODE alt_16550_fifo_size_get_tx(ALT_16550_HANDLE_t * handle,\r
553                                            uint32_t * size)\r
554 {\r
555     switch (handle->device)\r
556     {\r
557     case ALT_16550_DEVICE_SOCFPGA_UART0:\r
558     case ALT_16550_DEVICE_SOCFPGA_UART1:\r
559         // Read the CPR::FIFO_Mod (Component Parameter Register :: FIFO Mode).\r
560         // The FIFO size is 16x this value.\r
561         *size = ALT_UART_CPR_FIFO_MOD_GET(alt_read_word(ALT_UART_CPR_ADDR(handle->location))) << 4;\r
562         break;\r
563     case ALT_16550_DEVICE_ALTERA_16550_UART:\r
564         // Altera 16550 Compatible Soft UARTs have a configurable size and is\r
565         // stored in the CPR::FIFO_Mode (Component Parameter Register :: FIFO Depth).\r
566         // The FIFO size is 16x this value.\r
567         *size = ALT_ALTERA_16550_CPR_FIFO_MODE_GET(alt_read_word(ALT_ALTERA_16550_CPR_ADDR(handle->location))) << 4;\r
568         break;\r
569     default:\r
570         return ALT_E_ERROR;\r
571     }\r
572 \r
573     return ALT_E_SUCCESS;\r
574 }\r
575 \r
576 ALT_STATUS_CODE alt_16550_fifo_level_get_rx(ALT_16550_HANDLE_t * handle,\r
577                                             uint32_t * level)\r
578 {\r
579     // Verify that the FIFO is enabled\r
580     if (!(handle->fcr & ALT_UART_FCR_FIFOE_SET_MSK))\r
581     {\r
582         return ALT_E_ERROR;\r
583     }\r
584 \r
585     switch (handle->device)\r
586     {\r
587     case ALT_16550_DEVICE_SOCFPGA_UART0:\r
588     case ALT_16550_DEVICE_SOCFPGA_UART1:\r
589         // Read RFL (Receive FIFO Level).\r
590         *level = alt_read_word(ALT_UART_RFL_ADDR(handle->location));\r
591         break;\r
592     case ALT_16550_DEVICE_ALTERA_16550_UART:\r
593         // RFL not implemented. Return 0.\r
594         *level = 0;\r
595         break;\r
596     default:\r
597         return ALT_E_ERROR;\r
598     }\r
599 \r
600     return ALT_E_SUCCESS;\r
601 }\r
602 \r
603 ALT_STATUS_CODE alt_16550_fifo_level_get_tx(ALT_16550_HANDLE_t * handle,\r
604                                             uint32_t * level)\r
605 {\r
606     // Verify that the FIFO is enabled\r
607     if (!(handle->fcr & ALT_UART_FCR_FIFOE_SET_MSK))\r
608     {\r
609         return ALT_E_ERROR;\r
610     }\r
611 \r
612     switch (handle->device)\r
613     {\r
614     case ALT_16550_DEVICE_SOCFPGA_UART0:\r
615     case ALT_16550_DEVICE_SOCFPGA_UART1:\r
616         // Read TFL (Transmit FIFO Level).\r
617         *level = alt_read_word(ALT_UART_TFL_ADDR(handle->location));\r
618         break;\r
619     case ALT_16550_DEVICE_ALTERA_16550_UART:\r
620         // TFL not implemented. Return 0.\r
621         *level = 0;\r
622         break;\r
623     default:\r
624         return ALT_E_ERROR;\r
625     }\r
626 \r
627     return ALT_E_SUCCESS;\r
628 }\r
629 \r
630 ALT_STATUS_CODE alt_16550_fifo_trigger_set_rx(ALT_16550_HANDLE_t * handle,\r
631                                               ALT_16550_FIFO_TRIGGER_RX_t trigger)\r
632 {\r
633     // Verify that the FIFO is enabled\r
634     if (!(handle->fcr & ALT_UART_FCR_FIFOE_SET_MSK))\r
635     {\r
636         return ALT_E_ERROR;\r
637     }\r
638 \r
639     // Verify triggering parameter\r
640     switch (trigger)\r
641     {\r
642     case ALT_16550_FIFO_TRIGGER_RX_ANY:\r
643     case ALT_16550_FIFO_TRIGGER_RX_QUARTER_FULL:\r
644     case ALT_16550_FIFO_TRIGGER_RX_HALF_FULL:\r
645     case ALT_16550_FIFO_TRIGGER_RX_ALMOST_FULL:\r
646         break;\r
647     default:\r
648         return ALT_E_BAD_ARG;\r
649     }\r
650 \r
651     switch (handle->device)\r
652     {\r
653     case ALT_16550_DEVICE_SOCFPGA_UART0:\r
654     case ALT_16550_DEVICE_SOCFPGA_UART1:\r
655     case ALT_16550_DEVICE_ALTERA_16550_UART:\r
656         // Update FCR::RT (FIFO Control Register :: Receiver Trigger)\r
657         handle->fcr &= ~ALT_UART_FCR_RT_SET_MSK;\r
658         handle->fcr |= ALT_UART_FCR_RT_SET(trigger);\r
659         alt_write_word(ALT_UART_FCR_ADDR(handle->location), handle->fcr);\r
660         break;\r
661     default:\r
662         return ALT_E_ERROR;\r
663     }\r
664 \r
665     return ALT_E_SUCCESS;\r
666 }\r
667 \r
668 ALT_STATUS_CODE alt_16550_fifo_trigger_set_tx(ALT_16550_HANDLE_t * handle,\r
669                                               ALT_16550_FIFO_TRIGGER_TX_t trigger)\r
670 {\r
671     // Verify that the FIFO is enabled\r
672     if (!(handle->fcr & ALT_UART_FCR_FIFOE_SET_MSK))\r
673     {\r
674         return ALT_E_ERROR;\r
675     }\r
676 \r
677     // Verify triggering parameter\r
678     switch (trigger)\r
679     {\r
680     case ALT_16550_FIFO_TRIGGER_TX_EMPTY:\r
681     case ALT_16550_FIFO_TRIGGER_TX_ALMOST_EMPTY:\r
682     case ALT_16550_FIFO_TRIGGER_TX_QUARTER_FULL:\r
683     case ALT_16550_FIFO_TRIGGER_TX_HALF_FULL:\r
684         break;\r
685     default:\r
686         return ALT_E_BAD_ARG;\r
687     }\r
688 \r
689     switch (handle->device)\r
690     {\r
691     case ALT_16550_DEVICE_SOCFPGA_UART0:\r
692     case ALT_16550_DEVICE_SOCFPGA_UART1:\r
693     case ALT_16550_DEVICE_ALTERA_16550_UART:\r
694         // Update FCR::TET (FIFO Control Register :: Transmit Empty Trigger)\r
695         handle->fcr &= ~ALT_UART_FCR_TET_SET_MSK;\r
696         handle->fcr |= ALT_UART_FCR_TET_SET(trigger);\r
697         alt_write_word(ALT_UART_FCR_ADDR(handle->location), handle->fcr);\r
698         break;\r
699     default:\r
700         return ALT_E_ERROR;\r
701     }\r
702 \r
703     return ALT_E_SUCCESS;\r
704 }\r
705 \r
706 /////\r
707 \r
708 ALT_STATUS_CODE alt_16550_baudrate_get(ALT_16550_HANDLE_t * handle,\r
709                                        uint32_t * baudrate)\r
710 {\r
711     // Query the divisor cached in the handle data\r
712     uint32_t divisor = ALT_16550_HANDLE_DATA_DIVISOR_VALUE_GET(handle->data);\r
713 \r
714     // The divisor should never be zero. It is set to allow for a baud of 57600\r
715     // on initialization and a valid value is checked at\r
716     // alt_16550_divisor_set(). We do not check for users altering the data in\r
717     // the handle structure.\r
718 \r
719     // Formula for calculating the baudrate:\r
720     //    baudrate = clock / (16 * divisor)\r
721 \r
722     *baudrate = (handle->clock_freq >> 4) / divisor;\r
723 \r
724     return ALT_E_SUCCESS;\r
725 }\r
726 \r
727 ALT_STATUS_CODE alt_16550_baudrate_set(ALT_16550_HANDLE_t * handle,\r
728                                        uint32_t baudrate)\r
729 {\r
730     if (baudrate == 0)\r
731     {\r
732         return ALT_E_ARG_RANGE;\r
733     }\r
734 \r
735     // Formula for calculating the divisor:\r
736     //    baudrate = clock / (16 * divisor)\r
737     // => baudrate * 16 * divisor = clock\r
738     // => divisor = clock / (baudrate * 16)\r
739     // => divisor = (clock / 16) / baudrate\r
740 \r
741     // Add half of the denominator to address rounding errors.\r
742     uint32_t divisor = ((handle->clock_freq + (8 * baudrate)) / (16 * baudrate));\r
743 \r
744     // Check for divisor range is in alt_16550_divisor_set().\r
745     return alt_16550_divisor_set(handle, divisor);\r
746 }\r
747 \r
748 ALT_STATUS_CODE alt_16550_divisor_get(ALT_16550_HANDLE_t * handle,\r
749                                       uint32_t * divisor)\r
750 {\r
751     // Just read the divisor portion of the handle data.\r
752     *divisor = ALT_16550_HANDLE_DATA_DIVISOR_VALUE_GET(handle->data);\r
753 \r
754     return ALT_E_SUCCESS;\r
755 }\r
756 \r
757 ALT_STATUS_CODE alt_16550_divisor_set(ALT_16550_HANDLE_t * handle,\r
758                                       uint32_t divisor)\r
759 {\r
760     // Verify divisor value is in range.\r
761     if ((divisor > 0xffff) || (divisor == 0))\r
762     {\r
763         return ALT_E_ARG_RANGE;\r
764     }\r
765 \r
766     // Set the divisor portion of the handle data.\r
767     handle->data &= ~(0xffff);\r
768     handle->data |= divisor;\r
769 \r
770     // Even if the UART is enabled, don't do anything. It is documented that\r
771     // the change will take effect when the UART move to the enabled state.\r
772 \r
773     return ALT_E_SUCCESS;\r
774 }\r
775 \r
776 /////\r
777 \r
778 static ALT_STATUS_CODE alt_16550_ier_mask_set_helper(ALT_16550_HANDLE_t * handle, uint32_t setmask)\r
779 {\r
780     switch (handle->device)\r
781     {\r
782     case ALT_16550_DEVICE_SOCFPGA_UART0:\r
783     case ALT_16550_DEVICE_SOCFPGA_UART1:\r
784     case ALT_16550_DEVICE_ALTERA_16550_UART:\r
785         // Set bit in IER (Interrupt Enable Register)\r
786         alt_setbits_word(ALT_UART_IER_DLH_ADDR(handle->location), setmask);\r
787         break;\r
788     default:\r
789         return ALT_E_ERROR;\r
790     }\r
791 \r
792     return ALT_E_SUCCESS;\r
793 }\r
794 \r
795 static ALT_STATUS_CODE alt_16550_ier_mask_clr_helper(ALT_16550_HANDLE_t * handle, uint32_t setmask)\r
796 {\r
797     switch (handle->device)\r
798     {\r
799     case ALT_16550_DEVICE_SOCFPGA_UART0:\r
800     case ALT_16550_DEVICE_SOCFPGA_UART1:\r
801     case ALT_16550_DEVICE_ALTERA_16550_UART:\r
802         // Clear bit in IER (Interrupt Enable Register)\r
803         alt_clrbits_word(ALT_UART_IER_DLH_ADDR(handle->location), setmask);\r
804         break;\r
805     default:\r
806         return ALT_E_ERROR;\r
807     }\r
808 \r
809     return ALT_E_SUCCESS;\r
810 }\r
811 \r
812 ALT_STATUS_CODE alt_16550_int_enable_rx(ALT_16550_HANDLE_t * handle)\r
813 {\r
814     // Set the IER::ERBFI (Interrupt Enable Register :: Enable Receive Buffer Full Interrupt) bit.\r
815     return alt_16550_ier_mask_set_helper(handle, ALT_UART_IER_DLH_ERBFI_DLH0_SET_MSK);\r
816 }\r
817 \r
818 ALT_STATUS_CODE alt_16550_int_disable_rx(ALT_16550_HANDLE_t * handle)\r
819 {\r
820     // Clear the IER::ERBFI (Interrupt Enable Register :: Enable Receive Buffer Full Interrupt) bit.\r
821     return alt_16550_ier_mask_clr_helper(handle, ALT_UART_IER_DLH_ERBFI_DLH0_SET_MSK);\r
822 }\r
823 \r
824 ALT_STATUS_CODE alt_16550_int_enable_tx(ALT_16550_HANDLE_t * handle)\r
825 {\r
826     // Set the IER::ETBEI (Interrupt Enable Register :: Enable Transmit Buffer Empty Interrupt) bit.\r
827     return alt_16550_ier_mask_set_helper(handle, ALT_UART_IER_DLH_ETBEI_DLH1_SET_MSK);\r
828 }\r
829 \r
830 ALT_STATUS_CODE alt_16550_int_disable_tx(ALT_16550_HANDLE_t * handle)\r
831 {\r
832     // Clear the IER::ETBEI (Interrupt Enable Register :: Enable Transmit Buffer Empty Interrupt) bit.\r
833     return alt_16550_ier_mask_clr_helper(handle, ALT_UART_IER_DLH_ETBEI_DLH1_SET_MSK);\r
834 }\r
835 \r
836 ALT_STATUS_CODE alt_16550_int_enable_line(ALT_16550_HANDLE_t * handle)\r
837 {\r
838     // Set the IER::ELSI (Interrupt Enable Register :: Enable Line Status Interrupt) bit.\r
839     return alt_16550_ier_mask_set_helper(handle, ALT_UART_IER_DLH_ELSI_DHL2_SET_MSK);\r
840 }\r
841 \r
842 ALT_STATUS_CODE alt_16550_int_disable_line(ALT_16550_HANDLE_t * handle)\r
843 {\r
844     // Clear the IER::ELSI (Interrupt Enable Register :: Enable Line Status Interrupt) bit.\r
845     return alt_16550_ier_mask_clr_helper(handle, ALT_UART_IER_DLH_ELSI_DHL2_SET_MSK);\r
846 }\r
847 \r
848 ALT_STATUS_CODE alt_16550_int_enable_modem(ALT_16550_HANDLE_t * handle)\r
849 {\r
850     // Set the IER::EDSSI (Interrupt Enable Register :: Enable Modem Status Interrupt) bit.\r
851     return alt_16550_ier_mask_set_helper(handle, ALT_UART_IER_DLH_EDSSI_DHL3_SET_MSK);\r
852 }\r
853 \r
854 ALT_STATUS_CODE alt_16550_int_disable_modem(ALT_16550_HANDLE_t * handle)\r
855 {\r
856     // Clear the IER::EDSSI (Interrupt Enable Register :: Enable Modem Status Interrupt) bit.\r
857     return alt_16550_ier_mask_clr_helper(handle, ALT_UART_IER_DLH_EDSSI_DHL3_SET_MSK);\r
858 }\r
859 \r
860 ALT_STATUS_CODE alt_16550_int_disable_all(ALT_16550_HANDLE_t * handle)\r
861 {\r
862     // Clear the IER::(ERBFI | ETBEI | ELSI | EDSSI)\r
863     //   (Interrupt Enable Register :: (Enable Receive Buffer Full Interrupt   |\r
864     //                                  Enable Transmit Buffer Empty Interrupt |\r
865     //                                  Enable Line Status Interrupt           |\r
866     //                                  Enable Modem Status Interrupt)) bits\r
867     return alt_16550_ier_mask_clr_helper(handle, ALT_UART_IER_DLH_ERBFI_DLH0_SET_MSK |\r
868                                                  ALT_UART_IER_DLH_ETBEI_DLH1_SET_MSK |\r
869                                                  ALT_UART_IER_DLH_ELSI_DHL2_SET_MSK  |\r
870                                                  ALT_UART_IER_DLH_EDSSI_DHL3_SET_MSK);\r
871 }\r
872 \r
873 ALT_STATUS_CODE alt_16550_int_status_get(ALT_16550_HANDLE_t * handle,\r
874                                          ALT_16550_INT_STATUS_t * status)\r
875 {\r
876     switch (handle->device)\r
877     {\r
878     case ALT_16550_DEVICE_SOCFPGA_UART0:\r
879     case ALT_16550_DEVICE_SOCFPGA_UART1:\r
880     case ALT_16550_DEVICE_ALTERA_16550_UART:\r
881         // Read IIR::IID (Interrupt Identity Register :: Interrupt ID)\r
882         *status = (ALT_16550_INT_STATUS_t) ALT_UART_IIR_ID_GET(alt_read_word(ALT_UART_IIR_ADDR(handle->location)));\r
883         break;\r
884     default:\r
885         return ALT_E_ERROR;\r
886     }\r
887 \r
888     return ALT_E_SUCCESS;\r
889 }\r
890 \r
891 /////\r
892 \r
893 ALT_STATUS_CODE alt_16550_line_config_set(ALT_16550_HANDLE_t * handle,\r
894                                           ALT_16550_DATABITS_t databits,\r
895                                           ALT_16550_PARITY_t parity,\r
896                                           ALT_16550_STOPBITS_t stopbits)\r
897 {\r
898     // Validate the databits parameter.\r
899     switch (databits)\r
900     {\r
901     case ALT_16550_DATABITS_5:\r
902     case ALT_16550_DATABITS_6:\r
903     case ALT_16550_DATABITS_7:\r
904     case ALT_16550_DATABITS_8:\r
905         break;\r
906     default:\r
907         return ALT_E_ERROR;\r
908     }\r
909 \r
910     // Validate the parity parameter.\r
911     switch (parity)\r
912     {\r
913     case ALT_16550_PARITY_DISABLE:\r
914     case ALT_16550_PARITY_ODD:\r
915     case ALT_16550_PARITY_EVEN:\r
916         break;\r
917     default:\r
918         return ALT_E_ERROR;\r
919     }\r
920 \r
921     // Validate the stopbits parameter.\r
922     switch (stopbits)\r
923     {\r
924     case ALT_16550_STOPBITS_1:\r
925     case ALT_16550_STOPBITS_2:\r
926         break;\r
927     default:\r
928         return ALT_E_ERROR;\r
929     }\r
930 \r
931     // LCR (Line Control Register) cache.\r
932     uint32_t lcr = 0;\r
933 \r
934     switch (handle->device)\r
935     {\r
936     case ALT_16550_DEVICE_SOCFPGA_UART0:\r
937     case ALT_16550_DEVICE_SOCFPGA_UART1:\r
938     case ALT_16550_DEVICE_ALTERA_16550_UART:\r
939 \r
940         // Configure the number of databits\r
941         lcr |= ALT_UART_LCR_DLS_SET(databits);\r
942 \r
943         // Configure the number of stopbits\r
944         lcr |= ALT_UART_LCR_STOP_SET(stopbits);\r
945 \r
946         // Configure the parity\r
947         if (parity != ALT_16550_PARITY_DISABLE)\r
948         {\r
949             // Enable parity in LCR\r
950             lcr |= ALT_UART_LCR_PEN_SET_MSK;\r
951 \r
952             if (parity == ALT_16550_PARITY_EVEN)\r
953             {\r
954                 // Enable even parity in LCR; otherwise it's odd parity.\r
955                 lcr |= ALT_UART_LCR_EPS_SET_MSK;\r
956             }\r
957         }\r
958 \r
959         // Update LCR (Line Control Register)\r
960         alt_replbits_word(ALT_UART_LCR_ADDR(handle->location), \r
961                           ALT_UART_LCR_DLS_SET_MSK\r
962                         | ALT_UART_LCR_STOP_SET_MSK\r
963                         | ALT_UART_LCR_PEN_SET_MSK\r
964                         | ALT_UART_LCR_EPS_SET_MSK,\r
965                         lcr);\r
966 \r
967         break;\r
968 \r
969     default:\r
970         return ALT_E_ERROR;\r
971     }\r
972 \r
973     return ALT_E_SUCCESS;\r
974 }\r
975 \r
976 ALT_STATUS_CODE alt_16550_line_break_enable(ALT_16550_HANDLE_t * handle)\r
977 {\r
978     switch (handle->device)\r
979     {\r
980     case ALT_16550_DEVICE_SOCFPGA_UART0:\r
981     case ALT_16550_DEVICE_SOCFPGA_UART1:\r
982     case ALT_16550_DEVICE_ALTERA_16550_UART:\r
983         // Set the LCR::Break (Line Control Register :: Break) bit.\r
984         alt_setbits_word(ALT_UART_LCR_ADDR(handle->location), ALT_UART_LCR_BREAK_SET_MSK);\r
985         break;\r
986 \r
987     default:\r
988         return ALT_E_ERROR;\r
989     }\r
990 \r
991     return ALT_E_SUCCESS;\r
992 }\r
993 \r
994 ALT_STATUS_CODE alt_16550_line_break_disable(ALT_16550_HANDLE_t * handle)\r
995 {\r
996     switch (handle->device)\r
997     {\r
998     case ALT_16550_DEVICE_SOCFPGA_UART0:\r
999     case ALT_16550_DEVICE_SOCFPGA_UART1:\r
1000     case ALT_16550_DEVICE_ALTERA_16550_UART:\r
1001         // Clear the LCR::Break (Line Control Register :: Break) bit.\r
1002         alt_clrbits_word(ALT_UART_LCR_ADDR(handle->location), ALT_UART_LCR_BREAK_SET_MSK);\r
1003         break;\r
1004 \r
1005     default:\r
1006         return ALT_E_ERROR;\r
1007     }\r
1008 \r
1009 \r
1010     return ALT_E_SUCCESS;\r
1011 }\r
1012 \r
1013 ALT_STATUS_CODE alt_16550_line_status_get(ALT_16550_HANDLE_t * handle,\r
1014                                           uint32_t * status)\r
1015 {\r
1016     switch (handle->device)\r
1017     {\r
1018     case ALT_16550_DEVICE_SOCFPGA_UART0:\r
1019     case ALT_16550_DEVICE_SOCFPGA_UART1:\r
1020     case ALT_16550_DEVICE_ALTERA_16550_UART:\r
1021         // Read the LSR (Line Status Register).\r
1022         *status = alt_read_word(ALT_UART_LSR_ADDR(handle->location));\r
1023         break;\r
1024     default:\r
1025         return ALT_E_ERROR;\r
1026     }\r
1027 \r
1028     return ALT_E_SUCCESS;\r
1029 }\r
1030 \r
1031 /////\r
1032 \r
1033 static ALT_STATUS_CODE alt_16550_mcr_mask_set_helper(ALT_16550_HANDLE_t * handle,\r
1034                                                      uint32_t setmask)\r
1035 {\r
1036     switch (handle->device)\r
1037     {\r
1038     case ALT_16550_DEVICE_SOCFPGA_UART0:\r
1039     case ALT_16550_DEVICE_SOCFPGA_UART1:\r
1040     case ALT_16550_DEVICE_ALTERA_16550_UART:\r
1041         // Set the bit in MCR (Modem Control Register).\r
1042         alt_setbits_word(ALT_UART_MCR_ADDR(handle->location), setmask);\r
1043         break;\r
1044     default:\r
1045         return ALT_E_ERROR;\r
1046     }\r
1047 \r
1048     return ALT_E_SUCCESS;\r
1049 }\r
1050 \r
1051 static ALT_STATUS_CODE alt_16550_mcr_mask_clr_helper(ALT_16550_HANDLE_t * handle, uint32_t setmask)\r
1052 {\r
1053     switch (handle->device)\r
1054     {\r
1055     case ALT_16550_DEVICE_SOCFPGA_UART0:\r
1056     case ALT_16550_DEVICE_SOCFPGA_UART1:\r
1057     case ALT_16550_DEVICE_ALTERA_16550_UART:\r
1058         // Clear the bit in MCR (Modem Control Register).\r
1059         alt_clrbits_word(ALT_UART_MCR_ADDR(handle->location), setmask);\r
1060         break;\r
1061     default:\r
1062         return ALT_E_ERROR;\r
1063     }\r
1064 \r
1065     return ALT_E_SUCCESS;\r
1066 }\r
1067 \r
1068 ALT_STATUS_CODE alt_16550_flowcontrol_enable(ALT_16550_HANDLE_t * handle)\r
1069 {\r
1070     // Verify that the FIFO is enabled\r
1071     if (!(handle->fcr & ALT_UART_FCR_FIFOE_SET_MSK))\r
1072     {\r
1073         return ALT_E_ERROR;\r
1074     }\r
1075 \r
1076     // For the Altera 16550 Compatible Soft UART, check that Hardware Flowcontrol is enabled.\r
1077     if (handle->device == ALT_16550_DEVICE_ALTERA_16550_UART)\r
1078     {\r
1079         // Read the CPR::AFCE_Mode (Component Parameter Register :: Auto Flow Control mode) bit.\r
1080         uint32_t cpr = alt_read_word(ALT_ALTERA_16550_CPR_ADDR(handle->location));\r
1081         if (!(ALT_ALTERA_16550_CPR_AFCE_MODE_SET_MSK & cpr))\r
1082         {\r
1083             return ALT_E_ERROR;\r
1084         }\r
1085     }\r
1086 \r
1087     // Set MCR::AFCE (Modem Control Register :: Automatic FlowControl Enable) bit.\r
1088     return alt_16550_mcr_mask_set_helper(handle, ALT_UART_MCR_AFCE_SET_MSK);\r
1089 }\r
1090 \r
1091 ALT_STATUS_CODE alt_16550_flowcontrol_disable(ALT_16550_HANDLE_t * handle)\r
1092 {\r
1093     // Clear MCR::AFCE (Modem Control Register :: Automatic FlowControl Enable) bit.\r
1094     return alt_16550_mcr_mask_clr_helper(handle, ALT_UART_MCR_AFCE_SET_MSK);\r
1095 }\r
1096 \r
1097 ALT_STATUS_CODE alt_16550_loopback_enable(ALT_16550_HANDLE_t * handle)\r
1098 {\r
1099     // Loopback is not implemented in the Altera 16550 Compatible Soft UART.\r
1100     if (handle->device == ALT_16550_DEVICE_ALTERA_16550_UART)\r
1101     {\r
1102         return ALT_E_ERROR;\r
1103     }\r
1104 \r
1105     // Set MCR::Loopback (Modem Control Register :: Loopback) bit.\r
1106     return alt_16550_mcr_mask_set_helper(handle, ALT_UART_MCR_LOOPBACK_SET_MSK);\r
1107 }\r
1108 \r
1109 ALT_STATUS_CODE alt_16550_loopback_disable(ALT_16550_HANDLE_t * handle)\r
1110 {\r
1111     // Clear MCR::Loopback (Modem Control Register :: Loopback) bit.\r
1112     return alt_16550_mcr_mask_clr_helper(handle, ALT_UART_MCR_LOOPBACK_SET_MSK);\r
1113 }\r
1114 \r
1115 ALT_STATUS_CODE alt_16550_modem_enable_out1(ALT_16550_HANDLE_t * handle)\r
1116 {\r
1117     // Set MCR::Out1 (Modem Control Register :: Out1) bit.\r
1118     return alt_16550_mcr_mask_set_helper(handle, ALT_UART_MCR_OUT1_SET_MSK);\r
1119 }\r
1120 \r
1121 ALT_STATUS_CODE alt_16550_modem_disable_out1(ALT_16550_HANDLE_t * handle)\r
1122 {\r
1123     // Clear MCR::Out1 (Modem Control Register :: Out1) bit.\r
1124     return alt_16550_mcr_mask_clr_helper(handle, ALT_UART_MCR_OUT1_SET_MSK);\r
1125 }\r
1126 \r
1127 ALT_STATUS_CODE alt_16550_modem_enable_out2(ALT_16550_HANDLE_t * handle)\r
1128 {\r
1129     // Set MCR::Out2 (Modem Control Register :: Out2) bit.\r
1130     return alt_16550_mcr_mask_set_helper(handle, ALT_UART_MCR_OUT2_SET_MSK);\r
1131 }\r
1132 \r
1133 ALT_STATUS_CODE alt_16550_modem_disable_out2(ALT_16550_HANDLE_t * handle)\r
1134 {\r
1135     // Clear MCR::Out2 (Modem Control Register :: Out2) bit.\r
1136     return alt_16550_mcr_mask_clr_helper(handle, ALT_UART_MCR_OUT2_SET_MSK);\r
1137 }\r
1138 \r
1139 ALT_STATUS_CODE alt_16550_modem_enable_rts(ALT_16550_HANDLE_t * handle)\r
1140 {\r
1141     // Set MCR::RTS (Modem Control Register :: Request To Send) bit.\r
1142     return alt_16550_mcr_mask_set_helper(handle, ALT_UART_MCR_RTS_SET_MSK);\r
1143 }\r
1144 \r
1145 ALT_STATUS_CODE alt_16550_modem_disable_rts(ALT_16550_HANDLE_t * handle)\r
1146 {\r
1147     // Clear MCR::RTS (Modem Control Register :: Request To Send) bit.\r
1148     return alt_16550_mcr_mask_clr_helper(handle, ALT_UART_MCR_RTS_SET_MSK);\r
1149 }\r
1150 \r
1151 ALT_STATUS_CODE alt_16550_modem_enable_dtr(ALT_16550_HANDLE_t * handle)\r
1152 {\r
1153     // Set MCR::DTR (Modem Control Register :: Data Terminal Ready) bit.\r
1154     return alt_16550_mcr_mask_set_helper(handle, ALT_UART_MCR_DTR_SET_MSK);\r
1155 }\r
1156 \r
1157 ALT_STATUS_CODE alt_16550_modem_disable_dtr(ALT_16550_HANDLE_t * handle)\r
1158 {\r
1159     // Clear MCR::DTR (Modem Control Register :: Data Terminal Ready) bit.\r
1160     return alt_16550_mcr_mask_clr_helper(handle, ALT_UART_MCR_DTR_SET_MSK);\r
1161 }\r
1162 \r
1163 ALT_STATUS_CODE alt_16550_modem_status_get(ALT_16550_HANDLE_t * handle,\r
1164                                           uint32_t * status)\r
1165 {\r
1166     switch (handle->device)\r
1167     {\r
1168     case ALT_16550_DEVICE_SOCFPGA_UART0:\r
1169     case ALT_16550_DEVICE_SOCFPGA_UART1:\r
1170     case ALT_16550_DEVICE_ALTERA_16550_UART:\r
1171         // Read the MSR (Modem Status Register).\r
1172         *status = alt_read_word(ALT_UART_MSR_ADDR(handle->location));\r
1173         break;\r
1174     default:\r
1175         return ALT_E_ERROR;\r
1176     }\r
1177 \r
1178     return ALT_E_SUCCESS;\r
1179 }\r