diff --git a/sample/config/device_info/device_info.hcs b/sample/config/device_info/device_info.hcs new file mode 100755 index 00000000..f3cd30a2 --- /dev/null +++ b/sample/config/device_info/device_info.hcs @@ -0,0 +1,18 @@ +root { + device_info { + platform :: host { + hostName = "platform_host"; + priority = 50; + device_uart :: device { + device5 :: deviceNode { + policy = 2; + priority = 10; + permission = 0660; + moduleName = "UART_SAMPLE"; + serviceName = "HDF_PLATFORM_UART_5"; + deviceMatchAttr = "sample_uart_5"; + } + } + } + } +} diff --git a/sample/config/uart/uart_config.hcs b/sample/config/uart/uart_config.hcs new file mode 100755 index 00000000..2ea8900b --- /dev/null +++ b/sample/config/uart/uart_config.hcs @@ -0,0 +1,15 @@ +root { + platform { + uart_sample { + num = 5; + base = 0x120a0000; // UART base register address + irqNum = 38; + baudrate = 115200; + uartClk = 24000000; // 24 M + wlen = 0x60; // 8 bit width + parity = 0; + stopBit = 0; + match_attr = "sample_uart_5"; + } + } +} diff --git a/sample/platform/uart/BUILD.gn b/sample/platform/uart/BUILD.gn new file mode 100755 index 00000000..9404df09 --- /dev/null +++ b/sample/platform/uart/BUILD.gn @@ -0,0 +1,14 @@ +# Copyright (c) 2021 Huawei Device Co., Ltd. +# +# 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. + +import("//build/lite/config/component/lite_component.gni") + +lite_component("hello_uart_sample") { + features = [ + "dev:hello_uart", + "dispatch:hello_uart_dispatch", + ] +} diff --git a/sample/platform/uart/Kconfig b/sample/platform/uart/Kconfig new file mode 100755 index 00000000..2a317abf --- /dev/null +++ b/sample/platform/uart/Kconfig @@ -0,0 +1,12 @@ +# Copyright (c) 2021 Huawei Device Co., Ltd. +# +# 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. + +config DRIVERS_HDF_PLATFORM_UART_SAMPLE + bool "Enable HDF platform uart sample driver" + default n + depends on DRIVERS_HDF_PLATFORM + help + Answer Y to enable HDF platform uart sample driver. diff --git a/sample/platform/uart/dev/BUILD.gn b/sample/platform/uart/dev/BUILD.gn new file mode 100755 index 00000000..25f7815c --- /dev/null +++ b/sample/platform/uart/dev/BUILD.gn @@ -0,0 +1,41 @@ +# Copyright (c) 2021 Huawei Device Co., Ltd. +# +# 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. + +HDF_FRAMEWORKS = "//drivers/framework" + +executable("hello_uart") { + sources = [ "hello_uart_dev.c" ] + + include_dirs = [ + "$HDF_FRAMEWORKS/ability/sbuf/include", + "$HDF_FRAMEWORKS/core/shared/include", + "$HDF_FRAMEWORKS/core/host/include", + "$HDF_FRAMEWORKS/core/master/include", + "$HDF_FRAMEWORKS/include/core", + "$HDF_FRAMEWORKS/include/utils", + "$HDF_FRAMEWORKS/utils/include", + "$HDF_FRAMEWORKS/include/osal", + "//drivers/adapter/uhdf/posix/include", + "//third_party/bounds_checking_function/include", + "//base/hiviewdfx/hilog_lite/interfaces/native/innerkits", + ] + + deps = [ + "//base/hiviewdfx/hilog_lite/frameworks/featured:hilog_shared", + "//drivers/adapter/uhdf/manager:hdf_core", + "//drivers/adapter/uhdf/posix:hdf_posix_osal", + ] + + public_deps = [ "//third_party/bounds_checking_function:libsec_shared" ] + defines = [ "__USER__" ] + + cflags = [ + "-Wall", + "-Wextra", + "-Wno-format", + "-Wno-format-extra-args", + ] +} diff --git a/sample/platform/uart/dev/hello_uart_dev.c b/sample/platform/uart/dev/hello_uart_dev.c new file mode 100755 index 00000000..ffacc5df --- /dev/null +++ b/sample/platform/uart/dev/hello_uart_dev.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * 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 +#include +#include +#include "hdf_log.h" + +#define HDF_LOG_TAG hello_uart +#define INFO_SIZE 16 + +int main(void) +{ + int ret; + int fd; + const char info[INFO_SIZE] = {" HELLO UART! "}; + + fd = open("/dev/uartdev-5", O_RDWR); + if (fd < 0) { + HDF_LOGE("uartdev-5 open failed %d", fd); + return -1; + } + ret = write(fd, info, INFO_SIZE); + if (ret != 0) { + HDF_LOGE("write uartdev-5 ret is %d", ret); + } + ret = close(fd); + if (ret != 0) { + HDF_LOGE("uartdev-5 close failed %d", fd); + return -1; + } + return ret; +} \ No newline at end of file diff --git a/sample/platform/uart/dispatch/BUILD.gn b/sample/platform/uart/dispatch/BUILD.gn new file mode 100755 index 00000000..6813ed10 --- /dev/null +++ b/sample/platform/uart/dispatch/BUILD.gn @@ -0,0 +1,44 @@ +# Copyright (c) 2021 Huawei Device Co., Ltd. +# +# 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. + +HDF_FRAMEWORKS = "//drivers/framework" + +executable("hello_uart_dispatch") { + sources = [ + "hello_uart_dispatch.c", + "uart_if.c", + ] + + include_dirs = [ + "$HDF_FRAMEWORKS/ability/sbuf/include", + "$HDF_FRAMEWORKS/core/shared/include", + "$HDF_FRAMEWORKS/core/host/include", + "$HDF_FRAMEWORKS/core/master/include", + "$HDF_FRAMEWORKS/include/core", + "$HDF_FRAMEWORKS/include/utils", + "$HDF_FRAMEWORKS/utils/include", + "$HDF_FRAMEWORKS/include/osal", + "//drivers/adapter/uhdf/posix/include", + "//third_party/bounds_checking_function/include", + "//base/hiviewdfx/hilog_lite/interfaces/native/innerkits", + ] + + deps = [ + "//base/hiviewdfx/hilog_lite/frameworks/featured:hilog_shared", + "//drivers/adapter/uhdf/manager:hdf_core", + "//drivers/adapter/uhdf/posix:hdf_posix_osal", + ] + + public_deps = [ "//third_party/bounds_checking_function:libsec_shared" ] + defines = [ "__USER__" ] + + cflags = [ + "-Wall", + "-Wextra", + "-Wno-format", + "-Wno-format-extra-args", + ] +} diff --git a/sample/platform/uart/dispatch/hello_uart_dispatch.c b/sample/platform/uart/dispatch/hello_uart_dispatch.c new file mode 100755 index 00000000..ea123de1 --- /dev/null +++ b/sample/platform/uart/dispatch/hello_uart_dispatch.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * 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 +#include "hdf_log.h" +#include "osal_mem.h" +#include "uart_if.h" + +#define HDF_LOG_TAG hello_uart_dispatch +#define UART_PORT 5 + +int main() +{ + const char *info = " HELLO UART! "; + + struct DevHandle *handle = UartOpen(UART_PORT); + if (handle == NULL) { + HDF_LOGE("Failed to open uart %d", UART_PORT); + return HDF_FAILURE; + } + + int ret = UartWrite(handle, (uint8_t *)info, strlen(info)); + if (ret != HDF_SUCCESS) { + HDF_LOGE("Failed to send data to uart"); + } + + UartClose(handle); + return ret; +} \ No newline at end of file diff --git a/sample/platform/uart/dispatch/uart_if.c b/sample/platform/uart/dispatch/uart_if.c new file mode 100755 index 00000000..9fdb158c --- /dev/null +++ b/sample/platform/uart/dispatch/uart_if.c @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * 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_if.h" +#include "hdf_log.h" +#include "osal_mem.h" +#include "hdf_io_service_if.h" + +#define HDF_LOG_TAG uart_if + +struct DevHandle *UartOpen(uint32_t port) +{ + int32_t ret; + struct DevHandle *handle = NULL; + char *serviceName = NULL; + + handle = (struct DevHandle *)OsalMemCalloc(sizeof(struct DevHandle)); + if (handle == NULL) { + HDF_LOGE("Failed to OsalMemCalloc handle"); + return NULL; + } + + serviceName = (char *)OsalMemCalloc(sizeof(char) * (MAX_DEV_NAME_SIZE + 1)); + if (serviceName == NULL) { + HDF_LOGE("Failed to OsalMemCalloc serviceName"); + OsalMemFree(handle); + return NULL; + } + ret = snprintf_s(serviceName, MAX_DEV_NAME_SIZE + 1, MAX_DEV_NAME_SIZE, UART_DEV_SERVICE_NAME_PREFIX, port); + if (ret < 0) { + HDF_LOGE("Failed to snprintf_s"); + OsalMemFree(handle); + OsalMemFree(serviceName); + return NULL; + } + + struct HdfIoService *service = HdfIoServiceBind(serviceName); + if (service == NULL) { + HDF_LOGE("Failed to get service %s", serviceName); + OsalMemFree(handle); + OsalMemFree(serviceName); + return NULL; + } + OsalMemFree(serviceName); + handle->object = service; + return handle; +} + +int32_t UartWrite(struct DevHandle *handle, uint8_t *data, uint32_t size) +{ + int ret; + struct HdfIoService *service = NULL; + + if (handle == NULL || handle->object == NULL) { + HDF_LOGE("handle or handle->object is NULL"); + return HDF_FAILURE; + } + + struct HdfSBuf *sBuf = HdfSBufObtainDefaultSize(); + if (sBuf == NULL) { + HDF_LOGE("Failed to obtain sBuf"); + return HDF_FAILURE; + } + + if (!HdfSbufWriteBuffer(sBuf, data, size)) { + HDF_LOGE("Failed to write sbuf"); + HdfSBufRecycle(sBuf); + return HDF_FAILURE; + } + + service = (struct HdfIoService *)handle->object; + ret = service->dispatcher->Dispatch(&service->object, UART_WRITE, sBuf, NULL); + if (ret != HDF_SUCCESS) { + HDF_LOGE("Failed to send service call"); + } + HdfSBufRecycle(sBuf); + return ret; +} + +void UartClose(struct DevHandle *handle) +{ + struct HdfIoService *service = NULL; + + if (handle == NULL || handle->object == NULL) { + HDF_LOGE("handle or handle->object is NULL"); + return; + } + service = (struct HdfIoService *)handle->object; + HdfIoServiceRecycle(service); + OsalMemFree(handle); +} diff --git a/sample/platform/uart/dispatch/uart_if.h b/sample/platform/uart/dispatch/uart_if.h new file mode 100755 index 00000000..61ca0ad3 --- /dev/null +++ b/sample/platform/uart/dispatch/uart_if.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * 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. + */ + +#ifndef UART_IF_H +#define UART_IF_H + +#include + +#define UART_DEV_SERVICE_NAME_PREFIX "HDF_PLATFORM_UART_%d" +#define MAX_DEV_NAME_SIZE 32 + +enum { + UART_WRITE = 1 +}; + +struct DevHandle { + void *object; +}; + +struct DevHandle *UartOpen(uint32_t port); +int32_t UartWrite(struct DevHandle *handle, uint8_t *data, uint32_t size); +void UartClose(struct DevHandle *handle); + +#endif // UART_IF_H \ No newline at end of file diff --git a/sample/platform/uart/include/buf_fifo.h b/sample/platform/uart/include/buf_fifo.h new file mode 100755 index 00000000..ba9dab7d --- /dev/null +++ b/sample/platform/uart/include/buf_fifo.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * 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. + */ + +#ifndef BUF_FIFO_H +#define BUF_FIFO_H + +#include +#include +#include + +struct BufferFifo { + volatile uint32_t readPosition; + volatile uint32_t writePosition; + uint16_t bufSizeMask; + uint8_t *buffer; +}; + +static inline uint16_t BufferFifoGetDataSize(struct BufferFifo *fifo) +{ + return (fifo->writePosition - fifo->readPosition); +} + +static inline bool IsPowerOfTwo(int num) +{ + return (num > 0) && (num & (num - 1)) == 0; +} + +bool BufferFifoInit(struct BufferFifo *fifo, uint8_t *buf, uint16_t bufSize); + +#endif // BUF_FIFO_H + diff --git a/sample/platform/uart/include/uart_dev_sample.h b/sample/platform/uart/include/uart_dev_sample.h new file mode 100755 index 00000000..87150de3 --- /dev/null +++ b/sample/platform/uart/include/uart_dev_sample.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * 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. + */ + +#ifndef UART_DEV_SAMPLE_H +#define UART_DEV_SAMPLE_H + +#include "sys/ioctl.h" +#include "uart_core.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#define UART_IOC_MAGIC 'u' + +/* baudrate config */ +#define UART_CFG_BAUDRATE _IO(UART_IOC_MAGIC, 1) + +void AddUartDevice(struct UartHost *host); +void RemoveUartDevice(struct UartHost *host); + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#endif /* UART_DEV_SAMPLE_H */ diff --git a/sample/platform/uart/include/uart_dispatch_sample.h b/sample/platform/uart/include/uart_dispatch_sample.h new file mode 100755 index 00000000..42ca3c5b --- /dev/null +++ b/sample/platform/uart/include/uart_dispatch_sample.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * 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. + */ + +#ifndef UART_DISPATCH_SAMPLE_H +#define UART_DISPATCH_SAMPLE_H + +#include "uart_pl011_sample.h" + +enum { + UART_WRITE = 1 +}; + +int32_t SampleDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data, struct HdfSBuf *reply); + +#endif // UART_DISPATCH_SAMPLE_H diff --git a/sample/platform/uart/include/uart_pl011_sample.h b/sample/platform/uart/include/uart_pl011_sample.h new file mode 100755 index 00000000..ae2f6126 --- /dev/null +++ b/sample/platform/uart/include/uart_pl011_sample.h @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * 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. + */ + +#ifndef UART_PL011_SAMPLE_H +#define UART_PL011_SAMPLE_H + +#include +#include +#include "hdf_device_desc.h" +#include "buf_fifo.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct UartRegisterMap { + volatile uint32_t dr; /* Offset: 0x000 TYPE: (RW) Data register */ + union { + volatile uint32_t rsr; /* Offset: 0x004 TYPE: (RO) Receive status register */ + volatile uint32_t ecr; /* Offset: 0x004 TYPE: (WO) Error clear register */ + }; + volatile uint32_t reserved0[4]; /* Offset: 0x008-0x014 Reserved */ + volatile uint32_t fr; /* Offset: 0x018 TYPE: (RO) Flag register */ + volatile uint32_t reserved1; /* Offset: 0x01C Reserved */ + volatile uint32_t ilpr; /* Offset: 0x020 TYPE: (RW) IrDA low-power counter register */ + volatile uint32_t ibrd; /* Offset: 0x024 TYPE: (RW) Integer baud rate register */ + volatile uint32_t fbrd; /* Offset: 0x028 TYPE: (RW) Fractional baud rate register */ + volatile uint32_t lcr; /* Offset: 0x02C TYPE: (RW) Line control register */ + volatile uint32_t cr; /* Offset: 0x030 TYPE: (RW) Control register */ + volatile uint32_t ifls; /* Offset: 0x034 TYPE: (RW) Interrupt FIFO level select register */ + volatile uint32_t imsc; /* Offset: 0x038 TYPE: (RW) Interrupt mask set/clear register */ + volatile uint32_t ris; /* Offset: 0x03C TYPE: (RO) Raw interrupt status register */ + volatile uint32_t mis; /* Offset: 0x040 TYPE: (RO) Masked interrupt status register */ + volatile uint32_t icr; /* Offset: 0x044 TYPE: (WO) Interrupt clear register */ + volatile uint32_t dmacr; /* Offset: 0x048 TYPE: (RW) DMA control register */ +}; + +struct UartResource { + uint32_t num; /* UART port num */ + uint32_t base; /* UART PL011 base address */ + uint32_t irqNum; /* UART PL011 IRQ num */ + uint32_t baudrate; /* Default baudrate */ + uint32_t wlen; /* Default word length */ + uint32_t parity; /* Default parity */ + uint32_t stopBit; /* Default stop bits */ + uint32_t uartClk; /* UART clock */ + unsigned long physBase; +}; + +enum UartDeviceState { + UART_DEVICE_UNINITIALIZED = 0x0u, + UART_DEVICE_INITIALIZED = 0x1u, +}; + +struct UartDevice { + struct IDeviceIoService ioService; + struct UartResource resource; + enum UartDeviceState state; /* UART State */ + uint32_t uartClk; /* UART clock */ + uint32_t baudrate; /* Baudrate */ + struct BufferFifo rxFifo; +}; + +/* Receive Status Register/Error Clear Register data */ +#define UART_PL011_RSR_FRAMING_ERROR_MASK (1 << 0x0u) /* Framing error bit mask */ +#define UART_PL011_RSR_PARITY_ERROR_MASK (1 << 0x1u) /* Parity error bit mask */ +#define UART_PL011_RSR_BREAK_ERROR_MASK (1 << 0x2u) /* Break error bit mask */ +#define UART_PL011_RSR_OVERRUN_ERROR_MASK (1 << 0x3u) /* Overrun error bit mask */ + +/* Receive Status Register Error Mask */ +#define UART_PL011_RSR_RX_ERROR_MASK ( \ + UART_PL011_RSR_FRAMING_ERROR_MASK \ + | UART_PL011_RSR_PARITY_ERROR_MASK \ + | UART_PL011_RSR_BREAK_ERROR_MASK \ + | UART_PL011_RSR_OVERRUN_ERROR_MASK) + +#define UART_PL011_FR_CTS_MASK (1 << 0x0u) /* Clear to send bit mask */ +#define UART_PL011_FR_DSR_MASK (1 << 0x1u) /* Data set ready bit mask */ +#define UART_PL011_FR_DCD_MASK (1 << 0x2u) /* Data carrier detect bit mask */ +#define UART_PL011_FR_BUSY_MASK (1 << 0x3u) /* UART busy bit mask */ +#define UART_PL011_FR_RX_FIFO_EMPTY_MASK (1 << 0x4u) /* Receive FIFO empty bit mask */ +#define UART_PL011_FR_TX_FIFO_FULL_MASK (1 << 0x5u) /* Transmit FIFO full bit mask */ +#define UART_PL011_FR_RX_FIFO_FULL_MASK (1 << 0x6u) /* Receive FIFO full bit mask */ +#define UART_PL011_FR_TX_FIFO_EMPTY_MASK (1 << 0x7u) /* Transmit FIFO empty. bit mask */ +#define UART_PL011_FR_RI_MASK (1 << 0x8u) /* Ring indicator bit mask */ + +/* PL011 Line Control Register Data bits */ +#define UART_PL011_LCR_H_BRK_MASK (1 << 0x0u) /* Send Break bit mask */ +#define UART_PL011_LCR_H_PEN_MASK (1 << 0x1u) /* Parity enable bit mask */ +#define UART_PL011_LCR_H_EPS_MASK (1 << 0x2u) /* Even parity select bit mask . */ +#define UART_PL011_LCR_H_FEN_MASK (1 << 0x4u) /* Enable FIFOs bit mask */ +#define UART_PL011_LCR_H_SPS_MASK (1 << 0x7u) /* Stick parity select bit mask */ + +#define UART_PL011_LCR_H_WLEN_BIT_OFFSET 0x5u /* Word length bit offset */ +#define UART_PL011_LCR_H_WLEN_MASK ( \ + 0x3u << UART_PL011_LCR_H_WLEN_BIT_OFFSET) + +#define UART_PL011_WLEN_5BITS (0x0u << UART_PL011_LCR_H_WLEN_BIT_OFFSET) +#define UART_PL011_WLEN_6BITS (0x1u << UART_PL011_LCR_H_WLEN_BIT_OFFSET) +#define UART_PL011_WLEN_7BITS (0x2u << UART_PL011_LCR_H_WLEN_BIT_OFFSET) +#define UART_PL011_WLEN_8BITS (0x3u << UART_PL011_LCR_H_WLEN_BIT_OFFSET) + +#define UART_PL011_NONE_PARITY_CHECKED 0 + +#define UART_PL011_LCR_H_STP2_BIT_OFFSET 0x3u /* Two stop bits select */ + +#define UART_PL011_STOPBIT_1 (0x0u << UART_PL011_LCR_H_STP2_BIT_OFFSET) +#define UART_PL011_STOPBIT_2 (0x1u << UART_PL011_LCR_H_STP2_BIT_OFFSET) + +#define UART_PL011_LCR_H_PARITY_MASK ( \ + UART_PL011_LCR_H_PEN_MASK \ + | UART_PL011_LCR_H_EPS_MASK \ + | UART_PL011_LCR_H_SPS_MASK) + +#define UART_PL011_LCR_H_STOPBIT_MASK (0x1u << UART_PL011_LCR_H_STP2_BIT_OFFSET) + +#define UART_PL011_DATA_FORMAT_MASK ( \ + UART_PL011_LCR_H_PARITY_MASK \ + | UART_PL011_LCR_H_STOPBIT_MASK \ + | UART_PL011_LCR_H_WLEN_MASK) + +/* Control Register */ +#define UART_PL011_CR_UARTEN_MASK (0x1u << 0x0u) /* Uart enable bit mask */ +#define UART_PL011_CR_SIREN_MASK (0x1u << 0x1u) /* Sir enable bit mask */ +#define UART_PL011_CR_SIRLP_MASK (0x1u << 0x2u) /* SIR low-power IrDA mode bit mask */ +#define UART_PL011_CR_LBE_MASK (0x1u << 0x7u) /* Loopback enable bit mask */ +#define UART_PL011_CR_TXE_MASK (0x1u << 0x8u) /* Transmit enable bit mask */ +#define UART_PL011_CR_RXE_MASK (0x1u << 0x9u) /* Receive enable bit mask */ +#define UART_PL011_CR_DTR_MASK (0x1u << 0xAu) /* Data transmit ready.bit mask */ +#define UART_PL011_CR_RTS_MASK (0x1u << 0xBu) /* Request to send bit mask */ +#define UART_PL011_CR_OUT1_MASK (0x1u << 0xCu) /* Out1 bit field mask */ +#define UART_PL011_CR_OUT2_MASK (0x1u << 0xDu) /* Out2 bit field mask */ +#define UART_PL011_CR_RTSE_MASK (0x1u << 0xEu) /* RTS hardware flow control enable bit mask */ +#define UART_PL011_CR_CTSE_MASK (0x1u << 0xFu) /* CTS hardware flow control enable bit mask */ + + +/* Interrupt FIFO Level Select Register Transmit bit offset */ +#define UART_PL011_IFLS_TX_BIT_OFFSET 0x0u +/* Interrupt FIFO Level Select Register Receive bit offset */ +#define UART_PL011_IFLS_RX_BIT_OFFSET 0x3u + +#define UART_PL011_RX_FIFO_LVL_1_8 (0x0u << UART_PL011_IFLS_RX_BIT_OFFSET) +#define UART_PL011_RX_FIFO_LVL_1_4 (0x1u << UART_PL011_IFLS_RX_BIT_OFFSET) +#define UART_PL011_RX_FIFO_LVL_1_2 (0x2u << UART_PL011_IFLS_RX_BIT_OFFSET) +#define UART_PL011_RX_FIFO_LVL_3_4 (0x3u << UART_PL011_IFLS_RX_BIT_OFFSET) +#define UART_PL011_RX_FIFO_LVL_7_8 (0x4u << UART_PL011_IFLS_RX_BIT_OFFSET) + +#define UART_PL011_TX_FIFO_LVL_1_8 (0x0u << UART_PL011_IFLS_TX_BIT_OFFSET) +#define UART_PL011_TX_FIFO_LVL_1_4 (0x1u << UART_PL011_IFLS_TX_BIT_OFFSET) +#define UART_PL011_TX_FIFO_LVL_1_2 (0x2u << UART_PL011_IFLS_TX_BIT_OFFSET) +#define UART_PL011_TX_FIFO_LVL_3_4 (0x3u << UART_PL011_IFLS_TX_BIT_OFFSET) +#define UART_PL011_TX_FIFO_LVL_7_8 (0x4u << UART_PL011_IFLS_TX_BIT_OFFSET) + +/* Default register values of UART PL011 */ +#define UART_PL011_DEFAULT_DATA_REG_VALUE (0x0u) +#define UART_PL011_DEFAULT_ECR_VALUE (0xFFu) +#define UART_PL011_DEFAULT_ILPR_VALUE (0x0u) +#define UART_PL011_DEFAULT_IBRD_REG_VALUE (0x0u) +#define UART_PL011_DEFAULT_FBRD_REG_VALUE (0x0u) +/* Clear UARTLCR */ +#define UART_PL011_DEFAULT_LCR_H_VALUE (0x0u) +#define UART_PL011_DEFAULT_CTRL_REG_VALUE (0x0300u) + +#define UART_PL011_DEFAULT_IFLS_REG_VALUE ( \ + UART_PL011_RX_FIFO_LVL_1_2 \ + | UART_PL011_TX_FIFO_LVL_7_8) + +/* Clear interrupt mask */ +#define UART_PL011_DEFAULT_IMSC_REG_VALUE (0x0u) +/* Clear interrupt */ +#define UART_PL011_DEFAULT_ICR_VALUE (0x7FFu) +#define UART_PL011_DEFAULT_DMACR_VALUE (0x0u) + +#define FREQ_IRLPBAUD16_MIN (1420000u) /* 1.42 MHz */ +#define FREQ_IRLPBAUD16_MAX (2120000u) /* 2.12 MHz */ +#define SAMPLING_FACTOR (16u) +#define UART_PL011_FBRD_WIDTH (6u) + +/** + * \brief ARM UART PL011 error enumeration types + */ +typedef enum UartPl011Error { + UART_PL011_ERR_NONE = (0x0u), + UART_PL011_ERR_RX_FRAME = UART_PL011_RSR_FRAMING_ERROR_MASK, + UART_PL011_ERR_RX_PARITY = UART_PL011_RSR_PARITY_ERROR_MASK, + UART_PL011_ERR_RX_BREAK = UART_PL011_RSR_BREAK_ERROR_MASK, + UART_PL011_ERR_RX_OVERFLOW = UART_PL011_RSR_OVERRUN_ERROR_MASK, + UART_PL011_ERR_INVALID_ARG = (UART_PL011_RSR_RX_ERROR_MASK + 1), + UART_PL011_ERR_NOT_READY, + UART_PL011_ERR_INVALID_BAUD, + UART_PL011_ERR_NOT_INIT, +} UartPl011Error; + +static inline void UartPl011Enable(struct UartRegisterMap *regMap) +{ + regMap->cr |= UART_PL011_CR_UARTEN_MASK; +} + +static inline void UartPl011Disable(struct UartRegisterMap *regMap) +{ + regMap->cr &= ~UART_PL011_CR_UARTEN_MASK; +} + +static inline bool UartPl011IsEnabled(struct UartRegisterMap *regMap) +{ + return (bool)(regMap->cr & UART_PL011_CR_UARTEN_MASK); +} + +static inline bool UartPl011IsBusy(struct UartRegisterMap *regMap) +{ + return (bool)(regMap->fr & UART_PL011_FR_BUSY_MASK); +} + +void UartPl011SetLcrBits(struct UartRegisterMap *regMap, uint32_t bits); + +static inline void UartPl011Write(struct UartRegisterMap *regMap, uint8_t byte) +{ + while (UartPl011IsBusy(regMap)); + regMap->dr = byte; +} + +UartPl011Error UartPl011SetBaudrate(struct UartRegisterMap *regMap, uint32_t clk, uint32_t baudrate); + +void UartPl011SetDataFormat(struct UartRegisterMap *regMap, uint32_t wordLen, uint32_t parity, uint32_t stopBits); + +void UartPl011ResetRegisters(struct UartRegisterMap *regMap); + +static inline void UartPl011EnableFifo(struct UartRegisterMap *regMap) +{ + UartPl011SetLcrBits(regMap, UART_PL011_LCR_H_FEN_MASK); +} + +#ifdef __cplusplus +} +#endif +#endif /* UART_PL011_SAMPLE_H */ + diff --git a/sample/platform/uart/src/BUILD.gn b/sample/platform/uart/src/BUILD.gn new file mode 100755 index 00000000..a979792d --- /dev/null +++ b/sample/platform/uart/src/BUILD.gn @@ -0,0 +1,22 @@ +# Copyright (c) 2021 Huawei Device Co., Ltd. +# +# 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. + +import("//drivers/adapter/khdf/liteos/hdf.gni") + +module_switch = defined(LOSCFG_DRIVERS_HDF_PLATFORM_UART_SAMPLE) +module_name = "hdf_uart_sample" +hdf_driver(module_name) { + FRAMEWORK_UART_ROOT = "//drivers/framework/sample/platform/uart/src" + sources = [ + "$FRAMEWORK_UART_ROOT/buf_fifo.c", + "$FRAMEWORK_UART_ROOT/uart_dev_sample.c", + "$FRAMEWORK_UART_ROOT/uart_dispatch_sample.c", + "$FRAMEWORK_UART_ROOT/uart_pl011_sample.c", + "$FRAMEWORK_UART_ROOT/uart_sample.c", + ] + + include_dirs = [ "//drivers/framework/sample/platform/uart/include/" ] +} diff --git a/sample/platform/uart/src/buf_fifo.c b/sample/platform/uart/src/buf_fifo.c new file mode 100755 index 00000000..19da2dff --- /dev/null +++ b/sample/platform/uart/src/buf_fifo.c @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * 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 "buf_fifo.h" + +bool BufferFifoInit(struct BufferFifo *fifo, uint8_t *fifoBuffer, uint16_t fifoSize) +{ + if (fifoBuffer == NULL) { + return false; + } + if (!IsPowerOfTwo(fifoSize)) { + return false; + } + fifo->buffer = fifoBuffer; + fifo->bufSizeMask = fifoSize - 1; + fifo->readPosition = 0; + fifo->writePosition = 0; + return true; +} \ No newline at end of file diff --git a/sample/platform/uart/src/uart_dev_sample.c b/sample/platform/uart/src/uart_dev_sample.c new file mode 100755 index 00000000..1369188f --- /dev/null +++ b/sample/platform/uart/src/uart_dev_sample.c @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * 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_dev_sample.h" +#include "fs/fs.h" +#include "securec.h" +#include "user_copy.h" +#include "hdf_log.h" +#include "osal_mem.h" +#include "uart_pl011_sample.h" + +#define HDF_LOG_TAG uart_dev_sample +#define HDF_UART_FS_MODE 0660 + +static int32_t UartSampleDevOpen(struct file *filep) +{ + struct UartHost *host = NULL; + + if (filep == NULL || filep->f_vnode == NULL) { + return HDF_ERR_INVALID_PARAM; + } + struct drv_data *drv = (struct drv_data *)filep->f_vnode->data; + host = (struct UartHost *)drv->priv; + if (host == NULL) { + HDF_LOGE("%s: host is NULL", __func__); + return HDF_ERR_INVALID_PARAM; + } + HDF_LOGI("%s: open uart%d success", __func__, host->num); + return HDF_SUCCESS; +} +static int32_t UartSampleRelease(struct file *filep) +{ + struct UartHost *host = NULL; + + if (filep == NULL || filep->f_vnode == NULL) { + return HDF_ERR_INVALID_PARAM; + } + struct drv_data *drv = (struct drv_data *)filep->f_vnode->data; + host = (struct UartHost *)drv->priv; + if (host == NULL) { + HDF_LOGE("%s: host is NULL", __func__); + return HDF_ERR_INVALID_PARAM; + } + HDF_LOGI("%s: close uart%d success", __func__, host->num); + return HDF_SUCCESS; +} + +static ssize_t UartSampleRead(struct file *filep, char *buf, size_t count) +{ + int32_t ret; + uint8_t *tmpBuf = NULL; + struct UartHost *host = NULL; + + if (filep == NULL || filep->f_vnode == NULL) { + return HDF_ERR_INVALID_PARAM; + } + struct drv_data *drv = (struct drv_data *)filep->f_vnode->data; + host = (struct UartHost *)drv->priv; + + if (LOS_IsUserAddressRange((vaddr_t)(uintptr_t)buf, count)) { + tmpBuf = (uint8_t *)OsalMemCalloc(count); + if (tmpBuf == NULL) { + HDF_LOGE("%s: OsalMemCalloc error", __func__); + return HDF_ERR_MALLOC_FAIL; + } + ret = UartHostRead(host, tmpBuf, count); + if (ret == HDF_SUCCESS) { + ret = LOS_ArchCopyToUser(buf, tmpBuf, count); + } + OsalMemFree(tmpBuf); + return ret; + } else { + return UartHostRead(host, (uint8_t *)buf, count); + } +} + +static ssize_t UartSampleWrite(struct file *filep, const char *buf, size_t count) +{ + int32_t ret; + uint8_t *tmpBuf = NULL; + struct UartHost *host = NULL; + + if (filep == NULL || filep->f_vnode == NULL) { + return HDF_ERR_INVALID_PARAM; + } + struct drv_data *drv = (struct drv_data *)filep->f_vnode->data; + host = (struct UartHost *)drv->priv; + + if (LOS_IsUserAddressRange((vaddr_t)(uintptr_t)buf, count)) { + tmpBuf = (uint8_t *)OsalMemCalloc(count); + if (tmpBuf == NULL) { + HDF_LOGE("%s: OsalMemCalloc error", __func__); + return HDF_ERR_MALLOC_FAIL; + } + ret = LOS_ArchCopyFromUser(tmpBuf, buf, count); + if (ret != LOS_OK) { + OsalMemFree(tmpBuf); + return ret; + } + ret = UartHostWrite(host, tmpBuf, count); + OsalMemFree(tmpBuf); + return ret; + } else { + return UartHostWrite(host, (uint8_t *)buf, count); + } +} + +static int32_t UartSampleDevIoctl(struct file *filep, int32_t cmd, unsigned long arg) +{ + int32_t ret; + struct UartHost *host = NULL; + if (filep == NULL || filep->f_vnode == NULL) { + return HDF_ERR_INVALID_PARAM; + } + struct drv_data *drv = (struct drv_data *)filep->f_vnode->data; + host = (struct UartHost *)drv->priv; + if (host->priv == NULL) { + return HDF_ERR_INVALID_PARAM; + } + + ret = HDF_FAILURE; + switch (cmd) { + case UART_CFG_BAUDRATE: + ret = UartHostSetBaud(host, arg); + break; + default: + HDF_LOGE("%s cmd %d not support", __func__, cmd); + ret = HDF_ERR_NOT_SUPPORT; + break; + } + return ret; +} + +const struct file_operations_vfs g_uartSampleDevFops = { + .open = UartSampleDevOpen, + .close = UartSampleRelease, + .read = UartSampleRead, + .write = UartSampleWrite, + .ioctl = UartSampleDevIoctl, +}; + +#define MAX_DEV_NAME_SIZE 32 +static void AddRemoveUartDev(struct UartHost *host, bool add) +{ + int32_t ret; + char *devName = NULL; + + if (host == NULL || host->priv == NULL) { + HDF_LOGW("%s: invalid parameter", __func__); + return; + } + devName = (char *)OsalMemCalloc(sizeof(char) * (MAX_DEV_NAME_SIZE + 1)); + if (devName == NULL) { + HDF_LOGE("%s: OsalMemCalloc error", __func__); + return; + } + ret = snprintf_s(devName, MAX_DEV_NAME_SIZE + 1, MAX_DEV_NAME_SIZE, "/dev/uartdev-%d", host->num); + if (ret < 0) { + HDF_LOGE("%s: snprintf_s failed", __func__); + OsalMemFree(devName); + return; + } + if (add) { + if (register_driver(devName, &g_uartSampleDevFops, HDF_UART_FS_MODE, host)) { + HDF_LOGE("%s: gen /dev/uartdev-%d fail!", __func__, host->num); + OsalMemFree(devName); + return; + } + } else { + if (unregister_driver(devName)) { + HDF_LOGE("%s: remove /dev/uartdev-%d fail!", __func__, host->num); + OsalMemFree(devName); + return; + } + } + OsalMemFree(devName); +} + +void AddUartDevice(struct UartHost *host) +{ + AddRemoveUartDev(host, true); +} + +void RemoveUartDevice(struct UartHost *host) +{ + AddRemoveUartDev(host, false); +} diff --git a/sample/platform/uart/src/uart_dispatch_sample.c b/sample/platform/uart/src/uart_dispatch_sample.c new file mode 100755 index 00000000..6817896f --- /dev/null +++ b/sample/platform/uart/src/uart_dispatch_sample.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * 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_core.h" +#include "uart_dispatch_sample.h" +#include "hdf_log.h" +#include "hdf_sbuf.h" +#include "uart_pl011_sample.h" + +#define HDF_LOG_TAG uart_dispatch_sample + +static int32_t SampleDispatchWrite(struct UartDevice *device, struct HdfSBuf *txBuf) +{ + uint32_t idx; + uint32_t dataSize = 0; + const uint8_t *data = NULL; + struct UartRegisterMap *regMap = (struct UartRegisterMap *)device->resource.physBase; + + if (regMap == NULL) { + HDF_LOGE("%s: regMap is NULL", __func__); + return HDF_FAILURE; + } + + if (!HdfSbufReadBuffer(txBuf, (const void **)&data, &dataSize)) { + HDF_LOGE("%s: Failed to read sbuf", __func__); + return HDF_FAILURE; + } + regMap = (struct UartRegisterMap *)device->resource.physBase; + for (idx = 0; idx < dataSize; idx++) { + UartPl011Write(regMap, data[idx]); + } + return HDF_SUCCESS; +} + +int32_t SampleDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data, struct HdfSBuf *reply) +{ + int32_t result = HDF_FAILURE; + if (client == NULL || client->device == NULL) { + HDF_LOGE("%s: client or client->device is NULL", __func__); + return result; + } + struct UartHost *uartHost = (struct UartHost *)client->device->service; + if (uartHost == NULL) { + HDF_LOGE("%s: uartHost is NULL", __func__); + return result; + } + struct UartDevice *uartDevice = (struct UartDevice *)uartHost->priv; + if (uartDevice == NULL) { + HDF_LOGE("%s: uartDevice is NULL", __func__); + return result; + } + switch (cmdId) { + case UART_WRITE: { + result = SampleDispatchWrite(uartDevice, data); + break; + } + default: + break; + } + return result; +} diff --git a/sample/platform/uart/src/uart_pl011_sample.c b/sample/platform/uart/src/uart_pl011_sample.c new file mode 100755 index 00000000..12f2c6cf --- /dev/null +++ b/sample/platform/uart/src/uart_pl011_sample.c @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * 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_pl011_sample.h" + +void UartPl011SetLcrBits(struct UartRegisterMap *regMap, uint32_t bits) +{ + bool uartEnabled = UartPl011IsEnabled(regMap); + /* UART must be disabled before UARTLCR_H are reprogrammed */ + UartPl011Disable(regMap); + regMap->lcr |= (bits); + /* Restore uart enable state */ + if (uartEnabled) { + UartPl011Enable(regMap); + } +} + +void UartPl011UpdateLcr(struct UartRegisterMap *regMap) +{ + bool uartEnabled = UartPl011IsEnabled(regMap); + /* UART must be disabled before UARTLCR_H are reprogrammed */ + UartPl011Disable(regMap); + regMap->lcr = regMap->lcr; + /* restore uart enable state */ + if (uartEnabled) { + UartPl011Enable(regMap); + } +} + +UartPl011Error UartPl011SetBaudrate(struct UartRegisterMap *regMap, uint32_t clk, uint32_t baudrate) +{ + if (baudrate == 0) { + return UART_PL011_ERR_INVALID_ARG; + } + + uint32_t value = SAMPLING_FACTOR * baudrate; + uint32_t divider = clk / value; + uint32_t remainder = clk % value; + uint32_t fraction; + value = (SAMPLING_FACTOR * remainder) / baudrate; + fraction = (value >> 1) + (value & 1); + + regMap->ibrd = divider; + regMap->fbrd = fraction; + /* to internally update the contents of UARTIBRD or + * UARTFBRD, a UARTLCR_H write must always be performed at the end. + */ + UartPl011UpdateLcr(regMap); + return UART_PL011_ERR_NONE; +} + +void UartPl011SetDataFormat( + struct UartRegisterMap *regMap, uint32_t wordLen, uint32_t parity, uint32_t stopBits) +{ + bool uartEnabled = UartPl011IsEnabled(regMap); + uint32_t lcr = regMap->lcr & (~UART_PL011_DATA_FORMAT_MASK); + lcr |= wordLen & UART_PL011_LCR_H_WLEN_MASK; + lcr |= parity & UART_PL011_LCR_H_PARITY_MASK; + lcr |= stopBits & UART_PL011_LCR_H_STOPBIT_MASK; + /* UART must be disabled before UARTLCR_H are reprogrammed */ + UartPl011Disable(regMap); + regMap->lcr = lcr; + if (uartEnabled) { + UartPl011Enable(regMap); + } +} + +void UartPl011ResetRegisters(struct UartRegisterMap *regMap) +{ + regMap->cr = UART_PL011_DEFAULT_CTRL_REG_VALUE; + regMap->dr = UART_PL011_DEFAULT_DATA_REG_VALUE; + /* Clear all the errors */ + regMap->ecr = UART_PL011_DEFAULT_ECR_VALUE; + regMap->ilpr = UART_PL011_DEFAULT_ILPR_VALUE; + regMap->ibrd = UART_PL011_DEFAULT_IBRD_REG_VALUE; + regMap->fbrd = UART_PL011_DEFAULT_FBRD_REG_VALUE; + regMap->lcr = UART_PL011_DEFAULT_LCR_H_VALUE; + regMap->ifls = UART_PL011_DEFAULT_IFLS_REG_VALUE; + /* Clear all interrupt mask */ + regMap->imsc = UART_PL011_DEFAULT_IMSC_REG_VALUE; + /* Clear all interrupts */ + regMap->icr = UART_PL011_DEFAULT_ICR_VALUE; + regMap->dmacr = UART_PL011_DEFAULT_DMACR_VALUE; +} + diff --git a/sample/platform/uart/src/uart_sample.c b/sample/platform/uart/src/uart_sample.c new file mode 100755 index 00000000..19678890 --- /dev/null +++ b/sample/platform/uart/src/uart_sample.c @@ -0,0 +1,344 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * 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 "device_resource_if.h" +#include "buf_fifo.h" +#include "hdf_device_desc.h" +#include "hdf_log.h" +#include "hisoc/uart.h" +#include "osal_io.h" +#include "osal_mem.h" +#include "uart_core.h" +#include "uart_dev_sample.h" +#include "uart_dispatch_sample.h" +#include "uart_pl011_sample.h" + +#define HDF_LOG_TAG uart_sample +#define UART_RX_FIFO_SIZE 128 + +static uint8_t g_fifoBuffer[UART_RX_FIFO_SIZE] = {0}; + +/* HdfDriverEntry method definitions */ +static int32_t SampleUartDriverBind(struct HdfDeviceObject *device); +static int32_t SampleUartDriverInit(struct HdfDeviceObject *device); +static void SampleUartDriverRelease(struct HdfDeviceObject *device); + +/* HdfDriverEntry definitions */ +struct HdfDriverEntry g_sampleUartDriverEntry = { + .moduleVersion = 1, + .moduleName = "UART_SAMPLE", + .Bind = SampleUartDriverBind, + .Init = SampleUartDriverInit, + .Release = SampleUartDriverRelease, +}; + +// Initialize HdfDriverEntry +HDF_INIT(g_sampleUartDriverEntry); + +/* UartHostMethod method definitions */ +static int32_t SampleUartHostInit(struct UartHost *host); +static int32_t SampleUartHostDeinit(struct UartHost *host); +static int32_t SampleUartHostWrite(struct UartHost *host, uint8_t *data, uint32_t size); +static int32_t SampleUartHostSetBaud(struct UartHost *host, uint32_t baudRate); +static int32_t SampleUartHostGetBaud(struct UartHost *host, uint32_t *baudRate); + +/* UartHostMethod definitions */ +struct UartHostMethod g_sampleUartHostMethod = { + .Init = SampleUartHostInit, + .Deinit = SampleUartHostDeinit, + .Read = NULL, + .Write = SampleUartHostWrite, + .SetBaud = SampleUartHostSetBaud, + .GetBaud = SampleUartHostGetBaud, + .SetAttribute = NULL, + .GetAttribute = NULL, + .SetTransMode = NULL, +}; + +/* UartHostMethod implementations */ +static int32_t SampleUartHostInit(struct UartHost *host) +{ + HDF_LOGD("%s: Enter", __func__); + if (host == NULL) { + HDF_LOGW("%s: invalid parameter", __func__); + return HDF_ERR_INVALID_PARAM; + } + return HDF_SUCCESS; +} + +static int32_t SampleUartHostDeinit(struct UartHost *host) +{ + HDF_LOGD("%s: Enter", __func__); + if (host == NULL) { + HDF_LOGW("%s: invalid parameter", __func__); + return HDF_ERR_INVALID_PARAM; + } + return HDF_SUCCESS; +} + +static int32_t SampleUartHostWrite(struct UartHost *host, uint8_t *data, uint32_t size) +{ + uint32_t idx; + struct UartRegisterMap *regMap = NULL; + struct UartDevice *device = NULL; + HDF_LOGD("%s: Enter", __func__); + + if (host == NULL || data == NULL || size == 0) { + HDF_LOGW("%s: invalid parameter", __func__); + return HDF_ERR_INVALID_PARAM; + } + device = (struct UartDevice *)host->priv; + if (device == NULL) { + HDF_LOGW("%s: device is NULL", __func__); + return HDF_ERR_INVALID_PARAM; + } + regMap = (struct UartRegisterMap *)device->resource.physBase; + for (idx = 0; idx < size; idx++) { + UartPl011Write(regMap, data[idx]); + } + return HDF_SUCCESS; +} + +static int32_t SampleUartHostSetBaud(struct UartHost *host, uint32_t baudRate) +{ + struct UartDevice *device = NULL; + struct UartRegisterMap *regMap = NULL; + UartPl011Error err; + HDF_LOGD("%s: Enter", __func__); + + if (host == NULL) { + HDF_LOGW("%s: invalid parameter", __func__); + return HDF_ERR_INVALID_PARAM; + } + device = (struct UartDevice *)host->priv; + if (device == NULL) { + HDF_LOGW("%s: device is NULL", __func__); + return HDF_ERR_INVALID_PARAM; + } + regMap = (struct UartRegisterMap *)device->resource.physBase; + if (device->state != UART_DEVICE_INITIALIZED) { + return UART_PL011_ERR_NOT_INIT; + } + if (baudRate == 0) { + return UART_PL011_ERR_INVALID_BAUD; + } + err = UartPl011SetBaudrate(regMap, device->uartClk, baudRate); + if (err == UART_PL011_ERR_NONE) { + device->baudrate = baudRate; + } + return err; +} + +static int32_t SampleUartHostGetBaud(struct UartHost *host, uint32_t *baudRate) +{ + struct UartDevice *device = NULL; + HDF_LOGD("%s: Enter", __func__); + + if (host == NULL) { + HDF_LOGW("%s: invalid parameter", __func__); + return HDF_ERR_INVALID_PARAM; + } + device = (struct UartDevice *)host->priv; + if (device == NULL) { + HDF_LOGW("%s: device is NULL", __func__); + return HDF_ERR_INVALID_PARAM; + } + *baudRate = device->baudrate; + return HDF_SUCCESS; +} + +static int InitUartDevice(struct UartDevice *device) +{ + UartPl011Error err; + struct UartResource *resource = &device->resource; + struct UartRegisterMap *regMap = (struct UartRegisterMap *)resource->physBase; + if ((resource->uartClk == 0) || (resource->baudrate == 0)) { + return HDF_ERR_INVALID_PARAM; + } + /* Updating the system clock */ + device->uartClk = resource->uartClk; + uart_clk_cfg(0, true); + /* clear and reset registers. */ + UartPl011ResetRegisters(regMap); + /* set baud rate as device config */ + err = UartPl011SetBaudrate(regMap, resource->uartClk, resource->baudrate); + if (err != UART_PL011_ERR_NONE) { + return HDF_FAILURE; + } + /* set the data format as device config */ + UartPl011SetDataFormat(regMap, resource->wlen, resource->parity, resource->stopBit); + /* Enabling the FIFOs */ + UartPl011EnableFifo(regMap); + UartPl011Enable(regMap); + BufferFifoInit(&device->rxFifo, g_fifoBuffer, UART_RX_FIFO_SIZE); + device->state = UART_DEVICE_INITIALIZED; + return HDF_SUCCESS; +} + +static uint32_t GetUartDeviceResource( + struct UartDevice *device, const struct DeviceResourceNode *resourceNode) +{ + struct UartResource *resource = &device->resource; + struct DeviceResourceIface *dri = NULL; + dri = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE); + if (dri == NULL || dri->GetUint32 == NULL) { + HDF_LOGE("DeviceResourceIface is invalid"); + return HDF_FAILURE; + } + + if (dri->GetUint32(resourceNode, "num", &resource->num, 0) != HDF_SUCCESS) { + HDF_LOGE("uart config read num fail"); + return HDF_FAILURE; + } + if (dri->GetUint32(resourceNode, "base", &resource->base, 0) != HDF_SUCCESS) { + HDF_LOGE("uart config read base fail"); + return HDF_FAILURE; + } + resource->physBase = (unsigned long)OsalIoRemap(resource->base, 0x48); + if (resource->physBase == 0) { + HDF_LOGE("uart config fail to remap physBase"); + return HDF_FAILURE; + } + if (dri->GetUint32(resourceNode, "irqNum", &resource->irqNum, 0) != HDF_SUCCESS) { + HDF_LOGE("uart config read irqNum 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, "wlen", &resource->wlen, 0) != HDF_SUCCESS) { + HDF_LOGE("uart config read wlen 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; + } + if (dri->GetUint32(resourceNode, "uartClk", &resource->uartClk, 0) != HDF_SUCCESS) { + HDF_LOGE("uart config read uartClk fail"); + return HDF_FAILURE; + } + return HDF_SUCCESS; +} + +static int32_t AttachUartDevice(struct UartHost *host, struct HdfDeviceObject *device) +{ + int32_t ret; + struct UartDevice *uartDevice = NULL; + if (device->property == NULL) { + HDF_LOGW("%s: property is NULL", __func__); + return HDF_FAILURE; + } + uartDevice = (struct UartDevice *)OsalMemCalloc(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; + } + host->num = uartDevice->resource.num; + host->priv = uartDevice; + AddUartDevice(host); + return InitUartDevice(uartDevice); +} + +static void DeinitUartDevice(struct UartDevice *device) +{ + struct UartRegisterMap *regMap = (struct UartRegisterMap *)device->resource.physBase; + /* wait for uart enter idle. */ + while (UartPl011IsBusy(regMap)) { } + UartPl011ResetRegisters(regMap); + uart_clk_cfg(0, false); + OsalIoUnmap((void *)device->resource.physBase); + device->state = UART_DEVICE_UNINITIALIZED; +} + +static void DetachUartDevice(struct UartHost *host) +{ + struct UartDevice *uartDevice = NULL; + + if (host->priv == NULL) { + HDF_LOGW("%s: invalid parameter", __func__); + return; + } + uartDevice = host->priv; + DeinitUartDevice(uartDevice); + (void)OsalMemFree(uartDevice); + host->priv = NULL; +} + +/* HdfDriverEntry implementations */ +static int32_t SampleUartDriverBind(struct HdfDeviceObject *device) +{ + struct UartHost *uartHost = NULL; + HDF_LOGD("%s: Enter", __func__); + + if (device == NULL) { + return HDF_ERR_INVALID_OBJECT; + } + + uartHost = UartHostCreate(device); + if (uartHost == NULL) { + HDF_LOGE("%s: UartHostCreate failed", __func__); + return HDF_FAILURE; + } + uartHost->service.Dispatch = SampleDispatch; + return HDF_SUCCESS; +} + +static int32_t SampleUartDriverInit(struct HdfDeviceObject *device) +{ + int32_t ret; + struct UartHost *host = NULL; + HDF_LOGD("%s: Enter", __func__); + + 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 = AttachUartDevice(host, device); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: attach error", __func__); + return HDF_FAILURE; + } + host->method = &g_sampleUartHostMethod; + return ret; +} + +static void SampleUartDriverRelease(struct HdfDeviceObject *device) +{ + struct UartHost *host = NULL; + HDF_LOGD("%s: Enter", __func__); + + 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) { + DetachUartDevice(host); + } + UartHostDestroy(host); +}