/* * Copyright (c) 2022 ASR Microelectronics (Shanghai) Co., Ltd. All rights reserved. * * HDF 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 "uart/uart_core.h" #include "device_resource_if.h" #include "hdf_base.h" #include "hdf_log.h" #include "los_sem.h" #include "osal_mem.h" #include "duet_pinmux.h" #include "duet_uart.h" #define ASR_UART_NUM DUET_UART_NUM #define asr_uart_config_t duet_uart_config_t #define asr_uart_dev_t duet_uart_dev_t #define asr_uart_struct_init duet_uart_struct_init #define asr_uart_dma_config duet_uart_dma_config #define asr_uart_init duet_uart_init #define asr_uart_send duet_uart_send #define asr_uart_finalize duet_uart_finalize #define asr_uart_start duet_uart_start #define asr_uart_stop duet_uart_stop #define asr_uart_set_callback duet_uart_set_callback #define asr_uart_calc_baud duet_uart_calc_baud #define asr_uart_interrupt_config duet_uart_interrupt_config #define asr_uart_clear_interrupt duet_uart_clear_interrupt #define asr_uart_get_raw_interrupt_status duet_uart_get_raw_interrupt_status #define asr_uart_get_interrupt_status duet_uart_get_interrupt_status #define asr_uart_get_flag_status duet_uart_get_flag_status #define asr_uart_callback_func duet_uart_callback_func #define asr_pinmux_config duet_pinmux_config #define HDF_LOG_TAG uart_asr #define DEFAULT_BAUDRATE 115200 #define DEFAULT_DATABITS UART_ATTR_DATABIT_8 #define DEFAULT_STOPBITS UART_ATTR_STOPBIT_1 #define DEFAULT_PARITY UART_ATTR_PARITY_NONE #define CONFIG_MAX_BAUDRATE 921600 #define UART_STATE_NOT_OPENED 0 #define UART_STATE_OPENING 1 #define UART_STATE_USEABLE 2 #define UART_STATE_SUSPENED 3 #define UART_FLG_DMA_RX (1 << 0) #define UART_FLG_DMA_TX (1 << 1) #define UART_FLG_RD_BLOCK (1 << 2) #define UART_TRANS_TIMEOUT 1000 #define UART_RX_BUF_LEN 512 typedef int32_t (*app_uart_cfg_handler_t)(struct UartDriverData *udd); struct UartResource { uint32_t port; uint32_t pin_tx_pin; uint32_t pin_tx_mux; uint32_t pin_rx_pin; uint32_t pin_rx_mux; uint32_t tx_rx; }; struct UartDriverData { asr_uart_dev_t params; struct UartAttribute attr; struct UartResource resource; app_uart_cfg_handler_t config; int32_t count; int32_t state; uint32_t flags; }; static uint32_t g_uartTxMutex[ASR_UART_NUM]; static uint32_t g_uartRxMutex[ASR_UART_NUM]; static uint8_t *rx_buf[ASR_UART_NUM]; static uint16_t rx_head[ASR_UART_NUM]; static uint16_t rx_tail[ASR_UART_NUM]; static void Uart0Callback(char data); static void Uart1Callback(char data); static void Uart2Callback(char data); static const asr_uart_callback_func g_evtHandler[ASR_UART_NUM] = { Uart0Callback, Uart1Callback, Uart2Callback }; static void Uart0Callback(char data) { uint8_t *dst = rx_buf[UART0_INDEX]; if (dst) { dst[rx_head[UART0_INDEX]++] = (uint8_t)data; rx_head[UART0_INDEX] %= UART_RX_BUF_LEN; } } static void Uart1Callback(char data) { uint8_t *dst = rx_buf[UART1_INDEX]; if (dst) { dst[rx_head[UART1_INDEX]++] = (uint8_t)data; rx_head[UART1_INDEX] %= UART_RX_BUF_LEN; } } static void Uart2Callback(char data) { uint8_t *dst = rx_buf[UART2_INDEX]; if (dst) { dst[rx_head[UART2_INDEX]++] = (uint8_t)data; rx_head[UART2_INDEX] %= UART_RX_BUF_LEN; } } static uint32_t GetUartDataBits(uint32_t attrDataBits) { uint32_t dataBits; switch (attrDataBits) { case UART_ATTR_DATABIT_5: dataBits = DATA_5BIT; break; case UART_ATTR_DATABIT_6: dataBits = DATA_6BIT; break; case UART_ATTR_DATABIT_7: dataBits = DATA_7BIT; break; case UART_ATTR_DATABIT_8: dataBits = DATA_8BIT; break; default: dataBits = DATA_8BIT; break; } return dataBits; } static uint32_t GetUartStopBits(uint32_t attrStopBits) { uint32_t stopBits; switch (attrStopBits) { case UART_ATTR_STOPBIT_1: stopBits = STOP_1BIT; break; case UART_ATTR_STOPBIT_2: stopBits = STOP_2BITS; break; default: stopBits = STOP_1BIT; break; } return stopBits; } static uint32_t GetUartParity(uint32_t attrParity) { uint32_t parity; switch (attrParity) { case UART_ATTR_PARITY_NONE: parity = PARITY_NO; break; case UART_ATTR_PARITY_ODD: parity = PARITY_ODD; break; case UART_ATTR_PARITY_EVEN: parity = PARITY_EVEN; break; default: parity = PARITY_NO; break; } return parity; } static uint32_t GetUartFlowControl(uint32_t rts, uint32_t cts) { uint32_t flow_control; if (!rts && !cts) { flow_control = FLOW_CTRL_DISABLED; } else if (rts && cts) { flow_control = FLOW_CTRL_CTS_RTS; } else if (rts) { flow_control = FLOW_CTRL_RTS; } else { flow_control = FLOW_CTRL_CTS; } return flow_control; } static int32_t Asr582xUartConfig(struct UartDriverData *udd) { uint32_t ret; asr_uart_dev_t *params = NULL; if (udd == NULL) { return HDF_FAILURE; } asr_pinmux_config(udd->resource.pin_tx_pin, udd->resource.pin_tx_mux); asr_pinmux_config(udd->resource.pin_rx_pin, udd->resource.pin_rx_mux); params = &udd->params; params->port = udd->resource.port; params->config.data_width = GetUartDataBits(udd->attr.dataBits); params->config.stop_bits = GetUartStopBits(udd->attr.stopBits); params->config.parity = GetUartParity(udd->attr.parity); params->config.flow_control = GetUartFlowControl(udd->attr.rts, udd->attr.cts); params->config.mode = udd->resource.tx_rx; params->priv = (void *)g_evtHandler[udd->resource.port]; ret = asr_uart_init(params); if (ret != 0) { HDF_LOGE("%s , app uart init failed\r\n", __func__); return HDF_FAILURE; } return HDF_SUCCESS; } static int32_t UartHostDevRead(struct UartHost *host, uint8_t *data, uint32_t size) { uint32_t recv_len = 0; struct UartDriverData *udd = NULL; uint8_t port = 0; uint8_t *src = NULL; if ((host == NULL) || (host->priv == NULL) || (data == NULL)) { HDF_LOGE("%s: invalid parameter", __func__); return HDF_ERR_INVALID_PARAM; } udd = (struct UartDriverData *)host->priv; port = udd->resource.port; src = rx_buf[port]; if (udd->state != UART_STATE_USEABLE) { HDF_LOGE("%s: uart_%d not useable", __func__, port); return HDF_FAILURE; } LOS_MuxPend(g_uartRxMutex[port], LOS_WAIT_FOREVER); if (udd->flags & UART_FLG_RD_BLOCK) { while (recv_len != size) { if (rx_head[port] != rx_tail[port]) { data[recv_len++] = src[rx_tail[port]++]; rx_tail[port] %= UART_RX_BUF_LEN; } } } else { while ((recv_len != size) && (rx_head[port] != rx_tail[port])) { data[recv_len++] = src[rx_tail[port]++]; rx_tail[port] %= UART_RX_BUF_LEN; } } LOS_MuxPost(g_uartRxMutex[port]); return recv_len; } static int32_t UartHostDevWrite(struct UartHost *host, uint8_t *data, uint32_t size) { int32_t ret; struct UartDriverData *udd = NULL; if ((host == NULL) || (host->priv == NULL) || (data == NULL)) { HDF_LOGE("%s: invalid parameter", __func__); return HDF_ERR_INVALID_PARAM; } udd = (struct UartDriverData *)host->priv; if (udd->state != UART_STATE_USEABLE) { HDF_LOGE("%s: uart_%d not useable", __func__, udd->resource.port); return HDF_FAILURE; } LOS_MuxPend(g_uartTxMutex[udd->resource.port], LOS_WAIT_FOREVER); ret = asr_uart_send(&udd->params, data, size, UART_TRANS_TIMEOUT); if (ret != 0) { LOS_MuxPost(g_uartTxMutex[udd->resource.port]); HDF_LOGE("%s: uart_%d send %d data failed", __func__, udd->resource.port, size); return HDF_FAILURE; } LOS_MuxPost(g_uartTxMutex[udd->resource.port]); return HDF_SUCCESS; } static int32_t UartHostDevGetBaud(struct UartHost *host, uint32_t *baudRate) { struct UartDriverData *udd = NULL; if (host == NULL || host->priv == NULL || baudRate == NULL) { HDF_LOGE("%s: invalid parameter", __func__); return HDF_ERR_INVALID_PARAM; } udd = (struct UartDriverData *)host->priv; if (udd->state != UART_STATE_USEABLE) { HDF_LOGE("%s: uart_%d not useable", __func__, udd->resource.port); return HDF_FAILURE; } *baudRate = udd->params.config.baud_rate; return HDF_SUCCESS; } static int32_t UartHostDevSetBaud(struct UartHost *host, uint32_t baudRate) { struct UartDriverData *udd = NULL; if (host == NULL || host->priv == NULL) { HDF_LOGE("%s: invalid parameter", __func__); return HDF_ERR_INVALID_PARAM; } udd = (struct UartDriverData *)host->priv; if (udd->state != UART_STATE_USEABLE) { HDF_LOGE("%s: uart_%d not useable", __func__, udd->resource.port); return HDF_FAILURE; } if ((baudRate > 0) && (baudRate <= CONFIG_MAX_BAUDRATE)) { udd->params.config.baud_rate = baudRate; if (udd->config == NULL) { HDF_LOGE("%s: not support", __func__); return HDF_ERR_NOT_SUPPORT; } if (udd->config(udd) != HDF_SUCCESS) { HDF_LOGE("%s: config baudrate %d failed", __func__, baudRate); return HDF_FAILURE; } } else { HDF_LOGE("%s: invalid baudrate, which is:%d", __func__, baudRate); return HDF_FAILURE; } return HDF_SUCCESS; } static int32_t UartHostDevGetAttribute(struct UartHost *host, struct UartAttribute *attribute) { struct UartDriverData *udd = NULL; if (host == NULL || host->priv == NULL || attribute == NULL) { HDF_LOGE("%s: invalid parameter", __func__); return HDF_ERR_INVALID_PARAM; } udd = (struct UartDriverData *)host->priv; if (udd->state != UART_STATE_USEABLE) { return HDF_FAILURE; } *attribute = udd->attr; return HDF_SUCCESS; } static int32_t UartHostDevSetAttribute(struct UartHost *host, struct UartAttribute *attribute) { struct UartDriverData *udd = NULL; if (host == NULL || host->priv == NULL || attribute == NULL) { HDF_LOGE("%s: invalid parameter", __func__); return HDF_ERR_INVALID_PARAM; } udd = (struct UartDriverData *)host->priv; if (udd->state != UART_STATE_USEABLE) { HDF_LOGE("%s: uart_%d not useable", __func__, udd->resource.port); return HDF_FAILURE; } udd->attr = *attribute; if (udd->config == NULL) { HDF_LOGE("%s: not support", __func__); return HDF_ERR_NOT_SUPPORT; } if (udd->config(udd) != HDF_SUCCESS) { HDF_LOGE("%s: config failed", __func__); return HDF_FAILURE; } return HDF_SUCCESS; } static int32_t UartHostDevSetTransMode(struct UartHost *host, enum UartTransMode mode) { struct UartDriverData *udd = NULL; if (host == NULL || host->priv == NULL) { HDF_LOGE("%s: invalid parameter", __func__); return HDF_ERR_INVALID_PARAM; } udd = (struct UartDriverData *)host->priv; if (udd->state != UART_STATE_USEABLE) { HDF_LOGE("%s: uart_%d not useable", __func__, udd->resource.port); return HDF_FAILURE; } if (UART_MODE_RD_BLOCK == mode) { udd->flags |= UART_FLG_RD_BLOCK; } else if (UART_MODE_RD_NONBLOCK == mode) { udd->flags &= (~UART_FLG_RD_BLOCK); } else { HDF_LOGE("%s: uart_%d not support mode:%d", __func__, udd->resource.port, mode); return HDF_FAILURE; } return HDF_SUCCESS; } static int32_t UartDevSemInit(uint32_t id) { uint32_t uwRet; uwRet = LOS_MuxCreate(&g_uartTxMutex[id]); if (uwRet != LOS_OK) { return HDF_FAILURE; } uwRet = LOS_MuxCreate(&g_uartRxMutex[id]); if (uwRet != LOS_OK) { return HDF_FAILURE; } return HDF_SUCCESS; } static void UartDevSemDeinit(uint32_t id) { if (g_uartTxMutex[id] != 0) { LOS_MuxDelete(g_uartTxMutex[id]); } if (g_uartRxMutex[id] != 0) { LOS_MuxDelete(g_uartRxMutex[id]); } g_uartTxMutex[id] = 0; g_uartRxMutex[id] = 0; } static int32_t UartHostDevInit(struct UartHost *host) { struct UartDriverData *udd = NULL; uint32_t ret; uint8_t *ptxBuf = NULL; if (host == NULL || host->priv == NULL) { HDF_LOGE("%s: invalid parameter", __func__); return HDF_ERR_INVALID_PARAM; } udd = (struct UartDriverData *)host->priv; if (udd->resource.port >= ASR_UART_NUM) { HDF_LOGE("%s: uart id is greater than the maximum", __func__); return HDF_ERR_INVALID_PARAM; } if (udd->state == UART_STATE_NOT_OPENED) { udd->state = UART_STATE_OPENING; ptxBuf = (uint8_t *)OsalMemCalloc(UART_RX_BUF_LEN); if (ptxBuf == NULL) { HDF_LOGE("%s: alloc tx buffer failed", __func__); return HDF_ERR_MALLOC_FAIL; } ret = UartDevSemInit(udd->resource.port); if (ret != HDF_SUCCESS) { HDF_LOGE("%s: uart semaphor init failed", __func__); UartDevSemDeinit(udd->resource.port); return HDF_FAILURE; } rx_buf[udd->resource.port] = ptxBuf; udd->config = Asr582xUartConfig; if (udd->config(udd) != HDF_SUCCESS) { UartDevSemDeinit(udd->resource.port); (void)OsalMemFree(rx_buf[udd->resource.port]); rx_buf[udd->resource.port] = NULL; return HDF_FAILURE; } } udd->state = UART_STATE_USEABLE; udd->count++; return HDF_SUCCESS; } static int32_t UartHostDevDeinit(struct UartHost *host) { struct UartDriverData *udd = NULL; if (host == NULL || host->priv == NULL) { HDF_LOGE("%s: invalid parameter", __func__); return HDF_ERR_INVALID_PARAM; } udd = (struct UartDriverData *)host->priv; if ((--udd->count) != 0) { return HDF_SUCCESS; } asr_uart_finalize(&udd->params); UartDevSemDeinit(udd->resource.port); if (rx_buf[udd->resource.port] != NULL) { (void)OsalMemFree(rx_buf[udd->resource.port]); rx_buf[udd->resource.port] = NULL; } udd->state = UART_STATE_NOT_OPENED; return HDF_SUCCESS; } struct UartHostMethod g_uartHostMethod = { .Init = UartHostDevInit, .Deinit = UartHostDevDeinit, .Read = UartHostDevRead, .Write = UartHostDevWrite, .SetBaud = UartHostDevSetBaud, .GetBaud = UartHostDevGetBaud, .SetAttribute = UartHostDevSetAttribute, .GetAttribute = UartHostDevGetAttribute, .SetTransMode = UartHostDevSetTransMode, }; static int32_t UartGetPinConfigFromHcs(struct UartDriverData *udd, const struct DeviceResourceNode *node) { uint32_t resourceData; struct DeviceResourceIface *iface = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE); if (iface == NULL || iface->GetUint32 == NULL) { HDF_LOGE("%s: face is invalid", __func__); return HDF_FAILURE; } if (iface->GetUint32(node, "port", &resourceData, 0) != HDF_SUCCESS) { HDF_LOGE("%s: read port fail", __func__); return HDF_FAILURE; } udd->resource.port = resourceData; if (iface->GetUint32(node, "pin_tx_pin", &resourceData, 0) != HDF_SUCCESS) { HDF_LOGE("%s: read pin_tx_pin fail", __func__); return HDF_FAILURE; } udd->resource.pin_tx_pin = resourceData; if (iface->GetUint32(node, "pin_tx_mux", &resourceData, 0) != HDF_SUCCESS) { HDF_LOGE("%s: read pin_tx_pin fail", __func__); return HDF_FAILURE; } udd->resource.pin_tx_mux = resourceData; if (iface->GetUint32(node, "pin_rx_pin", &resourceData, 0) != HDF_SUCCESS) { HDF_LOGE("%s: read pin_rx_pin fail", __func__); return HDF_FAILURE; } udd->resource.pin_rx_pin = resourceData; if (iface->GetUint32(node, "pin_rx_mux", &resourceData, 0) != HDF_SUCCESS) { HDF_LOGE("%s: read pin_rx_pin fail", __func__); return HDF_FAILURE; } udd->resource.pin_rx_mux = resourceData; if (iface->GetUint32(node, "tx_rx", &resourceData, 0) != HDF_SUCCESS) { HDF_LOGE("%s: read tx_rx fail", __func__); return HDF_FAILURE; } udd->resource.tx_rx = resourceData; return HDF_SUCCESS; } static int32_t UartDevAttach(struct UartHost *host, struct HdfDeviceObject *device) { int32_t ret; struct UartDriverData *udd = NULL; if (device->property == NULL) { HDF_LOGE("%s: property is null", __func__); return HDF_FAILURE; } udd = (struct UartDriverData *)OsalMemCalloc(sizeof(*udd)); if (udd == NULL) { HDF_LOGE("%s: OsalMemCalloc udd error", __func__); return HDF_ERR_MALLOC_FAIL; } ret = UartGetPinConfigFromHcs(udd, device->property); if (ret != HDF_SUCCESS) { (void)OsalMemFree(udd); return HDF_FAILURE; } udd->state = UART_STATE_NOT_OPENED; udd->config = NULL; udd->count = 0; asr_uart_struct_init(&udd->params); udd->params.port = udd->resource.port; udd->params.config.baud_rate = DEFAULT_BAUDRATE; udd->attr.dataBits = DEFAULT_DATABITS; udd->attr.stopBits = DEFAULT_STOPBITS; udd->attr.parity = DEFAULT_PARITY; host->priv = udd; host->num = udd->resource.port; return HDF_SUCCESS; } static void UartDevDetach(struct UartHost *host) { struct UartDriverData *udd = NULL; if (host->priv == NULL) { HDF_LOGE("%s: invalid parameter", __func__); return; } udd = (struct UartDriverData *)host->priv; if (udd->state != UART_STATE_NOT_OPENED) { HDF_LOGE("%s: uart driver data state invalid", __func__); return; } (void)OsalMemFree(udd); host->priv = NULL; } static int32_t HdfUartDeviceBind(struct HdfDeviceObject *device) { if (device == NULL) { return HDF_ERR_INVALID_OBJECT; } return (UartHostCreate(device) == NULL) ? HDF_FAILURE : HDF_SUCCESS; } static int32_t HdfUartDeviceInit(struct HdfDeviceObject *device) { 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_FAILURE; } ret = UartDevAttach(host, device); if (ret != HDF_SUCCESS) { HDF_LOGE("%s: attach error", __func__); return HDF_FAILURE; } host->method = &g_uartHostMethod; return ret; } static void HdfUartDeviceRelease(struct HdfDeviceObject *device) { struct UartHost *host = NULL; if (device == NULL) { HDF_LOGE("%s: device is null", __func__); return; } host = UartHostFromDevice(device); if (host == NULL) { HDF_LOGE("%s: host is null", __func__); return; } if (host->priv != NULL) { UartDevDetach(host); } UartHostDestroy(host); } struct HdfDriverEntry g_hdfUartDevice = { .moduleVersion = 1, .moduleName = "HDF_PLATFORM_UART", .Bind = HdfUartDeviceBind, .Init = HdfUartDeviceInit, .Release = HdfUartDeviceRelease, }; HDF_INIT(g_hdfUartDevice);