/* * Copyright (c) 2022 Jiangsu Hoperun Software Co., Ltd. * * This file is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. * See the LICENSE file in the root of this repository for complete details. */ #include #include #include "osal_time.h" #include "osal_sem.h" #include "device_resource_if.h" #include "hdf_log.h" #include "wm_gpio_afsel.h" #include "uart_if.h" #include "uart_core.h" #include "wm_uart.h" #define HDF_UART_TMO 1000 #define TMO_MS_UNIT_CONV (1000) #define HDF_LOG_TAG uartDev #define UART_DEV_SERVICE_NAME_PREFIX "HDF_PLATFORM_UART%d" #define MAX_DEV_NAME_SIZE 32 struct UartResource { uint32_t num; /* UART port num */ uint32_t baudRate; /* Default baudrate */ uint32_t wLen; /* Default word length */ uint32_t parity; /* Default parity */ uint32_t stopBit; /* Default stop bits */ bool txDMA; bool rxDMA; }; enum UartDeviceState { UART_DEVICE_UNINITIALIZED = 0x0u, UART_DEVICE_INITIALIZED = 0x1u, }; struct UART_CTX_OBJ { bool txDMA; bool rxDMA; bool isBlock; struct OsalSem rxSem; struct OsalSem txSem; }; struct UartDevice { struct IDeviceIoService ioService; struct UartResource resource; tls_uart_options_t config; uint32_t uartId; bool initFlag; uint32_t transMode; }; enum { UART_READ = 0, UART_WRITE }; static struct UART_CTX_OBJ g_uartCtx[4] = {0}; static unsigned char *g_uartKfifoBuffer[4] = {NULL, NULL, NULL, NULL}; static void HalSetUartIomux(int uartId) { switch (uartId) { case TLS_UART_0: wm_uart0_tx_config(WM_IO_PB_19); wm_uart0_rx_config(WM_IO_PB_20); break; case TLS_UART_1: wm_uart1_tx_config(WM_IO_PB_06); wm_uart1_rx_config(WM_IO_PB_07); break; case TLS_UART_2: wm_uart2_tx_scio_config(WM_IO_PB_02); wm_uart2_rx_config(WM_IO_PB_03); break; case TLS_UART_3: wm_uart3_tx_config(WM_IO_PB_00); wm_uart3_rx_config(WM_IO_PB_01); break; case TLS_UART_4: wm_uart4_tx_config(WM_IO_PB_04); wm_uart4_rx_config(WM_IO_PB_05); break; default: HDF_LOGE("%s: uartId(%d) invalid", __func__, uartId); break; } } static void dma_tx_cmpl_callback(uint32_t arg) { uint32_t uartId = arg; OsalSemPost(&g_uartCtx[uartId].txSem); } static int32_t HalUartSend(uint32_t uartId, const uint8_t *data, uint32_t size, uint32_t timeOut) { int32_t ret = HDF_FAILURE; if (data == NULL || size == 0) { HDF_LOGE("%s %d Invalid input \r\n", __FILE__, __LINE__); return HDF_ERR_INVALID_PARAM; } tls_uart_dma_write(data, (uint16_t)size, dma_tx_cmpl_callback, (uint16_t)uartId); ret = OsalSemWait(&g_uartCtx[uartId].txSem, timeOut); return ret; } static int32_t HalUartRecv(uint8_t uartId, uint8_t *data, uint32_t expectSize, uint32_t *recvSize, uint32_t timeOut) { uint32_t fifoPopLen; uint32_t recvedLen = 0; uint32_t expectLen = expectSize; OsalTimespec hdfTs1 = { 0, 0 }; OsalTimespec hdfTs2 = { 0, 0 }; OsalTimespec hdfTsDiff = { 0, 0 }; if (data == NULL || expectSize == 0 || recvSize == NULL) { HDF_LOGE("%s %d Invalid input \r\n", __FILE__, __LINE__); return HDF_ERR_INVALID_PARAM; } OsalGetTime(&hdfTs1); do { fifoPopLen = tls_uart_read(uartId, (uint8_t *)data + recvedLen, expectLen); recvedLen += fifoPopLen; expectLen -= fifoPopLen; if (recvedLen >= expectSize) { break; } /* haven't get any data from fifo */ if (recvedLen == 0) { break; } /* if reaches here, it means need to wait for more data come */ OsalMSleep(1); /* time out break */ OsalGetTime(&hdfTs2); OsalDiffTime(&hdfTs1, &hdfTs2, &hdfTsDiff); if ((uint32_t)(hdfTsDiff.sec * TMO_MS_UNIT_CONV + hdfTsDiff.usec / TMO_MS_UNIT_CONV) >= timeOut) { break; } } while (true); *recvSize = recvedLen; return HDF_SUCCESS; } static void HalUartHandlerInit(const struct UartDevice *device) { uint32_t uartId; if (device == NULL) { HDF_LOGE("%s: INVALID PARAM", __func__); return; } uartId = device->uartId; OsalSemInit(&g_uartCtx[uartId].rxSem, 0); OsalSemInit(&g_uartCtx[uartId].txSem, 0); } static void UartStart(struct UartDevice *device) { uint32_t uartId; tls_uart_options_t *uartCfg = NULL; if (device == NULL) { HDF_LOGE("%s: INVALID PARAM", __func__); return; } uartId = device->uartId; uartCfg = &device->config; if (uartCfg == NULL) { HDF_LOGE("%s: INVALID OBJECT", __func__); return; } if (WM_SUCCESS != tls_uart_port_init(uartId, uartCfg, 0)) { HDF_LOGE("uart %d init error", uartId); } HDF_LOGI("%s %ld\r\n", __FUNCTION__, uartId); HalUartHandlerInit(device); } /* HdfDriverEntry method definitions */ static int32_t UartDriverBind(struct HdfDeviceObject *device); static int32_t UartDriverInit(struct HdfDeviceObject *device); static void UartDriverRelease(struct HdfDeviceObject *device); /* HdfDriverEntry definitions */ struct HdfDriverEntry g_UartDriverEntry = { .moduleVersion = 1, .moduleName = "W800_UART_MODULE_HDF", .Bind = UartDriverBind, .Init = UartDriverInit, .Release = UartDriverRelease, }; /* Initialize HdfDriverEntry */ HDF_INIT(g_UartDriverEntry); /* UartHostMethod method definitions */ static int32_t UartHostDevInit(struct UartHost *host); static int32_t UartHostDevDeinit(struct UartHost *host); static int32_t UartHostDevWrite(struct UartHost *host, uint8_t *data, uint32_t size); static int32_t UartHostDevSetBaud(struct UartHost *host, uint32_t baudRate); static int32_t UartHostDevGetBaud(struct UartHost *host, uint32_t *baudRate); static int32_t UartHostDevRead(struct UartHost *host, uint8_t *data, uint32_t size); static int32_t UartHostDevSetAttribute(struct UartHost *host, struct UartAttribute *attribute); static int32_t UartHostDevGetAttribute(struct UartHost *host, struct UartAttribute *attribute); static int32_t UartHostDevSetTransMode(struct UartHost *host, enum UartTransMode mode); /* UartHostMethod definitions */ struct UartHostMethod g_uartHostMethod = { .Init = UartHostDevInit, .Deinit = UartHostDevDeinit, .Read = UartHostDevRead, .Write = UartHostDevWrite, .SetBaud = UartHostDevSetBaud, .GetBaud = UartHostDevGetBaud, .SetAttribute = UartHostDevSetAttribute, .GetAttribute = UartHostDevGetAttribute, .SetTransMode = UartHostDevSetTransMode, }; static int InitUartDevice(struct UartHost *host) { HDF_LOGI("%s: Enter", __func__); struct UartDevice *uartDevice = NULL; if (host == NULL || host->priv == NULL) { HDF_LOGE("%s: invalid parameter", __func__); return HDF_ERR_INVALID_PARAM; } uartDevice = (struct UartDevice *)host->priv; if (!uartDevice->initFlag) { HDF_LOGI("uart %ld device init", uartDevice->uartId); HalSetUartIomux(uartDevice->uartId); UartStart(uartDevice); uartDevice->initFlag = true; } return HDF_SUCCESS; } static uint32_t GetUartDeviceResource(struct UartDevice *device, const struct DeviceResourceNode *resourceNode) { struct DeviceResourceIface *dri = NULL; struct UartResource *resource = NULL; if (device == NULL || resourceNode == NULL) { HDF_LOGE("%s: INVALID PARAM", __func__); return HDF_ERR_INVALID_PARAM; } resource = &device->resource; if (resource == NULL) { HDF_LOGE("%s: INVALID OBJECT", __func__); return HDF_ERR_INVALID_OBJECT; } dri = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE); if (dri == NULL || dri->GetUint32 == NULL) { HDF_LOGE("DeviceResourceIface is invalid"); return HDF_ERR_INVALID_PARAM; } if (dri->GetUint32(resourceNode, "num", &resource->num, 0) != HDF_SUCCESS) { HDF_LOGE("uart config read num fail"); return HDF_FAILURE; } if (dri->GetUint32(resourceNode, "baudrate", &resource->baudRate, 0) != HDF_SUCCESS) { HDF_LOGE("uart config read baudrate fail"); return HDF_FAILURE; } if (dri->GetUint32(resourceNode, "parity", &resource->parity, 0) != HDF_SUCCESS) { HDF_LOGE("uart config read parity fail"); return HDF_FAILURE; } if (dri->GetUint32(resourceNode, "stopBit", &resource->stopBit, 0) != HDF_SUCCESS) { HDF_LOGE("uart config read stopBit fail"); return HDF_FAILURE; } HDF_LOGI("%d, %d, %d", resource->num, resource->baudRate, resource->parity); // copy config device->uartId = resource->num; device->config.baudrate = resource->baudRate; device->config.paritytype = (TLS_UART_PMODE_T)resource->parity; device->config.stopbits = (TLS_UART_STOPBITS_T)resource->stopBit; device->config.charlength = TLS_UART_CHSIZE_8BIT; device->config.flow_ctrl = TLS_UART_FLOW_CTRL_NONE; return HDF_SUCCESS; } static int32_t AttachUartDevice(struct UartHost *uartHost, const struct HdfDeviceObject *device) { int32_t ret; struct UartDevice *uartDevice = NULL; if (uartHost == NULL || device == NULL || device->property == NULL) { HDF_LOGE("%s: property is NULL", __func__); return HDF_ERR_INVALID_PARAM; } uartDevice = (struct UartDevice *)OsalMemAlloc(sizeof(struct UartDevice)); if (uartDevice == NULL) { HDF_LOGE("%s: OsalMemCalloc uartDevice error", __func__); return HDF_ERR_MALLOC_FAIL; } ret = GetUartDeviceResource(uartDevice, device->property); if (ret != HDF_SUCCESS) { (void)OsalMemFree(uartDevice); return HDF_FAILURE; } uartHost->priv = uartDevice; return InitUartDevice(uartHost); } static int32_t UartDriverBind(struct HdfDeviceObject *device) { struct UartHost *devService; if (device == NULL) { HDF_LOGE("%s: invalid parameter", __func__); return HDF_ERR_INVALID_PARAM; } devService = (struct UartHost *)OsalMemAlloc(sizeof(*devService)); if (devService == NULL) { HDF_LOGE("%s: OsalMemCalloc error", __func__); return HDF_ERR_INVALID_OBJECT; } devService->device = device; device->service = &(devService->service); devService->priv = NULL; devService->method = NULL; return HDF_SUCCESS; } static void UartDriverRelease(struct HdfDeviceObject *device) { HDF_LOGI("Enter %s:", __func__); uint32_t uartId; struct UartHost *host = NULL; struct UartDevice *uartDevice = NULL; if (device == NULL) { HDF_LOGE("%s: device is NULL", __func__); return; } host = UartHostFromDevice(device); if (host == NULL || host->priv == NULL) { HDF_LOGE("%s: host is NULL", __func__); return; } uartDevice = (struct UartDevice *)host->priv; uartId = uartDevice->uartId; host->method = NULL; OsalSemDestroy(&g_uartCtx[uartId].rxSem); OsalSemDestroy(&g_uartCtx[uartId].txSem); OsalMemFree(uartDevice); OsalMemFree(host); } static int32_t UartDriverInit(struct HdfDeviceObject *device) { HDF_LOGI("Enter %s:", __func__); int32_t ret; struct UartHost *host = NULL; if (device == NULL) { HDF_LOGE("%s: device is NULL", __func__); return HDF_ERR_INVALID_OBJECT; } host = UartHostFromDevice(device); if (host == NULL) { HDF_LOGE("%s: host is NULL", __func__); return HDF_ERR_INVALID_OBJECT; } ret = AttachUartDevice(host, device); if (ret != HDF_SUCCESS) { HDF_LOGE("%s: attach error", __func__); return HDF_FAILURE; } host->method = &g_uartHostMethod; return ret; } /* UartHostMethod implementations */ static int32_t UartHostDevInit(struct UartHost *host) { HDF_LOGI("%s: Enter\r\n", __func__); if (host == NULL) { HDF_LOGE("%s: invalid parameter", __func__); return HDF_ERR_INVALID_PARAM; } InitUartDevice(host); return HDF_SUCCESS; } static int32_t UartHostDevDeinit(struct UartHost *host) { HDF_LOGI("%s: Enter", __func__); uint32_t uartId; struct UartDevice *uartDevice = NULL; if (host == NULL || host->priv == NULL) { HDF_LOGE("%s: invalid parameter", __func__); return HDF_ERR_INVALID_PARAM; } uartDevice = (struct UartDevice *)host->priv; uartId = uartDevice->uartId; uartDevice->initFlag = false; return HDF_SUCCESS; } static int32_t UartHostDevWrite(struct UartHost *host, uint8_t *data, uint32_t size) { struct UartDevice *device = NULL; uint32_t portId; if (host == NULL || data == NULL || size == 0 || host->priv == NULL) { HDF_LOGE("%s: invalid parameter", __func__); return HDF_ERR_INVALID_PARAM; } device = (struct UartDevice *)host->priv; portId = device->uartId; if (g_uartCtx[portId].txDMA) { return HalUartSend(portId, data, size, HDF_UART_TMO); } else { if (tls_uart_write(portId, data, size) < 0) { return HDF_FAILURE; } } return HDF_SUCCESS; } static int32_t UartHostDevRead(struct UartHost *host, uint8_t *data, uint32_t size) { uint32_t recvSize = 0; int32_t ret; uint32_t uartId; struct UartDevice *uartDevice = NULL; if (host == NULL || data == NULL || host->priv == NULL) { HDF_LOGE("%s: invalid parameter", __func__); return HDF_ERR_INVALID_PARAM; } uartDevice = (struct UartDevice *)host->priv; uartId = uartDevice->uartId; if (g_uartCtx[uartId].rxDMA) { ret = HalUartRecv(uartId, data, size, &recvSize, HDF_UART_TMO); if (ret != HDF_SUCCESS) { HDF_LOGE("uart %ld recev error\r\n", uartId); return ret; } ret = recvSize; } else { if (g_uartCtx[uartId].isBlock) { while (tls_uart_try_read(uartId, 1) == 0) { } ret = tls_uart_read(uartId, data, 1); } else { ret = tls_uart_read(uartId, data, 1); } ret = 1; } return ret; } static int32_t UartHostDevSetBaud(struct UartHost *host, uint32_t baudRate) { HDF_LOGI("%s: Enter", __func__); struct UartDevice *uartDevice = NULL; tls_uart_options_t *uartCfg = NULL; uint32_t uartId; if (host == NULL || host->priv == NULL) { HDF_LOGE("%s: invalid parameter", __func__); return HDF_ERR_INVALID_PARAM; } uartDevice = (struct UartDevice *)host->priv; uartId = uartDevice->uartId; uartCfg = &uartDevice->config; if (uartCfg == NULL) { HDF_LOGE("%s: device config is NULL", __func__); return HDF_ERR_INVALID_OBJECT; } uartCfg->baudrate = baudRate; tls_uart_set_baud_rate(uartId, uartCfg->baudrate); return HDF_SUCCESS; } static int32_t UartHostDevGetBaud(struct UartHost *host, uint32_t *baudRate) { HDF_LOGI("%s: Enter", __func__); struct UartDevice *uartDevice = NULL; tls_uart_options_t *uartCfg = NULL; uint32_t uartId; if (host == NULL || baudRate == NULL || host->priv == NULL) { HDF_LOGE("%s: invalid parameter", __func__); return HDF_ERR_INVALID_PARAM; } uartDevice = (struct UartDevice *)host->priv; uartId = uartDevice->uartId; uartCfg = &uartDevice->config; if (uartCfg == NULL) { HDF_LOGE("%s: device is NULL", __func__); return HDF_ERR_INVALID_OBJECT; } *baudRate = uartCfg->baudrate; return HDF_SUCCESS; } static int32_t UartHostDevSetAttribute(struct UartHost *host, struct UartAttribute *attribute) { struct UartDevice *uartDevice = NULL; tls_uart_options_t *uartCfg = NULL; uint32_t uartId; if (host == NULL || attribute == NULL || host->priv == NULL) { HDF_LOGE("%s: invalid parameter", __func__); return HDF_ERR_INVALID_PARAM; } uartDevice = (struct UartDevice *)host->priv; uartId = uartDevice->uartId; uartCfg = &uartDevice->config; if (uartCfg == NULL) { HDF_LOGE("%s: config is NULL", __func__); return HDF_ERR_INVALID_OBJECT; } uartCfg->paritytype = attribute->parity; tls_uart_set_parity(uartId, uartCfg->paritytype); switch (attribute->stopBits) { case UART_ATTR_STOPBIT_1: uartCfg->stopbits = TLS_UART_ONE_STOPBITS; break; case UART_ATTR_STOPBIT_2: uartCfg->stopbits = TLS_UART_TWO_STOPBITS; break; default: uartCfg->stopbits = TLS_UART_ONE_STOPBITS; break; } tls_uart_set_stop_bits(uartId, uartCfg->stopbits); if (attribute->rts && attribute->cts) { uartCfg->flow_ctrl = TLS_UART_FLOW_CTRL_HARDWARE; } else { uartCfg->flow_ctrl = TLS_UART_FLOW_CTRL_NONE; } tls_uart_set_fc_status(uartId, uartCfg->flow_ctrl); return HDF_SUCCESS; } static int32_t UartHostDevGetAttribute(struct UartHost *host, struct UartAttribute *attribute) { HDF_LOGI("%s: Enter", __func__); struct UartDevice *uartDevice = NULL; tls_uart_options_t *uartCfg = NULL; if (host == NULL || attribute == NULL || host->priv == NULL) { HDF_LOGE("%s: invalid parameter", __func__); return HDF_ERR_INVALID_PARAM; } uartDevice = (struct UartDevice *)host->priv; uartCfg = &uartDevice->config; if (uartCfg == NULL) { HDF_LOGE("%s: config is NULL", __func__); return HDF_ERR_INVALID_OBJECT; } attribute->parity = uartCfg->paritytype; switch (uartCfg->stopbits) { case TLS_UART_ONE_STOPBITS: attribute->stopBits = UART_ATTR_STOPBIT_1; break; case TLS_UART_TWO_STOPBITS: attribute->stopBits = UART_ATTR_STOPBIT_2; break; default: attribute->stopBits = UART_ATTR_STOPBIT_1; break; } switch (uartCfg->flow_ctrl) { case TLS_UART_FLOW_CTRL_HARDWARE: attribute->rts = 1; attribute->cts = 1; break; default: attribute->rts = 0; attribute->cts = 0; break; } return HDF_SUCCESS; } static int32_t UartHostDevSetTransMode(struct UartHost *host, enum UartTransMode mode) { HDF_LOGI("%s: Enter", __func__); struct UartDevice *uartDevice = NULL; uint32_t uartId; if (host == NULL || host->priv == NULL) { HDF_LOGE("%s: invalid parameter", __func__); return HDF_ERR_INVALID_PARAM; } uartDevice = (struct UartDevice *)host->priv; uartId = uartDevice->uartId; switch (mode) { case UART_MODE_RD_BLOCK: g_uartCtx[uartId].isBlock = true; break; case UART_MODE_RD_NONBLOCK: g_uartCtx[uartId].isBlock = false; break; case UART_MODE_DMA_RX_EN: g_uartCtx[uartId].rxDMA = true; break; case UART_MODE_DMA_RX_DIS: g_uartCtx[uartId].rxDMA = false; break; case UART_MODE_DMA_TX_EN: g_uartCtx[uartId].txDMA = true; break; case UART_MODE_DMA_TX_DIS: g_uartCtx[uartId].txDMA = false; break; default: HDF_LOGE("%s: UartTransMode(%d) invalid", __func__, mode); break; } return HDF_SUCCESS; }