summaryrefslogtreecommitdiffstats
path: root/bsps/arm/altera-cyclone-v/contrib/hwlib/src/hwmgr/alt_16550_uart.c
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2018-04-22 15:05:47 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2018-04-23 15:18:42 +0200
commitf004ace8280bd973b6b986402a805f684263aefb (patch)
tree52973fe737bd95f93605e60d17448b749ae1749e /bsps/arm/altera-cyclone-v/contrib/hwlib/src/hwmgr/alt_16550_uart.c
parentbsps: Move make/custom/* files to bsps (diff)
downloadrtems-f004ace8280bd973b6b986402a805f684263aefb.tar.bz2
bsp/altera-cyclone-v: Move hwlib to bsps
This patch is a part of the BSP source reorganization. Update #3285.
Diffstat (limited to 'bsps/arm/altera-cyclone-v/contrib/hwlib/src/hwmgr/alt_16550_uart.c')
-rw-r--r--bsps/arm/altera-cyclone-v/contrib/hwlib/src/hwmgr/alt_16550_uart.c1179
1 files changed, 1179 insertions, 0 deletions
diff --git a/bsps/arm/altera-cyclone-v/contrib/hwlib/src/hwmgr/alt_16550_uart.c b/bsps/arm/altera-cyclone-v/contrib/hwlib/src/hwmgr/alt_16550_uart.c
new file mode 100644
index 0000000000..7ed75c39d3
--- /dev/null
+++ b/bsps/arm/altera-cyclone-v/contrib/hwlib/src/hwmgr/alt_16550_uart.c
@@ -0,0 +1,1179 @@
+/******************************************************************************
+ *
+ * Copyright 2013 Altera Corporation. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************/
+
+#include <bsp/alt_16550_uart.h>
+#include <bsp/alt_clock_manager.h>
+#include <bsp/socal/alt_rstmgr.h>
+#include <bsp/socal/alt_uart.h>
+#include <bsp/socal/hps.h>
+#include <bsp/socal/socal.h>
+
+/////
+
+#define ALT_16550_HANDLE_DATA_UART_ENABLED_MSK (1UL << 31)
+#define ALT_16550_HANDLE_DATA_DIVISOR_VALUE_GET(value) (value & 0xffff)
+
+#define ALT_ALTERA_16550_CPR_OFST (0xF4)
+#define ALT_ALTERA_16550_CPR_ADDR(base) ALT_CAST(void *, (ALT_CAST(char *, (base)) + ALT_ALTERA_16550_CPR_OFST))
+#define ALT_ALTERA_16550_CPR_FIFO_MODE_GET(value) (((value) >> 16) & 0xff)
+#define ALT_ALTERA_16550_CPR_AFCE_MODE_SET_MSK (1 << 4)
+
+/////
+
+// Remove these macros as part of case:123835.
+#define ALT_UART_IER_DLH_VALUE_SET(value) ((value) & 0xff)
+#define ALT_UART_IER_DLH_ETBEI_DLH1_SET_MSK ALT_UART_IER_DLH_ETBEI_DLHL_SET_MSK
+
+/////
+
+//
+// Helper function which resets the UART and if requested, initializes the UART
+// to the default settings. Currently the default settings are:
+// - 8 databits
+// - no parity
+// - 1 stopbit
+// - 57600 baudrate
+// The reset routines depends on the hardware implementation of the UART.
+//
+
+// This helper is needed because the regular alt_read_word(src) essentially
+// resolves to "*(volatile uint32_t *)src". As there is no assignment, this
+// could potentially be optimized away. With the helper, the actual register
+// read should occur and be returned (and subsequently discarded).
+static inline uint32_t alt_read_word_helper(const void * addr)
+{
+ return alt_read_word(addr);
+}
+
+//
+// Helper function write the divisor in hardware.
+//
+static ALT_STATUS_CODE alt_16550_write_divisor_helper(ALT_16550_HANDLE_t * handle,
+ uint32_t divisor)
+{
+ // Validate the divisor parameter.
+ if (divisor > 0xffff)
+ {
+ // This should never happen as it is verified in divisor_set.
+ return ALT_E_ERROR;
+ }
+
+ switch (handle->device)
+ {
+ case ALT_16550_DEVICE_SOCFPGA_UART0:
+ case ALT_16550_DEVICE_SOCFPGA_UART1:
+ case ALT_16550_DEVICE_ALTERA_16550_UART:
+ // Set LCR::DLAB (Line Control Register :: Divisor Latch Access Bit)
+ alt_setbits_word(ALT_UART_LCR_ADDR(handle->location), ALT_UART_LCR_DLAB_SET_MSK);
+
+ // Write DLL (Divisor Latch Low).
+ alt_write_word(ALT_UART_RBR_THR_DLL_ADDR(handle->location), ALT_UART_RBR_THR_DLL_VALUE_SET(divisor));
+
+ // Write DLH (Divisor Latch High).
+ alt_write_word(ALT_UART_IER_DLH_ADDR(handle->location), ALT_UART_IER_DLH_VALUE_SET(divisor >> 8));
+
+ // Clear LCR::DLAB (Line Control Register :: Divisor Latch Access Bit)
+ alt_clrbits_word(ALT_UART_LCR_ADDR(handle->location), ALT_UART_LCR_DLAB_SET_MSK);
+
+ break;
+
+ default:
+ return ALT_E_ERROR;
+ }
+
+ // Update the enabled state in the handle data.
+ if (divisor != 0)
+ {
+ handle->data |= ALT_16550_HANDLE_DATA_UART_ENABLED_MSK;
+ }
+ else
+ {
+ handle->data &= ~ALT_16550_HANDLE_DATA_UART_ENABLED_MSK;
+ }
+
+ return ALT_E_SUCCESS;
+}
+
+//
+// Helper function to reset the UART.
+//
+static ALT_STATUS_CODE alt_16550_reset_helper(ALT_16550_HANDLE_t * handle, bool enable_init)
+{
+ switch (handle->device)
+ {
+ case ALT_16550_DEVICE_SOCFPGA_UART0:
+ case ALT_16550_DEVICE_SOCFPGA_UART1:
+ // Write SRR::UR (Shadow Reset Register :: UART Reset)
+ alt_write_word(ALT_UART_SRR_ADDR(handle->location), ALT_UART_SRR_UR_SET_MSK);
+
+ // Read the MSR to work around case:119085.
+ alt_read_word_helper(ALT_UART_MSR_ADDR(handle->location));
+ break;
+
+ case ALT_16550_DEVICE_ALTERA_16550_UART:
+ alt_16550_write_divisor_helper(handle, 0); // Disable UART
+ alt_16550_int_disable_all(handle); // Disable interrupts
+ alt_16550_fifo_disable(handle); // Disable FIFOs
+ alt_write_word(ALT_UART_MCR_ADDR(handle->location), 0); // 0 -> MCR (AFCE, LP, OUT2, OUT1, RTS, DTR)
+ break;
+
+ default:
+ return ALT_E_ERROR;
+ }
+
+ // If we are initializing (as opposed to just uninitializing)
+ if (enable_init)
+ {
+ ALT_STATUS_CODE status;
+
+ // Set bit IER::PTIME (Interrupt Enable Register :: Programmable THRE Mode Enable)
+ alt_setbits_word(ALT_UART_IER_DLH_ADDR(handle->location), ALT_UART_IER_DLH_PTIME_DLH7_SET_MSK);
+
+ // Set the line configuration to use 8-N-1.
+ status = alt_16550_line_config_set(handle, ALT_16550_DATABITS_8,
+ ALT_16550_PARITY_DISABLE,
+ ALT_16550_STOPBITS_1);
+ if (status != ALT_E_SUCCESS)
+ {
+ return status;
+ }
+
+ uint32_t divisor = ALT_16550_HANDLE_DATA_DIVISOR_VALUE_GET(handle->data);
+ if (divisor == 0)
+ {
+ // Set the default baudrate to 57600.
+ status = alt_16550_baudrate_set(handle, ALT_16550_BAUDRATE_57600);
+ if (status != ALT_E_SUCCESS)
+ {
+ return status;
+ }
+ }
+ }
+
+ return ALT_E_SUCCESS;
+}
+
+ALT_STATUS_CODE alt_16550_init(ALT_16550_DEVICE_t device,
+ void * location,
+ alt_freq_t clock_freq,
+ ALT_16550_HANDLE_t * handle)
+{
+ handle->device = device;
+ handle->data = 0;
+ handle->fcr = 0;
+
+ switch (device)
+ {
+ case ALT_16550_DEVICE_SOCFPGA_UART0:
+ case ALT_16550_DEVICE_SOCFPGA_UART1:
+ // The ALT_CLK_L4_SP is required for all SoCFPGA UARTs. Check that it's enabled.
+ if (alt_clk_is_enabled(ALT_CLK_L4_SP) != ALT_E_TRUE)
+ {
+ return ALT_E_BAD_CLK;
+ }
+ else
+ {
+ ALT_STATUS_CODE status;
+ status = alt_clk_freq_get(ALT_CLK_L4_SP, &handle->clock_freq);
+ if (status != ALT_E_SUCCESS)
+ {
+ return status;
+ }
+
+ if (device == ALT_16550_DEVICE_SOCFPGA_UART0)
+ {
+ handle->location = ALT_UART0_ADDR;
+
+ // Bring UART0 out of reset.
+ alt_clrbits_word(ALT_RSTMGR_PERMODRST_ADDR, ALT_RSTMGR_PERMODRST_UART0_SET_MSK);
+ }
+ else // device == ALT_16550_DEVICE_SOCFPGA_UART1
+ {
+ handle->location = ALT_UART1_ADDR;
+
+ // Bring UART1 out of reset.
+ alt_clrbits_word(ALT_RSTMGR_PERMODRST_ADDR, ALT_RSTMGR_PERMODRST_UART1_SET_MSK);
+ }
+
+ // Verify the UCR (UART Component Version)
+ uint32_t ucr = alt_read_word(ALT_UART_UCV_ADDR(handle->location));
+ if (ucr != ALT_UART_UCV_UART_COMPONENT_VER_RESET)
+ {
+ return ALT_E_ERROR;
+ }
+ }
+ break;
+ case ALT_16550_DEVICE_ALTERA_16550_UART:
+ handle->location = location;
+ handle->clock_freq = clock_freq;
+ break;
+ default:
+ return ALT_E_BAD_ARG;
+ }
+
+ return alt_16550_reset_helper(handle, true);
+}
+
+ALT_STATUS_CODE alt_16550_uninit(ALT_16550_HANDLE_t * handle)
+{
+ switch (handle->device)
+ {
+ case ALT_16550_DEVICE_SOCFPGA_UART0:
+ alt_setbits_word(ALT_RSTMGR_PERMODRST_ADDR, ALT_RSTMGR_PERMODRST_UART0_SET_MSK);
+ return ALT_E_SUCCESS;
+ case ALT_16550_DEVICE_SOCFPGA_UART1:
+ alt_setbits_word(ALT_RSTMGR_PERMODRST_ADDR, ALT_RSTMGR_PERMODRST_UART1_SET_MSK);
+ return ALT_E_SUCCESS;
+ case ALT_16550_DEVICE_ALTERA_16550_UART:
+ default:
+ return alt_16550_reset_helper(handle, false);
+ }
+}
+
+ALT_STATUS_CODE alt_16550_reset(ALT_16550_HANDLE_t * handle)
+{
+ return alt_16550_reset_helper(handle, true);
+}
+
+ALT_STATUS_CODE alt_16550_enable(ALT_16550_HANDLE_t * handle)
+{
+ // Write the divisor cached in the handle data to the divisor registers.
+ // This will effectively enable the UART.
+ return alt_16550_write_divisor_helper(handle,
+ ALT_16550_HANDLE_DATA_DIVISOR_VALUE_GET(handle->data));
+}
+
+ALT_STATUS_CODE alt_16550_disable(ALT_16550_HANDLE_t * handle)
+{
+ // Write 0 to the divisor the divisor registers. This will effectively
+ // disable the UART.
+ return alt_16550_write_divisor_helper(handle, 0);
+}
+
+ALT_STATUS_CODE alt_16550_read(ALT_16550_HANDLE_t * handle,
+ char * item)
+{
+ // Verify that the UART is enabled
+ if (!(handle->data & ALT_16550_HANDLE_DATA_UART_ENABLED_MSK))
+ {
+ return ALT_E_ERROR;
+ }
+
+ // Verify that the FIFO is disabled
+ if (handle->fcr & ALT_UART_FCR_FIFOE_SET_MSK)
+ {
+ return ALT_E_ERROR;
+ }
+
+ switch (handle->device)
+ {
+ case ALT_16550_DEVICE_SOCFPGA_UART0:
+ case ALT_16550_DEVICE_SOCFPGA_UART1:
+ case ALT_16550_DEVICE_ALTERA_16550_UART:
+ // Read the RBR (Receive Buffer Register) into *item.
+ *item = ALT_UART_RBR_THR_DLL_VALUE_GET(alt_read_word(ALT_UART_RBR_THR_DLL_ADDR(handle->location)));
+ break;
+ default:
+ return ALT_E_ERROR;
+ }
+ return ALT_E_SUCCESS;
+}
+
+ALT_STATUS_CODE alt_16550_write(ALT_16550_HANDLE_t * handle,
+ char item)
+{
+ // Verify that the UART is enabled
+ if (!(handle->data & ALT_16550_HANDLE_DATA_UART_ENABLED_MSK))
+ {
+ return ALT_E_ERROR;
+ }
+
+ // Verify that the FIFO is disabled
+ if (handle->fcr & ALT_UART_FCR_FIFOE_SET_MSK)
+ {
+ return ALT_E_ERROR;
+ }
+
+ switch (handle->device)
+ {
+ case ALT_16550_DEVICE_SOCFPGA_UART0:
+ case ALT_16550_DEVICE_SOCFPGA_UART1:
+ case ALT_16550_DEVICE_ALTERA_16550_UART:
+ // Write the buffer into the THR (Transmit Holding Register)
+ alt_write_word(ALT_UART_RBR_THR_DLL_ADDR(handle->location), item);
+ break;
+ default:
+ return ALT_E_ERROR;
+ }
+
+ return ALT_E_SUCCESS;
+}
+
+/////
+
+ALT_STATUS_CODE alt_16550_fifo_enable(ALT_16550_HANDLE_t * handle)
+{
+ switch (handle->device)
+ {
+ case ALT_16550_DEVICE_SOCFPGA_UART0:
+ case ALT_16550_DEVICE_SOCFPGA_UART1:
+ case ALT_16550_DEVICE_ALTERA_16550_UART:
+ // Set FCR::FIFOE (FIFO Control Register :: FIFO Enable) bit.
+ handle->fcr |= ALT_UART_FCR_FIFOE_SET_MSK;
+ alt_write_word(ALT_UART_FCR_ADDR(handle->location), handle->fcr);
+ break;
+ default:
+ return ALT_E_ERROR;
+ }
+
+ // No need to reset / clear the FIFOs. This is done automatically when
+ // FCR::FIFOE is changed.
+ return ALT_E_SUCCESS;
+}
+
+ALT_STATUS_CODE alt_16550_fifo_disable(ALT_16550_HANDLE_t * handle)
+{
+ switch (handle->device)
+ {
+ case ALT_16550_DEVICE_SOCFPGA_UART0:
+ case ALT_16550_DEVICE_SOCFPGA_UART1:
+ case ALT_16550_DEVICE_ALTERA_16550_UART:
+ // Clear FCR::FIFOE (FIFO Control Register :: FIFO Enable) bit.
+ handle->fcr &= ~ALT_UART_FCR_FIFOE_SET_MSK;
+ alt_write_word(ALT_UART_FCR_ADDR(handle->location), handle->fcr);
+ break;
+ default:
+ return ALT_E_ERROR;
+ }
+
+ return ALT_E_SUCCESS;
+}
+
+ALT_STATUS_CODE alt_16550_fifo_read(ALT_16550_HANDLE_t * handle,
+ char * buffer,
+ size_t count)
+{
+ // Verify that the UART is enabled
+ if (!(handle->data & ALT_16550_HANDLE_DATA_UART_ENABLED_MSK))
+ {
+ return ALT_E_ERROR;
+ }
+
+ // Verify that the FIFO is enabled
+ if (!(handle->fcr & ALT_UART_FCR_FIFOE_SET_MSK))
+ {
+ return ALT_E_ERROR;
+ }
+
+ switch (handle->device)
+ {
+ case ALT_16550_DEVICE_SOCFPGA_UART0:
+ case ALT_16550_DEVICE_SOCFPGA_UART1:
+ case ALT_16550_DEVICE_ALTERA_16550_UART:
+ // Read the RBR (Receive Buffer Register) into the buffer
+ for (size_t i = 0; i < count; ++i)
+ {
+ buffer[i] = ALT_UART_RBR_THR_DLL_VALUE_GET(alt_read_word(ALT_UART_RBR_THR_DLL_ADDR(handle->location)));
+ }
+ break;
+ default:
+ return ALT_E_ERROR;
+ }
+
+ return ALT_E_SUCCESS;
+}
+
+ALT_STATUS_CODE alt_16550_fifo_write(ALT_16550_HANDLE_t * handle,
+ const char * buffer,
+ size_t count)
+{
+ // Verify that the UART is enabled
+ if (!(handle->data & ALT_16550_HANDLE_DATA_UART_ENABLED_MSK))
+ {
+ return ALT_E_ERROR;
+ }
+
+ // Verify that the FIFO is enabled
+ if (!(handle->fcr & ALT_UART_FCR_FIFOE_SET_MSK))
+ {
+ return ALT_E_ERROR;
+ }
+
+ switch (handle->device)
+ {
+ case ALT_16550_DEVICE_SOCFPGA_UART0:
+ case ALT_16550_DEVICE_SOCFPGA_UART1:
+ case ALT_16550_DEVICE_ALTERA_16550_UART:
+ // Write the buffer into the THR (Transmit Holding Register)
+ for (size_t i = 0; i < count; ++i)
+ {
+ alt_write_word(ALT_UART_RBR_THR_DLL_ADDR(handle->location), buffer[i]);
+ }
+ break;
+ default:
+ return ALT_E_ERROR;
+ }
+
+ return ALT_E_SUCCESS;
+}
+
+ALT_STATUS_CODE alt_16550_fifo_clear_rx(ALT_16550_HANDLE_t * handle)
+{
+ // Verify that the FIFO is enabled
+ if (!(handle->fcr & ALT_UART_FCR_FIFOE_SET_MSK))
+ {
+ return ALT_E_ERROR;
+ }
+
+ switch (handle->device)
+ {
+ case ALT_16550_DEVICE_SOCFPGA_UART0:
+ case ALT_16550_DEVICE_SOCFPGA_UART1:
+ // Write SRR::RFR (Shadow Reset Register :: Receiver FIFO Reset) bit.
+ alt_write_word(ALT_UART_SRR_ADDR(handle->location), ALT_UART_SRR_RFR_SET_MSK);
+ break;
+ case ALT_16550_DEVICE_ALTERA_16550_UART:
+ // Write FCR::RFIFOR (FIFO Control Register :: Receiver FIFO Reset) bit.
+ alt_write_word(ALT_UART_FCR_ADDR(handle->location), handle->fcr | ALT_UART_FCR_RFIFOR_SET_MSK);
+ break;
+ default:
+ return ALT_E_ERROR;
+ }
+
+ return ALT_E_SUCCESS;
+}
+
+ALT_STATUS_CODE alt_16550_fifo_clear_tx(ALT_16550_HANDLE_t * handle)
+{
+ // Verify that the FIFO is enabled
+ if (!(handle->fcr & ALT_UART_FCR_FIFOE_SET_MSK))
+ {
+ return ALT_E_ERROR;
+ }
+
+ switch (handle->device)
+ {
+ case ALT_16550_DEVICE_SOCFPGA_UART0:
+ case ALT_16550_DEVICE_SOCFPGA_UART1:
+ // Write SRR::XFR (Shadow Reset Register :: Xmitter FIFO Reset) bit.
+ alt_write_word(ALT_UART_SRR_ADDR(handle->location), ALT_UART_SRR_XFR_SET_MSK);
+ break;
+ case ALT_16550_DEVICE_ALTERA_16550_UART:
+ // Write FCR::XFIFOR (FIFO Control Register :: Xmitter FIFO Reset) bit.
+ alt_write_word(ALT_UART_FCR_ADDR(handle->location), handle->fcr | ALT_UART_FCR_XFIFOR_SET_MSK);
+ break;
+ default:
+ return ALT_E_ERROR;
+ }
+
+ return ALT_E_SUCCESS;
+}
+
+ALT_STATUS_CODE alt_16550_fifo_clear_all(ALT_16550_HANDLE_t * handle)
+{
+ // Verify that the FIFO is enabled
+ if (!(handle->fcr & ALT_UART_FCR_FIFOE_SET_MSK))
+ {
+ return ALT_E_ERROR;
+ }
+
+ switch (handle->device)
+ {
+ case ALT_16550_DEVICE_SOCFPGA_UART0:
+ case ALT_16550_DEVICE_SOCFPGA_UART1:
+ // Write SRR::(RFR | XFR)
+ // (Shadow Reset Register :: (Receiver FIFO Reset | Xmitter FIFO Reset)) bits.
+ alt_write_word(ALT_UART_SRR_ADDR(handle->location),
+ ALT_UART_SRR_RFR_SET_MSK | ALT_UART_SRR_XFR_SET_MSK);
+ break;
+ case ALT_16550_DEVICE_ALTERA_16550_UART:
+ // Write FCR::(RFIFOR |XFIFOR)
+ // (FIFO Control Register :: (Receiver FIFO Reset | Xmitter FIFO Reset)) bits.
+ alt_write_word(ALT_UART_FCR_ADDR(handle->location),
+ handle->fcr | ALT_UART_FCR_RFIFOR_SET_MSK | ALT_UART_FCR_XFIFOR_SET_MSK);
+ break;
+ default:
+ return ALT_E_ERROR;
+ }
+
+ return ALT_E_SUCCESS;
+}
+
+ALT_STATUS_CODE alt_16550_fifo_size_get_rx(ALT_16550_HANDLE_t * handle,
+ uint32_t * size)
+{
+ switch (handle->device)
+ {
+ case ALT_16550_DEVICE_SOCFPGA_UART0:
+ case ALT_16550_DEVICE_SOCFPGA_UART1:
+ // Read the CPR::FIFO_Mod (Component Parameter Register :: FIFO Mode).
+ // The FIFO size is 16x this value.
+ *size = ALT_UART_CPR_FIFO_MOD_GET(alt_read_word(ALT_UART_CPR_ADDR(handle->location))) << 4;
+ break;
+ case ALT_16550_DEVICE_ALTERA_16550_UART:
+ // Altera 16550 Compatible Soft UARTs have a configurable size and is
+ // stored in the CPR::FIFO_Mode (Component Parameter Register :: FIFO Depth).
+ *size = ALT_ALTERA_16550_CPR_FIFO_MODE_GET(alt_read_word(ALT_ALTERA_16550_CPR_ADDR(handle->location))) << 4;
+ break;
+ default:
+ return ALT_E_ERROR;
+ }
+
+ return ALT_E_SUCCESS;
+}
+
+ALT_STATUS_CODE alt_16550_fifo_size_get_tx(ALT_16550_HANDLE_t * handle,
+ uint32_t * size)
+{
+ switch (handle->device)
+ {
+ case ALT_16550_DEVICE_SOCFPGA_UART0:
+ case ALT_16550_DEVICE_SOCFPGA_UART1:
+ // Read the CPR::FIFO_Mod (Component Parameter Register :: FIFO Mode).
+ // The FIFO size is 16x this value.
+ *size = ALT_UART_CPR_FIFO_MOD_GET(alt_read_word(ALT_UART_CPR_ADDR(handle->location))) << 4;
+ break;
+ case ALT_16550_DEVICE_ALTERA_16550_UART:
+ // Altera 16550 Compatible Soft UARTs have a configurable size and is
+ // stored in the CPR::FIFO_Mode (Component Parameter Register :: FIFO Depth).
+ // The FIFO size is 16x this value.
+ *size = ALT_ALTERA_16550_CPR_FIFO_MODE_GET(alt_read_word(ALT_ALTERA_16550_CPR_ADDR(handle->location))) << 4;
+ break;
+ default:
+ return ALT_E_ERROR;
+ }
+
+ return ALT_E_SUCCESS;
+}
+
+ALT_STATUS_CODE alt_16550_fifo_level_get_rx(ALT_16550_HANDLE_t * handle,
+ uint32_t * level)
+{
+ // Verify that the FIFO is enabled
+ if (!(handle->fcr & ALT_UART_FCR_FIFOE_SET_MSK))
+ {
+ return ALT_E_ERROR;
+ }
+
+ switch (handle->device)
+ {
+ case ALT_16550_DEVICE_SOCFPGA_UART0:
+ case ALT_16550_DEVICE_SOCFPGA_UART1:
+ // Read RFL (Receive FIFO Level).
+ *level = alt_read_word(ALT_UART_RFL_ADDR(handle->location));
+ break;
+ case ALT_16550_DEVICE_ALTERA_16550_UART:
+ // RFL not implemented. Return 0.
+ *level = 0;
+ break;
+ default:
+ return ALT_E_ERROR;
+ }
+
+ return ALT_E_SUCCESS;
+}
+
+ALT_STATUS_CODE alt_16550_fifo_level_get_tx(ALT_16550_HANDLE_t * handle,
+ uint32_t * level)
+{
+ // Verify that the FIFO is enabled
+ if (!(handle->fcr & ALT_UART_FCR_FIFOE_SET_MSK))
+ {
+ return ALT_E_ERROR;
+ }
+
+ switch (handle->device)
+ {
+ case ALT_16550_DEVICE_SOCFPGA_UART0:
+ case ALT_16550_DEVICE_SOCFPGA_UART1:
+ // Read TFL (Transmit FIFO Level).
+ *level = alt_read_word(ALT_UART_TFL_ADDR(handle->location));
+ break;
+ case ALT_16550_DEVICE_ALTERA_16550_UART:
+ // TFL not implemented. Return 0.
+ *level = 0;
+ break;
+ default:
+ return ALT_E_ERROR;
+ }
+
+ return ALT_E_SUCCESS;
+}
+
+ALT_STATUS_CODE alt_16550_fifo_trigger_set_rx(ALT_16550_HANDLE_t * handle,
+ ALT_16550_FIFO_TRIGGER_RX_t trigger)
+{
+ // Verify that the FIFO is enabled
+ if (!(handle->fcr & ALT_UART_FCR_FIFOE_SET_MSK))
+ {
+ return ALT_E_ERROR;
+ }
+
+ // Verify triggering parameter
+ switch (trigger)
+ {
+ case ALT_16550_FIFO_TRIGGER_RX_ANY:
+ case ALT_16550_FIFO_TRIGGER_RX_QUARTER_FULL:
+ case ALT_16550_FIFO_TRIGGER_RX_HALF_FULL:
+ case ALT_16550_FIFO_TRIGGER_RX_ALMOST_FULL:
+ break;
+ default:
+ return ALT_E_BAD_ARG;
+ }
+
+ switch (handle->device)
+ {
+ case ALT_16550_DEVICE_SOCFPGA_UART0:
+ case ALT_16550_DEVICE_SOCFPGA_UART1:
+ case ALT_16550_DEVICE_ALTERA_16550_UART:
+ // Update FCR::RT (FIFO Control Register :: Receiver Trigger)
+ handle->fcr &= ~ALT_UART_FCR_RT_SET_MSK;
+ handle->fcr |= ALT_UART_FCR_RT_SET(trigger);
+ alt_write_word(ALT_UART_FCR_ADDR(handle->location), handle->fcr);
+ break;
+ default:
+ return ALT_E_ERROR;
+ }
+
+ return ALT_E_SUCCESS;
+}
+
+ALT_STATUS_CODE alt_16550_fifo_trigger_set_tx(ALT_16550_HANDLE_t * handle,
+ ALT_16550_FIFO_TRIGGER_TX_t trigger)
+{
+ // Verify that the FIFO is enabled
+ if (!(handle->fcr & ALT_UART_FCR_FIFOE_SET_MSK))
+ {
+ return ALT_E_ERROR;
+ }
+
+ // Verify triggering parameter
+ switch (trigger)
+ {
+ case ALT_16550_FIFO_TRIGGER_TX_EMPTY:
+ case ALT_16550_FIFO_TRIGGER_TX_ALMOST_EMPTY:
+ case ALT_16550_FIFO_TRIGGER_TX_QUARTER_FULL:
+ case ALT_16550_FIFO_TRIGGER_TX_HALF_FULL:
+ break;
+ default:
+ return ALT_E_BAD_ARG;
+ }
+
+ switch (handle->device)
+ {
+ case ALT_16550_DEVICE_SOCFPGA_UART0:
+ case ALT_16550_DEVICE_SOCFPGA_UART1:
+ case ALT_16550_DEVICE_ALTERA_16550_UART:
+ // Update FCR::TET (FIFO Control Register :: Transmit Empty Trigger)
+ handle->fcr &= ~ALT_UART_FCR_TET_SET_MSK;
+ handle->fcr |= ALT_UART_FCR_TET_SET(trigger);
+ alt_write_word(ALT_UART_FCR_ADDR(handle->location), handle->fcr);
+ break;
+ default:
+ return ALT_E_ERROR;
+ }
+
+ return ALT_E_SUCCESS;
+}
+
+/////
+
+ALT_STATUS_CODE alt_16550_baudrate_get(ALT_16550_HANDLE_t * handle,
+ uint32_t * baudrate)
+{
+ // Query the divisor cached in the handle data
+ uint32_t divisor = ALT_16550_HANDLE_DATA_DIVISOR_VALUE_GET(handle->data);
+
+ // The divisor should never be zero. It is set to allow for a baud of 57600
+ // on initialization and a valid value is checked at
+ // alt_16550_divisor_set(). We do not check for users altering the data in
+ // the handle structure.
+
+ // Formula for calculating the baudrate:
+ // baudrate = clock / (16 * divisor)
+
+ *baudrate = (handle->clock_freq >> 4) / divisor;
+
+ return ALT_E_SUCCESS;
+}
+
+ALT_STATUS_CODE alt_16550_baudrate_set(ALT_16550_HANDLE_t * handle,
+ uint32_t baudrate)
+{
+ if (baudrate == 0)
+ {
+ return ALT_E_ARG_RANGE;
+ }
+
+ // Formula for calculating the divisor:
+ // baudrate = clock / (16 * divisor)
+ // => baudrate * 16 * divisor = clock
+ // => divisor = clock / (baudrate * 16)
+ // => divisor = (clock / 16) / baudrate
+
+ // Add half of the denominator to address rounding errors.
+ uint32_t divisor = ((handle->clock_freq + (8 * baudrate)) / (16 * baudrate));
+
+ // Check for divisor range is in alt_16550_divisor_set().
+ return alt_16550_divisor_set(handle, divisor);
+}
+
+ALT_STATUS_CODE alt_16550_divisor_get(ALT_16550_HANDLE_t * handle,
+ uint32_t * divisor)
+{
+ // Just read the divisor portion of the handle data.
+ *divisor = ALT_16550_HANDLE_DATA_DIVISOR_VALUE_GET(handle->data);
+
+ return ALT_E_SUCCESS;
+}
+
+ALT_STATUS_CODE alt_16550_divisor_set(ALT_16550_HANDLE_t * handle,
+ uint32_t divisor)
+{
+ // Verify divisor value is in range.
+ if ((divisor > 0xffff) || (divisor == 0))
+ {
+ return ALT_E_ARG_RANGE;
+ }
+
+ // Set the divisor portion of the handle data.
+ handle->data &= ~(0xffff);
+ handle->data |= divisor;
+
+ // Even if the UART is enabled, don't do anything. It is documented that
+ // the change will take effect when the UART move to the enabled state.
+
+ return ALT_E_SUCCESS;
+}
+
+/////
+
+static ALT_STATUS_CODE alt_16550_ier_mask_set_helper(ALT_16550_HANDLE_t * handle, uint32_t setmask)
+{
+ switch (handle->device)
+ {
+ case ALT_16550_DEVICE_SOCFPGA_UART0:
+ case ALT_16550_DEVICE_SOCFPGA_UART1:
+ case ALT_16550_DEVICE_ALTERA_16550_UART:
+ // Set bit in IER (Interrupt Enable Register)
+ alt_setbits_word(ALT_UART_IER_DLH_ADDR(handle->location), setmask);
+ break;
+ default:
+ return ALT_E_ERROR;
+ }
+
+ return ALT_E_SUCCESS;
+}
+
+static ALT_STATUS_CODE alt_16550_ier_mask_clr_helper(ALT_16550_HANDLE_t * handle, uint32_t setmask)
+{
+ switch (handle->device)
+ {
+ case ALT_16550_DEVICE_SOCFPGA_UART0:
+ case ALT_16550_DEVICE_SOCFPGA_UART1:
+ case ALT_16550_DEVICE_ALTERA_16550_UART:
+ // Clear bit in IER (Interrupt Enable Register)
+ alt_clrbits_word(ALT_UART_IER_DLH_ADDR(handle->location), setmask);
+ break;
+ default:
+ return ALT_E_ERROR;
+ }
+
+ return ALT_E_SUCCESS;
+}
+
+ALT_STATUS_CODE alt_16550_int_enable_rx(ALT_16550_HANDLE_t * handle)
+{
+ // Set the IER::ERBFI (Interrupt Enable Register :: Enable Receive Buffer Full Interrupt) bit.
+ return alt_16550_ier_mask_set_helper(handle, ALT_UART_IER_DLH_ERBFI_DLH0_SET_MSK);
+}
+
+ALT_STATUS_CODE alt_16550_int_disable_rx(ALT_16550_HANDLE_t * handle)
+{
+ // Clear the IER::ERBFI (Interrupt Enable Register :: Enable Receive Buffer Full Interrupt) bit.
+ return alt_16550_ier_mask_clr_helper(handle, ALT_UART_IER_DLH_ERBFI_DLH0_SET_MSK);
+}
+
+ALT_STATUS_CODE alt_16550_int_enable_tx(ALT_16550_HANDLE_t * handle)
+{
+ // Set the IER::ETBEI (Interrupt Enable Register :: Enable Transmit Buffer Empty Interrupt) bit.
+ return alt_16550_ier_mask_set_helper(handle, ALT_UART_IER_DLH_ETBEI_DLH1_SET_MSK);
+}
+
+ALT_STATUS_CODE alt_16550_int_disable_tx(ALT_16550_HANDLE_t * handle)
+{
+ // Clear the IER::ETBEI (Interrupt Enable Register :: Enable Transmit Buffer Empty Interrupt) bit.
+ return alt_16550_ier_mask_clr_helper(handle, ALT_UART_IER_DLH_ETBEI_DLH1_SET_MSK);
+}
+
+ALT_STATUS_CODE alt_16550_int_enable_line(ALT_16550_HANDLE_t * handle)
+{
+ // Set the IER::ELSI (Interrupt Enable Register :: Enable Line Status Interrupt) bit.
+ return alt_16550_ier_mask_set_helper(handle, ALT_UART_IER_DLH_ELSI_DHL2_SET_MSK);
+}
+
+ALT_STATUS_CODE alt_16550_int_disable_line(ALT_16550_HANDLE_t * handle)
+{
+ // Clear the IER::ELSI (Interrupt Enable Register :: Enable Line Status Interrupt) bit.
+ return alt_16550_ier_mask_clr_helper(handle, ALT_UART_IER_DLH_ELSI_DHL2_SET_MSK);
+}
+
+ALT_STATUS_CODE alt_16550_int_enable_modem(ALT_16550_HANDLE_t * handle)
+{
+ // Set the IER::EDSSI (Interrupt Enable Register :: Enable Modem Status Interrupt) bit.
+ return alt_16550_ier_mask_set_helper(handle, ALT_UART_IER_DLH_EDSSI_DHL3_SET_MSK);
+}
+
+ALT_STATUS_CODE alt_16550_int_disable_modem(ALT_16550_HANDLE_t * handle)
+{
+ // Clear the IER::EDSSI (Interrupt Enable Register :: Enable Modem Status Interrupt) bit.
+ return alt_16550_ier_mask_clr_helper(handle, ALT_UART_IER_DLH_EDSSI_DHL3_SET_MSK);
+}
+
+ALT_STATUS_CODE alt_16550_int_disable_all(ALT_16550_HANDLE_t * handle)
+{
+ // Clear the IER::(ERBFI | ETBEI | ELSI | EDSSI)
+ // (Interrupt Enable Register :: (Enable Receive Buffer Full Interrupt |
+ // Enable Transmit Buffer Empty Interrupt |
+ // Enable Line Status Interrupt |
+ // Enable Modem Status Interrupt)) bits
+ return alt_16550_ier_mask_clr_helper(handle, ALT_UART_IER_DLH_ERBFI_DLH0_SET_MSK |
+ ALT_UART_IER_DLH_ETBEI_DLH1_SET_MSK |
+ ALT_UART_IER_DLH_ELSI_DHL2_SET_MSK |
+ ALT_UART_IER_DLH_EDSSI_DHL3_SET_MSK);
+}
+
+ALT_STATUS_CODE alt_16550_int_status_get(ALT_16550_HANDLE_t * handle,
+ ALT_16550_INT_STATUS_t * status)
+{
+ switch (handle->device)
+ {
+ case ALT_16550_DEVICE_SOCFPGA_UART0:
+ case ALT_16550_DEVICE_SOCFPGA_UART1:
+ case ALT_16550_DEVICE_ALTERA_16550_UART:
+ // Read IIR::IID (Interrupt Identity Register :: Interrupt ID)
+ *status = (ALT_16550_INT_STATUS_t) ALT_UART_IIR_ID_GET(alt_read_word(ALT_UART_IIR_ADDR(handle->location)));
+ break;
+ default:
+ return ALT_E_ERROR;
+ }
+
+ return ALT_E_SUCCESS;
+}
+
+/////
+
+ALT_STATUS_CODE alt_16550_line_config_set(ALT_16550_HANDLE_t * handle,
+ ALT_16550_DATABITS_t databits,
+ ALT_16550_PARITY_t parity,
+ ALT_16550_STOPBITS_t stopbits)
+{
+ // Validate the databits parameter.
+ switch (databits)
+ {
+ case ALT_16550_DATABITS_5:
+ case ALT_16550_DATABITS_6:
+ case ALT_16550_DATABITS_7:
+ case ALT_16550_DATABITS_8:
+ break;
+ default:
+ return ALT_E_ERROR;
+ }
+
+ // Validate the parity parameter.
+ switch (parity)
+ {
+ case ALT_16550_PARITY_DISABLE:
+ case ALT_16550_PARITY_ODD:
+ case ALT_16550_PARITY_EVEN:
+ break;
+ default:
+ return ALT_E_ERROR;
+ }
+
+ // Validate the stopbits parameter.
+ switch (stopbits)
+ {
+ case ALT_16550_STOPBITS_1:
+ case ALT_16550_STOPBITS_2:
+ break;
+ default:
+ return ALT_E_ERROR;
+ }
+
+ // LCR (Line Control Register) cache.
+ uint32_t lcr = 0;
+
+ switch (handle->device)
+ {
+ case ALT_16550_DEVICE_SOCFPGA_UART0:
+ case ALT_16550_DEVICE_SOCFPGA_UART1:
+ case ALT_16550_DEVICE_ALTERA_16550_UART:
+
+ // Configure the number of databits
+ lcr |= ALT_UART_LCR_DLS_SET(databits);
+
+ // Configure the number of stopbits
+ lcr |= ALT_UART_LCR_STOP_SET(stopbits);
+
+ // Configure the parity
+ if (parity != ALT_16550_PARITY_DISABLE)
+ {
+ // Enable parity in LCR
+ lcr |= ALT_UART_LCR_PEN_SET_MSK;
+
+ if (parity == ALT_16550_PARITY_EVEN)
+ {
+ // Enable even parity in LCR; otherwise it's odd parity.
+ lcr |= ALT_UART_LCR_EPS_SET_MSK;
+ }
+ }
+
+ // Update LCR (Line Control Register)
+ alt_replbits_word(ALT_UART_LCR_ADDR(handle->location),
+ ALT_UART_LCR_DLS_SET_MSK
+ | ALT_UART_LCR_STOP_SET_MSK
+ | ALT_UART_LCR_PEN_SET_MSK
+ | ALT_UART_LCR_EPS_SET_MSK,
+ lcr);
+
+ break;
+
+ default:
+ return ALT_E_ERROR;
+ }
+
+ return ALT_E_SUCCESS;
+}
+
+ALT_STATUS_CODE alt_16550_line_break_enable(ALT_16550_HANDLE_t * handle)
+{
+ switch (handle->device)
+ {
+ case ALT_16550_DEVICE_SOCFPGA_UART0:
+ case ALT_16550_DEVICE_SOCFPGA_UART1:
+ case ALT_16550_DEVICE_ALTERA_16550_UART:
+ // Set the LCR::Break (Line Control Register :: Break) bit.
+ alt_setbits_word(ALT_UART_LCR_ADDR(handle->location), ALT_UART_LCR_BREAK_SET_MSK);
+ break;
+
+ default:
+ return ALT_E_ERROR;
+ }
+
+ return ALT_E_SUCCESS;
+}
+
+ALT_STATUS_CODE alt_16550_line_break_disable(ALT_16550_HANDLE_t * handle)
+{
+ switch (handle->device)
+ {
+ case ALT_16550_DEVICE_SOCFPGA_UART0:
+ case ALT_16550_DEVICE_SOCFPGA_UART1:
+ case ALT_16550_DEVICE_ALTERA_16550_UART:
+ // Clear the LCR::Break (Line Control Register :: Break) bit.
+ alt_clrbits_word(ALT_UART_LCR_ADDR(handle->location), ALT_UART_LCR_BREAK_SET_MSK);
+ break;
+
+ default:
+ return ALT_E_ERROR;
+ }
+
+
+ return ALT_E_SUCCESS;
+}
+
+ALT_STATUS_CODE alt_16550_line_status_get(ALT_16550_HANDLE_t * handle,
+ uint32_t * status)
+{
+ switch (handle->device)
+ {
+ case ALT_16550_DEVICE_SOCFPGA_UART0:
+ case ALT_16550_DEVICE_SOCFPGA_UART1:
+ case ALT_16550_DEVICE_ALTERA_16550_UART:
+ // Read the LSR (Line Status Register).
+ *status = alt_read_word(ALT_UART_LSR_ADDR(handle->location));
+ break;
+ default:
+ return ALT_E_ERROR;
+ }
+
+ return ALT_E_SUCCESS;
+}
+
+/////
+
+static ALT_STATUS_CODE alt_16550_mcr_mask_set_helper(ALT_16550_HANDLE_t * handle,
+ uint32_t setmask)
+{
+ switch (handle->device)
+ {
+ case ALT_16550_DEVICE_SOCFPGA_UART0:
+ case ALT_16550_DEVICE_SOCFPGA_UART1:
+ case ALT_16550_DEVICE_ALTERA_16550_UART:
+ // Set the bit in MCR (Modem Control Register).
+ alt_setbits_word(ALT_UART_MCR_ADDR(handle->location), setmask);
+ break;
+ default:
+ return ALT_E_ERROR;
+ }
+
+ return ALT_E_SUCCESS;
+}
+
+static ALT_STATUS_CODE alt_16550_mcr_mask_clr_helper(ALT_16550_HANDLE_t * handle, uint32_t setmask)
+{
+ switch (handle->device)
+ {
+ case ALT_16550_DEVICE_SOCFPGA_UART0:
+ case ALT_16550_DEVICE_SOCFPGA_UART1:
+ case ALT_16550_DEVICE_ALTERA_16550_UART:
+ // Clear the bit in MCR (Modem Control Register).
+ alt_clrbits_word(ALT_UART_MCR_ADDR(handle->location), setmask);
+ break;
+ default:
+ return ALT_E_ERROR;
+ }
+
+ return ALT_E_SUCCESS;
+}
+
+ALT_STATUS_CODE alt_16550_flowcontrol_enable(ALT_16550_HANDLE_t * handle)
+{
+ // Verify that the FIFO is enabled
+ if (!(handle->fcr & ALT_UART_FCR_FIFOE_SET_MSK))
+ {
+ return ALT_E_ERROR;
+ }
+
+ // For the Altera 16550 Compatible Soft UART, check that Hardware Flowcontrol is enabled.
+ if (handle->device == ALT_16550_DEVICE_ALTERA_16550_UART)
+ {
+ // Read the CPR::AFCE_Mode (Component Parameter Register :: Auto Flow Control mode) bit.
+ uint32_t cpr = alt_read_word(ALT_ALTERA_16550_CPR_ADDR(handle->location));
+ if (!(ALT_ALTERA_16550_CPR_AFCE_MODE_SET_MSK & cpr))
+ {
+ return ALT_E_ERROR;
+ }
+ }
+
+ // Set MCR::AFCE (Modem Control Register :: Automatic FlowControl Enable) bit.
+ return alt_16550_mcr_mask_set_helper(handle, ALT_UART_MCR_AFCE_SET_MSK);
+}
+
+ALT_STATUS_CODE alt_16550_flowcontrol_disable(ALT_16550_HANDLE_t * handle)
+{
+ // Clear MCR::AFCE (Modem Control Register :: Automatic FlowControl Enable) bit.
+ return alt_16550_mcr_mask_clr_helper(handle, ALT_UART_MCR_AFCE_SET_MSK);
+}
+
+ALT_STATUS_CODE alt_16550_loopback_enable(ALT_16550_HANDLE_t * handle)
+{
+ // Loopback is not implemented in the Altera 16550 Compatible Soft UART.
+ if (handle->device == ALT_16550_DEVICE_ALTERA_16550_UART)
+ {
+ return ALT_E_ERROR;
+ }
+
+ // Set MCR::Loopback (Modem Control Register :: Loopback) bit.
+ return alt_16550_mcr_mask_set_helper(handle, ALT_UART_MCR_LOOPBACK_SET_MSK);
+}
+
+ALT_STATUS_CODE alt_16550_loopback_disable(ALT_16550_HANDLE_t * handle)
+{
+ // Clear MCR::Loopback (Modem Control Register :: Loopback) bit.
+ return alt_16550_mcr_mask_clr_helper(handle, ALT_UART_MCR_LOOPBACK_SET_MSK);
+}
+
+ALT_STATUS_CODE alt_16550_modem_enable_out1(ALT_16550_HANDLE_t * handle)
+{
+ // Set MCR::Out1 (Modem Control Register :: Out1) bit.
+ return alt_16550_mcr_mask_set_helper(handle, ALT_UART_MCR_OUT1_SET_MSK);
+}
+
+ALT_STATUS_CODE alt_16550_modem_disable_out1(ALT_16550_HANDLE_t * handle)
+{
+ // Clear MCR::Out1 (Modem Control Register :: Out1) bit.
+ return alt_16550_mcr_mask_clr_helper(handle, ALT_UART_MCR_OUT1_SET_MSK);
+}
+
+ALT_STATUS_CODE alt_16550_modem_enable_out2(ALT_16550_HANDLE_t * handle)
+{
+ // Set MCR::Out2 (Modem Control Register :: Out2) bit.
+ return alt_16550_mcr_mask_set_helper(handle, ALT_UART_MCR_OUT2_SET_MSK);
+}
+
+ALT_STATUS_CODE alt_16550_modem_disable_out2(ALT_16550_HANDLE_t * handle)
+{
+ // Clear MCR::Out2 (Modem Control Register :: Out2) bit.
+ return alt_16550_mcr_mask_clr_helper(handle, ALT_UART_MCR_OUT2_SET_MSK);
+}
+
+ALT_STATUS_CODE alt_16550_modem_enable_rts(ALT_16550_HANDLE_t * handle)
+{
+ // Set MCR::RTS (Modem Control Register :: Request To Send) bit.
+ return alt_16550_mcr_mask_set_helper(handle, ALT_UART_MCR_RTS_SET_MSK);
+}
+
+ALT_STATUS_CODE alt_16550_modem_disable_rts(ALT_16550_HANDLE_t * handle)
+{
+ // Clear MCR::RTS (Modem Control Register :: Request To Send) bit.
+ return alt_16550_mcr_mask_clr_helper(handle, ALT_UART_MCR_RTS_SET_MSK);
+}
+
+ALT_STATUS_CODE alt_16550_modem_enable_dtr(ALT_16550_HANDLE_t * handle)
+{
+ // Set MCR::DTR (Modem Control Register :: Data Terminal Ready) bit.
+ return alt_16550_mcr_mask_set_helper(handle, ALT_UART_MCR_DTR_SET_MSK);
+}
+
+ALT_STATUS_CODE alt_16550_modem_disable_dtr(ALT_16550_HANDLE_t * handle)
+{
+ // Clear MCR::DTR (Modem Control Register :: Data Terminal Ready) bit.
+ return alt_16550_mcr_mask_clr_helper(handle, ALT_UART_MCR_DTR_SET_MSK);
+}
+
+ALT_STATUS_CODE alt_16550_modem_status_get(ALT_16550_HANDLE_t * handle,
+ uint32_t * status)
+{
+ switch (handle->device)
+ {
+ case ALT_16550_DEVICE_SOCFPGA_UART0:
+ case ALT_16550_DEVICE_SOCFPGA_UART1:
+ case ALT_16550_DEVICE_ALTERA_16550_UART:
+ // Read the MSR (Modem Status Register).
+ *status = alt_read_word(ALT_UART_MSR_ADDR(handle->location));
+ break;
+ default:
+ return ALT_E_ERROR;
+ }
+
+ return ALT_E_SUCCESS;
+}