/****************************************************************************** * * Copyright (C) 2002 - 2014 Xilinx, Inc. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * Use of the Software is limited solely to applications: * (a) running on a Xilinx device, or * (b) that interact with a Xilinx device through a bus or interconnect. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Except as contained in this notice, the name of the Xilinx shall not be used * in advertising or otherwise to promote the sale, use or other dealings in * this Software without prior written authorization from Xilinx. * ******************************************************************************/ /****************************************************************************/ /** * * @file xuartns550_options.c * * The implementation of the options functions for the XUartNs550 driver. * *
* MODIFICATION HISTORY: * * Ver Who Date Changes * ----- ---- -------- ----------------------------------------------- * 1.00b jhl 03/11/02 Repartitioned driver for smaller files. * 1.00b rpm 04/12/05 Added critical section protection in ReadFcrRegister * 1.11a sv 03/20/07 Updated to use the new coding guidelines. * 1.13a sdm 07/10/09 Added receive line interrupt option to OptionsTable[]. * 2.00a sdm 09/22/09 Converted all register accesses to 32 bit access. * 2.00a ktn 10/20/09 Converted all register accesses to 32 bit access. * Updated to use HAL Processor APIs. _m is removed from the * name of all the macro definitions. ** *****************************************************************************/ /***************************** Include Files ********************************/ #include "xuartns550.h" #include "xuartns550_i.h" #include "xil_io.h" /************************** Constant Definitions ****************************/ /**************************** Type Definitions ******************************/ /***************** Macros (Inline Functions) Definitions ********************/ /************************** Variable Definitions ****************************/ /* * The following data type maps an option to a register and the bits of the * regiser such that getting and setting the options may be table driven. */ typedef struct { u16 Option; u16 RegisterOffset; u8 Mask; } Mapping; /* * Create the table which contains options which are to be processed to get/set * the options. These options are table driven to allow easy maintenance and * expansion of the options. */ static Mapping OptionsTable[] = { { XUN_OPTION_SET_BREAK, XUN_LCR_OFFSET, XUN_LCR_SET_BREAK }, { XUN_OPTION_LOOPBACK, XUN_MCR_OFFSET, XUN_MCR_LOOP }, { XUN_OPTION_DATA_INTR, XUN_IER_OFFSET, XUN_IER_RX_DATA }, { XUN_OPTION_MODEM_INTR, XUN_IER_OFFSET, XUN_IER_MODEM_STATUS }, { XUN_OPTION_FIFOS_ENABLE, XUN_FCR_OFFSET, XUN_FIFO_ENABLE }, { XUN_OPTION_RESET_TX_FIFO, XUN_FCR_OFFSET, XUN_FIFO_TX_RESET }, { XUN_OPTION_RESET_RX_FIFO, XUN_FCR_OFFSET, XUN_FIFO_RX_RESET }, { XUN_OPTION_ASSERT_OUT2, XUN_MCR_OFFSET, XUN_MCR_OUT_2 }, { XUN_OPTION_ASSERT_OUT1, XUN_MCR_OFFSET, XUN_MCR_OUT_1 }, { XUN_OPTION_ASSERT_RTS, XUN_MCR_OFFSET, XUN_MCR_RTS }, { XUN_OPTION_ASSERT_DTR, XUN_MCR_OFFSET, XUN_MCR_DTR }, { XUN_OPTION_RXLINE_INTR, XUN_IER_OFFSET, XUN_IER_RX_LINE } }; /* Create a constants for the number of entries in the table */ #define XUN_NUM_OPTIONS (sizeof(OptionsTable) / sizeof(Mapping)) /************************** Function Prototypes *****************************/ static u32 ReadFcrRegister(u32 BaseAddress); /****************************************************************************/ /** * * Gets the options for the specified driver instance. The options are * implemented as bit masks such that multiple options may be enabled or * disabled simulataneously. * * @param InstancePtr is a pointer to the XUartNs550 instance. * * @return The current options for the UART. The optionss are bit masks * that are contained in the file xuartns550.h and * named XUN_OPTION_*. * * @note None. * *****************************************************************************/ u16 XUartNs550_GetOptions(XUartNs550 *InstancePtr) { u16 Options = 0; u32 Register; u32 Index; /* * Assert validates the input arguments */ Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); /* * Loop thru the options table to map the physical options in the * registers of the UART to the logical options to be returned */ for (Index = 0; Index < XUN_NUM_OPTIONS; Index++) { /* * If the FIFO control register is being read, the make sure to * setup the line control register so it can be read */ if (OptionsTable[Index].RegisterOffset == XUN_FCR_OFFSET) { Register = ReadFcrRegister(InstancePtr->BaseAddress); } else { Register = XUartNs550_ReadReg(InstancePtr->BaseAddress, OptionsTable[Index].RegisterOffset); } /* * If the bit in the register which correlates to the option * is set, then set the corresponding bit in the options, * ignoring any bits which are zero since the options variable * is initialized to zero */ if (Register & OptionsTable[Index].Mask) { Options |= OptionsTable[Index].Option; } } return Options; } /****************************************************************************/ /** * * Sets the options for the specified driver instance. The options are * implemented as bit masks such that multiple options may be enabled or * disabled simultaneously. * * The GetOptions function may be called to retrieve the currently enabled * options. The result is ORed in the desired new settings to be enabled and * ANDed with the inverse to clear the settings to be disabled. The resulting * value is then used as the options for the SetOption function call. * * @param InstancePtr is a pointer to the XUartNs550 instance. * @param Options contains the options to be set which are bit masks * contained in the file xuartns550.h and named XUN_OPTION_*. * * @return * - XST_SUCCESS if the options were set successfully. * - XST_UART_CONFIG_ERROR if the options could not be set because * the hardware does not support FIFOs * * @note None. * *****************************************************************************/ int XUartNs550_SetOptions(XUartNs550 *InstancePtr, u16 Options) { u32 Index; u32 Register; /* * Assert validates the input arguments */ Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); /* * Loop thru the options table to map the logical options to the * physical options in the registers of the UART */ for (Index = 0; Index < XUN_NUM_OPTIONS; Index++) { /* * If the FIFO control register is being read, this is a * special case that requires special register processing */ if (OptionsTable[Index].RegisterOffset == XUN_FCR_OFFSET) { Register = ReadFcrRegister(InstancePtr->BaseAddress); } else { /* * Read the register which contains option so that the * register can be changed without destoying any other * bits of the register */ Register = XUartNs550_ReadReg(InstancePtr->BaseAddress, OptionsTable[Index].RegisterOffset); } /* * If the option is set in the input, then set the * corresponding bit in the specified register, otherwise * clear the bit in the register */ if (Options & OptionsTable[Index].Option) { Register |= OptionsTable[Index].Mask; } else { Register &= ~OptionsTable[Index].Mask; } /* * Write the new value to the register to set the option */ XUartNs550_WriteReg(InstancePtr->BaseAddress, OptionsTable[Index].RegisterOffset, Register); } /* To be done, add error checks for enabling/resetting FIFOs */ return XST_SUCCESS; } /****************************************************************************/ /** * * This function gets the receive FIFO trigger level. The receive trigger * level indicates the number of bytes in the receive FIFO that cause a receive * data event (interrupt) to be generated. * * @param InstancePtr is a pointer to the XUartNs550 instance. * * @return The current receive FIFO trigger level. Constants which * define each trigger level are contained in the file * xuartns550.h and named XUN_FIFO_TRIGGER_*. * * @note None. * *****************************************************************************/ u8 XUartNs550_GetFifoThreshold(XUartNs550 *InstancePtr) { u32 FcrRegister; /* * Assert validates the input arguments */ Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); /* * Read the value of the FIFO control register so that the threshold * can be retrieved, this read takes special register processing */ FcrRegister = ReadFcrRegister(InstancePtr->BaseAddress); /* * Return only the trigger level from the register value */ return (u8)(FcrRegister & XUN_FIFO_RX_TRIGGER); } /****************************************************************************/ /** * * This functions sets the receive FIFO trigger level. The receive trigger * level specifies the number of bytes in the receive FIFO that cause a receive * data event (interrupt) to be generated. The FIFOs must be enabled to set the * trigger level. * * @param InstancePtr is a pointer to the XUartNs550 instance. * @param TriggerLevel contains the trigger level to set. Constants which * define each trigger level are contained in the file xuartns550.h * and named XUN_FIFO_TRIGGER_*. * * @return * - XST_SUCCESS if the trigger level was set * - XST_UART_CONFIG_ERROR if the trigger level could not be set, * either the hardware does not support the FIFOs or FIFOs * are not enabled * * @note None. * *****************************************************************************/ int XUartNs550_SetFifoThreshold(XUartNs550 *InstancePtr, u8 TriggerLevel) { u32 FcrRegister; /* * Assert validates the input arguments */ Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid((TriggerLevel == XUN_FIFO_TRIGGER_14) || (TriggerLevel == XUN_FIFO_TRIGGER_08) || (TriggerLevel == XUN_FIFO_TRIGGER_04) || (TriggerLevel == XUN_FIFO_TRIGGER_01)); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); /* * Read the value of the FIFO control register, this read takes special * register processing */ FcrRegister = ReadFcrRegister(InstancePtr->BaseAddress); /* * If the FIFO control register indicates that FIFOs are disabled, then * either they are just disabled or it has no FIFOs, return an error */ if ((FcrRegister & XUN_FIFO_ENABLE) == 0) { return XST_UART_CONFIG_ERROR; } /* * Set the receive FIFO trigger level by clearing out the old level in * the FIFO control register and writing in the new level */ FcrRegister &= ~XUN_FIFO_RX_TRIGGER; FcrRegister |= (u32) TriggerLevel; /* * Write the new value for the FIFO control register to it such that the * threshold is changed, writing to it is normal unlike reading from it */ XUartNs550_WriteReg(InstancePtr->BaseAddress, XUN_FCR_OFFSET, FcrRegister); return XST_SUCCESS; } /****************************************************************************/ /** * * This function returns the last errors that have occurred in the specified * UART. It also clears the errors such that they cannot be retrieved again. * The errors include parity error, receive overrun error, framing error, and * break detection. * * The last errors is an accumulation of the errors each time an error is * discovered in the driver. A status is checked for each received byte and * this status is accumulated in the last errors. * * If this function is called after receiving a buffer of data, it will indicate * any errors that occurred for the bytes of the buffer. It does not indicate * which bytes contained errors. * * @param InstancePtr is a pointer to the XUartNs550 instance. * * @return The last errors that occurred. The errors are bit masks * that are contained in the file xuartns550.h and * named XUN_ERROR_*. * * @note None. * *****************************************************************************/ u8 XUartNs550_GetLastErrors(XUartNs550 *InstancePtr) { u8 Temp = InstancePtr->LastErrors; /* * Assert validates the input arguments */ Xil_AssertNonvoid(InstancePtr != NULL); /* * Clear the last errors and return the previous value */ InstancePtr->LastErrors = 0; /* * Only return the bits that are reported errors which include * receive overrun, framing, parity and break detection, the last errors * variable holds an accumulation of the line status register bits which * have been set */ return Temp & XUN_LSR_ERROR_BREAK; } /****************************************************************************/ /** * * This function gets the modem status from the specified UART. The modem * status indicates any changes of the modem signals. This function allows * the modem status to be read in a polled mode. The modem status is updated * whenever it is read such that reading it twice may not yield the same * results. * * @param InstancePtr is a pointer to the XUartNs550 instance . * * @return The modem status which are bit masks that are contained in * the file xuartns550.h and named XUN_MODEM_*. * * @note * * The bit masks used for the modem status are the exact bits of the modem * status register with no abstraction. * *****************************************************************************/ u8 XUartNs550_GetModemStatus(XUartNs550 *InstancePtr) { u32 ModemStatusRegister; /* * Assert validates the input arguments */ Xil_AssertNonvoid(InstancePtr != NULL); /* * Read the modem status register to return */ ModemStatusRegister = XUartNs550_ReadReg(InstancePtr->BaseAddress, XUN_MSR_OFFSET); return (u8) ModemStatusRegister; } /****************************************************************************/ /** * * This function determines if the specified UART is sending data. If the * transmitter register is not empty, it is sending data. * * @param InstancePtr is a pointer to the XUartNs550 instance. * * @return A value of TRUE if the UART is sending data, otherwise FALSE. * * @note None. * *****************************************************************************/ int XUartNs550_IsSending(XUartNs550 *InstancePtr) { u32 LsrRegister; /* * Assert validates the input arguments */ Xil_AssertNonvoid(InstancePtr != NULL); /* * Read the line status register to determine if the transmitter is * empty */ LsrRegister = XUartNs550_GetLineStatusReg(InstancePtr->BaseAddress); /* * If the transmitter is not empty then indicate that the UART is still * sending some data */ return ((LsrRegister & XUN_LSR_TX_EMPTY) == 0); } /****************************************************************************/ /** * * This functions reads the FIFO control register. It's primary purpose is to * isolate the special processing for reading this register. It is necessary * to write to the line control register, then read the FIFO control register, * and then restore the line control register. * * @param BaseAddress contains the base address of the registers in the * device. * * @return The contents of the FIFO control register. * * @note None. * *****************************************************************************/ static u32 ReadFcrRegister(u32 BaseAddress) { u32 LcrRegister; u32 FcrRegister; u32 IerRegister; /* * Enter a critical section here by disabling Uart interrupts. We do * not want to receive an interrupt while we have the FCR latched since * the interrupt handler may want to read the IIR */ IerRegister = XUartNs550_ReadReg(BaseAddress, XUN_IER_OFFSET); XUartNs550_WriteReg(BaseAddress, XUN_IER_OFFSET, 0); /* * Get the line control register contents and set the divisor latch * access bit so the FIFO control register can be read, this can't * be done with a true 16550, but is a feature in the Xilinx device */ LcrRegister = XUartNs550_GetLineControlReg(BaseAddress); XUartNs550_SetLineControlReg(BaseAddress, LcrRegister | XUN_LCR_DLAB); /* * Read the FIFO control register so it can be returned */ FcrRegister = XUartNs550_ReadReg(BaseAddress, XUN_FCR_OFFSET); /* * Restore the line control register to it's original contents such * that the DLAB bit is no longer set and return the register */ XUartNs550_SetLineControlReg(BaseAddress, LcrRegister); /* * Exit the critical section by restoring the IER */ XUartNs550_WriteReg(BaseAddress, XUN_IER_OFFSET, IerRegister); return FcrRegister; }