/* * Copyright (c) 2014-2019, Texas Instruments Incorporated * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * 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. * * * Neither the name of Texas Instruments Incorporated nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR * CONTRIBUTORS 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 /* * By default disable both asserts and log for this module. * This must be done before DebugP.h is included. */ #ifndef DebugP_ASSERT_ENABLED #define DebugP_ASSERT_ENABLED 0 #endif #ifndef DebugP_LOG_ENABLED #define DebugP_LOG_ENABLED 0 #endif #include #include #include #include #include #include #include #include /* driverlib header files */ #include #include #include #include #include #include #include #include #include /* DMA can handle transfers of at most 1024 elements */ #define MAXXFERSIZE 1024 /* Pad configuration defines */ #define PAD_CONFIG_BASE (OCP_SHARED_BASE + OCP_SHARED_O_GPIO_PAD_CONFIG_0) #define PAD_RESET_STATE 0xC61 /* UARTCC32XXDMA functions */ void UARTCC32XXDMA_close(UART_Handle handle); int_fast16_t UARTCC32XXDMA_control(UART_Handle handle, uint_fast16_t cmd, void *arg); void UARTCC32XXDMA_init(UART_Handle handle); UART_Handle UARTCC32XXDMA_open(UART_Handle handle, UART_Params *params); int_fast32_t UARTCC32XXDMA_read(UART_Handle handle, void *buffer, size_t size); void UARTCC32XXDMA_readCancel(UART_Handle handle); int_fast32_t UARTCC32XXDMA_readPolling(UART_Handle handle, void *buffer, size_t size); int_fast32_t UARTCC32XXDMA_write(UART_Handle handle, const void *buffer, size_t size); void UARTCC32XXDMA_writeCancel(UART_Handle handle); int_fast32_t UARTCC32XXDMA_writePolling(UART_Handle handle, const void *buffer, size_t size); /* UART function table for UARTCC32XXDMA implementation */ const UART_FxnTable UARTCC32XXDMA_fxnTable = { UARTCC32XXDMA_close, UARTCC32XXDMA_control, UARTCC32XXDMA_init, UARTCC32XXDMA_open, UARTCC32XXDMA_read, UARTCC32XXDMA_readPolling, UARTCC32XXDMA_readCancel, UARTCC32XXDMA_write, UARTCC32XXDMA_writePolling, UARTCC32XXDMA_writeCancel }; /* Static functions */ static void UARTCC32XXDMA_configDMA(UART_Handle handle, bool isWrite); static void UARTCC32XXDMA_hwiIntFxn(uintptr_t arg); static unsigned int getPowerMgrId(unsigned int baseAddr); static void initHw(UART_Handle handle); static int postNotifyFxn(unsigned int eventType, uintptr_t eventArg, uintptr_t clientArg); static size_t readCancel(UART_Handle handle); static void readSemCallback(UART_Handle handle, void *buffer, size_t count); static void startTxFifoEmptyClk(UART_Handle handle, unsigned int size); static size_t writeCancel(UART_Handle handle); static void writeFinishedDoCallback(UART_Handle handle); static void writeSemCallback(UART_Handle handle, void *buffer, size_t count); /* * Function for checking whether flow control is enabled. */ static inline bool isFlowControlEnabled(UARTCC32XXDMA_HWAttrsV1 const *hwAttrs) { return ((hwAttrs->flowControl == UARTCC32XXDMA_FLOWCTRL_HARDWARE) && (hwAttrs->ctsPin != UARTCC32XXDMA_PIN_UNASSIGNED) && (hwAttrs->rtsPin != UARTCC32XXDMA_PIN_UNASSIGNED)); } static const uint32_t dataLength[] = { UART_CONFIG_WLEN_5, /* UART_LEN_5 */ UART_CONFIG_WLEN_6, /* UART_LEN_6 */ UART_CONFIG_WLEN_7, /* UART_LEN_7 */ UART_CONFIG_WLEN_8 /* UART_LEN_8 */ }; static const uint32_t stopBits[] = { UART_CONFIG_STOP_ONE, /* UART_STOP_ONE */ UART_CONFIG_STOP_TWO /* UART_STOP_TWO */ }; static const uint32_t parityType[] = { UART_CONFIG_PAR_NONE, /* UART_PAR_NONE */ UART_CONFIG_PAR_EVEN, /* UART_PAR_EVEN */ UART_CONFIG_PAR_ODD, /* UART_PAR_ODD */ UART_CONFIG_PAR_ZERO, /* UART_PAR_ZERO */ UART_CONFIG_PAR_ONE /* UART_PAR_ONE */ }; /* * ======== UARTCC32XXDMA_close ======== */ void UARTCC32XXDMA_close(UART_Handle handle) { UARTCC32XXDMA_Object *object = handle->object; UARTCC32XXDMA_HWAttrsV1 const *hwAttrs = handle->hwAttrs; uint32_t padRegister; /* Disable UART and interrupts. */ MAP_UARTDMADisable(hwAttrs->baseAddr, UART_DMA_TX | UART_DMA_RX); MAP_UARTDisable(hwAttrs->baseAddr); if (object->hwiHandle) { HwiP_delete(object->hwiHandle); } if (object->writeSem) { SemaphoreP_delete(object->writeSem); } if (object->readSem) { SemaphoreP_delete(object->readSem); } if (object->txFifoEmptyClk) { ClockP_delete(object->txFifoEmptyClk); } if (object->dmaHandle) { UDMACC32XX_close(object->dmaHandle); } Power_unregisterNotify(&object->postNotify); Power_releaseDependency(object->powerMgrId); if (object->txPin != (uint16_t)-1) { PowerCC32XX_restoreParkState((PowerCC32XX_Pin)object->txPin, object->prevParkTX); object->txPin = (uint16_t)-1; } if (object->rtsPin != (uint16_t)-1) { PowerCC32XX_restoreParkState((PowerCC32XX_Pin)object->rtsPin, object->prevParkRTS); object->rtsPin = (uint16_t)-1; } /* Restore pin pads to their reset states */ padRegister = (PinToPadGet((hwAttrs->rxPin) & 0xff)<<2) + PAD_CONFIG_BASE; HWREG(padRegister) = PAD_RESET_STATE; padRegister = (PinToPadGet((hwAttrs->txPin) & 0xff)<<2) + PAD_CONFIG_BASE; HWREG(padRegister) = PAD_RESET_STATE; if (isFlowControlEnabled(hwAttrs)) { padRegister = (PinToPadGet((hwAttrs->ctsPin) & 0xff)<<2) + PAD_CONFIG_BASE; HWREG(padRegister) = PAD_RESET_STATE; padRegister = (PinToPadGet((hwAttrs->rtsPin) & 0xff)<<2) + PAD_CONFIG_BASE; HWREG(padRegister) = PAD_RESET_STATE; } object->opened = false; DebugP_log1("UART:(%p) closed", hwAttrs->baseAddr); } /* * ======== UARTCC32XXDMA_control ======== * @pre Function assumes that the handle is not NULL */ int_fast16_t UARTCC32XXDMA_control(UART_Handle handle, uint_fast16_t cmd, void *arg) { UARTCC32XXDMA_HWAttrsV1 const *hwAttrs = handle->hwAttrs; switch (cmd) { /* Specific UART CMDs */ case (UARTCC32XXDMA_CMD_IS_BUSY): *(bool *)arg = MAP_UARTBusy(hwAttrs->baseAddr); return (UART_STATUS_SUCCESS); case (UARTCC32XXDMA_CMD_IS_RX_DATA_AVAILABLE): *(bool *)arg = MAP_UARTCharsAvail(hwAttrs->baseAddr); return (UART_STATUS_SUCCESS); case (UARTCC32XXDMA_CMD_IS_TX_SPACE_AVAILABLE): *(bool *)arg = MAP_UARTSpaceAvail(hwAttrs->baseAddr); return (UART_STATUS_SUCCESS); default: DebugP_log2("UART:(%p) UART CMD undefined: %d", hwAttrs->baseAddr, cmd); return (UART_STATUS_UNDEFINEDCMD); } } /* * ======== UARTCC32XXDMA_init ======== */ void UARTCC32XXDMA_init(UART_Handle handle) { } /* * ======== UARTCC32XXDMA_open ======== */ UART_Handle UARTCC32XXDMA_open(UART_Handle handle, UART_Params *params) { uintptr_t key; UARTCC32XXDMA_Object *object = handle->object; UARTCC32XXDMA_HWAttrsV1 const *hwAttrs = handle->hwAttrs; SemaphoreP_Params semParams; HwiP_Params hwiParams; ClockP_Params clockParams; uint16_t pin; uint16_t mode; /* Timeouts cannot be 0 */ DebugP_assert((params->writeTimeout != 0) && (params->readTimeout != 0)); /* Check that a callback is set */ DebugP_assert((params->readMode != UART_MODE_CALLBACK) || (params->readCallback != NULL)); DebugP_assert((params->writeMode != UART_MODE_CALLBACK) || (params->writeCallback != NULL)); /* Initialize the DMA */ UDMACC32XX_init(); object->powerMgrId = getPowerMgrId(hwAttrs->baseAddr); if (object->powerMgrId == (unsigned int)-1) { DebugP_log1("UART:(%p) Failed to determine power resource id", hwAttrs->baseAddr); return (NULL); } /* Disable preemption while checking if the UART is open. */ key = HwiP_disable(); /* Check if the UART is open already with the base addr. */ if (object->opened == true) { HwiP_restore(key); DebugP_log1("UART:(%p) already in use.", hwAttrs->baseAddr); return (NULL); } object->opened = true; HwiP_restore(key); /* * Register power dependency. Keeps the clock running in SLP * and DSLP modes. */ Power_setDependency(object->powerMgrId); /* Do a software reset of the peripheral */ PowerCC32XX_reset(object->powerMgrId); Power_registerNotify(&object->postNotify, PowerCC32XX_AWAKE_LPDS, postNotifyFxn, (uintptr_t)handle); object->readMode = params->readMode; object->writeMode = params->writeMode; object->readTimeout = params->readTimeout; object->writeTimeout = params->writeTimeout; object->readCallback = params->readCallback; object->writeCallback = params->writeCallback; object->readReturnMode = params->readReturnMode; object->readDataMode = params->readDataMode; object->writeDataMode = params->writeDataMode; object->readEcho = params->readEcho; object->baudRate = params->baudRate; object->stopBits = params->stopBits; object->dataLength = params->dataLength; object->parityType = params->parityType; /* Set UART variables to defaults. */ object->writeBuf = NULL; object->readBuf = NULL; object->writeCount = 0; object->readCount = 0; object->writeSize = 0; object->readSize = 0; object->readSem = NULL; object->writeSem = NULL; object->txFifoEmptyClk = NULL; object->txPin = (uint16_t)-1; /* DMA first */ object->dmaHandle = UDMACC32XX_open(); if (object->dmaHandle == NULL) { UARTCC32XXDMA_close(handle); DebugP_log1("UART:(%p) UDMACC32XX_open() failed.", hwAttrs->baseAddr); return (NULL); } pin = (hwAttrs->rxPin) & 0xff; mode = (hwAttrs->rxPin >> 8) & 0xff; MAP_PinTypeUART((unsigned long)pin, (unsigned long)mode); pin = (hwAttrs->txPin) & 0xff; mode = (hwAttrs->txPin >> 8) & 0xff; MAP_PinTypeUART((unsigned long)pin, (unsigned long)mode); /* * Read and save TX pin park state; set to "don't park" while UART is * open as device default is logic '1' during LPDS */ object->prevParkTX = (PowerCC32XX_ParkState) PowerCC32XX_getParkState((PowerCC32XX_Pin)pin); PowerCC32XX_setParkState((PowerCC32XX_Pin)pin, ~1); object->txPin = pin; if (isFlowControlEnabled(hwAttrs)) { pin = (hwAttrs->ctsPin) & 0xff; mode = (hwAttrs->ctsPin >> 8) & 0xff; MAP_PinTypeUART((unsigned long)pin, (unsigned long)mode); pin = (hwAttrs->rtsPin) & 0xff; mode = (hwAttrs->rtsPin >> 8) & 0xff; MAP_PinTypeUART((unsigned long)pin, (unsigned long)mode); /* * Read and save RTS pin park state; set to "don't park" while UART is * open as device default is logic '1' during LPDS */ object->prevParkRTS = (PowerCC32XX_ParkState)PowerCC32XX_getParkState( (PowerCC32XX_Pin)pin); PowerCC32XX_setParkState((PowerCC32XX_Pin)pin, ~1); object->rtsPin = pin; /* Flow control will be enabled in initHw() */ } HwiP_clearInterrupt(hwAttrs->intNum); HwiP_Params_init(&hwiParams); hwiParams.arg = (uintptr_t)handle; hwiParams.priority = hwAttrs->intPriority; object->hwiHandle = HwiP_create(hwAttrs->intNum, UARTCC32XXDMA_hwiIntFxn, &hwiParams); if (object->hwiHandle == NULL) { DebugP_log1("UART:(%p) HwiP_create() failed", hwAttrs->baseAddr); UARTCC32XXDMA_close(handle); return (NULL); } /* Disable the UART interrupt. */ MAP_UARTIntDisable(hwAttrs->baseAddr, (UART_INT_TX | UART_INT_RX | UART_INT_RT)); SemaphoreP_Params_init(&semParams); semParams.mode = SemaphoreP_Mode_BINARY; /* Create semaphores and set callbacks for BLOCKING modes. */ if (object->writeMode == UART_MODE_BLOCKING) { object->writeCallback = &writeSemCallback; object->writeSem = SemaphoreP_create(0, &semParams); if (object->writeSem == NULL) { UARTCC32XXDMA_close(handle); DebugP_log1("UART:(%p) Failed to create semaphore.", hwAttrs->baseAddr); return (NULL); } } if (object->readMode == UART_MODE_BLOCKING) { object->readCallback = &readSemCallback; object->readSem = SemaphoreP_create(0, &semParams); if (object->readSem == NULL) { UARTCC32XXDMA_close(handle); DebugP_log1("UART:(%p) Failed to create semaphore.", hwAttrs->baseAddr); return (NULL); } } /* * Clock object to ensure FIFO is drained before releasing Power * constraints. */ ClockP_Params_init(&clockParams); clockParams.arg = (uintptr_t)handle; object->txFifoEmptyClk = ClockP_create((ClockP_Fxn)&writeFinishedDoCallback, 0 /* timeout */, &(clockParams)); if (object->txFifoEmptyClk == NULL) { UARTCC32XXDMA_close(handle); DebugP_log1("UART:(%p) ClockP_create() failed.", hwAttrs->baseAddr); return (NULL); } /* Initialize the hardware */ initHw(handle); DebugP_log1("UART:(%p) opened", hwAttrs->baseAddr); /* Return the handle */ return (handle); } /* * ======== UARTCC32XXDMA_read ======== */ int_fast32_t UARTCC32XXDMA_read(UART_Handle handle, void *buffer, size_t size) { uintptr_t key; UARTCC32XXDMA_Object *object = handle->object; /* DMA cannot handle transfer sizes > 1024 elements */ if (size > MAXXFERSIZE) { DebugP_log1("UART:(%p) Data size too large.", ((UARTCC32XXDMA_HWAttrsV1 const *)(handle->hwAttrs))->baseAddr); return (UART_ERROR); } /* Disable preemption while checking if the uart is in use. */ key = HwiP_disable(); if (object->readSize) { HwiP_restore(key); DebugP_log1("UART:(%p) Could not read data, uart in use.", ((UARTCC32XXDMA_HWAttrsV1 const *)(handle->hwAttrs))->baseAddr); return (UART_ERROR); } /* Save the data to be read and restore interrupts. */ object->readBuf = buffer; object->readSize = size; object->readCount = 0; /* Set constraints to guarantee transaction */ Power_setConstraint(PowerCC32XX_DISALLOW_LPDS); /* * Start the DMA transfer. Do this inside the critical * section to prevent UARTCC32XXDMA_readCancel() being called * after object->readSize is set, but before the DMA is * configured. If that happened, the size in the DMA control * register would be 0, causing UARTCC32XXDMA_readCancel() * to assume all bytes were transferred. */ UARTCC32XXDMA_configDMA(handle, false /* isWrite */); HwiP_restore(key); /* If readMode is blocking, block and get the status. */ if (object->readMode == UART_MODE_BLOCKING) { /* Pend on semaphore and wait for Hwi to finish. */ if (SemaphoreP_OK != SemaphoreP_pend(object->readSem, object->readTimeout)) { key = HwiP_disable(); /* Cancel the DMA without posting the semaphore */ (void)readCancel(handle); /* * If ISR ran after timeout, but before the call to * readCancel(), readSem would be posted. Pend on * the semaphore with 0 timeout so the next read * will block. */ if (object->readCount == size) { SemaphoreP_pend(object->readSem, 0); } HwiP_restore(key); DebugP_log2("UART:(%p) Read timed out, %d bytes read", ((UARTCC32XXDMA_HWAttrsV1 const *)(handle->hwAttrs))->baseAddr, object->readCount); } return (object->readCount); } return (0); } /* * ======== UARTCC32XXDMA_readPolling ======== */ int_fast32_t UARTCC32XXDMA_readPolling(UART_Handle handle, void *buf, size_t size) { int32_t count = 0; UARTCC32XXDMA_Object *object = handle->object; UARTCC32XXDMA_HWAttrsV1 const *hwAttrs = handle->hwAttrs; unsigned char *buffer = (unsigned char *)buf; /* Read characters. */ while (size) { *buffer = MAP_UARTCharGet(hwAttrs->baseAddr); DebugP_log2("UART:(%p) Read character 0x%x", hwAttrs->baseAddr, *buffer); count++; size--; if (object->readDataMode == UART_DATA_TEXT && *buffer == '\r') { /* Echo character if enabled. */ if (object->readEcho) { MAP_UARTCharPut(hwAttrs->baseAddr, '\r'); } *buffer = '\n'; } /* Echo character if enabled. */ if (object->readEcho) { MAP_UARTCharPut(hwAttrs->baseAddr, *buffer); } /* If read return mode is newline, finish if a newline was received. */ if (object->readReturnMode == UART_RETURN_NEWLINE && *buffer == '\n') { return (count); } buffer++; } DebugP_log2("UART:(%p) Read polling finished, %d bytes read", hwAttrs->baseAddr, count); return (count); } /* * ======== UARTCC32XXDMA_readCancel ======== */ void UARTCC32XXDMA_readCancel(UART_Handle handle) { UARTCC32XXDMA_Object *object = handle->object; size_t size; /* Stop any ongoing DMA read */ size = readCancel(handle); if (size == 0) { return; } if (object->readMode == UART_MODE_CALLBACK) { object->readCallback(handle, object->readBuf, object->readCount); } else if (object->readMode == UART_MODE_BLOCKING) { /* We don't know if we're in an ISR, but we'll assume not. */ SemaphoreP_post(object->readSem); } DebugP_log1("UART:(%p) Read canceled, 0 bytes read", ((UARTCC32XXDMA_HWAttrsV1 const *)(handle->hwAttrs))->baseAddr); } /* * ======== UARTCC32XXDMA_write ======== */ int_fast32_t UARTCC32XXDMA_write(UART_Handle handle, const void *buffer, size_t size) { uintptr_t key; UARTCC32XXDMA_Object *object = handle->object; UARTCC32XXDMA_HWAttrsV1 const *hwAttrs = handle->hwAttrs; /* DMA cannot handle transfer sizes > 1024 elements */ if (size > MAXXFERSIZE) { DebugP_log1("UART:(%p) Data size too large.", hwAttrs->baseAddr); return (UART_ERROR); } /* Disable preemption while checking if the uart is in use. */ key = HwiP_disable(); if (object->writeSize || UARTBusy(hwAttrs->baseAddr)) { HwiP_restore(key); DebugP_log1("UART:(%p) Could not write data, uart in use.", ((UARTCC32XXDMA_HWAttrsV1 const *)(handle->hwAttrs))->baseAddr); return (UART_ERROR); } /* Save the data to be written and restore interrupts. */ object->writeBuf = buffer; object->writeCount = 0; object->writeSize = size; /* Set constraints to guarantee transaction */ Power_setConstraint(PowerCC32XX_DISALLOW_LPDS); UARTCC32XXDMA_configDMA(handle, true /* isWrite */); HwiP_restore(key); /* If writeMode is blocking, block and get the status. */ if (object->writeMode == UART_MODE_BLOCKING) { /* Pend on semaphore and wait for Hwi to finish. */ if (SemaphoreP_OK != SemaphoreP_pend(object->writeSem, object->writeTimeout)) { key = HwiP_disable(); /* Stop any ongoing DMA writes and release Power constraints. */ (void)writeCancel(handle); /* * If ISR ran after timeout, but before the call to * writeCancel(), writeSem would be posted. Pend on * the semaphore so the next write call will block. */ if (object->writeCount == size) { SemaphoreP_pend(object->writeSem, 0); } HwiP_restore(key); DebugP_log2("UART:(%p) Write timed out, %d bytes written", ((UARTCC32XXDMA_HWAttrsV1 const *)(handle->hwAttrs))->baseAddr, object->writeCount); } return (object->writeCount); } return (0); } /* * ======== UARTCC32XXDMA_writePolling ======== */ int_fast32_t UARTCC32XXDMA_writePolling(UART_Handle handle, const void *buf, size_t size) { int32_t count = 0; UARTCC32XXDMA_Object *object = handle->object; UARTCC32XXDMA_HWAttrsV1 const *hwAttrs = handle->hwAttrs; unsigned char *buffer = (unsigned char *)buf; /* Write characters. */ while (size) { if (object->writeDataMode == UART_DATA_TEXT && *buffer == '\n') { MAP_UARTCharPut(hwAttrs->baseAddr, '\r'); count++; } MAP_UARTCharPut(hwAttrs->baseAddr, *buffer); DebugP_log2("UART:(%p) Wrote character 0x%x", ((UARTCC32XXDMA_HWAttrsV1 const *)(handle->hwAttrs))->baseAddr, *buffer); buffer++; count++; size--; } DebugP_log2("UART:(%p) Write polling finished, %d bytes written", ((UARTCC32XXDMA_HWAttrsV1 const *)(handle->hwAttrs))->baseAddr, count); return (count); } /* * ======== UARTCC32XXDMA_writeCancel ======== */ void UARTCC32XXDMA_writeCancel(UART_Handle handle) { UARTCC32XXDMA_Object *object = handle->object; size_t size; /* Stop any ongoing DMA transmits */ size = writeCancel(handle); if (size == 0) { return; } if (object->writeMode == UART_MODE_CALLBACK) { object->writeCallback(handle, (uint8_t*)object->writeBuf, object->writeCount); } else if (object->writeMode == UART_MODE_BLOCKING) { /* We don't know if we're in an ISR, but we'll assume not. */ SemaphoreP_post(object->writeSem); } DebugP_log2("UART:(%p) Write canceled, %d bytes written", ((UARTCC32XXDMA_HWAttrsV1 const *)(handle->hwAttrs))->baseAddr, object->writeCount); } /* * ======== UARTCC32XXDMA_configDMA ======== * Call with interrupts disabled. */ static void UARTCC32XXDMA_configDMA(UART_Handle handle, bool isWrite) { UARTCC32XXDMA_Object *object = handle->object; UARTCC32XXDMA_HWAttrsV1 const *hwAttrs = handle->hwAttrs; unsigned long channelControlOptions; if (isWrite) { channelControlOptions = UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE | UDMA_ARB_4; MAP_uDMAChannelControlSet(hwAttrs->txChannelIndex | UDMA_PRI_SELECT, channelControlOptions); MAP_uDMAChannelTransferSet(hwAttrs->txChannelIndex | UDMA_PRI_SELECT, UDMA_MODE_BASIC, (void *)object->writeBuf, (void *)(hwAttrs->baseAddr + UART_O_DR), object->writeSize); /* * Enable the DMA channel * This sets the channel's corresponding bit in the uDMA ENASET register. * The bit will be cleared when the transfer completes. */ MAP_uDMAChannelEnable(hwAttrs->txChannelIndex); MAP_UARTIntClear(hwAttrs->baseAddr, UART_INT_DMATX); MAP_UARTIntEnable(hwAttrs->baseAddr, UART_INT_DMATX); } else { channelControlOptions = UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 | UDMA_ARB_4; MAP_uDMAChannelControlSet(hwAttrs->rxChannelIndex | UDMA_PRI_SELECT, channelControlOptions); MAP_uDMAChannelTransferSet(hwAttrs->rxChannelIndex | UDMA_PRI_SELECT, UDMA_MODE_BASIC, (void *)(hwAttrs->baseAddr + UART_O_DR), object->readBuf, object->readSize); /* Enable DMA Channel */ MAP_uDMAChannelEnable(hwAttrs->rxChannelIndex); MAP_UARTIntClear(hwAttrs->baseAddr, UART_INT_DMARX); MAP_UARTIntEnable(hwAttrs->baseAddr, UART_INT_DMARX); } DebugP_log1("UART:(%p) DMA transfer enabled", hwAttrs->baseAddr); if (isWrite) { DebugP_log3("UART:(%p) DMA transmit, txBuf: %p; Count: %d", hwAttrs->baseAddr, (uintptr_t)(object->writeBuf), object->writeSize); } else { DebugP_log3("UART:(%p) DMA receive, rxBuf: %p; Count: %d", hwAttrs->baseAddr, (uintptr_t)(object->readBuf), object->readSize); } } /* * ======== UARTCC32XXDMA_hwiIntFxn ======== * Hwi function that processes UART interrupts. * * Three UART interrupts are enabled: Transmit FIFO is 4/8 empty, * receive FIFO is 4/8 full and a receive timeout between the time * the last character was received. * * @param(arg) The UART_Handle for this Hwi. */ static void UARTCC32XXDMA_hwiIntFxn(uintptr_t arg) { uint32_t status; UARTCC32XXDMA_Object *object = ((UART_Handle)arg)->object; UARTCC32XXDMA_HWAttrsV1 const *hwAttrs = ((UART_Handle)arg)->hwAttrs; /* * Clear interrupts * UARTIntStatus(base, false) - read the raw interrupt status * UARTIntStatus(base, true) - read masked interrupt status */ status = MAP_UARTIntStatus(hwAttrs->baseAddr, false); if (status & UART_INT_DMATX) { MAP_UARTIntDisable(hwAttrs->baseAddr, UART_INT_DMATX); MAP_UARTIntClear(hwAttrs->baseAddr, UART_INT_DMATX); } if (status & UART_INT_DMARX) { MAP_UARTIntDisable(hwAttrs->baseAddr, UART_INT_DMARX); MAP_UARTIntClear(hwAttrs->baseAddr, UART_INT_DMARX); } DebugP_log2("UART:(%p) Interrupt with mask 0x%x", hwAttrs->baseAddr, status); /* Read data if characters are available. */ if (object->readSize && !MAP_uDMAChannelIsEnabled(hwAttrs->rxChannelIndex)) { object->readCount = object->readSize; object->readSize = 0; object->readCallback((UART_Handle)arg, object->readBuf, object->readCount); Power_releaseConstraint(PowerCC32XX_DISALLOW_LPDS); DebugP_log2("UART:(%p) Read finished, %d bytes read", hwAttrs->baseAddr, object->readCount); } /* Write completed. */ if (object->writeSize && !MAP_uDMAChannelIsEnabled(hwAttrs->txChannelIndex)) { object->writeCount = object->writeSize; object->writeSize = 0; /* * No more to write, but data is not shifted out yet. * Start TX FIFO Empty clock. * + 4 because it is 4 bytes left in TX FIFO when the TX FIFO * threshold interrupt occurs. */ startTxFifoEmptyClk((UART_Handle)arg, 4); DebugP_log2("UART:(%p) Write finished, %d bytes written", hwAttrs->baseAddr, object->writeCount); } } /* * ======== getPowerMgrId ======== */ static unsigned int getPowerMgrId(unsigned int baseAddr) { switch (baseAddr) { case UARTA0_BASE: return (PowerCC32XX_PERIPH_UARTA0); case UARTA1_BASE: return (PowerCC32XX_PERIPH_UARTA1); default: return ((unsigned int)-1); } } /* * ======== initHw ======== * Initialize the hardware. */ static void initHw(UART_Handle handle) { ClockP_FreqHz freq; UARTCC32XXDMA_Object *object = handle->object; UARTCC32XXDMA_HWAttrsV1 const *hwAttrs = handle->hwAttrs; /* * Set the FIFO level to 4/8 empty and 4/8 full. * The UART generates a burst request based on the FIFO trigger * level. The arbitration size should be set to the amount * of data that the FIFO can transfer when the trigger level is reached. * Since arbitration size is a power of 2, we'll set the FIFO levels * to 4_8 so they can match the arbitration size of 4. */ MAP_UARTFIFOLevelSet(hwAttrs->baseAddr, UART_FIFO_TX4_8, UART_FIFO_RX4_8); if (isFlowControlEnabled(hwAttrs)) { /* Set flow control */ MAP_UARTFlowControlSet(hwAttrs->baseAddr, UART_FLOWCONTROL_TX | UART_FLOWCONTROL_RX); } else { MAP_UARTFlowControlSet(hwAttrs->baseAddr, UART_FLOWCONTROL_NONE); } ClockP_getCpuFreq(&freq); MAP_UARTConfigSetExpClk(hwAttrs->baseAddr, freq.lo, object->baudRate, dataLength[object->dataLength] | stopBits[object->stopBits] | parityType[object->parityType]); MAP_UARTDMAEnable(hwAttrs->baseAddr, UART_DMA_TX | UART_DMA_RX); /* Configure DMA for TX and RX */ MAP_uDMAChannelAssign(hwAttrs->txChannelIndex); MAP_uDMAChannelAttributeDisable(hwAttrs->txChannelIndex, UDMA_ATTR_ALTSELECT); MAP_uDMAChannelAssign(hwAttrs->rxChannelIndex); MAP_uDMAChannelAttributeDisable(hwAttrs->rxChannelIndex, UDMA_ATTR_ALTSELECT); MAP_UARTEnable(hwAttrs->baseAddr); } /* * ======== postNotifyFxn ======== * Called by Power module when waking up from LPDS. */ static int postNotifyFxn(unsigned int eventType, uintptr_t eventArg, uintptr_t clientArg) { initHw((UART_Handle)clientArg); return (Power_NOTIFYDONE); } /* * ======== readCancel ======== * Stop the current DMA receive transfer. */ static size_t readCancel(UART_Handle handle) { uintptr_t key; UARTCC32XXDMA_Object *object = handle->object; UARTCC32XXDMA_HWAttrsV1 const *hwAttrs = handle->hwAttrs; uint32_t remainder; int bytesTransferred; size_t size; /* Disable interrupts to avoid reading data while changing state. */ key = HwiP_disable(); size = object->readSize; /* Return if there is no read. */ if (!object->readSize) { HwiP_restore(key); return (size); } /* Set channel bit in the ENACLR register */ MAP_uDMAChannelDisable(hwAttrs->rxChannelIndex); remainder = MAP_uDMAChannelSizeGet(hwAttrs->rxChannelIndex); bytesTransferred = object->readSize - remainder; /* * Since object->readSize != 0, the ISR has not run and released * the Power constraint. Release the constraint here. Setting * object->readSize to 0 will prevent the ISR from releasing the * constraint in case it is pending. */ Power_releaseConstraint(PowerCC32XX_DISALLOW_LPDS); /* Set size = 0 to prevent reading and restore interrupts. */ object->readSize = 0; object->readCount = bytesTransferred; HwiP_restore(key); return (size); } /* * ======== readSemCallback ======== * Simple callback to post a semaphore for the blocking mode. */ static void readSemCallback(UART_Handle handle, void *buffer, size_t count) { UARTCC32XXDMA_Object *object = handle->object; SemaphoreP_post(object->readSem); } /* * ======== writeSemCallback ======== * Simple callback to post a semaphore for the blocking mode. */ static void writeSemCallback(UART_Handle handle, void *buffer, size_t count) { UARTCC32XXDMA_Object *object = handle->object; SemaphoreP_post(object->writeSem); } /* * ======== writeCancel ======== */ static size_t writeCancel(UART_Handle handle) { uintptr_t key; UARTCC32XXDMA_Object *object = handle->object; UARTCC32XXDMA_HWAttrsV1 const *hwAttrs = handle->hwAttrs; uint32_t remainder; int bytesTransferred; size_t size; /* Disable interrupts to avoid writing data while changing state. */ key = HwiP_disable(); size = object->writeSize; /* Set channel bit in the ENACLR register */ MAP_uDMAChannelDisable(hwAttrs->txChannelIndex); remainder = MAP_uDMAChannelSizeGet(hwAttrs->txChannelIndex); bytesTransferred = object->writeSize - remainder; /* Return if there is no write. */ if (!object->writeSize) { HwiP_restore(key); return (size); } /* * If the transfer didn't complete, the ISR will not run to * release the Power constraint, so do it here. */ if (bytesTransferred < object->writeSize) { Power_releaseConstraint(PowerCC32XX_DISALLOW_LPDS); } /* Set size = 0 to prevent writing and restore interrupts. */ object->writeSize = 0; object->writeCount = bytesTransferred; HwiP_restore(key); return (size); } /* * ======== startTxFifoEmptyClk ======== * Last write to TX FIFO is done, but not shifted out yet. Start a clock * which will trigger when the TX FIFO should be empty. * * @param(handle) The UART_Handle for ongoing write. * @param(numData) The number of data present in FIFO after last write */ static void startTxFifoEmptyClk(UART_Handle handle, unsigned int numData) { UARTCC32XXDMA_Object *object = handle->object; unsigned int writeTimeout; unsigned int ticksPerSec; /* No more to write, but data is not shiftet out properly yet. * 1. Compute appropriate wait time for FIFO to empty out * - 8 - for maximum data length * - 3 - for one start bit and maximum of two stop bits */ ticksPerSec = ClockP_getSystemTickFreq(); writeTimeout = ((numData * (8 + 3) * ticksPerSec) + object->baudRate - 1) / object->baudRate; /* 2. Configure clock object to trigger when FIFO is empty */ ClockP_setTimeout(object->txFifoEmptyClk, writeTimeout); ClockP_start(object->txFifoEmptyClk); } /* * ======== writeFinishedDoCallback ======== * Write finished - make callback * * This function is called when the txFifoEmptyClk times out. The TX FIFO * should now be empty. Standby is allowed again. * * @param(handle) The UART_Handle for ongoing write. */ static void writeFinishedDoCallback(UART_Handle handle) { UARTCC32XXDMA_Object *object; UARTCC32XXDMA_HWAttrsV1 const *hwAttrs; /* Get the pointer to the object and hwAttrs */ object = handle->object; hwAttrs = handle->hwAttrs; /* Stop the txFifoEmpty clock */ ClockP_stop((ClockP_Handle)object->txFifoEmptyClk); /* 1. Function verifies that the FIFO is empty via BUSY flag */ /* 2. Polls this flag if not yet ready (should not be necessary) */ while (MAP_UARTBusy(hwAttrs->baseAddr)); /* Release constraint since transaction is done */ Power_releaseConstraint(PowerCC32XX_DISALLOW_LPDS); /* Make callback */ object->writeCallback(handle, (uint8_t *)object->writeBuf, object->writeCount); DebugP_log2("UART:(%p) Write finished, %d bytes written", hwAttrs->baseAddr, object->writeCount); }